Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -2233,6 +2233,9 @@
#define BILINEAR_SUBDIVISIONS 3
#endif

// Add 'G29 P' to fill the mesh with a single value
//#define ABL_BILINEAR_G29_P_FILL_MESH

#endif

#elif ENABLED(AUTO_BED_LEVELING_UBL)
Expand Down
12 changes: 8 additions & 4 deletions Marlin/src/feature/bedlevel/abl/bbl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,19 @@ void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, c
#endif
#endif

void LevelingBilinear::reset() {
grid_start.reset();
grid_spacing.reset();
void LevelingBilinear::fill(const float val/*=NAN*/) {
GRID_LOOP(x, y) {
z_values[x][y] = NAN;
z_values[x][y] = val;
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
}
}

void LevelingBilinear::reset() {
grid_start.reset();
grid_spacing.reset();
fill();
}

void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) {
grid_spacing = _grid_spacing;
grid_start = _grid_start;
Expand Down
1 change: 1 addition & 0 deletions Marlin/src/feature/bedlevel/abl/bbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class LevelingBilinear {
#endif

public:
static void fill(const float val=NAN);
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();
Expand Down
158 changes: 90 additions & 68 deletions Marlin/src/gcode/bedlevel/abl/G29.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,15 @@ class G29_State {
*
* With AUTO_BED_LEVELING_BILINEAR:
* Z<float> Supply additional Z offset to all probe points.
* W<bool> Write a mesh point. (If G29 is idle.)
* I<index> Index for mesh point
* J<index> Index for mesh point
* X<float> For mesh point, overrides I
* Y<float> For mesh point, overrides J
* Z<float> For mesh point. If omitted, uses current position's raw Z
* W<bool> Write a mesh point. (If G29 is idle.)
* I<index> Index for mesh point
* J<index> Index for mesh point
* X<float> For mesh point, overrides I
* Y<float> For mesh point, overrides J
* Z<float> For mesh point. If omitted, uses current position's raw Z
*
* With ABL_BILINEAR_G29_P_FILL_MESH
* P<float> Populate the mesh with a specified Z value
*
* With DEBUG_LEVELING_FEATURE:
* C<bool> Make a totally fake grid with no actual probing.
Expand Down Expand Up @@ -242,14 +245,89 @@ G29_TYPE GcodeSuite::G29() {
if (DISABLED(PROBE_MANUALLY) && seenQ) G29_RETURN(false, false);
#endif

// W = Write a mesh point (below)
const bool seenW = TERN0(AUTO_BED_LEVELING_BILINEAR, parser.seen_test('W'));
if (seenW && g29_in_progress) {
SERIAL_WARN_MSG("(W) ignored.");
G29_RETURN(false, false);
}

// J = Jettison bed leveling data
const bool seenJ = !seenW && parser.seen_test('J');
if (seenJ) {
if (g29_in_progress) {
SERIAL_WARN_MSG("(J) ignored.");
G29_RETURN(false, false);
}
else
reset_bed_level();
}

// P = Populate the mesh with a specified value
#if ENABLED(ABL_BILINEAR_G29_P_FILL_MESH)
if (parser.seenval('P')) {
const float init_val = parser.value_linear_units();
if (!WITHIN(init_val, -10.0f, 10.0f)) {
SERIAL_WARN_MSG("(P) value out of range (-10-10).\n");
G29_RETURN(false, false);
}
bedlevel.fill(init_val);
}
#endif

#if ENABLED(AUTO_BED_LEVELING_BILINEAR)

if (seenW) {

const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position.z;
if (!WITHIN(rz, -10, 10)) {
SERIAL_ERROR_MSG("(W) value out of range (-10-10).");
G29_RETURN(false, false);
}

const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
int8_t i = parser.byteval('I', -1), j = parser.byteval('J', -1);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"

if (!isnan(rx) && !isnan(ry)) {
// Get nearest i / j from rx / ry
i = (rx - bedlevel.grid_start.x) / bedlevel.grid_spacing.x + 0.5f;
j = (ry - bedlevel.grid_start.y) / bedlevel.grid_spacing.y + 0.5f;
LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
}

#pragma GCC diagnostic pop

if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
set_bed_leveling_enabled(false);
bedlevel.z_values[i][j] = rz;
bedlevel.refresh_bed_level();
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
if (!leveling_is_valid()) SERIAL_WARN_MSG("Bilinear grid is invalid.");
if (abl.reenable) {
set_bed_leveling_enabled(true);
report_current_position();
}
}

G29_RETURN(false, false);

} // seenW

#endif

// A = Abort manual probing
// C<bool> = Generate fake probe points (DEBUG_LEVELING_FEATURE)
const bool seenA = TERN0(PROBE_MANUALLY, parser.seen_test('A')),
no_action = seenA || seenQ,
faux = ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action;
faux = (ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action);

// O = Don't level if leveling is already active
if (!no_action && planner.leveling_active && parser.boolval('O')) {
if (parser.boolval('O') && !no_action && planner.leveling_active) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Auto-level not needed, skip");
G29_RETURN(false, false);
}
Expand All @@ -259,7 +337,7 @@ G29_TYPE GcodeSuite::G29() {
process_subcommands_now(TERN(CAN_SET_LEVELING_AFTER_G28, F("G28L0"), FPSTR(G28_STR)));

// Don't allow auto-leveling without homing first
if (homing_needed_error()) G29_RETURN(false, false);
if (!faux && homing_needed_error()) G29_RETURN(false, false);

// 3-point leveling gets points from the probe class
#if ENABLED(AUTO_BED_LEVELING_3POINT)
Expand Down Expand Up @@ -297,63 +375,6 @@ G29_TYPE GcodeSuite::G29() {

abl.reenable = planner.leveling_active;

#if ENABLED(AUTO_BED_LEVELING_BILINEAR)

const bool seen_w = parser.seen_test('W');
if (seen_w) {
if (!leveling_is_valid()) {
SERIAL_ERROR_MSG("No bilinear grid");
G29_RETURN(false, false);
}

const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position.z;
if (!WITHIN(rz, -10, 10)) {
SERIAL_ERROR_MSG("Bad Z value");
G29_RETURN(false, false);
}

const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
int8_t i = parser.byteval('I', -1), j = parser.byteval('J', -1);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"

if (!isnan(rx) && !isnan(ry)) {
// Get nearest i / j from rx / ry
i = (rx - bedlevel.grid_start.x) / bedlevel.grid_spacing.x + 0.5f;
j = (ry - bedlevel.grid_start.y) / bedlevel.grid_spacing.y + 0.5f;
LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
}

#pragma GCC diagnostic pop

if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
set_bed_leveling_enabled(false);
bedlevel.z_values[i][j] = rz;
bedlevel.refresh_bed_level();
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
if (abl.reenable) {
set_bed_leveling_enabled(true);
report_current_position();
}
}
G29_RETURN(false, false);
} // parser.seen_test('W')

#else

constexpr bool seen_w = false;

#endif

// Jettison bed leveling data
if (!seen_w && parser.seen_test('J')) {
reset_bed_level();
G29_RETURN(false, false);
}

abl.verbose_level = parser.intval('V');
if (!WITHIN(abl.verbose_level, 0, 4)) {
SERIAL_ECHOLNPGM(GCODE_ERR_MSG("(V)erbose level implausible (0-4)."));
Expand Down Expand Up @@ -714,8 +735,9 @@ G29_TYPE GcodeSuite::G29() {
if (PR_INNER_VAR == inStart) {
char tmp_1[32];

// move to the start point of new line
// Move to the start point of new line
abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);

// Go to the end of the row/column ... and back up by one
// TODO: Why not just use... PR_INNER_VAR = inStop - inInc
for (PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc);
Expand Down Expand Up @@ -817,7 +839,7 @@ G29_TYPE GcodeSuite::G29() {

// Retain the last probe position
abl.probePos = xy_pos_t(points[i]);
abl.measured_z = faux ? 0.001 * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
if (isnan(abl.measured_z)) {
set_bed_leveling_enabled(abl.reenable);
break;
Expand Down