diff --git a/Marlin/src/gcode/probe/M401_M402.cpp b/Marlin/src/gcode/probe/M401_M402.cpp index 3389574919..7114cad9e8 100644 --- a/Marlin/src/gcode/probe/M401_M402.cpp +++ b/Marlin/src/gcode/probe/M401_M402.cpp @@ -38,30 +38,33 @@ * With BLTOUCH_HS_MODE: * H Report the current BLTouch HS mode state and exit * S Set High Speed (HS) Mode and exit without deploy + * + * R Remain in place after deploying (and before activating) the probe */ void GcodeSuite::M401() { - const bool seenH = parser.seen_test('H'), - seenS = parser.seen('S'); - if (seenH || seenS) { - #ifdef BLTOUCH_HS_MODE + #ifdef BLTOUCH_HS_MODE + const bool seenH = parser.seen_test('H'), + seenS = parser.seen('S'); + if (seenH || seenS) { if (seenS) bltouch.high_speed_mode = parser.value_bool(); SERIAL_ECHO_START(); SERIAL_ECHOPGM("BLTouch HS mode "); serialprintln_onoff(bltouch.high_speed_mode); - #endif - } - else { - probe.deploy(); - TERN_(PROBE_TARE, probe.tare()); - report_current_position(); - } + return; + } + #endif + + probe.deploy(parser.boolval('R')); + TERN_(PROBE_TARE, probe.tare()); + report_current_position(); } /** * M402: Deactivate and stow the Z probe + * R Remain in place after stowing (and before deactivating) the probe */ void GcodeSuite::M402() { - probe.stow(); + probe.stow(parser.boolval('R')); probe.move_z_after_probing(); report_current_position(); } diff --git a/Marlin/src/lcd/menu/menu_bed_tramming.cpp b/Marlin/src/lcd/menu/menu_bed_tramming.cpp index 5f1b547871..8129a347c3 100644 --- a/Marlin/src/lcd/menu/menu_bed_tramming.cpp +++ b/Marlin/src/lcd/menu/menu_bed_tramming.cpp @@ -43,6 +43,10 @@ #define BED_TRAMMING_HEIGHT 0.0 #endif +#if BOTH(HAS_STOWABLE_PROBE, BED_TRAMMING_USE_PROBE) && DISABLED(BLTOUCH) + #define NEEDS_PROBE_DEPLOY 1 +#endif + #if ENABLED(BED_TRAMMING_USE_PROBE) #include "../../module/probe.h" #include "../../module/endstops.h" @@ -97,38 +101,38 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] static int8_t bed_corner; /** - * Select next corner coordinates + * Move to the next corner coordinates */ -static void _lcd_bed_tramming_get_next_position() { +static void _lcd_goto_next_corner() { + xy_pos_t corner_point = lf; // Left front if (tramming_3_points) { if (bed_corner >= available_points) bed_corner = 0; // Above max position -> move back to first corner switch (bed_corner) { case 0 ... 1: // First two corners set explicitly by the configuration - current_position = lf; // Left front switch (lco[bed_corner]) { - case RF: current_position.x = rb.x; break; // Right Front - case RB: current_position = rb; break; // Right Back - case LB: current_position.y = rb.y; break; // Left Back + case RF: corner_point.x = rb.x; break; // Right Front + case RB: corner_point = rb; break; // Right Back + case LB: corner_point.y = rb.y; break; // Left Back } break; case 2: // Determine which edge to probe for 3rd point - current_position.set(lf.x + (rb.x - lf.x) / 2, lf.y + (rb.y - lf.y) / 2); - if ((lco[0] == LB && lco[1] == RB) || (lco[0] == RB && lco[1] == LB)) current_position.y = lf.y; // Front Center - if ((lco[0] == LF && lco[1] == LB) || (lco[0] == LB && lco[1] == LF)) current_position.x = rb.x; // Center Right - if ((lco[0] == RF && lco[1] == RB) || (lco[0] == RB && lco[1] == RF)) current_position.x = lf.x; // Left Center - if ((lco[0] == LF && lco[1] == RF) || (lco[0] == RF && lco[1] == LF)) current_position.y = rb.y; // Center Back - #if DISABLED(BED_TRAMMING_INCLUDE_CENTER) && ENABLED(BED_TRAMMING_USE_PROBE) + corner_point.set(lf.x + (rb.x - lf.x) / 2, lf.y + (rb.y - lf.y) / 2); + if ((lco[0] == LB && lco[1] == RB) || (lco[0] == RB && lco[1] == LB)) corner_point.y = lf.y; // Front Center + if ((lco[0] == LF && lco[1] == LB) || (lco[0] == LB && lco[1] == LF)) corner_point.x = rb.x; // Center Right + if ((lco[0] == RF && lco[1] == RB) || (lco[0] == RB && lco[1] == RF)) corner_point.x = lf.x; // Left Center + if ((lco[0] == LF && lco[1] == RF) || (lco[0] == RF && lco[1] == LF)) corner_point.y = rb.y; // Center Back + #if ENABLED(BED_TRAMMING_USE_PROBE) && DISABLED(BED_TRAMMING_INCLUDE_CENTER) bed_corner++; // Must increment the count to ensure it resets the loop if the 3rd point is out of tolerance #endif break; #if ENABLED(BED_TRAMMING_INCLUDE_CENTER) case 3: - current_position.set(X_CENTER, Y_CENTER); + corner_point.set(X_CENTER, Y_CENTER); break; #endif } @@ -136,23 +140,29 @@ static void _lcd_bed_tramming_get_next_position() { else { // Four-Corner Bed Tramming with optional center if (TERN0(BED_TRAMMING_INCLUDE_CENTER, bed_corner == center_index)) { - current_position.set(X_CENTER, Y_CENTER); - TERN_(BED_TRAMMING_USE_PROBE, good_points--); // Decrement to allow one additional probe point + corner_point.set(X_CENTER, Y_CENTER); } else { - current_position = lf; // Left front switch (lco[bed_corner]) { - case RF: current_position.x = rb.x; break; // Right Front - case RB: current_position = rb; break; // Right Back - case LB: current_position.y = rb.y; break; // Left Back + case RF: corner_point.x = rb.x; break; // Right Front + case RB: corner_point = rb; break; // Right Back + case LB: corner_point.y = rb.y; break; // Left Back } } } + + float z = BED_TRAMMING_Z_HOP; + #if BOTH(BED_TRAMMING_USE_PROBE, BLTOUCH) + z += bltouch.z_extra_clearance(); + #endif + line_to_z(z); + do_blocking_move_to_xy(DIFF_TERN(BED_TRAMMING_USE_PROBE, corner_point, probe.offset_xy), manual_feedrate_mm_s.x); + #if DISABLED(BED_TRAMMING_USE_PROBE) + line_to_z(BED_TRAMMING_HEIGHT); + if (++bed_corner >= available_points) bed_corner = 0; + #endif } -/** - * Level corners, starting in the front-left corner. - */ #if ENABLED(BED_TRAMMING_USE_PROBE) #define VALIDATE_POINT(X, Y, STR) static_assert(Probe::build_time::can_reach((X), (Y)), \ @@ -210,13 +220,21 @@ static void _lcd_bed_tramming_get_next_position() { MenuItem_confirm::select_screen( GET_TEXT_F(TERN(HAS_LEVELING, MSG_BUTTON_LEVEL, MSG_BUTTON_DONE)) , TERN(HAS_LEVELING, GET_TEXT_F(MSG_BUTTON_BACK), nullptr) - , []{ queue.inject(TERN(HAS_LEVELING, F("G29N"), FPSTR(G28_STR))); ui.return_to_status(); } - , TERN(HAS_LEVELING, ui.goto_previous_screen_no_defer, []{}) + , []{ + tramming_done = true; + queue.inject(TERN(HAS_LEVELING, F("G29N"), FPSTR(G28_STR))); + ui.goto_previous_screen_no_defer(); + } + , []{ + tramming_done = true; + TERN_(HAS_LEVELING, ui.goto_previous_screen_no_defer()); + TERN_(NEEDS_PROBE_DEPLOY, probe.stow(true)); + } , GET_TEXT_F(MSG_BED_TRAMMING_IN_RANGE) ); } - bool _lcd_bed_tramming_probe(bool verify=false) { + bool _lcd_bed_tramming_probe(const bool verify=false) { if (verify) line_to_z(BED_TRAMMING_Z_HOP); // do clearance if needed TERN_(BLTOUCH, if (!bltouch.high_speed_mode) bltouch.deploy()); // Deploy in LOW SPEED MODE on every probe action do_blocking_move_to_z(last_z - BED_TRAMMING_PROBE_TOLERANCE, MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW)); // Move down to lower tolerance @@ -232,6 +250,11 @@ static void _lcd_bed_tramming_get_next_position() { last_z = current_position.z; // Above tolerance. Set a new Z for subsequent corners. good_points = 0; // ...and start over } + + // Raise the probe after the last point to give clearance for stow + if (TERN0(NEEDS_PROBE_DEPLOY, good_points == nr_edge_points - 1)) + line_to_z(BED_TRAMMING_Z_HOP); + return true; // probe triggered } line_to_z(last_z); // go back to tolerance middle point before raise @@ -267,11 +290,7 @@ static void _lcd_bed_tramming_get_next_position() { ui.refresh(LCDVIEW_REDRAW_NOW); _lcd_draw_probing(); // update screen with # of good points - line_to_z(current_position.z + BED_TRAMMING_Z_HOP + TERN0(BLTOUCH, bltouch.z_extra_clearance())); // clearance - - _lcd_bed_tramming_get_next_position(); // Select next corner coordinates - current_position -= probe.offset_xy; // Account for probe offsets - do_blocking_move_to_xy(current_position); // Goto corner + _lcd_goto_next_corner(); // Goto corner TERN_(BLTOUCH, if (bltouch.high_speed_mode) bltouch.deploy()); // Deploy in HIGH SPEED MODE if (!_lcd_bed_tramming_probe()) { // Probe down to tolerance @@ -306,31 +325,26 @@ static void _lcd_bed_tramming_get_next_position() { ui.set_selection(true); } -#else // !BED_TRAMMING_USE_PROBE - - static void _lcd_goto_next_corner() { - line_to_z(BED_TRAMMING_Z_HOP); - - // Select next corner coordinates - _lcd_bed_tramming_get_next_position(); - - line_to_current_position(manual_feedrate_mm_s.x); - line_to_z(BED_TRAMMING_HEIGHT); - if (++bed_corner >= available_points) bed_corner = 0; - } - -#endif // !BED_TRAMMING_USE_PROBE +#endif // BED_TRAMMING_USE_PROBE void _lcd_bed_tramming_homing() { - _lcd_draw_homing(); - if (!all_axes_homed()) return; + if (!all_axes_homed() && TERN1(NEEDS_PROBE_DEPLOY, probe.deploy())) return; + + #if HAS_LEVELING // Disable leveling so the planner won't mess with us + menu_leveling_was_active = planner.leveling_active; + set_bed_leveling_enabled(false); + #endif #if ENABLED(BED_TRAMMING_USE_PROBE) - _lcd_test_corners(); - if (tramming_done) ui.goto_previous_screen_no_defer(); + if (!tramming_done) _lcd_test_corners(); // May set tramming_done + if (tramming_done) { + ui.goto_previous_screen_no_defer(); + TERN_(NEEDS_PROBE_DEPLOY, probe.stow(true)); + } + tramming_done = true; TERN_(HAS_LEVELING, set_bed_leveling_enabled(menu_leveling_was_active)); - endstops.enable_z_probe(false); + TERN_(BLTOUCH, endstops.enable_z_probe(false)); #else // !BED_TRAMMING_USE_PROBE @@ -354,20 +368,28 @@ void _lcd_bed_tramming_homing() { #endif // !BED_TRAMMING_USE_PROBE } -void _lcd_bed_tramming() { - ui.defer_status_screen(); - if (!all_axes_trusted()) { - set_all_unhomed(); - queue.inject_P(G28_STR); +#if NEEDS_PROBE_DEPLOY + + void deploy_probe() { + if (!tramming_done) probe.deploy(true); + ui.goto_screen([]{ + if (ui.should_draw()) MenuItem_static::draw((LCD_HEIGHT - 1) / 2, GET_TEXT_F(MSG_MANUAL_DEPLOY)); + if (!probe.deploy() && !tramming_done) _lcd_bed_tramming_homing(); + }); } - // Disable leveling so the planner won't mess with us - #if HAS_LEVELING - menu_leveling_was_active = planner.leveling_active; - set_bed_leveling_enabled(false); - #endif +#endif // NEEDS_PROBE_DEPLOY - ui.goto_screen(_lcd_bed_tramming_homing); +void _lcd_bed_tramming() { + TERN_(BED_TRAMMING_USE_PROBE, tramming_done = false); + ui.defer_status_screen(); + set_all_unhomed(); + queue.inject(TERN(CAN_SET_LEVELING_AFTER_G28, F("G28L0"), FPSTR(G28_STR))); + ui.goto_screen([]{ + _lcd_draw_homing(); + if (!all_axes_homed()) return; + TERN(NEEDS_PROBE_DEPLOY, deploy_probe(), ui.goto_screen(_lcd_bed_tramming_homing)); + }); } #endif // HAS_MARLINUI_MENU && LCD_BED_TRAMMING diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index da69b725b9..ea17eee6ee 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -500,11 +500,11 @@ void Probe::probe_error_stop() { * * Return TRUE if the probe could not be deployed/stowed */ -bool Probe::set_deployed(const bool deploy) { +bool Probe::set_deployed(const bool deploy, const bool no_return/*=false*/) { if (DEBUGGING(LEVELING)) { DEBUG_POS("Probe::set_deployed", current_position); - DEBUG_ECHOLNPGM("deploy: ", deploy); + DEBUG_ECHOLNPGM("deploy=", deploy, " no_return=", no_return); } if (endstops.z_probe_enabled == deploy) return false; @@ -557,7 +557,8 @@ bool Probe::set_deployed(const bool deploy) { // If preheating is required before any probing... TERN_(PREHEAT_BEFORE_PROBING, if (deploy) preheat_for_probing(PROBING_NOZZLE_TEMP, PROBING_BED_TEMP)); - do_blocking_move_to(old_xy); + if (!no_return) do_blocking_move_to(old_xy); // Return to the original location unless handled externally + endstops.enable_z_probe(deploy); return false; } diff --git a/Marlin/src/module/probe.h b/Marlin/src/module/probe.h index b50f79ed5d..9aff9cff06 100644 --- a/Marlin/src/module/probe.h +++ b/Marlin/src/module/probe.h @@ -90,7 +90,7 @@ public: static void probe_error_stop(); - static bool set_deployed(const bool deploy); + static bool set_deployed(const bool deploy, const bool no_return=false); #if IS_KINEMATIC @@ -182,7 +182,7 @@ public: static constexpr xyz_pos_t offset = xyz_pos_t(NUM_AXIS_ARRAY_1(0)); // See #16767 - static bool set_deployed(const bool) { return false; } + static bool set_deployed(const bool, const bool=false) { return false; } static bool can_reach(const_float_t rx, const_float_t ry, const bool=true) { return position_is_reachable(rx, ry); } @@ -216,8 +216,8 @@ public: static constexpr xy_pos_t offset_xy = xy_pos_t({ 0, 0 }); // See #16767 #endif - static bool deploy() { return set_deployed(true); } - static bool stow() { return set_deployed(false); } + static bool deploy(const bool no_return=false) { return set_deployed(true, no_return); } + static bool stow(const bool no_return=false) { return set_deployed(false, no_return); } #if HAS_BED_PROBE || HAS_LEVELING #if IS_KINEMATIC