Skip to content

Commit 0369ceb

Browse files
committed
'G29 P' optional, other improvements
1 parent 9cd897f commit 0369ceb

File tree

4 files changed

+99
-101
lines changed

4 files changed

+99
-101
lines changed

Marlin/Configuration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,9 @@
22332233
#define BILINEAR_SUBDIVISIONS 3
22342234
#endif
22352235

2236+
// Add 'G29 P' to fill the mesh with a single value
2237+
//#define ABL_BILINEAR_G29_P_FILL_MESH
2238+
22362239
#endif
22372240

22382241
#elif ENABLED(AUTO_BED_LEVELING_UBL)

Marlin/src/feature/bedlevel/abl/bbl.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,19 @@ void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, c
9797
#endif
9898
#endif
9999

100-
void LevelingBilinear::reset() {
101-
grid_start.reset();
102-
grid_spacing.reset();
100+
void LevelingBilinear::fill(const float val/*=NAN*/) {
103101
GRID_LOOP(x, y) {
104-
z_values[x][y] = NAN;
102+
z_values[x][y] = val;
105103
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0));
106104
}
107105
}
108106

107+
void LevelingBilinear::reset() {
108+
grid_start.reset();
109+
grid_spacing.reset();
110+
fill();
111+
}
112+
109113
void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) {
110114
grid_spacing = _grid_spacing;
111115
grid_start = _grid_start;

Marlin/src/feature/bedlevel/abl/bbl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class LevelingBilinear {
5050
#endif
5151

5252
public:
53+
static void fill(const float val=NAN);
5354
static void reset();
5455
static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start);
5556
static void extrapolate_unprobed_bed_level();

Marlin/src/gcode/bedlevel/abl/G29.cpp

Lines changed: 87 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,15 @@ class G29_State {
200200
*
201201
* With AUTO_BED_LEVELING_BILINEAR:
202202
* Z<float> Supply additional Z offset to all probe points.
203-
* W<bool> Write a mesh point. (If G29 is idle.)
204-
* I<index> Index for mesh point
205-
* J<index> Index for mesh point
206-
* X<float> For mesh point, overrides I
207-
* Y<float> For mesh point, overrides J
208-
* Z<float> For mesh point. If omitted, uses current position's raw Z
209-
* P<float> Populate the mesh with a specified Z value.
203+
* W<bool> Write a mesh point. (If G29 is idle.)
204+
* I<index> Index for mesh point
205+
* J<index> Index for mesh point
206+
* X<float> For mesh point, overrides I
207+
* Y<float> For mesh point, overrides J
208+
* Z<float> For mesh point. If omitted, uses current position's raw Z
209+
*
210+
* With ABL_BILINEAR_G29_P_FILL_MESH
211+
* P<float> Populate the mesh with a specified Z value
210212
*
211213
* With DEBUG_LEVELING_FEATURE:
212214
* C<bool> Make a totally fake grid with no actual probing.
@@ -243,30 +245,89 @@ G29_TYPE GcodeSuite::G29() {
243245
if (DISABLED(PROBE_MANUALLY) && seenQ) G29_RETURN(false, false);
244246
#endif
245247

246-
// P = populate grid with specified Z value
247-
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
248-
bool do_init = parser.seenval('P');
249-
float init_val = 0.0f;
250-
if (do_init) {
251-
init_val = RAW_Z_POSITION(parser.value_linear_units());
252-
if (!WITHIN(init_val, -10, 10)) {
253-
SERIAL_ERROR_MSG("Bad initialization value");
248+
// W = Write a mesh point (below)
249+
const bool seenW = TERN0(AUTO_BED_LEVELING_BILINEAR, parser.seen_test('W'));
250+
if (seenW && g29_in_progress) {
251+
SERIAL_WARN_MSG("(W) ignored.");
252+
G29_RETURN(false, false);
253+
}
254+
255+
// J = Jettison bed leveling data
256+
const bool seenJ = !seenW && parser.seen_test('J');
257+
if (seenJ) {
258+
if (g29_in_progress) {
259+
SERIAL_WARN_MSG("(J) ignored.");
260+
G29_RETURN(false, false);
261+
}
262+
else
263+
reset_bed_level();
264+
}
265+
266+
// P = Populate the mesh with a specified value
267+
#if ENABLED(ABL_BILINEAR_G29_P_FILL_MESH)
268+
if (parser.seenval('P')) {
269+
const float init_val = parser.value_linear_units();
270+
if (!WITHIN(init_val, -10.0f, 10.0f)) {
271+
SERIAL_WARN_MSG("(P) value out of range (-10-10).\n");
254272
G29_RETURN(false, false);
255273
}
274+
bedlevel.fill(init_val);
256275
}
257-
#else
258-
constexpr bool do_init = false;
259-
constexpr float init_val = 0.0f;
276+
#endif
277+
278+
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
279+
280+
if (seenW) {
281+
282+
const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position.z;
283+
if (!WITHIN(rz, -10, 10)) {
284+
SERIAL_ERROR_MSG("(W) value out of range (-10-10).");
285+
G29_RETURN(false, false);
286+
}
287+
288+
const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
289+
ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
290+
int8_t i = parser.byteval('I', -1), j = parser.byteval('J', -1);
291+
292+
#pragma GCC diagnostic push
293+
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
294+
295+
if (!isnan(rx) && !isnan(ry)) {
296+
// Get nearest i / j from rx / ry
297+
i = (rx - bedlevel.grid_start.x) / bedlevel.grid_spacing.x + 0.5f;
298+
j = (ry - bedlevel.grid_start.y) / bedlevel.grid_spacing.y + 0.5f;
299+
LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
300+
LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
301+
}
302+
303+
#pragma GCC diagnostic pop
304+
305+
if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
306+
set_bed_leveling_enabled(false);
307+
bedlevel.z_values[i][j] = rz;
308+
bedlevel.refresh_bed_level();
309+
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
310+
if (!leveling_is_valid()) SERIAL_WARN_MSG("Bilinear grid is invalid.");
311+
if (abl.reenable) {
312+
set_bed_leveling_enabled(true);
313+
report_current_position();
314+
}
315+
}
316+
317+
G29_RETURN(false, false);
318+
319+
} // seenW
320+
260321
#endif
261322

262323
// A = Abort manual probing
263324
// C<bool> = Generate fake probe points (DEBUG_LEVELING_FEATURE)
264325
const bool seenA = TERN0(PROBE_MANUALLY, parser.seen_test('A')),
265326
no_action = seenA || seenQ,
266-
faux = (ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action) || do_init;
327+
faux = (ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action);
267328

268329
// O = Don't level if leveling is already active
269-
if (!no_action && planner.leveling_active && parser.boolval('O')) {
330+
if (parser.boolval('O') && !no_action && planner.leveling_active) {
270331
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Auto-level not needed, skip");
271332
G29_RETURN(false, false);
272333
}
@@ -275,14 +336,8 @@ G29_TYPE GcodeSuite::G29() {
275336
if (parser.seen_test('N'))
276337
process_subcommands_now(TERN(CAN_SET_LEVELING_AFTER_G28, F("G28L0"), FPSTR(G28_STR)));
277338

278-
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
279-
const bool seen_w = parser.seen_test('W');
280-
#else
281-
constexpr bool seen_w = false;
282-
#endif
283-
284339
// Don't allow auto-leveling without homing first
285-
if (!seen_w && !faux && homing_needed_error()) G29_RETURN(false, false);
340+
if (!faux && homing_needed_error()) G29_RETURN(false, false);
286341

287342
// 3-point leveling gets points from the probe class
288343
#if ENABLED(AUTO_BED_LEVELING_3POINT)
@@ -320,58 +375,6 @@ G29_TYPE GcodeSuite::G29() {
320375

321376
abl.reenable = planner.leveling_active;
322377

323-
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
324-
325-
if (seen_w) {
326-
if (!leveling_is_valid()) {
327-
SERIAL_ERROR_MSG("No bilinear grid");
328-
G29_RETURN(false, false);
329-
}
330-
331-
const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position.z;
332-
if (!WITHIN(rz, -10, 10)) {
333-
SERIAL_ERROR_MSG("Bad Z value");
334-
G29_RETURN(false, false);
335-
}
336-
337-
const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
338-
ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
339-
int8_t i = parser.byteval('I', -1), j = parser.byteval('J', -1);
340-
341-
#pragma GCC diagnostic push
342-
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
343-
344-
if (!isnan(rx) && !isnan(ry)) {
345-
// Get nearest i / j from rx / ry
346-
i = (rx - bedlevel.grid_start.x) / bedlevel.grid_spacing.x + 0.5f;
347-
j = (ry - bedlevel.grid_start.y) / bedlevel.grid_spacing.y + 0.5f;
348-
LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
349-
LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
350-
}
351-
352-
#pragma GCC diagnostic pop
353-
354-
if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
355-
set_bed_leveling_enabled(false);
356-
bedlevel.z_values[i][j] = rz;
357-
bedlevel.refresh_bed_level();
358-
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz));
359-
if (abl.reenable) {
360-
set_bed_leveling_enabled(true);
361-
report_current_position();
362-
}
363-
}
364-
G29_RETURN(false, false);
365-
} // parser.seen_test('W')
366-
367-
#endif
368-
369-
// Jettison bed leveling data
370-
if (!seen_w && parser.seen_test('J')) {
371-
reset_bed_level();
372-
G29_RETURN(false, false);
373-
}
374-
375378
abl.verbose_level = parser.intval('V');
376379
if (!WITHIN(abl.verbose_level, 0, 4)) {
377380
SERIAL_ECHOLNPGM(GCODE_ERR_MSG("(V)erbose level implausible (0-4)."));
@@ -732,12 +735,9 @@ G29_TYPE GcodeSuite::G29() {
732735
if (PR_INNER_VAR == inStart) {
733736
char tmp_1[32];
734737

735-
// move to the start point of new line
736-
if (faux)
737-
abl.measured_z = do_init ? init_val : 0.001f * random(-100, 101);
738-
else
739-
abl.measured_z = probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
740-
738+
// Move to the start point of new line
739+
abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
740+
741741
// Go to the end of the row/column ... and back up by one
742742
// TODO: Why not just use... PR_INNER_VAR = inStop - inInc
743743
for (PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc);
@@ -790,10 +790,7 @@ G29_TYPE GcodeSuite::G29() {
790790

791791
#else // !BD_SENSOR_PROBE_NO_STOP
792792

793-
if (faux)
794-
abl.measured_z = do_init ? init_val : 0.001f * random(-100, 101);
795-
else
796-
abl.measured_z = probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
793+
abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
797794

798795
#endif
799796

@@ -842,10 +839,7 @@ G29_TYPE GcodeSuite::G29() {
842839

843840
// Retain the last probe position
844841
abl.probePos = xy_pos_t(points[i]);
845-
if (faux)
846-
abl.measured_z = do_init ? init_val : 0.001f * random(-100, 101);
847-
else
848-
abl.measured_z = probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
842+
abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level);
849843
if (isnan(abl.measured_z)) {
850844
set_bed_leveling_enabled(abl.reenable);
851845
break;
@@ -1036,10 +1030,6 @@ G29_TYPE GcodeSuite::G29() {
10361030
// Restore state after probing
10371031
if (!faux) restore_feedrate_and_scaling();
10381032

1039-
// Return here if we merely initialized for a with value (bilinear G29 P<value>)
1040-
// No need to do the after G29 gcode or the other stuff
1041-
if (do_init) G29_RETURN(false, true);
1042-
10431033
TERN_(HAS_BED_PROBE, probe.move_z_after_probing());
10441034

10451035
#ifdef EVENT_GCODE_AFTER_G29

0 commit comments

Comments
 (0)