♻️ Refactor and fix ABL Bilinear (#23868, #24009, #24107)

This commit is contained in:
tombrazier 2022-04-01 03:13:16 +01:00 committed by Scott Lahteine
parent 4ec9af42b8
commit 74565890f3
16 changed files with 210 additions and 168 deletions

View File

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

View File

@ -1,45 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfigPre.h"
extern xy_pos_t bilinear_grid_spacing, bilinear_start;
extern xy_float_t bilinear_grid_factor;
extern bed_mesh_t z_values;
float bilinear_z_offset(const xy_pos_t &raw);
void extrapolate_unprobed_bed_level();
void print_bilinear_leveling_grid();
void refresh_bed_level();
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
void print_bilinear_leveling_grid_virt();
void bed_level_virt_interpolate();
#endif
#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
#endif
#define _GET_MESH_X(I) float(bilinear_start.x + (I) * bilinear_grid_spacing.x)
#define _GET_MESH_Y(J) float(bilinear_start.y + (J) * bilinear_grid_spacing.y)
#define Z_VALUES_ARR z_values

View File

@ -35,14 +35,19 @@
#include "../../../lcd/extui/ui_api.h" #include "../../../lcd/extui/ui_api.h"
#endif #endif
xy_pos_t bilinear_grid_spacing, bilinear_start; LevelingBilinear bbl;
xy_float_t bilinear_grid_factor;
bed_mesh_t z_values; xy_pos_t LevelingBilinear::grid_spacing,
LevelingBilinear::grid_start;
xy_float_t LevelingBilinear::grid_factor;
bed_mesh_t LevelingBilinear::z_values;
xy_pos_t LevelingBilinear::cached_rel;
xy_int8_t LevelingBilinear::cached_g;
/** /**
* Extrapolate a single point from its neighbors * Extrapolate a single point from its neighbors
*/ */
static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) { void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
if (!isnan(z_values[x][y])) return; if (!isnan(z_values[x][y])) return;
if (DEBUGGING(LEVELING)) { if (DEBUGGING(LEVELING)) {
DEBUG_ECHOPGM("Extrapolate ["); DEBUG_ECHOPGM("Extrapolate [");
@ -92,11 +97,26 @@ static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t
#endif #endif
#endif #endif
void LevelingBilinear::reset() {
grid_start.reset();
grid_spacing.reset();
GRID_LOOP(x, y) {
z_values[x][y] = NAN;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
}
}
void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) {
grid_spacing = _grid_spacing;
grid_start = _grid_start;
grid_factor = grid_spacing.reciprocal();
}
/** /**
* Fill in the unprobed points (corners of circular print surface) * Fill in the unprobed points (corners of circular print surface)
* using linear extrapolation, away from the center. * using linear extrapolation, away from the center.
*/ */
void extrapolate_unprobed_bed_level() { void LevelingBilinear::extrapolate_unprobed_bed_level() {
#ifdef HALF_IN_X #ifdef HALF_IN_X
constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1; constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1;
#else #else
@ -131,35 +151,31 @@ void extrapolate_unprobed_bed_level() {
#endif #endif
extrapolate_one_point(x2, y2, -1, -1); // right-above - - extrapolate_one_point(x2, y2, -1, -1); // right-above - -
} }
} }
void print_bilinear_leveling_grid() { void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL*/) {
// print internal grid(s) or just the one passed as a parameter
SERIAL_ECHOLNPGM("Bilinear Leveling Grid:"); SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, _z_values ? *_z_values[0] : z_values[0]);
[](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
); #if ENABLED(ABL_BILINEAR_SUBDIVISION)
if (!_z_values) {
SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, z_values_virt[0]);
}
#endif
} }
#if ENABLED(ABL_BILINEAR_SUBDIVISION) #if ENABLED(ABL_BILINEAR_SUBDIVISION)
#define ABL_GRID_POINTS_VIRT_X GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1
#define ABL_GRID_POINTS_VIRT_Y GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1
#define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2) #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
#define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2) #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; float LevelingBilinear::z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
xy_pos_t bilinear_grid_spacing_virt; xy_pos_t LevelingBilinear::grid_spacing_virt;
xy_float_t bilinear_grid_factor_virt; xy_float_t LevelingBilinear::grid_factor_virt;
void print_bilinear_leveling_grid_virt() {
SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
[](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; }
);
}
#define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I)) #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
float bed_level_virt_coord(const uint8_t x, const uint8_t y) { float LevelingBilinear::bed_level_virt_coord(const uint8_t x, const uint8_t y) {
uint8_t ep = 0, ip = 1; uint8_t ep = 0, ip = 1;
if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) { if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) {
// The requested point requires extrapolating two points beyond the mesh. // The requested point requires extrapolating two points beyond the mesh.
@ -204,7 +220,7 @@ void print_bilinear_leveling_grid() {
return z_values[x - 1][y - 1]; return z_values[x - 1][y - 1];
} }
static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) { float LevelingBilinear::bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
return ( return (
p[i-1] * -t * sq(1 - t) p[i-1] * -t * sq(1 - t)
+ p[i] * (2 - 5 * sq(t) + 3 * t * sq(t)) + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t))
@ -213,7 +229,7 @@ void print_bilinear_leveling_grid() {
) * 0.5f; ) * 0.5f;
} }
static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { float LevelingBilinear::bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) {
float row[4], column[4]; float row[4], column[4];
LOOP_L_N(i, 4) { LOOP_L_N(i, 4) {
LOOP_L_N(j, 4) { LOOP_L_N(j, 4) {
@ -224,9 +240,9 @@ void print_bilinear_leveling_grid() {
return bed_level_virt_cmr(row, 1, tx); return bed_level_virt_cmr(row, 1, tx);
} }
void bed_level_virt_interpolate() { void LevelingBilinear::bed_level_virt_interpolate() {
bilinear_grid_spacing_virt = bilinear_grid_spacing / (BILINEAR_SUBDIVISIONS); grid_spacing_virt = grid_spacing / (BILINEAR_SUBDIVISIONS);
bilinear_grid_factor_virt = bilinear_grid_spacing_virt.reciprocal(); grid_factor_virt = grid_spacing_virt.reciprocal();
LOOP_L_N(y, GRID_MAX_POINTS_Y) LOOP_L_N(y, GRID_MAX_POINTS_Y)
LOOP_L_N(x, GRID_MAX_POINTS_X) LOOP_L_N(x, GRID_MAX_POINTS_X)
LOOP_L_N(ty, BILINEAR_SUBDIVISIONS) LOOP_L_N(ty, BILINEAR_SUBDIVISIONS)
@ -244,38 +260,40 @@ void print_bilinear_leveling_grid() {
} }
#endif // ABL_BILINEAR_SUBDIVISION #endif // ABL_BILINEAR_SUBDIVISION
// Refresh after other values have been updated // Refresh after other values have been updated
void refresh_bed_level() { void LevelingBilinear::refresh_bed_level() {
bilinear_grid_factor = bilinear_grid_spacing.reciprocal();
TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
cached_rel.x = cached_rel.y = -999.999;
cached_g.x = cached_g.y = -99;
} }
#if ENABLED(ABL_BILINEAR_SUBDIVISION) #if ENABLED(ABL_BILINEAR_SUBDIVISION)
#define ABL_BG_SPACING(A) bilinear_grid_spacing_virt.A #define ABL_BG_SPACING(A) grid_spacing_virt.A
#define ABL_BG_FACTOR(A) bilinear_grid_factor_virt.A #define ABL_BG_FACTOR(A) grid_factor_virt.A
#define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X #define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X
#define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y #define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y
#define ABL_BG_GRID(X,Y) z_values_virt[X][Y] #define ABL_BG_GRID(X,Y) z_values_virt[X][Y]
#else #else
#define ABL_BG_SPACING(A) bilinear_grid_spacing.A #define ABL_BG_SPACING(A) grid_spacing.A
#define ABL_BG_FACTOR(A) bilinear_grid_factor.A #define ABL_BG_FACTOR(A) grid_factor.A
#define ABL_BG_POINTS_X GRID_MAX_POINTS_X #define ABL_BG_POINTS_X GRID_MAX_POINTS_X
#define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y #define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y
#define ABL_BG_GRID(X,Y) z_values[X][Y] #define ABL_BG_GRID(X,Y) z_values[X][Y]
#endif #endif
// Get the Z adjustment for non-linear bed leveling // Get the Z adjustment for non-linear bed leveling
float bilinear_z_offset(const xy_pos_t &raw) { float LevelingBilinear::get_z_correction(const xy_pos_t &raw) {
static float z1, d2, z3, d4, L, D; static float z1, d2, z3, d4, L, D;
static xy_pos_t prev { -999.999, -999.999 }, ratio; static xy_pos_t ratio;
// Whole units for the grid line indices. Constrained within bounds. // Whole units for the grid line indices. Constrained within bounds.
static xy_int8_t thisg, nextg, lastg { -99, -99 }; static xy_int8_t thisg, nextg;
// XY relative to the probed area // XY relative to the probed area
xy_pos_t rel = raw - bilinear_start.asFloat(); xy_pos_t rel = raw - grid_start.asFloat();
#if ENABLED(EXTRAPOLATE_BEYOND_GRID) #if ENABLED(EXTRAPOLATE_BEYOND_GRID)
#define FAR_EDGE_OR_BOX 2 // Keep using the last grid box #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) {
#define FAR_EDGE_OR_BOX 1 // Just use the grid far edge #define FAR_EDGE_OR_BOX 1 // Just use the grid far edge
#endif #endif
if (prev.x != rel.x) { if (cached_rel.x != rel.x) {
prev.x = rel.x; cached_rel.x = rel.x;
ratio.x = rel.x * ABL_BG_FACTOR(x); ratio.x = rel.x * ABL_BG_FACTOR(x);
const float gx = constrain(FLOOR(ratio.x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX)); const float gx = constrain(FLOOR(ratio.x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX));
ratio.x -= gx; // Subtract whole to get the ratio within the grid box 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) {
nextg.x = _MIN(thisg.x + 1, ABL_BG_POINTS_X - 1); nextg.x = _MIN(thisg.x + 1, ABL_BG_POINTS_X - 1);
} }
if (prev.y != rel.y || lastg.x != thisg.x) { if (cached_rel.y != rel.y || cached_g.x != thisg.x) {
if (prev.y != rel.y) { if (cached_rel.y != rel.y) {
prev.y = rel.y; cached_rel.y = rel.y;
ratio.y = rel.y * ABL_BG_FACTOR(y); ratio.y = rel.y * ABL_BG_FACTOR(y);
const float gy = constrain(FLOOR(ratio.y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX)); const float gy = constrain(FLOOR(ratio.y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX));
ratio.y -= gy; ratio.y -= gy;
@ -315,8 +333,8 @@ float bilinear_z_offset(const xy_pos_t &raw) {
nextg.y = _MIN(thisg.y + 1, ABL_BG_POINTS_Y - 1); nextg.y = _MIN(thisg.y + 1, ABL_BG_POINTS_Y - 1);
} }
if (lastg != thisg) { if (cached_g != thisg) {
lastg = thisg; cached_g = thisg;
// Z at the box corners // Z at the box corners
z1 = ABL_BG_GRID(thisg.x, thisg.y); // left-front z1 = ABL_BG_GRID(thisg.x, thisg.y); // left-front
d2 = ABL_BG_GRID(thisg.x, nextg.y) - z1; // left-back (delta) 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) {
/* /*
static float last_offset = 0; static float last_offset = 0;
if (ABS(last_offset - offset) > 0.2) { if (ABS(last_offset - offset) > 0.2) {
SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", bilinear_grid_spacing.x, " -> thisg.x=", thisg.x); SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", grid_spacing.x, " -> thisg.x=", thisg.x);
SERIAL_ECHOLNPGM(" y=", rel.y, " / ", bilinear_grid_spacing.y, " -> thisg.y=", thisg.y); SERIAL_ECHOLNPGM(" y=", rel.y, " / ", grid_spacing.y, " -> thisg.y=", thisg.y);
SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y); SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y);
SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4); SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4);
SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset); SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset);
@ -350,13 +368,13 @@ float bilinear_z_offset(const xy_pos_t &raw) {
#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
#define CELL_INDEX(A,V) ((V - bilinear_start.A) * ABL_BG_FACTOR(A)) #define CELL_INDEX(A,V) ((V - grid_start.A) * ABL_BG_FACTOR(A))
/** /**
* Prepare a bilinear-leveled linear move on Cartesian, * Prepare a bilinear-leveled linear move on Cartesian,
* splitting the move where it crosses grid borders. * splitting the move where it crosses grid borders.
*/ */
void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { void LevelingBilinear::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) {
// Get current and destination cells for this line // Get current and destination cells for this line
xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) }, xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) },
c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) }; c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) };
@ -384,7 +402,7 @@ float bilinear_z_offset(const xy_pos_t &raw) {
// Split on the X grid line // Split on the X grid line
CBI(x_splits, gc.x); CBI(x_splits, gc.x);
end = destination; end = destination;
destination.x = bilinear_start.x + ABL_BG_SPACING(x) * gc.x; destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x;
normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x); normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x);
destination.y = LINE_SEGMENT_END(y); destination.y = LINE_SEGMENT_END(y);
} }
@ -393,7 +411,7 @@ float bilinear_z_offset(const xy_pos_t &raw) {
// Split on the Y grid line // Split on the Y grid line
CBI(y_splits, gc.y); CBI(y_splits, gc.y);
end = destination; end = destination;
destination.y = bilinear_start.y + ABL_BG_SPACING(y) * gc.y; destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y;
normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y); normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y);
destination.x = LINE_SEGMENT_END(x); destination.x = LINE_SEGMENT_END(x);
} }
@ -409,11 +427,11 @@ float bilinear_z_offset(const xy_pos_t &raw) {
destination.e = LINE_SEGMENT_END(e); destination.e = LINE_SEGMENT_END(e);
// Do the split and look for more borders // Do the split and look for more borders
bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
// Restore destination from stack // Restore destination from stack
destination = end; destination = end;
bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
} }
#endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES

View File

@ -0,0 +1,73 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfigPre.h"
class LevelingBilinear {
private:
static xy_pos_t grid_spacing, grid_start;
static xy_float_t grid_factor;
static bed_mesh_t z_values;
static xy_pos_t cached_rel;
static xy_int8_t cached_g;
static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir);
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
#define ABL_GRID_POINTS_VIRT_X (GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1)
#define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1)
static float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
static xy_pos_t grid_spacing_virt;
static xy_float_t grid_factor_virt;
static float bed_level_virt_coord(const uint8_t x, const uint8_t y);
static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t);
static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty);
static void bed_level_virt_interpolate();
#endif
public:
static void reset();
static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start);
static void extrapolate_unprobed_bed_level();
static void print_leveling_grid(const bed_mesh_t* _z_values = NULL);
static void refresh_bed_level();
static bool has_mesh() { return !!grid_spacing.x; }
static bed_mesh_t& get_z_values() { return z_values; }
static const xy_pos_t& get_grid_spacing() { return grid_spacing; }
static const xy_pos_t& get_grid_start() { return grid_start; }
static float get_mesh_x(int16_t i) { return grid_start.x + i * grid_spacing.x; }
static float get_mesh_y(int16_t j) { return grid_start.y + j * grid_spacing.y; }
static float get_z_correction(const xy_pos_t &raw);
#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES)
static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
#endif
};
extern LevelingBilinear bbl;
#define _GET_MESH_X(I) bbl.get_mesh_x(I)
#define _GET_MESH_Y(J) bbl.get_mesh_y(J)
#define Z_VALUES_ARR bbl.get_z_values()

View File

@ -48,7 +48,7 @@
bool leveling_is_valid() { bool leveling_is_valid() {
return TERN1(MESH_BED_LEVELING, mbl.has_mesh()) return TERN1(MESH_BED_LEVELING, mbl.has_mesh())
&& TERN1(AUTO_BED_LEVELING_BILINEAR, !!bilinear_grid_spacing.x) && TERN1(AUTO_BED_LEVELING_BILINEAR, bbl.has_mesh())
&& TERN1(AUTO_BED_LEVELING_UBL, ubl.mesh_is_valid()); && TERN1(AUTO_BED_LEVELING_UBL, ubl.mesh_is_valid());
} }
@ -67,12 +67,6 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
planner.synchronize(); planner.synchronize();
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
// Force bilinear_z_offset to re-calculate next time
const xyz_pos_t reset { -9999.999, -9999.999, 0 };
(void)bilinear_z_offset(reset);
#endif
if (planner.leveling_active) { // leveling from on to off if (planner.leveling_active) { // leveling from on to off
if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling ON", current_position); if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling ON", current_position);
// change unleveled current_position to physical current_position without moving steppers. // change unleveled current_position to physical current_position without moving steppers.
@ -129,12 +123,7 @@ void reset_bed_level() {
#if ENABLED(MESH_BED_LEVELING) #if ENABLED(MESH_BED_LEVELING)
mbl.reset(); mbl.reset();
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
bilinear_start.reset(); bbl.reset();
bilinear_grid_spacing.reset();
GRID_LOOP(x, y) {
z_values[x][y] = NAN;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
}
#elif ABL_PLANAR #elif ABL_PLANAR
planner.bed_level_matrix.set_to_identity(); planner.bed_level_matrix.set_to_identity();
#endif #endif
@ -156,7 +145,7 @@ void reset_bed_level() {
/** /**
* Print calibration results for plotting or manual frame adjustment. * Print calibration results for plotting or manual frame adjustment.
*/ */
void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn) { void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values) {
#ifndef SCAD_MESH_OUTPUT #ifndef SCAD_MESH_OUTPUT
LOOP_L_N(x, sx) { LOOP_L_N(x, sx) {
serial_spaces(precision + (x < 10 ? 3 : 2)); serial_spaces(precision + (x < 10 ? 3 : 2));
@ -176,7 +165,7 @@ void reset_bed_level() {
#endif #endif
LOOP_L_N(x, sx) { LOOP_L_N(x, sx) {
SERIAL_CHAR(' '); SERIAL_CHAR(' ');
const float offset = fn(x, y); const float offset = values[x * sx + y];
if (!isnan(offset)) { if (!isnan(offset)) {
if (offset >= 0) SERIAL_CHAR('+'); if (offset >= 0) SERIAL_CHAR('+');
SERIAL_ECHO_F(offset, int(precision)); SERIAL_ECHO_F(offset, int(precision));

View File

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

View File

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

View File

@ -67,14 +67,17 @@ void GcodeSuite::M420() {
const float x_min = probe.min_x(), x_max = probe.max_x(), const float x_min = probe.min_x(), x_max = probe.max_x(),
y_min = probe.min_y(), y_max = probe.max_y(); y_min = probe.min_y(), y_max = probe.max_y();
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
bilinear_start.set(x_min, y_min); xy_pos_t start, spacing;
bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X), start.set(x_min, y_min);
(y_max - y_min) / (GRID_MAX_CELLS_Y)); spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X),
(y_max - y_min) / (GRID_MAX_CELLS_Y));
bbl.set_grid(spacing, start);
#endif #endif
GRID_LOOP(x, y) { GRID_LOOP(x, y) {
Z_VALUES(x, y) = 0.001 * random(-200, 200); Z_VALUES(x, y) = 0.001 * random(-200, 200);
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y)));
} }
TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh "); SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh ");
SERIAL_ECHOPGM(" (", x_min); SERIAL_ECHOPGM(" (", x_min);
SERIAL_CHAR(','); SERIAL_ECHO(y_min); SERIAL_CHAR(','); SERIAL_ECHO(y_min);
@ -178,7 +181,7 @@ void GcodeSuite::M420() {
Z_VALUES(x, y) -= zmean; Z_VALUES(x, y) -= zmean;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y)));
} }
TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
} }
#endif #endif
@ -199,8 +202,7 @@ void GcodeSuite::M420() {
#else #else
if (leveling_is_valid()) { if (leveling_is_valid()) {
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
print_bilinear_leveling_grid(); bbl.print_leveling_grid();
TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt());
#elif ENABLED(MESH_BED_LEVELING) #elif ENABLED(MESH_BED_LEVELING)
SERIAL_ECHOLNPGM("Mesh Bed Level data:"); SERIAL_ECHOLNPGM("Mesh Bed Level data:");
mbl.report_mesh(); mbl.report_mesh();

View File

@ -124,6 +124,7 @@ public:
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
float Z_offset; float Z_offset;
bed_mesh_t z_values;
#endif #endif
#if ENABLED(AUTO_BED_LEVELING_LINEAR) #if ENABLED(AUTO_BED_LEVELING_LINEAR)
@ -308,8 +309,8 @@ G29_TYPE GcodeSuite::G29() {
if (!isnan(rx) && !isnan(ry)) { if (!isnan(rx) && !isnan(ry)) {
// Get nearest i / j from rx / ry // Get nearest i / j from rx / ry
i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x; i = (rx - bbl.get_grid_start().x) / bbl.get_grid_spacing().x + 0.5f;
j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y; j = (ry - bbl.get_grid_start().y) / bbl.get_grid_spacing().y + 0.5f;
LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1); LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1); LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
} }
@ -318,8 +319,8 @@ G29_TYPE GcodeSuite::G29() {
if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) { if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
set_bed_leveling_enabled(false); set_bed_leveling_enabled(false);
z_values[i][j] = rz; Z_VALUES_ARR[i][j] = rz;
TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); bbl.refresh_bed_level();
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz)); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
set_bed_leveling_enabled(abl.reenable); set_bed_leveling_enabled(abl.reenable);
if (abl.reenable) report_current_position(); if (abl.reenable) report_current_position();
@ -451,19 +452,19 @@ G29_TYPE GcodeSuite::G29() {
#endif #endif
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
if (TERN1(PROBE_MANUALLY, !no_action) if (!abl.dryrun
&& (abl.gridSpacing != bilinear_grid_spacing || abl.probe_position_lf != bilinear_start) && (abl.gridSpacing != bbl.get_grid_spacing() || abl.probe_position_lf != bbl.get_grid_start())
) { ) {
// Reset grid to 0.0 or "not probed". (Also disables ABL) // Reset grid to 0.0 or "not probed". (Also disables ABL)
reset_bed_level(); reset_bed_level();
// Initialize a grid with the given dimensions
bilinear_grid_spacing = abl.gridSpacing;
bilinear_start = abl.probe_position_lf;
// Can't re-enable (on error) until the new grid is written // Can't re-enable (on error) until the new grid is written
abl.reenable = false; abl.reenable = false;
} }
// Pre-populate local Z values from the stored mesh
TERN_(IS_KINEMATIC, COPY(abl.z_values, Z_VALUES_ARR));
#endif // AUTO_BED_LEVELING_BILINEAR #endif // AUTO_BED_LEVELING_BILINEAR
} // !g29_in_progress } // !g29_in_progress
@ -531,7 +532,7 @@ G29_TYPE GcodeSuite::G29() {
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
const float newz = abl.measured_z + abl.Z_offset; const float newz = abl.measured_z + abl.Z_offset;
z_values[abl.meshCount.x][abl.meshCount.y] = newz; abl.z_values[abl.meshCount.x][abl.meshCount.y] = newz;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, newz)); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, newz));
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); 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);
@ -680,7 +681,7 @@ G29_TYPE GcodeSuite::G29() {
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
const float z = abl.measured_z + abl.Z_offset; const float z = abl.measured_z + abl.Z_offset;
z_values[abl.meshCount.x][abl.meshCount.y] = z; abl.z_values[abl.meshCount.x][abl.meshCount.y] = z;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z)); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z));
#endif #endif
@ -751,12 +752,16 @@ G29_TYPE GcodeSuite::G29() {
if (!isnan(abl.measured_z)) { if (!isnan(abl.measured_z)) {
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
if (!abl.dryrun) extrapolate_unprobed_bed_level(); if (abl.dryrun)
print_bilinear_leveling_grid(); bbl.print_leveling_grid(&abl.z_values);
else {
bbl.set_grid(abl.gridSpacing, abl.probe_position_lf);
COPY(Z_VALUES_ARR, abl.z_values);
TERN_(IS_KINEMATIC, bbl.extrapolate_unprobed_bed_level());
bbl.refresh_bed_level();
refresh_bed_level(); bbl.print_leveling_grid();
}
TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt());
#elif ENABLED(AUTO_BED_LEVELING_LINEAR) #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
@ -876,7 +881,7 @@ G29_TYPE GcodeSuite::G29() {
// Unapply the offset because it is going to be immediately applied // Unapply the offset because it is going to be immediately applied
// and cause compensation movement in Z // and cause compensation movement in Z
const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1); const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1);
current_position.z -= fade_scaling_factor * bilinear_z_offset(current_position); current_position.z -= fade_scaling_factor * bbl.get_z_correction(current_position);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" corrected Z:", current_position.z); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" corrected Z:", current_position.z);
} }

View File

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

View File

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

View File

@ -200,7 +200,7 @@ void DGUSScreenHandler::StoreSettings(char *buff) {
data.initialized = true; data.initialized = true;
data.volume = dgus_display.GetVolume(); data.volume = dgus_display.GetVolume();
data.brightness = dgus_display.GetBrightness(); data.brightness = dgus_display.GetBrightness();
data.abl = (ExtUI::getLevelingActive() && ExtUI::getMeshValid()); data.abl_okay = (ExtUI::getLevelingActive() && ExtUI::getMeshValid());
memcpy(buff, &data, sizeof(data)); memcpy(buff, &data, sizeof(data));
} }
@ -216,8 +216,7 @@ void DGUSScreenHandler::LoadSettings(const char *buff) {
dgus_display.SetBrightness(data.initialized ? data.brightness : DGUS_DEFAULT_BRIGHTNESS); dgus_display.SetBrightness(data.initialized ? data.brightness : DGUS_DEFAULT_BRIGHTNESS);
if (data.initialized) { if (data.initialized) {
leveling_active = (data.abl && ExtUI::getMeshValid()); leveling_active = (data.abl_okay && ExtUI::getMeshValid());
ExtUI::setLevelingActive(leveling_active); ExtUI::setLevelingActive(leveling_active);
} }
} }

View File

@ -134,7 +134,7 @@ private:
bool initialized; bool initialized;
uint8_t volume; uint8_t volume;
uint8_t brightness; uint8_t brightness;
bool abl; bool abl_okay;
} eeprom_data_t; } eeprom_data_t;
}; };

View File

@ -1074,7 +1074,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
#if ENABLED(MESH_BED_LEVELING) #if ENABLED(MESH_BED_LEVELING)
mbl.line_to_destination(scaled_fr_mm_s); mbl.line_to_destination(scaled_fr_mm_s);
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
bilinear_line_to_destination(scaled_fr_mm_s); bbl.line_to_destination(scaled_fr_mm_s);
#endif #endif
return true; return true;
} }

View File

@ -1591,7 +1591,7 @@ void Planner::check_axes_activity() {
#elif ENABLED(AUTO_BED_LEVELING_UBL) #elif ENABLED(AUTO_BED_LEVELING_UBL)
fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0 fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0 fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0
#endif #endif
); );
@ -1624,7 +1624,7 @@ void Planner::check_axes_activity() {
#elif ENABLED(AUTO_BED_LEVELING_UBL) #elif ENABLED(AUTO_BED_LEVELING_UBL)
fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0 fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0 fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0
#endif #endif
); );

View File

@ -597,7 +597,7 @@ void MarlinSettings::postprocess() {
TERN_(ENABLE_LEVELING_FADE_HEIGHT, set_z_fade_height(new_z_fade_height, false)); // false = no report TERN_(ENABLE_LEVELING_FADE_HEIGHT, set_z_fade_height(new_z_fade_height, false)); // false = no report
TERN_(AUTO_BED_LEVELING_BILINEAR, refresh_bed_level()); TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level());
TERN_(HAS_MOTOR_CURRENT_PWM, stepper.refresh_motor_power()); TERN_(HAS_MOTOR_CURRENT_PWM, stepper.refresh_motor_power());
@ -876,22 +876,26 @@ void MarlinSettings::postprocess() {
{ {
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
static_assert( static_assert(
sizeof(z_values) == (GRID_MAX_POINTS) * sizeof(z_values[0][0]), sizeof(Z_VALUES_ARR) == (GRID_MAX_POINTS) * sizeof(Z_VALUES_ARR[0][0]),
"Bilinear Z array is the wrong size." "Bilinear Z array is the wrong size."
); );
#else
const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0};
#endif #endif
const uint8_t grid_max_x = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_X, 3), const uint8_t grid_max_x = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_X, 3),
grid_max_y = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_Y, 3); grid_max_y = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_Y, 3);
EEPROM_WRITE(grid_max_x); EEPROM_WRITE(grid_max_x);
EEPROM_WRITE(grid_max_y); EEPROM_WRITE(grid_max_y);
EEPROM_WRITE(bilinear_grid_spacing); #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
EEPROM_WRITE(bilinear_start); EEPROM_WRITE(bbl.get_grid_spacing());
EEPROM_WRITE(bbl.get_grid_start());
#else
const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0};
EEPROM_WRITE(bilinear_grid_spacing);
EEPROM_WRITE(bilinear_start);
#endif
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
EEPROM_WRITE(z_values); // 9-256 floats EEPROM_WRITE(Z_VALUES_ARR); // 9-256 floats
#else #else
dummyf = 0; dummyf = 0;
for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummyf); for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummyf);
@ -1791,20 +1795,19 @@ void MarlinSettings::postprocess() {
uint8_t grid_max_x, grid_max_y; uint8_t grid_max_x, grid_max_y;
EEPROM_READ_ALWAYS(grid_max_x); // 1 byte EEPROM_READ_ALWAYS(grid_max_x); // 1 byte
EEPROM_READ_ALWAYS(grid_max_y); // 1 byte EEPROM_READ_ALWAYS(grid_max_y); // 1 byte
xy_pos_t spacing, start;
EEPROM_READ(spacing); // 2 ints
EEPROM_READ(start); // 2 ints
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
if (grid_max_x == (GRID_MAX_POINTS_X) && grid_max_y == (GRID_MAX_POINTS_Y)) { if (grid_max_x == (GRID_MAX_POINTS_X) && grid_max_y == (GRID_MAX_POINTS_Y)) {
if (!validating) set_bed_leveling_enabled(false); if (!validating) set_bed_leveling_enabled(false);
EEPROM_READ(bilinear_grid_spacing); // 2 ints bbl.set_grid(spacing, start);
EEPROM_READ(bilinear_start); // 2 ints EEPROM_READ(Z_VALUES_ARR); // 9 to 256 floats
EEPROM_READ(z_values); // 9 to 256 floats
} }
else // EEPROM data is stale else // EEPROM data is stale
#endif // AUTO_BED_LEVELING_BILINEAR #endif // AUTO_BED_LEVELING_BILINEAR
{ {
// Skip past disabled (or stale) Bilinear Grid data // Skip past disabled (or stale) Bilinear Grid data
xy_pos_t bgs, bs;
EEPROM_READ(bgs);
EEPROM_READ(bs);
for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummyf); for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummyf);
} }
} }
@ -3337,7 +3340,7 @@ void MarlinSettings::reset() {
LOOP_L_N(px, GRID_MAX_POINTS_X) { LOOP_L_N(px, GRID_MAX_POINTS_X) {
CONFIG_ECHO_START(); CONFIG_ECHO_START();
SERIAL_ECHOPGM(" G29 W I", px, " J", py); SERIAL_ECHOPGM(" G29 W I", px, " J", py);
SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(z_values[px][py]), 5); SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(Z_VALUES_ARR[px][py]), 5);
} }
} }
} }