From 8b8ad14178374c06858444434988291993903fbb Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Mon, 9 Apr 2018 01:46:23 -0500
Subject: [PATCH] Add Z_PROBE_LOW_POINT to prevent damage

---
 Marlin/Configuration.h                    |  2 ++
 Marlin/src/config/default/Configuration.h |  2 ++
 Marlin/src/gcode/calibrate/G33.cpp        |  2 +-
 Marlin/src/inc/SanityCheck.h              |  4 +++
 Marlin/src/module/probe.cpp               | 35 ++++++++++++++++++-----
 Marlin/src/module/probe.h                 |  2 +-
 6 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index d3753dafcf..e21b580e3f 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -777,6 +777,8 @@
 #define Z_CLEARANCE_BETWEEN_PROBES  5 // Z Clearance between probe points
 //#define Z_AFTER_PROBING           5 // Z position after probing is done
 
+#define Z_PROBE_LOW_POINT          -2 // Farthest distance below the trigger-point to go before stopping
+
 // For M851 give a range for adjusting the Z probe offset
 #define Z_PROBE_OFFSET_RANGE_MIN -20
 #define Z_PROBE_OFFSET_RANGE_MAX 20
diff --git a/Marlin/src/config/default/Configuration.h b/Marlin/src/config/default/Configuration.h
index d3753dafcf..e21b580e3f 100644
--- a/Marlin/src/config/default/Configuration.h
+++ b/Marlin/src/config/default/Configuration.h
@@ -777,6 +777,8 @@
 #define Z_CLEARANCE_BETWEEN_PROBES  5 // Z Clearance between probe points
 //#define Z_AFTER_PROBING           5 // Z position after probing is done
 
+#define Z_PROBE_LOW_POINT          -2 // Farthest distance below the trigger-point to go before stopping
+
 // For M851 give a range for adjusting the Z probe offset
 #define Z_PROBE_OFFSET_RANGE_MIN -20
 #define Z_PROBE_OFFSET_RANGE_MAX 20
diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp
index 036b3425f3..72f4a01067 100644
--- a/Marlin/src/gcode/calibrate/G33.cpp
+++ b/Marlin/src/gcode/calibrate/G33.cpp
@@ -137,7 +137,7 @@ static void G33_cleanup(
 
 inline float calibration_probe(const float nx, const float ny, const bool stow) {
   #if HAS_BED_PROBE
-    return probe_pt(nx, ny, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, false);
+    return probe_pt(nx, ny, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, true);
   #else
     UNUSED(stow);
     return lcd_probe_pt(nx, ny);
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index cb390d0429..8af08e09ce 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -780,6 +780,10 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
     #error "MULTIPLE_PROBING must be >= 2."
   #endif
 
+  #if Z_PROBE_LOW_POINT > 0
+    #error "Z_PROBE_LOW_POINT must be less than or equal to 0."
+  #endif
+
 #else
 
   /**
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index 9375ff247c..ed585299bf 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -539,17 +539,34 @@ static bool do_probe_move(const float z, const float fr_mm_m) {
  *
  * @return The raw Z position where the probe was triggered
  */
-static float run_z_probe() {
+#define HAS_CALIBRATION_PROBE (ENABLED(DELTA_AUTO_CALIBRATION) && Z_PROBE_LOW_POINT < 0)
+static float run_z_probe(
+  #if HAS_CALIBRATION_PROBE
+    const bool is_calibration
+  #endif
+) {
 
   #if ENABLED(DEBUG_LEVELING_FEATURE)
     if (DEBUGGING(LEVELING)) DEBUG_POS(">>> run_z_probe", current_position);
   #endif
 
+  #if Z_PROBE_LOW_POINT < 0
+    // Stop the probe before it goes too low to prevent damage.
+    // If Z isn't known or this is a "calibration probe" then probe to -10mm.
+    #if !HAS_CALIBRATION_PROBE
+      constexpr bool is_calibration = false;
+    #endif
+    const float z_probe_low_point = !is_calibration && axis_known_position[Z_AXIS] ? -zprobe_zoffset + Z_PROBE_LOW_POINT : -10.0;
+  #else
+    // Assertively move down in all cases
+    constexpr float z_probe_low_point = -10.0;
+  #endif
+
   // Double-probing does a fast probe followed by a slow probe
   #if MULTIPLE_PROBING == 2
 
     // Do a first probe at the fast speed
-    if (do_probe_move(-10, Z_PROBE_SPEED_FAST)) return NAN;
+    if (do_probe_move(z_probe_low_point, Z_PROBE_SPEED_FAST)) return NAN;
 
     float first_probe_z = current_position[Z_AXIS];
 
@@ -580,7 +597,7 @@ static float run_z_probe() {
   #endif
 
       // Move down slowly to find bed, not too far
-      if (do_probe_move(-10, Z_PROBE_SPEED_SLOW)) return NAN;
+      if (do_probe_move(z_probe_low_point, Z_PROBE_SPEED_SLOW)) return NAN;
 
   #if MULTIPLE_PROBING > 2
       probes_total += current_position[Z_AXIS];
@@ -628,14 +645,14 @@ static float run_z_probe() {
  *   - Raise to the BETWEEN height
  * - Return the probed Z position
  */
-float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after/*=PROBE_PT_NONE*/, const uint8_t verbose_level/*=0*/, const bool probe_relative/*=true*/) {
+float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after/*=PROBE_PT_NONE*/, const uint8_t verbose_level/*=0*/, const bool is_calibration/*=false*/) {
   #if ENABLED(DEBUG_LEVELING_FEATURE)
     if (DEBUGGING(LEVELING)) {
       SERIAL_ECHOPAIR(">>> probe_pt(", LOGICAL_X_POSITION(rx));
       SERIAL_ECHOPAIR(", ", LOGICAL_Y_POSITION(ry));
       SERIAL_ECHOPAIR(", ", raise_after == PROBE_PT_RAISE ? "raise" : raise_after == PROBE_PT_STOW ? "stow" : "none");
       SERIAL_ECHOPAIR(", ", int(verbose_level));
-      SERIAL_ECHOPAIR(", ", probe_relative ? "probe" : "nozzle");
+      SERIAL_ECHOPAIR(", ", is_calibration ? "nozzle" : "probe");
       SERIAL_ECHOLNPGM("_relative)");
       DEBUG_POS("", current_position);
     }
@@ -643,7 +660,7 @@ float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after/
 
   // TODO: Adapt for SCARA, where the offset rotates
   float nx = rx, ny = ry;
-  if (probe_relative) {
+  if (!is_calibration) {
     if (!position_is_reachable_by_probe(rx, ry)) return NAN;  // The given position is in terms of the probe
     nx -= (X_PROBE_OFFSET_FROM_EXTRUDER);                     // Get the nozzle position
     ny -= (Y_PROBE_OFFSET_FROM_EXTRUDER);
@@ -667,7 +684,11 @@ float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after/
 
   float measured_z = NAN;
   if (!DEPLOY_PROBE()) {
-    measured_z = run_z_probe() + zprobe_zoffset;
+    measured_z = run_z_probe(
+      #if HAS_CALIBRATION_PROBE
+        is_calibration
+      #endif
+    ) + zprobe_zoffset;
 
     if (raise_after == PROBE_PT_RAISE)
       do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
diff --git a/Marlin/src/module/probe.h b/Marlin/src/module/probe.h
index 655fad8701..60052e3ec2 100644
--- a/Marlin/src/module/probe.h
+++ b/Marlin/src/module/probe.h
@@ -40,7 +40,7 @@
     PROBE_PT_STOW,  // Do a complete stow after run_z_probe
     PROBE_PT_RAISE  // Raise to "between" clearance after run_z_probe
   };
-  float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool probe_relative=true);
+  float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool is_calibration=false);
   #define DEPLOY_PROBE() set_probe_deployed(true)
   #define STOW_PROBE() set_probe_deployed(false)
 #else