diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a443d4b302..9f136b1180 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2169,6 +2169,13 @@ //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING +/** + * Base the Probe Z Offset on a trustworthy Z endstop + * Requires the Z axis to be homed with an endstop. + * Use 'M206 Z' to adjust the Z endstop to match the height at bed center. + */ +//#define AUTO_Z_PROBE_OFFSET + /** * Commands to execute at the start of G29 probing, * after switching to the PROBING_TOOL. diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 6341933bfb..805c134e2b 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -318,16 +318,28 @@ void unified_bed_leveling::G29() { // Check for commands that require the printer to be homed if (may_move) { planner.synchronize(); - #if ALL(DWIN_LCD_PROUI, ZHOME_BEFORE_LEVELING) - save_ubl_active_state_and_disable(); - gcode.process_subcommands_now(F("G28Z")); - restore_ubl_active_state(false); // ...without telling ExtUI "done" - #else - // Send 'N' to force homing before G29 (internal only) - if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes(); - #endif + + // Send 'N' to force homing before G29 (internal only) + const bool force_home = axes_should_home() || parser.seen_test('N'); + if (force_home) { + gcode.home_all_axes(); + } + else { + #if ALL(DWIN_LCD_PROUI, ZHOME_BEFORE_LEVELING) + save_ubl_active_state_and_disable(); + gcode.process_subcommands_now(F("G28Z")); + restore_ubl_active_state(false); // ...without telling ExtUI "done" + #elif ENABLED(AUTO_Z_PROBE_OFFSET) + gcode.process_subcommands_now(F("G28XYL0")); // Home X and Y only + #endif + } + probe.use_probing_tool(); + #if ENABLED(AUTO_Z_PROBE_OFFSET) + (void)probe.probe_to_obtain_z_offset(); + #endif + #ifdef EVENT_GCODE_BEFORE_G29 if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29); gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 800d51dac6..e631f0e123 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -292,6 +292,10 @@ G29_TYPE GcodeSuite::G29() { gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); #endif + #if ENABLED(AUTO_Z_PROBE_OFFSET) + (void)probe.probe_to_obtain_z_offset(); + #endif + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) abl.abl_probe_index = -1; #endif @@ -588,7 +592,7 @@ G29_TYPE GcodeSuite::G29() { abl.z_values[abl.meshCount.x][abl.meshCount.y] = 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, newz); #endif } diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 5856723c77..7101caab71 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2544,6 +2544,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "Z_HOME_DIR must be -1 when homing Z with the probe." #elif ALL(USE_PROBE_FOR_Z_HOMING, HOME_Z_FIRST) #error "HOME_Z_FIRST can't be used when homing Z with a probe." +#elif ALL(USE_PROBE_FOR_Z_HOMING, AUTO_Z_PROBE_OFFSET) + #error "AUTO_Z_PROBE_OFFSET requires Z Endstop Homing." #endif #if Z_HOME_TO_MAX && defined(Z_AFTER_HOMING) && DISABLED(ALLOW_Z_AFTER_HOMING) diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 3a8bb2b6c6..fd489a4614 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -763,6 +763,25 @@ bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s) { } #endif +#if ENABLED(AUTO_Z_PROBE_OFFSET) + + // Determine the probe.offset.z based on the trusted Z0 + // Return 'true' on error condition. + bool Probe::probe_to_obtain_z_offset() { + use_probing_tool(); + do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE); + const xy_pos_t ref_xy = { + TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_X_POINT, X_CENTER), + TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_Y_POINT, Y_CENTER) + }; + const float zval = probe_at_point(ref_xy, PROBE_PT_RAISE); + if (zval == NAN) return true; + offset.z = -zval; + return false; + } + +#endif // AUTO_Z_PROBE_OFFSET + /** * @brief Probe at the current XY (possibly more than once) to find the bed Z. * diff --git a/Marlin/src/module/probe.h b/Marlin/src/module/probe.h index d0f0ada34c..5a9a5ba711 100644 --- a/Marlin/src/module/probe.h +++ b/Marlin/src/module/probe.h @@ -363,6 +363,10 @@ public: static bool tare(); #endif + #if ENABLED(AUTO_Z_PROBE_OFFSET) + static bool probe_to_obtain_z_offset(); + #endif + // Basic functions for Sensorless Homing and Probing #if HAS_DELTA_SENSORLESS_PROBING static void set_offset_sensorless_adj(const float sz);