My Marlin configs for Fabrikator Mini and CTC i3 Pro B
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

abl.cpp 15KB

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