Browse Source

♻️ Refactor and fix ABL Bilinear (#23868)

tombrazier 2 years ago
parent
commit
ae53033cea
No account linked to committer's email address

+ 1
- 1
Marlin/src/core/utility.cpp View File

@@ -135,7 +135,7 @@ void safe_delay(millis_t ms) {
135 135
             const float rz = ubl.get_z_correction(current_position);
136 136
           #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
137 137
             SERIAL_ECHOPGM("ABL Adjustment Z");
138
-            const float rz = bilinear_z_offset(current_position);
138
+            const float rz = bbl.get_z_correction(current_position);
139 139
           #endif
140 140
           SERIAL_ECHO(ftostr43sign(rz, '+'));
141 141
           #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)

+ 0
- 45
Marlin/src/feature/bedlevel/abl/abl.h View File

@@ -1,45 +0,0 @@
1
-/**
2
- * Marlin 3D Printer Firmware
3
- * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
20
- *
21
- */
22
-#pragma once
23
-
24
-#include "../../../inc/MarlinConfigPre.h"
25
-
26
-extern xy_pos_t bilinear_grid_spacing, bilinear_start;
27
-extern xy_float_t bilinear_grid_factor;
28
-extern bed_mesh_t z_values;
29
-float bilinear_z_offset(const xy_pos_t &raw);
30
-
31
-void extrapolate_unprobed_bed_level();
32
-void print_bilinear_leveling_grid();
33
-void refresh_bed_level();
34
-#if ENABLED(ABL_BILINEAR_SUBDIVISION)
35
-  void print_bilinear_leveling_grid_virt();
36
-  void bed_level_virt_interpolate();
37
-#endif
38
-
39
-#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
40
-  void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
41
-#endif
42
-
43
-#define _GET_MESH_X(I) float(bilinear_start.x + (I) * bilinear_grid_spacing.x)
44
-#define _GET_MESH_Y(J) float(bilinear_start.y + (J) * bilinear_grid_spacing.y)
45
-#define Z_VALUES_ARR  z_values

Marlin/src/feature/bedlevel/abl/abl.cpp → Marlin/src/feature/bedlevel/abl/bbl.cpp View File

@@ -35,14 +35,19 @@
35 35
   #include "../../../lcd/extui/ui_api.h"
36 36
 #endif
37 37
 
38
-xy_pos_t bilinear_grid_spacing, bilinear_start;
39
-xy_float_t bilinear_grid_factor;
40
-bed_mesh_t z_values;
38
+LevelingBilinear bbl;
39
+
40
+xy_pos_t LevelingBilinear::grid_spacing,
41
+         LevelingBilinear::grid_start;
42
+xy_float_t LevelingBilinear::grid_factor;
43
+bed_mesh_t LevelingBilinear::z_values;
44
+xy_pos_t LevelingBilinear::cached_rel;
45
+xy_int8_t LevelingBilinear::cached_g;
41 46
 
42 47
 /**
43 48
  * Extrapolate a single point from its neighbors
44 49
  */
45
-static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
50
+void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
46 51
   if (!isnan(z_values[x][y])) return;
47 52
   if (DEBUGGING(LEVELING)) {
48 53
     DEBUG_ECHOPGM("Extrapolate [");
@@ -92,11 +97,26 @@ static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t
92 97
   #endif
93 98
 #endif
94 99
 
100
+void LevelingBilinear::reset() {
101
+  grid_start.reset();
102
+  grid_spacing.reset();
103
+  GRID_LOOP(x, y) {
104
+    z_values[x][y] = NAN;
105
+    TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
106
+  }
107
+}
108
+
109
+void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) {
110
+  grid_spacing = _grid_spacing;
111
+  grid_start = _grid_start;
112
+  grid_factor = grid_spacing.reciprocal();
113
+}
114
+
95 115
 /**
96 116
  * Fill in the unprobed points (corners of circular print surface)
97 117
  * using linear extrapolation, away from the center.
98 118
  */
99
-void extrapolate_unprobed_bed_level() {
119
+void LevelingBilinear::extrapolate_unprobed_bed_level() {
100 120
   #ifdef HALF_IN_X
101 121
     constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1;
102 122
   #else
@@ -131,35 +151,31 @@ void extrapolate_unprobed_bed_level() {
131 151
       #endif
132 152
       extrapolate_one_point(x2, y2, -1, -1);       // right-above - -
133 153
     }
134
-
135 154
 }
136 155
 
137
-void print_bilinear_leveling_grid() {
156
+void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL*/) {
157
+  // print internal grid(s) or just the one passed as a parameter
138 158
   SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
139
-  print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3,
140
-    [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
141
-  );
159
+  print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, _z_values ? *_z_values[0] : z_values[0]);
160
+
161
+  #if ENABLED(ABL_BILINEAR_SUBDIVISION)
162
+    if (!_z_values) {
163
+      SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
164
+      print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, z_values_virt[0]);
165
+    }
166
+  #endif
142 167
 }
143 168
 
144 169
 #if ENABLED(ABL_BILINEAR_SUBDIVISION)
145 170
 
146
-  #define ABL_GRID_POINTS_VIRT_X GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1
147
-  #define ABL_GRID_POINTS_VIRT_Y GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1
148 171
   #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
149 172
   #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
150
-  float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
151
-  xy_pos_t bilinear_grid_spacing_virt;
152
-  xy_float_t bilinear_grid_factor_virt;
153
-
154
-  void print_bilinear_leveling_grid_virt() {
155
-    SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
156
-    print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
157
-      [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; }
158
-    );
159
-  }
173
+  float LevelingBilinear::z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
174
+  xy_pos_t LevelingBilinear::grid_spacing_virt;
175
+  xy_float_t LevelingBilinear::grid_factor_virt;
160 176
 
161 177
   #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
162
-  float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
178
+  float LevelingBilinear::bed_level_virt_coord(const uint8_t x, const uint8_t y) {
163 179
     uint8_t ep = 0, ip = 1;
164 180
     if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) {
165 181
       // The requested point requires extrapolating two points beyond the mesh.
@@ -204,7 +220,7 @@ void print_bilinear_leveling_grid() {
204 220
     return z_values[x - 1][y - 1];
205 221
   }
206 222
 
207
-  static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
223
+  float LevelingBilinear::bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
208 224
     return (
209 225
         p[i-1] * -t * sq(1 - t)
210 226
       + p[i]   * (2 - 5 * sq(t) + 3 * t * sq(t))
@@ -213,7 +229,7 @@ void print_bilinear_leveling_grid() {
213 229
     ) * 0.5f;
214 230
   }
215 231
 
216
-  static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) {
232
+  float LevelingBilinear::bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) {
217 233
     float row[4], column[4];
218 234
     LOOP_L_N(i, 4) {
219 235
       LOOP_L_N(j, 4) {
@@ -224,9 +240,9 @@ void print_bilinear_leveling_grid() {
224 240
     return bed_level_virt_cmr(row, 1, tx);
225 241
   }
226 242
 
227
-  void bed_level_virt_interpolate() {
228
-    bilinear_grid_spacing_virt = bilinear_grid_spacing / (BILINEAR_SUBDIVISIONS);
229
-    bilinear_grid_factor_virt = bilinear_grid_spacing_virt.reciprocal();
243
+  void LevelingBilinear::bed_level_virt_interpolate() {
244
+    grid_spacing_virt = grid_spacing / (BILINEAR_SUBDIVISIONS);
245
+    grid_factor_virt = grid_spacing_virt.reciprocal();
230 246
     LOOP_L_N(y, GRID_MAX_POINTS_Y)
231 247
       LOOP_L_N(x, GRID_MAX_POINTS_X)
232 248
         LOOP_L_N(ty, BILINEAR_SUBDIVISIONS)
@@ -244,38 +260,40 @@ void print_bilinear_leveling_grid() {
244 260
   }
245 261
 #endif // ABL_BILINEAR_SUBDIVISION
246 262
 
263
+
247 264
 // Refresh after other values have been updated
248
-void refresh_bed_level() {
249
-  bilinear_grid_factor = bilinear_grid_spacing.reciprocal();
265
+void LevelingBilinear::refresh_bed_level() {
250 266
   TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
267
+  cached_rel.x = cached_rel.y = -999.999;
268
+  cached_g.x = cached_g.y = -99;
251 269
 }
252 270
 
253 271
 #if ENABLED(ABL_BILINEAR_SUBDIVISION)
254
-  #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt.A
255
-  #define ABL_BG_FACTOR(A)  bilinear_grid_factor_virt.A
272
+  #define ABL_BG_SPACING(A) grid_spacing_virt.A
273
+  #define ABL_BG_FACTOR(A)  grid_factor_virt.A
256 274
   #define ABL_BG_POINTS_X   ABL_GRID_POINTS_VIRT_X
257 275
   #define ABL_BG_POINTS_Y   ABL_GRID_POINTS_VIRT_Y
258 276
   #define ABL_BG_GRID(X,Y)  z_values_virt[X][Y]
259 277
 #else
260
-  #define ABL_BG_SPACING(A) bilinear_grid_spacing.A
261
-  #define ABL_BG_FACTOR(A)  bilinear_grid_factor.A
278
+  #define ABL_BG_SPACING(A) grid_spacing.A
279
+  #define ABL_BG_FACTOR(A)  grid_factor.A
262 280
   #define ABL_BG_POINTS_X   GRID_MAX_POINTS_X
263 281
   #define ABL_BG_POINTS_Y   GRID_MAX_POINTS_Y
264 282
   #define ABL_BG_GRID(X,Y)  z_values[X][Y]
265 283
 #endif
266 284
 
267 285
 // Get the Z adjustment for non-linear bed leveling
268
-float bilinear_z_offset(const xy_pos_t &raw) {
286
+float LevelingBilinear::get_z_correction(const xy_pos_t &raw) {
269 287
 
270 288
   static float z1, d2, z3, d4, L, D;
271 289
 
272
-  static xy_pos_t prev { -999.999, -999.999 }, ratio;
290
+  static xy_pos_t ratio;
273 291
 
274 292
   // Whole units for the grid line indices. Constrained within bounds.
275
-  static xy_int8_t thisg, nextg, lastg { -99, -99 };
293
+  static xy_int8_t thisg, nextg;
276 294
 
277 295
   // XY relative to the probed area
278
-  xy_pos_t rel = raw - bilinear_start.asFloat();
296
+  xy_pos_t rel = raw - grid_start.asFloat();
279 297
 
280 298
   #if ENABLED(EXTRAPOLATE_BEYOND_GRID)
281 299
     #define FAR_EDGE_OR_BOX 2   // Keep using the last grid box
@@ -283,8 +301,8 @@ float bilinear_z_offset(const xy_pos_t &raw) {
283 301
     #define FAR_EDGE_OR_BOX 1   // Just use the grid far edge
284 302
   #endif
285 303
 
286
-  if (prev.x != rel.x) {
287
-    prev.x = rel.x;
304
+  if (cached_rel.x != rel.x) {
305
+    cached_rel.x = rel.x;
288 306
     ratio.x = rel.x * ABL_BG_FACTOR(x);
289 307
     const float gx = constrain(FLOOR(ratio.x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX));
290 308
     ratio.x -= gx;      // Subtract whole to get the ratio within the grid box
@@ -298,10 +316,10 @@ float bilinear_z_offset(const xy_pos_t &raw) {
298 316
     nextg.x = _MIN(thisg.x + 1, ABL_BG_POINTS_X - 1);
299 317
   }
300 318
 
301
-  if (prev.y != rel.y || lastg.x != thisg.x) {
319
+  if (cached_rel.y != rel.y || cached_g.x != thisg.x) {
302 320
 
303
-    if (prev.y != rel.y) {
304
-      prev.y = rel.y;
321
+    if (cached_rel.y != rel.y) {
322
+      cached_rel.y = rel.y;
305 323
       ratio.y = rel.y * ABL_BG_FACTOR(y);
306 324
       const float gy = constrain(FLOOR(ratio.y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX));
307 325
       ratio.y -= gy;
@@ -315,8 +333,8 @@ float bilinear_z_offset(const xy_pos_t &raw) {
315 333
       nextg.y = _MIN(thisg.y + 1, ABL_BG_POINTS_Y - 1);
316 334
     }
317 335
 
318
-    if (lastg != thisg) {
319
-      lastg = thisg;
336
+    if (cached_g != thisg) {
337
+      cached_g = thisg;
320 338
       // Z at the box corners
321 339
       z1 = ABL_BG_GRID(thisg.x, thisg.y);       // left-front
322 340
       d2 = ABL_BG_GRID(thisg.x, nextg.y) - z1;  // left-back (delta)
@@ -336,8 +354,8 @@ float bilinear_z_offset(const xy_pos_t &raw) {
336 354
   /*
337 355
   static float last_offset = 0;
338 356
   if (ABS(last_offset - offset) > 0.2) {
339
-    SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", bilinear_grid_spacing.x, " -> thisg.x=", thisg.x);
340
-    SERIAL_ECHOLNPGM(" y=", rel.y, " / ", bilinear_grid_spacing.y, " -> thisg.y=", thisg.y);
357
+    SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", grid_spacing.x, " -> thisg.x=", thisg.x);
358
+    SERIAL_ECHOLNPGM(" y=", rel.y, " / ", grid_spacing.y, " -> thisg.y=", thisg.y);
341 359
     SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y);
342 360
     SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4);
343 361
     SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset);
@@ -350,13 +368,13 @@ float bilinear_z_offset(const xy_pos_t &raw) {
350 368
 
351 369
 #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
352 370
 
353
-  #define CELL_INDEX(A,V) ((V - bilinear_start.A) * ABL_BG_FACTOR(A))
371
+  #define CELL_INDEX(A,V) ((V - grid_start.A) * ABL_BG_FACTOR(A))
354 372
 
355 373
   /**
356 374
    * Prepare a bilinear-leveled linear move on Cartesian,
357 375
    * splitting the move where it crosses grid borders.
358 376
    */
359
-  void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) {
377
+  void LevelingBilinear::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) {
360 378
     // Get current and destination cells for this line
361 379
     xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) },
362 380
              c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) };
@@ -384,7 +402,7 @@ float bilinear_z_offset(const xy_pos_t &raw) {
384 402
       // Split on the X grid line
385 403
       CBI(x_splits, gc.x);
386 404
       end = destination;
387
-      destination.x = bilinear_start.x + ABL_BG_SPACING(x) * gc.x;
405
+      destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x;
388 406
       normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x);
389 407
       destination.y = LINE_SEGMENT_END(y);
390 408
     }
@@ -393,7 +411,7 @@ float bilinear_z_offset(const xy_pos_t &raw) {
393 411
       // Split on the Y grid line
394 412
       CBI(y_splits, gc.y);
395 413
       end = destination;
396
-      destination.y = bilinear_start.y + ABL_BG_SPACING(y) * gc.y;
414
+      destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y;
397 415
       normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y);
398 416
       destination.x = LINE_SEGMENT_END(x);
399 417
     }
@@ -409,11 +427,11 @@ float bilinear_z_offset(const xy_pos_t &raw) {
409 427
     destination.e = LINE_SEGMENT_END(e);
410 428
 
411 429
     // Do the split and look for more borders
412
-    bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
430
+    line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
413 431
 
414 432
     // Restore destination from stack
415 433
     destination = end;
416
-    bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
434
+    line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
417 435
   }
418 436
 
419 437
 #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES

+ 72
- 0
Marlin/src/feature/bedlevel/abl/bbl.h View File

@@ -0,0 +1,72 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include "../../../inc/MarlinConfigPre.h"
25
+
26
+class LevelingBilinear {
27
+  static xy_pos_t grid_spacing, grid_start;
28
+  static xy_float_t grid_factor;
29
+  static bed_mesh_t z_values;
30
+  static xy_pos_t cached_rel;
31
+  static xy_int8_t cached_g;
32
+
33
+  static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir);
34
+
35
+  #if ENABLED(ABL_BILINEAR_SUBDIVISION)
36
+    #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1)
37
+    #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1)
38
+
39
+    static float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
40
+    static xy_pos_t grid_spacing_virt;
41
+    static xy_float_t grid_factor_virt;
42
+
43
+    static float bed_level_virt_coord(const uint8_t x, const uint8_t y);
44
+    static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t);
45
+    static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty);
46
+    static void bed_level_virt_interpolate();
47
+  #endif
48
+
49
+public:
50
+  static void reset();
51
+  static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start);
52
+  static void extrapolate_unprobed_bed_level();
53
+  static void print_leveling_grid(const bed_mesh_t* _z_values = NULL);
54
+  static void refresh_bed_level();
55
+  static bool has_mesh() { return !!grid_spacing.x; }
56
+  static bed_mesh_t& get_z_values() { return z_values; }
57
+  static const xy_pos_t& get_grid_spacing() { return grid_spacing; }
58
+  static const xy_pos_t& get_grid_start() { return grid_start; }
59
+  static float get_mesh_x(int16_t i) { return grid_start.x + i * grid_spacing.x; }
60
+  static float get_mesh_y(int16_t j) { return grid_start.y + j * grid_spacing.y; }
61
+  static float get_z_correction(const xy_pos_t &raw);
62
+
63
+  #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
64
+    static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
65
+  #endif
66
+};
67
+
68
+extern LevelingBilinear bbl;
69
+
70
+#define _GET_MESH_X(I) bbl.get_mesh_x(I)
71
+#define _GET_MESH_Y(J) bbl.get_mesh_y(J)
72
+#define Z_VALUES_ARR bbl.get_z_values()

+ 4
- 15
Marlin/src/feature/bedlevel/bedlevel.cpp View File

@@ -48,7 +48,7 @@
48 48
 
49 49
 bool leveling_is_valid() {
50 50
   return TERN1(MESH_BED_LEVELING,          mbl.has_mesh())
51
-      && TERN1(AUTO_BED_LEVELING_BILINEAR, !!bilinear_grid_spacing.x)
51
+      && TERN1(AUTO_BED_LEVELING_BILINEAR, bbl.has_mesh())
52 52
       && TERN1(AUTO_BED_LEVELING_UBL,      ubl.mesh_is_valid());
53 53
 }
54 54
 
@@ -67,12 +67,6 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
67 67
 
68 68
     planner.synchronize();
69 69
 
70
-    #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
71
-      // Force bilinear_z_offset to re-calculate next time
72
-      const xyz_pos_t reset { -9999.999, -9999.999, 0 };
73
-      (void)bilinear_z_offset(reset);
74
-    #endif
75
-
76 70
     if (planner.leveling_active) {      // leveling from on to off
77 71
       if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling ON", current_position);
78 72
       // change unleveled current_position to physical current_position without moving steppers.
@@ -129,12 +123,7 @@ void reset_bed_level() {
129 123
     #if ENABLED(MESH_BED_LEVELING)
130 124
       mbl.reset();
131 125
     #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
132
-      bilinear_start.reset();
133
-      bilinear_grid_spacing.reset();
134
-      GRID_LOOP(x, y) {
135
-        z_values[x][y] = NAN;
136
-        TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
137
-      }
126
+      bbl.reset();
138 127
     #elif ABL_PLANAR
139 128
       planner.bed_level_matrix.set_to_identity();
140 129
     #endif
@@ -156,7 +145,7 @@ void reset_bed_level() {
156 145
   /**
157 146
    * Print calibration results for plotting or manual frame adjustment.
158 147
    */
159
-  void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn) {
148
+  void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values) {
160 149
     #ifndef SCAD_MESH_OUTPUT
161 150
       LOOP_L_N(x, sx) {
162 151
         serial_spaces(precision + (x < 10 ? 3 : 2));
@@ -176,7 +165,7 @@ void reset_bed_level() {
176 165
       #endif
177 166
       LOOP_L_N(x, sx) {
178 167
         SERIAL_CHAR(' ');
179
-        const float offset = fn(x, y);
168
+        const float offset = values[x * sx + y];
180 169
         if (!isnan(offset)) {
181 170
           if (offset >= 0) SERIAL_CHAR('+');
182 171
           SERIAL_ECHO_F(offset, int(precision));

+ 2
- 2
Marlin/src/feature/bedlevel/bedlevel.h View File

@@ -62,7 +62,7 @@ class TemporaryBedLevelingState {
62 62
   typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
63 63
 
64 64
   #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
65
-    #include "abl/abl.h"
65
+    #include "abl/bbl.h"
66 66
   #elif ENABLED(AUTO_BED_LEVELING_UBL)
67 67
     #include "ubl/ubl.h"
68 68
   #elif ENABLED(MESH_BED_LEVELING)
@@ -81,7 +81,7 @@ class TemporaryBedLevelingState {
81 81
     /**
82 82
      * Print calibration results for plotting or manual frame adjustment.
83 83
      */
84
-    void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn);
84
+    void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values);
85 85
 
86 86
   #endif
87 87
 

+ 1
- 3
Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp View File

@@ -125,9 +125,7 @@
125 125
   void mesh_bed_leveling::report_mesh() {
126 126
     SERIAL_ECHOPAIR_F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: ", z_offset, 5);
127 127
     SERIAL_ECHOLNPGM("\nMeasured points:");
128
-    print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5,
129
-      [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
130
-    );
128
+    print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]);
131 129
   }
132 130
 
133 131
 #endif // MESH_BED_LEVELING

+ 8
- 6
Marlin/src/gcode/bedlevel/M420.cpp View File

@@ -67,14 +67,17 @@ void GcodeSuite::M420() {
67 67
       const float x_min = probe.min_x(), x_max = probe.max_x(),
68 68
                   y_min = probe.min_y(), y_max = probe.max_y();
69 69
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
70
-        bilinear_start.set(x_min, y_min);
71
-        bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X),
72
-                                  (y_max - y_min) / (GRID_MAX_CELLS_Y));
70
+        xy_pos_t start, spacing;
71
+        start.set(x_min, y_min);
72
+        spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X),
73
+                    (y_max - y_min) / (GRID_MAX_CELLS_Y));
74
+        bbl.set_grid(spacing, start);
73 75
       #endif
74 76
       GRID_LOOP(x, y) {
75 77
         Z_VALUES(x, y) = 0.001 * random(-200, 200);
76 78
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y)));
77 79
       }
80
+      TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
78 81
       SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh ");
79 82
       SERIAL_ECHOPGM(" (", x_min);
80 83
       SERIAL_CHAR(','); SERIAL_ECHO(y_min);
@@ -178,7 +181,7 @@ void GcodeSuite::M420() {
178 181
               Z_VALUES(x, y) -= zmean;
179 182
               TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y)));
180 183
             }
181
-            TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
184
+            TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
182 185
           }
183 186
 
184 187
         #endif
@@ -199,8 +202,7 @@ void GcodeSuite::M420() {
199 202
     #else
200 203
       if (leveling_is_valid()) {
201 204
         #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
202
-          print_bilinear_leveling_grid();
203
-          TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt());
205
+          bbl.print_leveling_grid();
204 206
         #elif ENABLED(MESH_BED_LEVELING)
205 207
           SERIAL_ECHOLNPGM("Mesh Bed Level data:");
206 208
           mbl.report_mesh();

+ 19
- 18
Marlin/src/gcode/bedlevel/abl/G29.cpp View File

@@ -124,6 +124,7 @@ public:
124 124
 
125 125
     #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
126 126
       float Z_offset;
127
+      bed_mesh_t z_values;
127 128
     #endif
128 129
 
129 130
     #if ENABLED(AUTO_BED_LEVELING_LINEAR)
@@ -308,8 +309,8 @@ G29_TYPE GcodeSuite::G29() {
308 309
 
309 310
         if (!isnan(rx) && !isnan(ry)) {
310 311
           // Get nearest i / j from rx / ry
311
-          i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x;
312
-          j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y;
312
+          i = (rx - bbl.get_grid_start().x) / bbl.get_grid_spacing().x + 0.5f;
313
+          j = (ry - bbl.get_grid_start().y) / bbl.get_grid_spacing().y + 0.5f;
313 314
           LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
314 315
           LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
315 316
         }
@@ -318,8 +319,8 @@ G29_TYPE GcodeSuite::G29() {
318 319
 
319 320
         if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
320 321
           set_bed_leveling_enabled(false);
321
-          z_values[i][j] = rz;
322
-          TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
322
+          Z_VALUES_ARR[i][j] = rz;
323
+          bbl.refresh_bed_level();
323 324
           TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
324 325
           set_bed_leveling_enabled(abl.reenable);
325 326
           if (abl.reenable) report_current_position();
@@ -451,16 +452,12 @@ G29_TYPE GcodeSuite::G29() {
451 452
     #endif
452 453
 
453 454
     #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
454
-      if (TERN1(PROBE_MANUALLY, !no_action)
455
-        && (abl.gridSpacing != bilinear_grid_spacing || abl.probe_position_lf != bilinear_start)
455
+      if (!abl.dryrun
456
+        && (abl.gridSpacing != bbl.get_grid_spacing() || abl.probe_position_lf != bbl.get_grid_start())
456 457
       ) {
457 458
         // Reset grid to 0.0 or "not probed". (Also disables ABL)
458 459
         reset_bed_level();
459 460
 
460
-        // Initialize a grid with the given dimensions
461
-        bilinear_grid_spacing = abl.gridSpacing;
462
-        bilinear_start = abl.probe_position_lf;
463
-
464 461
         // Can't re-enable (on error) until the new grid is written
465 462
         abl.reenable = false;
466 463
       }
@@ -531,7 +528,7 @@ G29_TYPE GcodeSuite::G29() {
531 528
       #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
532 529
 
533 530
         const float newz = abl.measured_z + abl.Z_offset;
534
-        z_values[abl.meshCount.x][abl.meshCount.y] = newz;
531
+        abl.z_values[abl.meshCount.x][abl.meshCount.y] = newz;
535 532
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, newz));
536 533
 
537 534
         if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(PSTR("Save X"), abl.meshCount.x, SP_Y_STR, abl.meshCount.y, SP_Z_STR, abl.measured_z + abl.Z_offset);
@@ -682,7 +679,7 @@ G29_TYPE GcodeSuite::G29() {
682 679
           #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
683 680
 
684 681
             const float z = abl.measured_z + abl.Z_offset;
685
-            z_values[abl.meshCount.x][abl.meshCount.y] = z;
682
+            abl.z_values[abl.meshCount.x][abl.meshCount.y] = z;
686 683
             TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z));
687 684
 
688 685
           #endif
@@ -753,12 +750,16 @@ G29_TYPE GcodeSuite::G29() {
753 750
   if (!isnan(abl.measured_z)) {
754 751
     #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
755 752
 
756
-      if (!abl.dryrun) extrapolate_unprobed_bed_level();
757
-      print_bilinear_leveling_grid();
758
-
759
-      refresh_bed_level();
753
+      if (abl.dryrun)
754
+        bbl.print_leveling_grid(&abl.z_values);
755
+      else {
756
+        bbl.set_grid(abl.gridSpacing, abl.probe_position_lf);
757
+        COPY(Z_VALUES_ARR, abl.z_values);
758
+        TERN_(IS_KINEMATIC, bbl.extrapolate_unprobed_bed_level());
759
+        bbl.refresh_bed_level();
760 760
 
761
-      TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt());
761
+        bbl.print_leveling_grid();
762
+      }
762 763
 
763 764
     #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
764 765
 
@@ -878,7 +879,7 @@ G29_TYPE GcodeSuite::G29() {
878 879
         // Unapply the offset because it is going to be immediately applied
879 880
         // and cause compensation movement in Z
880 881
         const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1);
881
-        current_position.z -= fade_scaling_factor * bilinear_z_offset(current_position);
882
+        current_position.z -= fade_scaling_factor * bbl.get_z_correction(current_position);
882 883
 
883 884
         if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" corrected Z:", current_position.z);
884 885
       }

+ 3
- 3
Marlin/src/gcode/bedlevel/abl/M421.cpp View File

@@ -58,11 +58,11 @@ void GcodeSuite::M421() {
58 58
               sy = iy >= 0 ? iy : 0, ey = iy >= 0 ? iy : GRID_MAX_POINTS_Y - 1;
59 59
       LOOP_S_LE_N(x, sx, ex) {
60 60
         LOOP_S_LE_N(y, sy, ey) {
61
-          z_values[x][y] = zval + (hasQ ? z_values[x][y] : 0);
62
-          TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
61
+          Z_VALUES_ARR[x][y] = zval + (hasQ ? Z_VALUES_ARR[x][y] : 0);
62
+          TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES_ARR[x][y]));
63 63
         }
64 64
       }
65
-      TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
65
+      bbl.refresh_bed_level();
66 66
     }
67 67
     else
68 68
       SERIAL_ERROR_MSG(STR_ERR_MESH_XY);

+ 1
- 1
Marlin/src/lcd/e3v2/jyersui/dwin.cpp View File

@@ -3417,7 +3417,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
3417 3417
               Draw_Menu_Item(row, ICON_Back, F("Back"));
3418 3418
             else {
3419 3419
               set_bed_leveling_enabled(level_state);
3420
-              TERN_(AUTO_BED_LEVELING_BILINEAR, refresh_bed_level());
3420
+              TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
3421 3421
               Draw_Menu(Leveling, LEVELING_MANUAL);
3422 3422
             }
3423 3423
             break;

+ 2
- 2
Marlin/src/module/planner.cpp View File

@@ -1591,7 +1591,7 @@ void Planner::check_axes_activity() {
1591 1591
         #elif ENABLED(AUTO_BED_LEVELING_UBL)
1592 1592
           fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0
1593 1593
         #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
1594
-          fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0
1594
+          fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0
1595 1595
         #endif
1596 1596
       );
1597 1597
 
@@ -1624,7 +1624,7 @@ void Planner::check_axes_activity() {
1624 1624
           #elif ENABLED(AUTO_BED_LEVELING_UBL)
1625 1625
             fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0
1626 1626
           #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
1627
-            fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0
1627
+            fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0
1628 1628
           #endif
1629 1629
         );
1630 1630
 

+ 17
- 14
Marlin/src/module/settings.cpp View File

@@ -597,7 +597,7 @@ void MarlinSettings::postprocess() {
597 597
 
598 598
   TERN_(ENABLE_LEVELING_FADE_HEIGHT, set_z_fade_height(new_z_fade_height, false)); // false = no report
599 599
 
600
-  TERN_(AUTO_BED_LEVELING_BILINEAR, refresh_bed_level());
600
+  TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
601 601
 
602 602
   TERN_(HAS_MOTOR_CURRENT_PWM, stepper.refresh_motor_power());
603 603
 
@@ -876,22 +876,26 @@ void MarlinSettings::postprocess() {
876 876
     {
877 877
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
878 878
         static_assert(
879
-          sizeof(z_values) == (GRID_MAX_POINTS) * sizeof(z_values[0][0]),
879
+          sizeof(Z_VALUES_ARR) == (GRID_MAX_POINTS) * sizeof(Z_VALUES_ARR[0][0]),
880 880
           "Bilinear Z array is the wrong size."
881 881
         );
882
-      #else
883
-        const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0};
884 882
       #endif
885 883
 
886 884
       const uint8_t grid_max_x = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_X, 3),
887 885
                     grid_max_y = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_Y, 3);
888 886
       EEPROM_WRITE(grid_max_x);
889 887
       EEPROM_WRITE(grid_max_y);
890
-      EEPROM_WRITE(bilinear_grid_spacing);
891
-      EEPROM_WRITE(bilinear_start);
888
+      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
889
+        EEPROM_WRITE(bbl.get_grid_spacing());
890
+        EEPROM_WRITE(bbl.get_grid_start());
891
+      #else
892
+        const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0};
893
+        EEPROM_WRITE(bilinear_grid_spacing);
894
+        EEPROM_WRITE(bilinear_start);
895
+      #endif
892 896
 
893 897
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
894
-        EEPROM_WRITE(z_values);              // 9-256 floats
898
+        EEPROM_WRITE(Z_VALUES_ARR);              // 9-256 floats
895 899
       #else
896 900
         dummyf = 0;
897 901
         for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummyf);
@@ -1791,20 +1795,19 @@ void MarlinSettings::postprocess() {
1791 1795
         uint8_t grid_max_x, grid_max_y;
1792 1796
         EEPROM_READ_ALWAYS(grid_max_x);                // 1 byte
1793 1797
         EEPROM_READ_ALWAYS(grid_max_y);                // 1 byte
1798
+        xy_pos_t spacing, start;
1799
+        EEPROM_READ(spacing);                          // 2 ints
1800
+        EEPROM_READ(start);                            // 2 ints
1794 1801
         #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
1795 1802
           if (grid_max_x == (GRID_MAX_POINTS_X) && grid_max_y == (GRID_MAX_POINTS_Y)) {
1796 1803
             if (!validating) set_bed_leveling_enabled(false);
1797
-            EEPROM_READ(bilinear_grid_spacing);        // 2 ints
1798
-            EEPROM_READ(bilinear_start);               // 2 ints
1799
-            EEPROM_READ(z_values);                     // 9 to 256 floats
1804
+            bbl.set_grid(spacing, start);
1805
+            EEPROM_READ(Z_VALUES_ARR);                 // 9 to 256 floats
1800 1806
           }
1801 1807
           else // EEPROM data is stale
1802 1808
         #endif // AUTO_BED_LEVELING_BILINEAR
1803 1809
           {
1804 1810
             // Skip past disabled (or stale) Bilinear Grid data
1805
-            xy_pos_t bgs, bs;
1806
-            EEPROM_READ(bgs);
1807
-            EEPROM_READ(bs);
1808 1811
             for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummyf);
1809 1812
           }
1810 1813
       }
@@ -3337,7 +3340,7 @@ void MarlinSettings::reset() {
3337 3340
             LOOP_L_N(px, GRID_MAX_POINTS_X) {
3338 3341
               CONFIG_ECHO_START();
3339 3342
               SERIAL_ECHOPGM("  G29 W I", px, " J", py);
3340
-              SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(z_values[px][py]), 5);
3343
+              SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(Z_VALUES_ARR[px][py]), 5);
3341 3344
             }
3342 3345
           }
3343 3346
         }

Loading…
Cancel
Save