My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

abl.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "../../../inc/MarlinConfig.h"
  23. #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
  24. #include "abl.h"
  25. #include "../../../module/motion.h"
  26. int bilinear_grid_spacing[2], bilinear_start[2];
  27. float bilinear_grid_factor[2],
  28. z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
  29. /**
  30. * Extrapolate a single point from its neighbors
  31. */
  32. static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
  33. #if ENABLED(DEBUG_LEVELING_FEATURE)
  34. if (DEBUGGING(LEVELING)) {
  35. SERIAL_ECHOPGM("Extrapolate [");
  36. if (x < 10) SERIAL_CHAR(' ');
  37. SERIAL_ECHO((int)x);
  38. SERIAL_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' ');
  39. SERIAL_CHAR(' ');
  40. if (y < 10) SERIAL_CHAR(' ');
  41. SERIAL_ECHO((int)y);
  42. SERIAL_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' ');
  43. SERIAL_CHAR(']');
  44. }
  45. #endif
  46. if (!isnan(z_values[x][y])) {
  47. #if ENABLED(DEBUG_LEVELING_FEATURE)
  48. if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
  49. #endif
  50. return; // Don't overwrite good values.
  51. }
  52. SERIAL_EOL();
  53. // Get X neighbors, Y neighbors, and XY neighbors
  54. const uint8_t x1 = x + xdir, y1 = y + ydir, x2 = x1 + xdir, y2 = y1 + ydir;
  55. float a1 = z_values[x1][y ], a2 = z_values[x2][y ],
  56. b1 = z_values[x ][y1], b2 = z_values[x ][y2],
  57. c1 = z_values[x1][y1], c2 = z_values[x2][y2];
  58. // Treat far unprobed points as zero, near as equal to far
  59. if (isnan(a2)) a2 = 0.0;
  60. if (isnan(a1)) a1 = a2;
  61. if (isnan(b2)) b2 = 0.0;
  62. if (isnan(b1)) b1 = b2;
  63. if (isnan(c2)) c2 = 0.0;
  64. if (isnan(c1)) c1 = c2;
  65. const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;
  66. // Take the average instead of the median
  67. z_values[x][y] = (a + b + c) / 3.0;
  68. // Median is robust (ignores outliers).
  69. // z_values[x][y] = (a < b) ? ((b < c) ? b : (c < a) ? a : c)
  70. // : ((c < b) ? b : (a < c) ? a : c);
  71. }
  72. //Enable this if your SCARA uses 180° of total area
  73. //#define EXTRAPOLATE_FROM_EDGE
  74. #if ENABLED(EXTRAPOLATE_FROM_EDGE)
  75. #if GRID_MAX_POINTS_X < GRID_MAX_POINTS_Y
  76. #define HALF_IN_X
  77. #elif GRID_MAX_POINTS_Y < GRID_MAX_POINTS_X
  78. #define HALF_IN_Y
  79. #endif
  80. #endif
  81. /**
  82. * Fill in the unprobed points (corners of circular print surface)
  83. * using linear extrapolation, away from the center.
  84. */
  85. void extrapolate_unprobed_bed_level() {
  86. #ifdef HALF_IN_X
  87. constexpr uint8_t ctrx2 = 0, xlen = GRID_MAX_POINTS_X - 1;
  88. #else
  89. constexpr uint8_t ctrx1 = (GRID_MAX_POINTS_X - 1) / 2, // left-of-center
  90. ctrx2 = (GRID_MAX_POINTS_X) / 2, // right-of-center
  91. xlen = ctrx1;
  92. #endif
  93. #ifdef HALF_IN_Y
  94. constexpr uint8_t ctry2 = 0, ylen = GRID_MAX_POINTS_Y - 1;
  95. #else
  96. constexpr uint8_t ctry1 = (GRID_MAX_POINTS_Y - 1) / 2, // top-of-center
  97. ctry2 = (GRID_MAX_POINTS_Y) / 2, // bottom-of-center
  98. ylen = ctry1;
  99. #endif
  100. for (uint8_t xo = 0; xo <= xlen; xo++)
  101. for (uint8_t yo = 0; yo <= ylen; yo++) {
  102. uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo;
  103. #ifndef HALF_IN_X
  104. const uint8_t x1 = ctrx1 - xo;
  105. #endif
  106. #ifndef HALF_IN_Y
  107. const uint8_t y1 = ctry1 - yo;
  108. #ifndef HALF_IN_X
  109. extrapolate_one_point(x1, y1, +1, +1); // left-below + +
  110. #endif
  111. extrapolate_one_point(x2, y1, -1, +1); // right-below - +
  112. #endif
  113. #ifndef HALF_IN_X
  114. extrapolate_one_point(x1, y2, +1, -1); // left-above + -
  115. #endif
  116. extrapolate_one_point(x2, y2, -1, -1); // right-above - -
  117. }
  118. }
  119. void print_bilinear_leveling_grid() {
  120. SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
  121. print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3,
  122. [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
  123. );
  124. }
  125. #if ENABLED(ABL_BILINEAR_SUBDIVISION)
  126. #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_POINTS_X - 1) * (BILINEAR_SUBDIVISIONS) + 1
  127. #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_POINTS_Y - 1) * (BILINEAR_SUBDIVISIONS) + 1
  128. #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
  129. #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
  130. float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
  131. int bilinear_grid_spacing_virt[2] = { 0 };
  132. float bilinear_grid_factor_virt[2] = { 0 };
  133. void print_bilinear_leveling_grid_virt() {
  134. SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
  135. print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
  136. [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; }
  137. );
  138. }
  139. #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
  140. float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
  141. uint8_t ep = 0, ip = 1;
  142. if (!x || x == ABL_TEMP_POINTS_X - 1) {
  143. if (x) {
  144. ep = GRID_MAX_POINTS_X - 1;
  145. ip = GRID_MAX_POINTS_X - 2;
  146. }
  147. if (WITHIN(y, 1, ABL_TEMP_POINTS_Y - 2))
  148. return LINEAR_EXTRAPOLATION(
  149. z_values[ep][y - 1],
  150. z_values[ip][y - 1]
  151. );
  152. else
  153. return LINEAR_EXTRAPOLATION(
  154. bed_level_virt_coord(ep + 1, y),
  155. bed_level_virt_coord(ip + 1, y)
  156. );
  157. }
  158. if (!y || y == ABL_TEMP_POINTS_Y - 1) {
  159. if (y) {
  160. ep = GRID_MAX_POINTS_Y - 1;
  161. ip = GRID_MAX_POINTS_Y - 2;
  162. }
  163. if (WITHIN(x, 1, ABL_TEMP_POINTS_X - 2))
  164. return LINEAR_EXTRAPOLATION(
  165. z_values[x - 1][ep],
  166. z_values[x - 1][ip]
  167. );
  168. else
  169. return LINEAR_EXTRAPOLATION(
  170. bed_level_virt_coord(x, ep + 1),
  171. bed_level_virt_coord(x, ip + 1)
  172. );
  173. }
  174. return z_values[x - 1][y - 1];
  175. }
  176. static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
  177. return (
  178. p[i-1] * -t * sq(1 - t)
  179. + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t))
  180. + p[i+1] * t * (1 + 4 * t - 3 * sq(t))
  181. - p[i+2] * sq(t) * (1 - t)
  182. ) * 0.5;
  183. }
  184. static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const float &tx, const float &ty) {
  185. float row[4], column[4];
  186. for (uint8_t i = 0; i < 4; i++) {
  187. for (uint8_t j = 0; j < 4; j++) {
  188. column[j] = bed_level_virt_coord(i + x - 1, j + y - 1);
  189. }
  190. row[i] = bed_level_virt_cmr(column, 1, ty);
  191. }
  192. return bed_level_virt_cmr(row, 1, tx);
  193. }
  194. void bed_level_virt_interpolate() {
  195. bilinear_grid_spacing_virt[X_AXIS] = bilinear_grid_spacing[X_AXIS] / (BILINEAR_SUBDIVISIONS);
  196. bilinear_grid_spacing_virt[Y_AXIS] = bilinear_grid_spacing[Y_AXIS] / (BILINEAR_SUBDIVISIONS);
  197. bilinear_grid_factor_virt[X_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[X_AXIS]);
  198. bilinear_grid_factor_virt[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[Y_AXIS]);
  199. for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
  200. for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
  201. for (uint8_t ty = 0; ty < BILINEAR_SUBDIVISIONS; ty++)
  202. for (uint8_t tx = 0; tx < BILINEAR_SUBDIVISIONS; tx++) {
  203. if ((ty && y == GRID_MAX_POINTS_Y - 1) || (tx && x == GRID_MAX_POINTS_X - 1))
  204. continue;
  205. z_values_virt[x * (BILINEAR_SUBDIVISIONS) + tx][y * (BILINEAR_SUBDIVISIONS) + ty] =
  206. bed_level_virt_2cmr(
  207. x + 1,
  208. y + 1,
  209. (float)tx / (BILINEAR_SUBDIVISIONS),
  210. (float)ty / (BILINEAR_SUBDIVISIONS)
  211. );
  212. }
  213. }
  214. #endif // ABL_BILINEAR_SUBDIVISION
  215. // Refresh after other values have been updated
  216. void refresh_bed_level() {
  217. bilinear_grid_factor[X_AXIS] = RECIPROCAL(bilinear_grid_spacing[X_AXIS]);
  218. bilinear_grid_factor[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing[Y_AXIS]);
  219. #if ENABLED(ABL_BILINEAR_SUBDIVISION)
  220. bed_level_virt_interpolate();
  221. #endif
  222. }
  223. #if ENABLED(ABL_BILINEAR_SUBDIVISION)
  224. #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt[A]
  225. #define ABL_BG_FACTOR(A) bilinear_grid_factor_virt[A]
  226. #define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X
  227. #define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y
  228. #define ABL_BG_GRID(X,Y) z_values_virt[X][Y]
  229. #else
  230. #define ABL_BG_SPACING(A) bilinear_grid_spacing[A]
  231. #define ABL_BG_FACTOR(A) bilinear_grid_factor[A]
  232. #define ABL_BG_POINTS_X GRID_MAX_POINTS_X
  233. #define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y
  234. #define ABL_BG_GRID(X,Y) z_values[X][Y]
  235. #endif
  236. // Get the Z adjustment for non-linear bed leveling
  237. float bilinear_z_offset(const float raw[XYZ]) {
  238. static float z1, d2, z3, d4, L, D, ratio_x, ratio_y,
  239. last_x = -999.999, last_y = -999.999;
  240. // Whole units for the grid line indices. Constrained within bounds.
  241. static int8_t gridx, gridy, nextx, nexty,
  242. last_gridx = -99, last_gridy = -99;
  243. // XY relative to the probed area
  244. const float rx = raw[X_AXIS] - bilinear_start[X_AXIS],
  245. ry = raw[Y_AXIS] - bilinear_start[Y_AXIS];
  246. #if ENABLED(EXTRAPOLATE_BEYOND_GRID)
  247. // Keep using the last grid box
  248. #define FAR_EDGE_OR_BOX 2
  249. #else
  250. // Just use the grid far edge
  251. #define FAR_EDGE_OR_BOX 1
  252. #endif
  253. if (last_x != rx) {
  254. last_x = rx;
  255. ratio_x = rx * ABL_BG_FACTOR(X_AXIS);
  256. const float gx = constrain(FLOOR(ratio_x), 0, ABL_BG_POINTS_X - FAR_EDGE_OR_BOX);
  257. ratio_x -= gx; // Subtract whole to get the ratio within the grid box
  258. #if DISABLED(EXTRAPOLATE_BEYOND_GRID)
  259. // Beyond the grid maintain height at grid edges
  260. NOLESS(ratio_x, 0); // Never < 0.0. (> 1.0 is ok when nextx==gridx.)
  261. #endif
  262. gridx = gx;
  263. nextx = MIN(gridx + 1, ABL_BG_POINTS_X - 1);
  264. }
  265. if (last_y != ry || last_gridx != gridx) {
  266. if (last_y != ry) {
  267. last_y = ry;
  268. ratio_y = ry * ABL_BG_FACTOR(Y_AXIS);
  269. const float gy = constrain(FLOOR(ratio_y), 0, ABL_BG_POINTS_Y - FAR_EDGE_OR_BOX);
  270. ratio_y -= gy;
  271. #if DISABLED(EXTRAPOLATE_BEYOND_GRID)
  272. // Beyond the grid maintain height at grid edges
  273. NOLESS(ratio_y, 0); // Never < 0.0. (> 1.0 is ok when nexty==gridy.)
  274. #endif
  275. gridy = gy;
  276. nexty = MIN(gridy + 1, ABL_BG_POINTS_Y - 1);
  277. }
  278. if (last_gridx != gridx || last_gridy != gridy) {
  279. last_gridx = gridx;
  280. last_gridy = gridy;
  281. // Z at the box corners
  282. z1 = ABL_BG_GRID(gridx, gridy); // left-front
  283. d2 = ABL_BG_GRID(gridx, nexty) - z1; // left-back (delta)
  284. z3 = ABL_BG_GRID(nextx, gridy); // right-front
  285. d4 = ABL_BG_GRID(nextx, nexty) - z3; // right-back (delta)
  286. }
  287. // Bilinear interpolate. Needed since ry or gridx has changed.
  288. L = z1 + d2 * ratio_y; // Linear interp. LF -> LB
  289. const float R = z3 + d4 * ratio_y; // Linear interp. RF -> RB
  290. D = R - L;
  291. }
  292. const float offset = L + ratio_x * D; // the offset almost always changes
  293. /*
  294. static float last_offset = 0;
  295. if (ABS(last_offset - offset) > 0.2) {
  296. SERIAL_ECHOPGM("Sudden Shift at ");
  297. SERIAL_ECHOPAIR("x=", rx);
  298. SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[X_AXIS]);
  299. SERIAL_ECHOLNPAIR(" -> gridx=", gridx);
  300. SERIAL_ECHOPAIR(" y=", ry);
  301. SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[Y_AXIS]);
  302. SERIAL_ECHOLNPAIR(" -> gridy=", gridy);
  303. SERIAL_ECHOPAIR(" ratio_x=", ratio_x);
  304. SERIAL_ECHOLNPAIR(" ratio_y=", ratio_y);
  305. SERIAL_ECHOPAIR(" z1=", z1);
  306. SERIAL_ECHOPAIR(" z2=", z2);
  307. SERIAL_ECHOPAIR(" z3=", z3);
  308. SERIAL_ECHOLNPAIR(" z4=", z4);
  309. SERIAL_ECHOPAIR(" L=", L);
  310. SERIAL_ECHOPAIR(" R=", R);
  311. SERIAL_ECHOLNPAIR(" offset=", offset);
  312. }
  313. last_offset = offset;
  314. //*/
  315. return offset;
  316. }
  317. #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
  318. #define CELL_INDEX(A,V) ((V - bilinear_start[_AXIS(A)]) * ABL_BG_FACTOR(_AXIS(A)))
  319. /**
  320. * Prepare a bilinear-leveled linear move on Cartesian,
  321. * splitting the move where it crosses grid borders.
  322. */
  323. void bilinear_line_to_destination(const float fr_mm_s, uint16_t x_splits, uint16_t y_splits) {
  324. // Get current and destination cells for this line
  325. int cx1 = CELL_INDEX(X, current_position[X_AXIS]),
  326. cy1 = CELL_INDEX(Y, current_position[Y_AXIS]),
  327. cx2 = CELL_INDEX(X, destination[X_AXIS]),
  328. cy2 = CELL_INDEX(Y, destination[Y_AXIS]);
  329. cx1 = constrain(cx1, 0, ABL_BG_POINTS_X - 2);
  330. cy1 = constrain(cy1, 0, ABL_BG_POINTS_Y - 2);
  331. cx2 = constrain(cx2, 0, ABL_BG_POINTS_X - 2);
  332. cy2 = constrain(cy2, 0, ABL_BG_POINTS_Y - 2);
  333. // Start and end in the same cell? No split needed.
  334. if (cx1 == cx2 && cy1 == cy2) {
  335. buffer_line_to_destination(fr_mm_s);
  336. set_current_from_destination();
  337. return;
  338. }
  339. #define LINE_SEGMENT_END(A) (current_position[_AXIS(A)] + (destination[_AXIS(A)] - current_position[_AXIS(A)]) * normalized_dist)
  340. float normalized_dist, end[XYZE];
  341. const int8_t gcx = MAX(cx1, cx2), gcy = MAX(cy1, cy2);
  342. // Crosses on the X and not already split on this X?
  343. // The x_splits flags are insurance against rounding errors.
  344. if (cx2 != cx1 && TEST(x_splits, gcx)) {
  345. // Split on the X grid line
  346. CBI(x_splits, gcx);
  347. COPY(end, destination);
  348. destination[X_AXIS] = bilinear_start[X_AXIS] + ABL_BG_SPACING(X_AXIS) * gcx;
  349. normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
  350. destination[Y_AXIS] = LINE_SEGMENT_END(Y);
  351. }
  352. // Crosses on the Y and not already split on this Y?
  353. else if (cy2 != cy1 && TEST(y_splits, gcy)) {
  354. // Split on the Y grid line
  355. CBI(y_splits, gcy);
  356. COPY(end, destination);
  357. destination[Y_AXIS] = bilinear_start[Y_AXIS] + ABL_BG_SPACING(Y_AXIS) * gcy;
  358. normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
  359. destination[X_AXIS] = LINE_SEGMENT_END(X);
  360. }
  361. else {
  362. // Must already have been split on these border(s)
  363. // This should be a rare case.
  364. buffer_line_to_destination(fr_mm_s);
  365. set_current_from_destination();
  366. return;
  367. }
  368. destination[Z_AXIS] = LINE_SEGMENT_END(Z);
  369. destination[E_AXIS] = LINE_SEGMENT_END(E);
  370. // Do the split and look for more borders
  371. bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
  372. // Restore destination from stack
  373. COPY(destination, end);
  374. bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
  375. }
  376. #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES
  377. #endif // AUTO_BED_LEVELING_BILINEAR