From 3bf990ec346b0aaa536bc1d46b668dd2b4973916 Mon Sep 17 00:00:00 2001
From: rudihorn <rh@rudi-horn.de>
Date: Thu, 11 Jun 2020 00:25:17 +0100
Subject: [PATCH] PTC: Extend options, fix probing bugs (#18253)

---
 Marlin/Configuration_adv.h              | 31 ++++++++++++++++++
 Marlin/src/feature/probe_temp_comp.cpp  | 43 ++++++++++++++++---------
 Marlin/src/feature/probe_temp_comp.h    | 41 +++++++++++++++++++++--
 Marlin/src/gcode/calibrate/G76_M871.cpp |  6 ++--
 4 files changed, 100 insertions(+), 21 deletions(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index b76a4adf94..5d9bcc7158 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1662,6 +1662,37 @@
     // Enable additional compensation using hotend temperature
     // Note: this values cannot be calibrated automatically but have to be set manually
     //#define USE_TEMP_EXT_COMPENSATION
+
+    // Probe temperature calibration generates a table of values starting at PTC_SAMPLE_START
+    // (e.g. 30), in steps of PTC_SAMPLE_RES (e.g. 5) with PTC_SAMPLE_COUNT (e.g. 10) samples.
+
+    // #define PTC_SAMPLE_START  30.0f
+    // #define PTC_SAMPLE_RES    5.0f
+    // #define PTC_SAMPLE_COUNT  10U
+
+    // Bed temperature calibration builds a similar table.
+
+    // #define BTC_SAMPLE_START  60.0f
+    // #define BTC_SAMPLE_RES    5.0f
+    // #define BTC_SAMPLE_COUNT  10U
+
+    // The temperature the probe should be at while taking measurements during bed temperature
+    // calibration.
+    // #define BTC_PROBE_TEMP 30.0f
+
+    // Height above Z=0.0f to raise the nozzle. Lowering this can help the probe to heat faster.
+    // Note: the Z=0.0f offset is determined by the probe offset which can be set using M851.
+    // #define PTC_PROBE_HEATING_OFFSET 0.5f
+
+    // Height to raise the Z-probe between heating and taking the next measurement. Some probes
+    // may fail to untrigger if they have been triggered for a long time, which can be solved by
+    // increasing the height the probe is raised to.
+    // #define PTC_PROBE_RAISE 15U
+
+    // If the probe is outside of the defined range, use linear extrapolation using the closest 
+    // point and the PTC_LINEAR_EXTRAPOLATION'th next point. E.g. if set to 4 it will use data[0]
+    // and data[4] to perform linear extrapolation for values below PTC_SAMPLE_START.
+    // #define PTC_LINEAR_EXTRAPOLATION 4
   #endif
 #endif
 
diff --git a/Marlin/src/feature/probe_temp_comp.cpp b/Marlin/src/feature/probe_temp_comp.cpp
index 92ff2e9771..c3459d2345 100644
--- a/Marlin/src/feature/probe_temp_comp.cpp
+++ b/Marlin/src/feature/probe_temp_comp.cpp
@@ -165,28 +165,41 @@ void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const float &
 }
 
 float ProbeTempComp::get_offset_for_temperature(const TempSensorID tsi, const float &temp) {
-
   const uint8_t measurements = cali_info[tsi].measurements;
   const float start_temp = cali_info[tsi].start_temp,
-                end_temp = cali_info[tsi].end_temp,
                 res_temp = cali_info[tsi].temp_res;
   const int16_t * const data = sensor_z_offsets[tsi];
 
-  if (temp <= start_temp) return 0.0f;
-  if (temp >= end_temp) return static_cast<float>(data[measurements - 1]) / 1000.0f;
+  auto point = [&](uint8_t i) {
+    return xy_float_t({start_temp + i*res_temp, static_cast<float>(data[i])});
+  };
+
+  auto linear_interp = [](float x, xy_float_t p1, xy_float_t p2) {
+    return (p2.y - p1.y) / (p2.x - p2.y) * (x - p1.x) + p1.y;
+  };
 
   // Linear interpolation
-  int16_t val1 = 0, val2 = data[0];
-  uint8_t idx = 0;
-  float meas_temp = start_temp + res_temp;
-  while (meas_temp < temp) {
-    if (++idx >= measurements) return static_cast<float>(val2) / 1000.0f;
-    meas_temp += res_temp;
-    val1 = val2;
-    val2 = data[idx];
-  }
-  const float factor = (meas_temp - temp) / static_cast<float>(res_temp);
-  return (static_cast<float>(val2) - static_cast<float>(val2 - val1) * factor) / 1000.0f;
+  uint8_t idx = static_cast<uint8_t>(temp - start_temp / res_temp);
+
+  // offset in um
+  float offset = 0.0f;
+
+  #if !defined(PTC_LINEAR_EXTRAPOLATION) || PTC_LINEAR_EXTRAPOLATION <= 0
+    if (idx < 0)
+      offset = 0.0f;
+    else if (idx > measurements - 2)
+      offset = static_cast<float>(data[measurements - 1]);
+  #else
+    if (idx < 0) 
+      offset = linear_interp(temp, point(0), point(PTC_LINEAR_EXTRAPOLATION));
+    else if (idx > measurements - 2) 
+      offset = linear_interp(temp, point(measurements - PTC_LINEAR_EXTRAPOLATION - 1), point(measurements - 1));
+  #endif
+    else
+      offset = linear_interp(temp, point(idx), point(idx + 1));
+
+  // return offset in mm
+  return offset / 1000.0f;
 }
 
 bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d) {
diff --git a/Marlin/src/feature/probe_temp_comp.h b/Marlin/src/feature/probe_temp_comp.h
index 5ae4175104..2562722d12 100644
--- a/Marlin/src/feature/probe_temp_comp.h
+++ b/Marlin/src/feature/probe_temp_comp.h
@@ -45,9 +45,44 @@ typedef struct {
  * measurement errors/shifts due to changed temperature.
  */
 
+// Probe temperature calibration constants
+#ifndef PTC_SAMPLE_COUNT
+  #define PTC_SAMPLE_COUNT 10U
+#endif
+#ifndef PTC_SAMPLE_RES
+  #define PTC_SAMPLE_RES 5.0f
+#endif
+#ifndef PTC_SAMPLE_START
+  #define PTC_SAMPLE_START 30.0f
+#endif
+#define PTC_SAMPLE_END ((PTC_SAMPLE_START) + (PTC_SAMPLE_COUNT) * (PTC_SAMPLE_RES))
+
+// Bed temperature calibration constants
+#ifndef BTC_PROBE_TEMP
+  #define BTC_PROBE_TEMP 30.0f
+#endif
+#ifndef BTC_SAMPLE_COUNT
+  #define BTC_SAMPLE_COUNT 10U
+#endif
+#ifndef BTC_SAMPLE_STEP
+  #define BTC_SAMPLE_RES 5.0f
+#endif
+#ifndef BTC_SAMPLE_START
+  #define BTC_SAMPLE_START 60.0f
+#endif
+#define BTC_SAMPLE_END ((BTC_SAMPLE_START) + (BTC_SAMPLE_COUNT) * (BTC_SAMPLE_RES))
+
+#ifndef PTC_PROBE_HEATING_OFFSET
+  #define PTC_PROBE_HEATING_OFFSET 0.5f
+#endif
+
+#ifndef PTC_PROBE_RAISE
+  #define PTC_PROBE_RAISE 10.0f
+#endif
+
 static constexpr temp_calib_t cali_info_init[TSI_COUNT] = {
-    {  10,  5,  30,  30 + 10 *  5 },       // Probe
-    {  10,  5,  60,  60 + 10 *  5 },       // Bed
+    {  PTC_SAMPLE_COUNT, PTC_SAMPLE_RES, PTC_SAMPLE_START, PTC_SAMPLE_END },       // Probe
+    {  BTC_SAMPLE_COUNT, BTC_SAMPLE_RES, BTC_SAMPLE_START, BTC_SAMPLE_END },       // Bed
   #if ENABLED(USE_TEMP_EXT_COMPENSATION)
     {  20,  5, 180, 180 +  5 * 20 }        // Extruder
   #endif
@@ -66,7 +101,7 @@ class ProbeTempComp {
                             //measure_point    = { 12.0f, 7.3f };   // Coordinates for the MK52 magnetic heatbed
 
     static constexpr int  probe_calib_bed_temp = BED_MAX_TARGET,  // Bed temperature while calibrating probe
-                          bed_calib_probe_temp = 30;                // Probe temperature while calibrating bed
+                          bed_calib_probe_temp = BTC_PROBE_TEMP;  // Probe temperature while calibrating bed
 
     static int16_t *sensor_z_offsets[TSI_COUNT],
                    z_offsets_probe[cali_info_init[TSI_PROBE].measurements], // (µm)
diff --git a/Marlin/src/gcode/calibrate/G76_M871.cpp b/Marlin/src/gcode/calibrate/G76_M871.cpp
index adabf22344..bc7aee8f4d 100644
--- a/Marlin/src/gcode/calibrate/G76_M871.cpp
+++ b/Marlin/src/gcode/calibrate/G76_M871.cpp
@@ -105,7 +105,7 @@ void GcodeSuite::G76() {
 
   auto g76_probe = [](const TempSensorID sid, uint16_t &targ, const xy_pos_t &nozpos) {
     do_blocking_move_to_z(5.0); // Raise nozzle before probing
-    const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_NONE, 0, false);  // verbose=0, probe_relative=false
+    const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_STOW, 0, false);  // verbose=0, probe_relative=false
     if (isnan(measured_z))
       SERIAL_ECHOLNPGM("!Received NAN. Aborting.");
     else {
@@ -132,8 +132,8 @@ void GcodeSuite::G76() {
   planner.synchronize();
 
   const xyz_pos_t parkpos = temp_comp.park_point,
-            probe_pos_xyz = temp_comp.measure_point + xyz_pos_t({ 0.0f, 0.0f, 0.5f }),
-              noz_pos_xyz = probe_pos_xyz - probe.offset_xy; // Nozzle position based on probe position
+            probe_pos_xyz = xyz_pos_t(temp_comp.measure_point) + xyz_pos_t({ 0.0f, 0.0f, PTC_PROBE_HEATING_OFFSET }),
+              noz_pos_xyz = probe_pos_xyz - xy_pos_t(probe.offset_xy); // Nozzle position based on probe position
 
   if (do_bed_cal || do_probe_cal) {
     // Ensure park position is reachable
-- 
GitLab