🚸 More flexible Probe Temperature Compensation (#23033)
This commit is contained in:
		
				
					committed by
					
						 Scott Lahteine
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							efd9329c81
						
					
				
				
					commit
					0b84194127
				
			| @@ -1988,65 +1988,69 @@ | ||||
|  | ||||
| /** | ||||
|  * Thermal Probe Compensation | ||||
|  * Probe measurements are adjusted to compensate for temperature distortion. | ||||
|  * Use G76 to calibrate this feature. Use M871 to set values manually. | ||||
|  * For a more detailed explanation of the process see G76_M871.cpp. | ||||
|  * | ||||
|  * Adjust probe measurements to compensate for distortion associated with the temperature | ||||
|  * of the probe, bed, and/or hotend. | ||||
|  * Use G76 to automatically calibrate this feature for probe and bed temperatures. | ||||
|  * (Extruder temperature/offset values must be calibrated manually.) | ||||
|  * Use M871 to set temperature/offset values manually. | ||||
|  * For more details see https://marlinfw.org/docs/features/probe_temp_compensation.html | ||||
|  */ | ||||
| #if HAS_BED_PROBE && TEMP_SENSOR_PROBE && TEMP_SENSOR_BED | ||||
|   // Enable thermal first layer compensation using bed and probe temperatures | ||||
|   #define PROBE_TEMP_COMPENSATION | ||||
| //#define PTC_PROBE    // Compensate based on probe temperature | ||||
| //#define PTC_BED      // Compensate based on bed temperature | ||||
| //#define PTC_HOTEND   // Compensate based on hotend temperature | ||||
|  | ||||
|   // Add additional compensation depending on hotend temperature | ||||
|   // Note: this values cannot be calibrated and have to be set manually | ||||
|   #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
| #if ANY(PTC_PROBE, PTC_BED, PTC_HOTEND) | ||||
|   /** | ||||
|    * If the probe is outside the defined range, use linear extrapolation with the closest | ||||
|    * point and the point with index PTC_LINEAR_EXTRAPOLATION. e.g., If set to 4 it will use the | ||||
|    * linear extrapolation between data[0] and data[4] for values below PTC_PROBE_START. | ||||
|    */ | ||||
|   //#define PTC_LINEAR_EXTRAPOLATION 4 | ||||
|  | ||||
|   #if ENABLED(PTC_PROBE) | ||||
|     // Probe temperature calibration generates a table of values starting at PTC_PROBE_START | ||||
|     // (e.g., 30), in steps of PTC_PROBE_RES (e.g., 5) with PTC_PROBE_COUNT (e.g., 10) samples. | ||||
|     #define PTC_PROBE_START   30    // (°C) | ||||
|     #define PTC_PROBE_RES      5    // (°C) | ||||
|     #define PTC_PROBE_COUNT   10 | ||||
|     #define PTC_PROBE_ZOFFS   { 0 } // (µm) Z adjustments per sample | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(PTC_BED) | ||||
|     // Bed temperature calibration builds a similar table. | ||||
|     #define PTC_BED_START     60    // (°C) | ||||
|     #define PTC_BED_RES        5    // (°C) | ||||
|     #define PTC_BED_COUNT     10 | ||||
|     #define PTC_BED_ZOFFS     { 0 } // (µm) Z adjustments per sample | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(PTC_HOTEND) | ||||
|     // Note: There is no automatic calibration for the hotend. Use M871. | ||||
|     #define PTC_HOTEND_START 180    // (°C) | ||||
|     #define PTC_HOTEND_RES     5    // (°C) | ||||
|     #define PTC_HOTEND_COUNT  20 | ||||
|     #define PTC_HOTEND_ZOFFS  { 0 } // (µm) Z adjustments per sample | ||||
|   #endif | ||||
|  | ||||
|   // G76 options | ||||
|   #if BOTH(PTC_PROBE, PTC_BED) | ||||
|     // Park position to wait for probe cooldown | ||||
|     #define PTC_PARK_POS   { 0, 0, 100 } | ||||
|  | ||||
|     // Probe position to probe and wait for probe to reach target temperature | ||||
|     //#define PTC_PROBE_POS  { 12.0f, 7.3f } // Example: MK52 magnetic heatbed | ||||
|     #define PTC_PROBE_POS  { 90, 100 } | ||||
|  | ||||
|     // Enable additional compensation using hotend temperature | ||||
|     // Note: this values cannot be calibrated automatically but have to be set manually via M871. | ||||
|     //#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  // (°C) | ||||
|     //#define PTC_SAMPLE_RES     5  // (°C) | ||||
|     //#define PTC_SAMPLE_COUNT  10 | ||||
|  | ||||
|     // Bed temperature calibration builds a similar table. | ||||
|  | ||||
|     //#define BTC_SAMPLE_START  60  // (°C) | ||||
|     //#define BTC_SAMPLE_RES     5  // (°C) | ||||
|     //#define BTC_SAMPLE_COUNT  10 | ||||
|  | ||||
|     #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|       //#define ETC_SAMPLE_START 180  // (°C) | ||||
|       //#define ETC_SAMPLE_RES     5  // (°C) | ||||
|       //#define ETC_SAMPLE_COUNT  20 | ||||
|     #endif | ||||
|  | ||||
|     // The temperature the probe should be at while taking measurements during bed temperature | ||||
|     // calibration. | ||||
|     //#define BTC_PROBE_TEMP    30  // (°C) | ||||
|     // The temperature the probe should be at while taking measurements during | ||||
|     // bed temperature calibration. | ||||
|     #define PTC_PROBE_TEMP    30  // (°C) | ||||
|  | ||||
|     // Height above Z=0.0 to raise the nozzle. Lowering this can help the probe to heat faster. | ||||
|     // Note: the Z=0.0 offset is determined by the probe offset which can be set using M851. | ||||
|     //#define PTC_PROBE_HEATING_OFFSET 0.5 | ||||
|  | ||||
|     // 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 15 | ||||
|  | ||||
|     // 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 | ||||
|     // Note: The Z=0.0 offset is determined by the probe Z offset (e.g., as set with M851 Z). | ||||
|     #define PTC_PROBE_HEATING_OFFSET 0.5 | ||||
|   #endif | ||||
| #endif | ||||
| #endif // PTC_PROBE || PTC_BED || PTC_HOTEND | ||||
|  | ||||
| // @section extras | ||||
|  | ||||
|   | ||||
| @@ -22,39 +22,53 @@ | ||||
|  | ||||
| #include "../inc/MarlinConfigPre.h" | ||||
|  | ||||
| #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
| #if HAS_PTC | ||||
|  | ||||
| //#define DEBUG_PTC   // Print extra debug output with 'M871' | ||||
|  | ||||
| #include "probe_temp_comp.h" | ||||
| #include <math.h> | ||||
|  | ||||
| ProbeTempComp temp_comp; | ||||
| ProbeTempComp ptc; | ||||
|  | ||||
| int16_t ProbeTempComp::z_offsets_probe[cali_info_init[TSI_PROBE].measurements],  // = {0} | ||||
|         ProbeTempComp::z_offsets_bed[cali_info_init[TSI_BED].measurements];      // = {0} | ||||
| #if ENABLED(PTC_PROBE) | ||||
|   constexpr int16_t z_offsets_probe_default[PTC_PROBE_COUNT] = PTC_PROBE_ZOFFS; | ||||
|   int16_t ProbeTempComp::z_offsets_probe[PTC_PROBE_COUNT] = PTC_PROBE_ZOFFS; | ||||
| #endif | ||||
|  | ||||
| #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|   int16_t ProbeTempComp::z_offsets_ext[cali_info_init[TSI_EXT].measurements];    // = {0} | ||||
| #if ENABLED(PTC_BED) | ||||
|   constexpr int16_t z_offsets_bed_default[PTC_BED_COUNT] = PTC_BED_ZOFFS; | ||||
|   int16_t ProbeTempComp::z_offsets_bed[PTC_BED_COUNT] = PTC_BED_ZOFFS; | ||||
| #endif | ||||
|  | ||||
| #if ENABLED(PTC_HOTEND) | ||||
|   constexpr int16_t z_offsets_hotend_default[PTC_HOTEND_COUNT] = PTC_HOTEND_ZOFFS; | ||||
|   int16_t ProbeTempComp::z_offsets_hotend[PTC_HOTEND_COUNT] = PTC_HOTEND_ZOFFS; | ||||
| #endif | ||||
|  | ||||
| int16_t *ProbeTempComp::sensor_z_offsets[TSI_COUNT] = { | ||||
|   ProbeTempComp::z_offsets_probe, ProbeTempComp::z_offsets_bed | ||||
|   OPTARG(USE_TEMP_EXT_COMPENSATION, ProbeTempComp::z_offsets_ext) | ||||
|   #if ENABLED(PTC_PROBE) | ||||
|     ProbeTempComp::z_offsets_probe, | ||||
|   #endif | ||||
|   #if ENABLED(PTC_BED) | ||||
|     ProbeTempComp::z_offsets_bed, | ||||
|   #endif | ||||
|   #if ENABLED(PTC_HOTEND) | ||||
|     ProbeTempComp::z_offsets_hotend, | ||||
|   #endif | ||||
| }; | ||||
|  | ||||
| const temp_calib_t ProbeTempComp::cali_info[TSI_COUNT] = { | ||||
|   cali_info_init[TSI_PROBE], cali_info_init[TSI_BED] | ||||
|   OPTARG(USE_TEMP_EXT_COMPENSATION, cali_info_init[TSI_EXT]) | ||||
| }; | ||||
|  | ||||
| constexpr xyz_pos_t ProbeTempComp::park_point; | ||||
| constexpr xy_pos_t ProbeTempComp::measure_point; | ||||
| constexpr celsius_t ProbeTempComp::probe_calib_bed_temp; | ||||
| constexpr temp_calib_t ProbeTempComp::cali_info[TSI_COUNT]; | ||||
|  | ||||
| uint8_t ProbeTempComp::calib_idx; // = 0 | ||||
| float ProbeTempComp::init_measurement; // = 0.0 | ||||
|  | ||||
| void ProbeTempComp::reset() { | ||||
|   TERN_(PTC_PROBE, LOOP_L_N(i, PTC_PROBE_COUNT) z_offsets_probe[i] = z_offsets_probe_default[i]); | ||||
|   TERN_(PTC_BED, LOOP_L_N(i, PTC_BED_COUNT) z_offsets_bed[i] = z_offsets_bed_default[i]); | ||||
|   TERN_(PTC_HOTEND, LOOP_L_N(i, PTC_HOTEND_COUNT) z_offsets_hotend[i] = z_offsets_hotend_default[i]); | ||||
| } | ||||
|  | ||||
| void ProbeTempComp::clear_offsets(const TempSensorID tsi) { | ||||
|   LOOP_L_N(i, cali_info[tsi].measurements) | ||||
|     sensor_z_offsets[tsi][i] = 0; | ||||
| @@ -71,10 +85,9 @@ void ProbeTempComp::print_offsets() { | ||||
|   LOOP_L_N(s, TSI_COUNT) { | ||||
|     celsius_t temp = cali_info[s].start_temp; | ||||
|     for (int16_t i = -1; i < cali_info[s].measurements; ++i) { | ||||
|       SERIAL_ECHOF(s == TSI_BED ? F("Bed") : | ||||
|         #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|           s == TSI_EXT ? F("Extruder") : | ||||
|         #endif | ||||
|       SERIAL_ECHOF( | ||||
|         TERN_(PTC_BED, s == TSI_BED ? F("Bed") :) | ||||
|         TERN_(PTC_HOTEND, s == TSI_EXT ? F("Extruder") :) | ||||
|         F("Probe") | ||||
|       ); | ||||
|       SERIAL_ECHOLNPGM( | ||||
| @@ -100,21 +113,13 @@ void ProbeTempComp::prepare_new_calibration(const_float_t init_meas_z) { | ||||
| } | ||||
|  | ||||
| void ProbeTempComp::push_back_new_measurement(const TempSensorID tsi, const_float_t meas_z) { | ||||
|   switch (tsi) { | ||||
|     case TSI_PROBE: | ||||
|     case TSI_BED: | ||||
|     //case TSI_EXT: | ||||
|       if (calib_idx >= cali_info[tsi].measurements) return; | ||||
|       sensor_z_offsets[tsi][calib_idx++] = static_cast<int16_t>(meas_z * 1000.0f - init_measurement * 1000.0f); | ||||
|     default: break; | ||||
|   } | ||||
|   if (calib_idx >= cali_info[tsi].measurements) return; | ||||
|   sensor_z_offsets[tsi][calib_idx++] = static_cast<int16_t>((meas_z - init_measurement) * 1000.0f); | ||||
| } | ||||
|  | ||||
| bool ProbeTempComp::finish_calibration(const TempSensorID tsi) { | ||||
|   if (tsi != TSI_PROBE && tsi != TSI_BED) return false; | ||||
|  | ||||
|   if (calib_idx < 3) { | ||||
|     SERIAL_ECHOLNPGM("!Insufficient measurements (min. 3)."); | ||||
|   if (!calib_idx) { | ||||
|     SERIAL_ECHOLNPGM("!No measurements."); | ||||
|     clear_offsets(tsi); | ||||
|     return false; | ||||
|   } | ||||
| @@ -130,16 +135,15 @@ bool ProbeTempComp::finish_calibration(const TempSensorID tsi) { | ||||
|     SERIAL_ECHOLNPGM("Got ", calib_idx, " measurements. "); | ||||
|     if (linear_regression(tsi, k, d)) { | ||||
|       SERIAL_ECHOPGM("Applying linear extrapolation"); | ||||
|       calib_idx--; | ||||
|       for (; calib_idx < measurements; ++calib_idx) { | ||||
|         const celsius_float_t temp = start_temp + float(calib_idx) * res_temp; | ||||
|         const celsius_float_t temp = start_temp + float(calib_idx + 1) * res_temp; | ||||
|         data[calib_idx] = static_cast<int16_t>(k * temp + d); | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       // Simply use the last measured value for higher temperatures | ||||
|       SERIAL_ECHOPGM("Failed to extrapolate"); | ||||
|       const int16_t last_val = data[calib_idx]; | ||||
|       const int16_t last_val = data[calib_idx-1]; | ||||
|       for (; calib_idx < measurements; ++calib_idx) | ||||
|         data[calib_idx] = last_val; | ||||
|     } | ||||
| @@ -157,7 +161,7 @@ bool ProbeTempComp::finish_calibration(const TempSensorID tsi) { | ||||
|     // Restrict the max. offset difference between two probings | ||||
|     if (calib_idx > 0 && ABS(data[calib_idx - 1] - data[calib_idx]) > 800) { | ||||
|       SERIAL_ECHOLNPGM("!Invalid Z-offset between two probings detected (0-0.8)."); | ||||
|       clear_offsets(TSI_PROBE); | ||||
|       clear_offsets(tsi); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| @@ -168,8 +172,8 @@ bool ProbeTempComp::finish_calibration(const TempSensorID tsi) { | ||||
| void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const celsius_t temp, float &meas_z) { | ||||
|   const uint8_t measurements = cali_info[tsi].measurements; | ||||
|   const celsius_t start_temp = cali_info[tsi].start_temp, | ||||
|                     end_temp = cali_info[tsi].end_temp, | ||||
|                     res_temp = cali_info[tsi].temp_resolution; | ||||
|                   res_temp = cali_info[tsi].temp_resolution, | ||||
|                   end_temp = start_temp + measurements * res_temp; | ||||
|   const int16_t * const data = sensor_z_offsets[tsi]; | ||||
|  | ||||
|   // Given a data index, return { celsius, zoffset } in the form { x, y } | ||||
| @@ -208,9 +212,7 @@ void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const celsius | ||||
| } | ||||
|  | ||||
| bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d) { | ||||
|   if (tsi != TSI_PROBE && tsi != TSI_BED) return false; | ||||
|  | ||||
|   if (!WITHIN(calib_idx, 2, cali_info[tsi].measurements)) return false; | ||||
|   if (!WITHIN(calib_idx, 1, cali_info[tsi].measurements)) return false; | ||||
|  | ||||
|   const celsius_t start_temp = cali_info[tsi].start_temp, | ||||
|                     res_temp = cali_info[tsi].temp_resolution; | ||||
| @@ -243,4 +245,4 @@ bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| #endif // PROBE_TEMP_COMPENSATION | ||||
| #endif // HAS_PTC | ||||
|   | ||||
| @@ -24,9 +24,13 @@ | ||||
| #include "../inc/MarlinConfig.h" | ||||
|  | ||||
| enum TempSensorID : uint8_t { | ||||
|   TSI_PROBE, | ||||
|   TSI_BED, | ||||
|   #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|   #if ENABLED(PTC_PROBE) | ||||
|     TSI_PROBE, | ||||
|   #endif | ||||
|   #if ENABLED(PTC_BED) | ||||
|     TSI_BED, | ||||
|   #endif | ||||
|   #if ENABLED(PTC_HOTEND) | ||||
|     TSI_EXT, | ||||
|   #endif | ||||
|   TSI_COUNT | ||||
| @@ -35,8 +39,7 @@ enum TempSensorID : uint8_t { | ||||
| typedef struct { | ||||
|   uint8_t measurements;       // Max. number of measurements to be stored (35 - 80°C) | ||||
|   celsius_t temp_resolution,  // Resolution in °C between measurements | ||||
|             start_temp,       // Base measurement; z-offset == 0 | ||||
|             end_temp; | ||||
|             start_temp;       // Base measurement; z-offset == 0 | ||||
| } temp_calib_t; | ||||
|  | ||||
| /** | ||||
| @@ -45,93 +48,40 @@ typedef struct { | ||||
|  * measurement errors/shifts due to changed temperature. | ||||
|  */ | ||||
|  | ||||
| // Probe temperature calibration constants | ||||
| #ifndef PTC_SAMPLE_COUNT | ||||
|   #define PTC_SAMPLE_COUNT 10 | ||||
| #endif | ||||
| #ifndef PTC_SAMPLE_RES | ||||
|   #define PTC_SAMPLE_RES 5 | ||||
| #endif | ||||
| #ifndef PTC_SAMPLE_START | ||||
|   #define PTC_SAMPLE_START 30 | ||||
| #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 | ||||
| #endif | ||||
| #ifndef BTC_SAMPLE_COUNT | ||||
|   #define BTC_SAMPLE_COUNT 10 | ||||
| #endif | ||||
| #ifndef BTC_SAMPLE_RES | ||||
|   #define BTC_SAMPLE_RES 5 | ||||
| #endif | ||||
| #ifndef BTC_SAMPLE_START | ||||
|   #define BTC_SAMPLE_START 60 | ||||
| #endif | ||||
| #define BTC_SAMPLE_END (BTC_SAMPLE_START + (BTC_SAMPLE_COUNT) * BTC_SAMPLE_RES) | ||||
|  | ||||
| // Extruder temperature calibration constants | ||||
| #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|   #ifndef ETC_SAMPLE_COUNT | ||||
|     #define ETC_SAMPLE_COUNT 20 | ||||
|   #endif | ||||
|   #ifndef ETC_SAMPLE_RES | ||||
|     #define ETC_SAMPLE_RES 5 | ||||
|   #endif | ||||
|   #ifndef ETC_SAMPLE_START | ||||
|     #define ETC_SAMPLE_START 180 | ||||
|   #endif | ||||
|   #define ETC_SAMPLE_END (ETC_SAMPLE_START + (ETC_SAMPLE_COUNT) * ETC_SAMPLE_RES) | ||||
| #endif | ||||
|  | ||||
| #ifndef PTC_PROBE_HEATING_OFFSET | ||||
|   #define PTC_PROBE_HEATING_OFFSET 0.5f | ||||
| #endif | ||||
|  | ||||
| #ifndef PTC_PROBE_RAISE | ||||
|   #define PTC_PROBE_RAISE 10 | ||||
| #endif | ||||
|  | ||||
| static constexpr temp_calib_t cali_info_init[TSI_COUNT] = { | ||||
|   { 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) | ||||
|     { ETC_SAMPLE_COUNT, ETC_SAMPLE_RES, ETC_SAMPLE_START, ETC_SAMPLE_END }, // Extruder | ||||
|   #endif | ||||
| }; | ||||
|  | ||||
| class ProbeTempComp { | ||||
|   public: | ||||
|  | ||||
|     static const temp_calib_t cali_info[TSI_COUNT]; | ||||
|     static constexpr temp_calib_t cali_info[TSI_COUNT] = { | ||||
|       #if ENABLED(PTC_PROBE) | ||||
|         { PTC_PROBE_COUNT, PTC_PROBE_RES, PTC_PROBE_START },   // Probe | ||||
|       #endif | ||||
|       #if ENABLED(PTC_BED) | ||||
|         { PTC_BED_COUNT, PTC_BED_RES, PTC_BED_START },   // Bed | ||||
|       #endif | ||||
|       #if ENABLED(PTC_HOTEND) | ||||
|         { PTC_HOTEND_COUNT, PTC_HOTEND_RES, PTC_HOTEND_START }, // Extruder | ||||
|       #endif | ||||
|     }; | ||||
|  | ||||
|     // Where to park nozzle to wait for probe cooldown | ||||
|     static constexpr xyz_pos_t park_point = PTC_PARK_POS; | ||||
|  | ||||
|     // XY coordinates of nozzle for probing the bed | ||||
|     static constexpr xy_pos_t measure_point    = PTC_PROBE_POS;     // Coordinates to probe | ||||
|                             //measure_point    = { 12.0f, 7.3f };   // Coordinates for the MK52 magnetic heatbed | ||||
|  | ||||
|     static constexpr celsius_t probe_calib_bed_temp = BED_MAX_TARGET,  // Bed temperature while calibrating probe | ||||
|                                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) | ||||
|                    z_offsets_bed[cali_info_init[TSI_BED].measurements];     // (µm) | ||||
|  | ||||
|     #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|       static int16_t z_offsets_ext[cali_info_init[TSI_EXT].measurements];   // (µm) | ||||
|     static int16_t *sensor_z_offsets[TSI_COUNT]; | ||||
|     #if ENABLED(PTC_PROBE) | ||||
|       static int16_t z_offsets_probe[PTC_PROBE_COUNT]; // (µm) | ||||
|     #endif | ||||
|     #if ENABLED(PTC_BED) | ||||
|       static int16_t z_offsets_bed[PTC_BED_COUNT];   // (µm) | ||||
|     #endif | ||||
|     #if ENABLED(PTC_HOTEND) | ||||
|       static int16_t z_offsets_hotend[PTC_HOTEND_COUNT];   // (µm) | ||||
|     #endif | ||||
|  | ||||
|     static inline void reset_index() { calib_idx = 0; }; | ||||
|     static inline uint8_t get_index() { return calib_idx; } | ||||
|     static void reset(); | ||||
|     static void clear_offsets(const TempSensorID tsi); | ||||
|     static inline void clear_all_offsets() { | ||||
|       clear_offsets(TSI_BED); | ||||
|       clear_offsets(TSI_PROBE); | ||||
|       TERN_(USE_TEMP_EXT_COMPENSATION, clear_offsets(TSI_EXT)); | ||||
|       TERN_(PTC_PROBE, clear_offsets(TSI_PROBE)); | ||||
|       TERN_(PTC_BED, clear_offsets(TSI_BED)); | ||||
|       TERN_(PTC_HOTEND, clear_offsets(TSI_EXT)); | ||||
|     } | ||||
|     static bool set_offset(const TempSensorID tsi, const uint8_t idx, const int16_t offset); | ||||
|     static void print_offsets(); | ||||
| @@ -156,4 +106,4 @@ class ProbeTempComp { | ||||
|     static bool linear_regression(const TempSensorID tsi, float &k, float &d); | ||||
| }; | ||||
|  | ||||
| extern ProbeTempComp temp_comp; | ||||
| extern ProbeTempComp ptc; | ||||
|   | ||||
| @@ -36,7 +36,7 @@ | ||||
| #include "../../../module/probe.h" | ||||
| #include "../../queue.h" | ||||
|  | ||||
| #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
| #if HAS_PTC | ||||
|   #include "../../../feature/probe_temp_comp.h" | ||||
|   #include "../../../module/temperature.h" | ||||
| #endif | ||||
| @@ -645,11 +645,9 @@ G29_TYPE GcodeSuite::G29() { | ||||
|             break; // Breaks out of both loops | ||||
|           } | ||||
|  | ||||
|           #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|             temp_comp.compensate_measurement(TSI_BED, thermalManager.degBed(), abl.measured_z); | ||||
|             temp_comp.compensate_measurement(TSI_PROBE, thermalManager.degProbe(), abl.measured_z); | ||||
|             TERN_(USE_TEMP_EXT_COMPENSATION, temp_comp.compensate_measurement(TSI_EXT, thermalManager.degHotend(0), abl.measured_z)); | ||||
|           #endif | ||||
|           TERN_(PTC_BED,    ptc.compensate_measurement(TSI_BED,   thermalManager.degBed(),     abl.measured_z)); | ||||
|           TERN_(PTC_PROBE,  ptc.compensate_measurement(TSI_PROBE, thermalManager.degProbe(),   abl.measured_z)); | ||||
|           TERN_(PTC_HOTEND, ptc.compensate_measurement(TSI_EXT,   thermalManager.degHotend(0), abl.measured_z)); | ||||
|  | ||||
|           #if ENABLED(AUTO_BED_LEVELING_LINEAR) | ||||
|  | ||||
|   | ||||
| @@ -1,358 +0,0 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||||
|  * | ||||
|  * Based on Sprinter and grbl. | ||||
|  * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * G76_M871.cpp - Temperature calibration/compensation for z-probing | ||||
|  */ | ||||
|  | ||||
| #include "../../inc/MarlinConfig.h" | ||||
|  | ||||
| #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|  | ||||
| #include "../gcode.h" | ||||
| #include "../../module/motion.h" | ||||
| #include "../../module/planner.h" | ||||
| #include "../../module/probe.h" | ||||
| #include "../../feature/bedlevel/bedlevel.h" | ||||
| #include "../../module/temperature.h" | ||||
| #include "../../module/probe.h" | ||||
| #include "../../feature/probe_temp_comp.h" | ||||
| #include "../../lcd/marlinui.h" | ||||
|  | ||||
| /** | ||||
|  * G76: calibrate probe and/or bed temperature offsets | ||||
|  *  Notes: | ||||
|  *  - When calibrating probe, bed temperature is held constant. | ||||
|  *    Compensation values are deltas to first probe measurement at probe temp. = 30°C. | ||||
|  *  - When calibrating bed, probe temperature is held constant. | ||||
|  *    Compensation values are deltas to first probe measurement at bed temp. = 60°C. | ||||
|  *  - The hotend will not be heated at any time. | ||||
|  *  - On my Průša MK3S clone I put a piece of paper between the probe and the hotend | ||||
|  *    so the hotend fan would not cool my probe constantly. Alternatively you could just | ||||
|  *    make sure the fan is not running while running the calibration process. | ||||
|  * | ||||
|  *  Probe calibration: | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Heats up bed to 100°C. | ||||
|  *  - Moves probe to probing point (1mm above heatbed). | ||||
|  *  - Waits until probe reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (=base value) and increases target temperature by 5°C. | ||||
|  *  - Waits until probe reaches increased target temperature. | ||||
|  *  - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. | ||||
|  *  - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). | ||||
|  *  - Compensation values of higher temperatures will be extrapolated (using linear regression first). | ||||
|  *    While this is not exact by any means it is still better than simply using the last compensation value. | ||||
|  * | ||||
|  *  Bed calibration: | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Heats up bed to 60°C. | ||||
|  *  - Moves probe to probing point (1mm above heatbed). | ||||
|  *  - Waits until probe reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (=base value) and increases bed temperature by 5°C. | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Waits until probe is below 30°C and bed has reached target temperature. | ||||
|  *  - Moves probe to probing point and waits until it reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. | ||||
|  *  - Repeats last four points until max. bed temperature reached (110°C) or timeout. | ||||
|  *  - Compensation values of higher temperatures will be extrapolated (using linear regression first). | ||||
|  *    While this is not exact by any means it is still better than simply using the last compensation value. | ||||
|  * | ||||
|  *  G76 [B | P] | ||||
|  *  - no flag - Both calibration procedures will be run. | ||||
|  *  - `B` - Run bed temperature calibration. | ||||
|  *  - `P` - Run probe temperature calibration. | ||||
|  */ | ||||
|  | ||||
| static void say_waiting_for()               { SERIAL_ECHOPGM("Waiting for "); } | ||||
| static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); } | ||||
| static void say_successfully_calibrated()   { SERIAL_ECHOPGM("Successfully calibrated"); } | ||||
| static void say_failed_to_calibrate()       { SERIAL_ECHOPGM("!Failed to calibrate"); } | ||||
|  | ||||
| void GcodeSuite::G76() { | ||||
|   // Check if heated bed is available and z-homing is done with probe | ||||
|   #if TEMP_SENSOR_BED == 0 || !(HOMING_Z_WITH_PROBE) | ||||
|     return; | ||||
|   #endif | ||||
|  | ||||
|   auto report_temps = [](millis_t &ntr, millis_t timeout=0) { | ||||
|     idle_no_sleep(); | ||||
|     const millis_t ms = millis(); | ||||
|     if (ELAPSED(ms, ntr)) { | ||||
|       ntr = ms + 1000; | ||||
|       thermalManager.print_heater_states(active_extruder); | ||||
|     } | ||||
|     return (timeout && ELAPSED(ms, timeout)); | ||||
|   }; | ||||
|  | ||||
|   auto wait_for_temps = [&](const celsius_t tb, const celsius_t tp, millis_t &ntr, const millis_t timeout=0) { | ||||
|     say_waiting_for(); SERIAL_ECHOLNPGM("bed and probe temperature."); | ||||
|     while (thermalManager.wholeDegBed() != tb || thermalManager.wholeDegProbe() > tp) | ||||
|       if (report_temps(ntr, timeout)) return true; | ||||
|     return false; | ||||
|   }; | ||||
|  | ||||
|   auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) { | ||||
|     do_z_clearance(5.0); // Raise nozzle before probing | ||||
|     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 { | ||||
|       SERIAL_ECHOLNPAIR_F("Measured: ", measured_z); | ||||
|       if (targ == cali_info_init[sid].start_temp) | ||||
|         temp_comp.prepare_new_calibration(measured_z); | ||||
|       else | ||||
|         temp_comp.push_back_new_measurement(sid, measured_z); | ||||
|       targ += cali_info_init[sid].temp_resolution; | ||||
|     } | ||||
|     return measured_z; | ||||
|   }; | ||||
|  | ||||
|   #if ENABLED(BLTOUCH) | ||||
|     // Make sure any BLTouch error condition is cleared | ||||
|     bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY); | ||||
|     set_bltouch_deployed(false); | ||||
|   #endif | ||||
|  | ||||
|   bool do_bed_cal = parser.boolval('B'), do_probe_cal = parser.boolval('P'); | ||||
|   if (!do_bed_cal && !do_probe_cal) do_bed_cal = do_probe_cal = true; | ||||
|  | ||||
|   // Synchronize with planner | ||||
|   planner.synchronize(); | ||||
|  | ||||
|   const xyz_pos_t parkpos = temp_comp.park_point, | ||||
|             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 - probe.offset_xy;  // Nozzle position based on probe position | ||||
|  | ||||
|   if (do_bed_cal || do_probe_cal) { | ||||
|     // Ensure park position is reachable | ||||
|     bool reachable = position_is_reachable(parkpos) || WITHIN(parkpos.z, Z_MIN_POS - fslop, Z_MAX_POS + fslop); | ||||
|     if (!reachable) | ||||
|       SERIAL_ECHOLNPGM("!Park"); | ||||
|     else { | ||||
|       // Ensure probe position is reachable | ||||
|       reachable = probe.can_reach(probe_pos_xyz); | ||||
|       if (!reachable) SERIAL_ECHOLNPGM("!Probe"); | ||||
|     } | ||||
|  | ||||
|     if (!reachable) { | ||||
|       SERIAL_ECHOLNPGM(" position unreachable - aborting."); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     process_subcommands_now(FPSTR(G28_STR)); | ||||
|   } | ||||
|  | ||||
|   remember_feedrate_scaling_off(); | ||||
|  | ||||
|   /****************************************** | ||||
|    * Calibrate bed temperature offsets | ||||
|    ******************************************/ | ||||
|  | ||||
|   // Report temperatures every second and handle heating timeouts | ||||
|   millis_t next_temp_report = millis() + 1000; | ||||
|  | ||||
|   auto report_targets = [&](const celsius_t tb, const celsius_t tp) { | ||||
|     SERIAL_ECHOLNPGM("Target Bed:", tb, " Probe:", tp); | ||||
|   }; | ||||
|  | ||||
|   if (do_bed_cal) { | ||||
|  | ||||
|     celsius_t target_bed = cali_info_init[TSI_BED].start_temp, | ||||
|             target_probe = temp_comp.bed_calib_probe_temp; | ||||
|  | ||||
|     say_waiting_for(); SERIAL_ECHOLNPGM(" cooling."); | ||||
|     while (thermalManager.wholeDegBed() > target_bed || thermalManager.wholeDegProbe() > target_probe) | ||||
|       report_temps(next_temp_report); | ||||
|  | ||||
|     // Disable leveling so it won't mess with us | ||||
|     TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); | ||||
|  | ||||
|     for (;;) { | ||||
|       thermalManager.setTargetBed(target_bed); | ||||
|  | ||||
|       report_targets(target_bed, target_probe); | ||||
|  | ||||
|       // Park nozzle | ||||
|       do_blocking_move_to(parkpos); | ||||
|  | ||||
|       // Wait for heatbed to reach target temp and probe to cool below target temp | ||||
|       if (wait_for_temps(target_bed, target_probe, next_temp_report, millis() + MIN_TO_MS(15))) { | ||||
|         SERIAL_ECHOLNPGM("!Bed heating timeout."); | ||||
|         break; | ||||
|       } | ||||
|  | ||||
|       // Move the nozzle to the probing point and wait for the probe to reach target temp | ||||
|       do_blocking_move_to(noz_pos_xyz); | ||||
|       say_waiting_for_probe_heating(); | ||||
|       SERIAL_EOL(); | ||||
|       while (thermalManager.wholeDegProbe() < target_probe) | ||||
|         report_temps(next_temp_report); | ||||
|  | ||||
|       const float measured_z = g76_probe(TSI_BED, target_bed, noz_pos_xyz); | ||||
|       if (isnan(measured_z) || target_bed > (BED_MAX_TARGET)) break; | ||||
|     } | ||||
|  | ||||
|     SERIAL_ECHOLNPGM("Retrieved measurements: ", temp_comp.get_index()); | ||||
|     if (temp_comp.finish_calibration(TSI_BED)) { | ||||
|       say_successfully_calibrated(); | ||||
|       SERIAL_ECHOLNPGM(" bed."); | ||||
|     } | ||||
|     else { | ||||
|       say_failed_to_calibrate(); | ||||
|       SERIAL_ECHOLNPGM(" bed. Values reset."); | ||||
|     } | ||||
|  | ||||
|     // Cleanup | ||||
|     thermalManager.setTargetBed(0); | ||||
|     TERN_(HAS_LEVELING, set_bed_leveling_enabled(true)); | ||||
|   } // do_bed_cal | ||||
|  | ||||
|   /******************************************** | ||||
|    * Calibrate probe temperature offsets | ||||
|    ********************************************/ | ||||
|  | ||||
|   if (do_probe_cal) { | ||||
|  | ||||
|     // Park nozzle | ||||
|     do_blocking_move_to(parkpos); | ||||
|  | ||||
|     // Initialize temperatures | ||||
|     const celsius_t target_bed = temp_comp.probe_calib_bed_temp; | ||||
|     thermalManager.setTargetBed(target_bed); | ||||
|  | ||||
|     celsius_t target_probe = cali_info_init[TSI_PROBE].start_temp; | ||||
|  | ||||
|     report_targets(target_bed, target_probe); | ||||
|  | ||||
|     // Wait for heatbed to reach target temp and probe to cool below target temp | ||||
|     wait_for_temps(target_bed, target_probe, next_temp_report); | ||||
|  | ||||
|     // Disable leveling so it won't mess with us | ||||
|     TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); | ||||
|  | ||||
|     bool timeout = false; | ||||
|     for (;;) { | ||||
|       // Move probe to probing point and wait for it to reach target temperature | ||||
|       do_blocking_move_to(noz_pos_xyz); | ||||
|  | ||||
|       say_waiting_for_probe_heating(); | ||||
|       SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe); | ||||
|       const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL); | ||||
|       while (thermalManager.degProbe() < target_probe) { | ||||
|         if (report_temps(next_temp_report, probe_timeout_ms)) { | ||||
|           SERIAL_ECHOLNPGM("!Probe heating timed out."); | ||||
|           timeout = true; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       if (timeout) break; | ||||
|  | ||||
|       const float measured_z = g76_probe(TSI_PROBE, target_probe, noz_pos_xyz); | ||||
|       if (isnan(measured_z) || target_probe > cali_info_init[TSI_PROBE].end_temp) break; | ||||
|     } | ||||
|  | ||||
|     SERIAL_ECHOLNPGM("Retrieved measurements: ", temp_comp.get_index()); | ||||
|     if (temp_comp.finish_calibration(TSI_PROBE)) | ||||
|       say_successfully_calibrated(); | ||||
|     else | ||||
|       say_failed_to_calibrate(); | ||||
|     SERIAL_ECHOLNPGM(" probe."); | ||||
|  | ||||
|     // Cleanup | ||||
|     thermalManager.setTargetBed(0); | ||||
|     TERN_(HAS_LEVELING, set_bed_leveling_enabled(true)); | ||||
|  | ||||
|     SERIAL_ECHOLNPGM("Final compensation values:"); | ||||
|     temp_comp.print_offsets(); | ||||
|   } // do_probe_cal | ||||
|  | ||||
|   restore_feedrate_and_scaling(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * M871: Report / reset temperature compensation offsets. | ||||
|  *       Note: This does not affect values in EEPROM until M500. | ||||
|  * | ||||
|  *   M871 [ R | B | P | E ] | ||||
|  * | ||||
|  *    No Parameters - Print current offset values. | ||||
|  * | ||||
|  * Select only one of these flags: | ||||
|  *    R - Reset all offsets to zero (i.e., disable compensation). | ||||
|  *    B - Manually set offset for bed | ||||
|  *    P - Manually set offset for probe | ||||
|  *    E - Manually set offset for extruder | ||||
|  * | ||||
|  * With B, P, or E: | ||||
|  *    I[index] - Index in the array | ||||
|  *    V[value] - Adjustment in µm | ||||
|  */ | ||||
| void GcodeSuite::M871() { | ||||
|  | ||||
|   if (parser.seen('R')) { | ||||
|     // Reset z-probe offsets to factory defaults | ||||
|     temp_comp.clear_all_offsets(); | ||||
|     SERIAL_ECHOLNPGM("Offsets reset to default."); | ||||
|   } | ||||
|   else if (parser.seen("BPE")) { | ||||
|     if (!parser.seenval('V')) return; | ||||
|     const int16_t offset_val = parser.value_int(); | ||||
|     if (!parser.seenval('I')) return; | ||||
|     const int16_t idx = parser.value_int(); | ||||
|     const TempSensorID mod = (parser.seen('B') ? TSI_BED : | ||||
|                                 #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|                                   parser.seen('E') ? TSI_EXT : | ||||
|                                 #endif | ||||
|                                 TSI_PROBE | ||||
|                               ); | ||||
|     if (idx > 0 && temp_comp.set_offset(mod, idx - 1, offset_val)) | ||||
|       SERIAL_ECHOLNPGM("Set value: ", offset_val); | ||||
|     else | ||||
|       SERIAL_ECHOLNPGM("!Invalid index. Failed to set value (note: value at index 0 is constant)."); | ||||
|  | ||||
|   } | ||||
|   else // Print current Z-probe adjustments. Note: Values in EEPROM might differ. | ||||
|     temp_comp.print_offsets(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * M192: Wait for probe temperature sensor to reach a target | ||||
|  * | ||||
|  * Select only one of these flags: | ||||
|  *    R - Wait for heating or cooling | ||||
|  *    S - Wait only for heating | ||||
|  */ | ||||
| void GcodeSuite::M192() { | ||||
|   if (DEBUGGING(DRYRUN)) return; | ||||
|  | ||||
|   const bool no_wait_for_cooling = parser.seenval('S'); | ||||
|   if (!no_wait_for_cooling && ! parser.seenval('R')) { | ||||
|     SERIAL_ERROR_MSG("No target temperature set."); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const celsius_t target_temp = parser.value_celsius(); | ||||
|   ui.set_status(thermalManager.isProbeBelowTemp(target_temp) ? GET_TEXT_F(MSG_PROBE_HEATING) : GET_TEXT_F(MSG_PROBE_COOLING)); | ||||
|   thermalManager.wait_for_probe(target_temp, no_wait_for_cooling); | ||||
| } | ||||
|  | ||||
| #endif // PROBE_TEMP_COMPENSATION | ||||
							
								
								
									
										337
									
								
								Marlin/src/gcode/calibrate/G76_M871.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										337
									
								
								Marlin/src/gcode/calibrate/G76_M871.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,337 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||||
|  * | ||||
|  * Based on Sprinter and grbl. | ||||
|  * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * G76_M871.cpp - Temperature calibration/compensation for z-probing | ||||
|  */ | ||||
|  | ||||
| #include "../../inc/MarlinConfig.h" | ||||
|  | ||||
| #if HAS_PTC | ||||
|  | ||||
| #include "../gcode.h" | ||||
| #include "../../module/motion.h" | ||||
| #include "../../module/planner.h" | ||||
| #include "../../module/probe.h" | ||||
| #include "../../feature/bedlevel/bedlevel.h" | ||||
| #include "../../module/temperature.h" | ||||
| #include "../../module/probe.h" | ||||
| #include "../../feature/probe_temp_comp.h" | ||||
| #include "../../lcd/marlinui.h" | ||||
|  | ||||
| /** | ||||
|  * G76: calibrate probe and/or bed temperature offsets | ||||
|  *  Notes: | ||||
|  *  - When calibrating probe, bed temperature is held constant. | ||||
|  *    Compensation values are deltas to first probe measurement at probe temp. = 30°C. | ||||
|  *  - When calibrating bed, probe temperature is held constant. | ||||
|  *    Compensation values are deltas to first probe measurement at bed temp. = 60°C. | ||||
|  *  - The hotend will not be heated at any time. | ||||
|  *  - On my Průša MK3S clone I put a piece of paper between the probe and the hotend | ||||
|  *    so the hotend fan would not cool my probe constantly. Alternatively you could just | ||||
|  *    make sure the fan is not running while running the calibration process. | ||||
|  * | ||||
|  *  Probe calibration: | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Heats up bed to 100°C. | ||||
|  *  - Moves probe to probing point (1mm above heatbed). | ||||
|  *  - Waits until probe reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (=base value) and increases target temperature by 5°C. | ||||
|  *  - Waits until probe reaches increased target temperature. | ||||
|  *  - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. | ||||
|  *  - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). | ||||
|  *  - Compensation values of higher temperatures will be extrapolated (using linear regression first). | ||||
|  *    While this is not exact by any means it is still better than simply using the last compensation value. | ||||
|  * | ||||
|  *  Bed calibration: | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Heats up bed to 60°C. | ||||
|  *  - Moves probe to probing point (1mm above heatbed). | ||||
|  *  - Waits until probe reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (=base value) and increases bed temperature by 5°C. | ||||
|  *  - Moves probe to cooldown point. | ||||
|  *  - Waits until probe is below 30°C and bed has reached target temperature. | ||||
|  *  - Moves probe to probing point and waits until it reaches target temperature (30°C). | ||||
|  *  - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. | ||||
|  *  - Repeats last four points until max. bed temperature reached (110°C) or timeout. | ||||
|  *  - Compensation values of higher temperatures will be extrapolated (using linear regression first). | ||||
|  *    While this is not exact by any means it is still better than simply using the last compensation value. | ||||
|  * | ||||
|  *  G76 [B | P] | ||||
|  *  - no flag - Both calibration procedures will be run. | ||||
|  *  - `B` - Run bed temperature calibration. | ||||
|  *  - `P` - Run probe temperature calibration. | ||||
|  */ | ||||
|  | ||||
| static void say_waiting_for()               { SERIAL_ECHOPGM("Waiting for "); } | ||||
| static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); } | ||||
| static void say_successfully_calibrated()   { SERIAL_ECHOPGM("Successfully calibrated"); } | ||||
| static void say_failed_to_calibrate()       { SERIAL_ECHOPGM("!Failed to calibrate"); } | ||||
|  | ||||
| #if BOTH(PTC_PROBE, PTC_BED) | ||||
|  | ||||
|   void GcodeSuite::G76() { | ||||
|     auto report_temps = [](millis_t &ntr, millis_t timeout=0) { | ||||
|       idle_no_sleep(); | ||||
|       const millis_t ms = millis(); | ||||
|       if (ELAPSED(ms, ntr)) { | ||||
|         ntr = ms + 1000; | ||||
|         thermalManager.print_heater_states(active_extruder); | ||||
|       } | ||||
|       return (timeout && ELAPSED(ms, timeout)); | ||||
|     }; | ||||
|  | ||||
|     auto wait_for_temps = [&](const celsius_t tb, const celsius_t tp, millis_t &ntr, const millis_t timeout=0) { | ||||
|       say_waiting_for(); SERIAL_ECHOLNPGM("bed and probe temperature."); | ||||
|       while (thermalManager.wholeDegBed() != tb || thermalManager.wholeDegProbe() > tp) | ||||
|         if (report_temps(ntr, timeout)) return true; | ||||
|       return false; | ||||
|     }; | ||||
|  | ||||
|     auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) { | ||||
|       do_z_clearance(5.0); // Raise nozzle before probing | ||||
|       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 { | ||||
|         SERIAL_ECHOLNPAIR_F("Measured: ", measured_z); | ||||
|         if (targ == ProbeTempComp::cali_info[sid].start_temp) | ||||
|           ptc.prepare_new_calibration(measured_z); | ||||
|         else | ||||
|           ptc.push_back_new_measurement(sid, measured_z); | ||||
|         targ += ProbeTempComp::cali_info[sid].temp_resolution; | ||||
|       } | ||||
|       return measured_z; | ||||
|     }; | ||||
|  | ||||
|     #if ENABLED(BLTOUCH) | ||||
|       // Make sure any BLTouch error condition is cleared | ||||
|       bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY); | ||||
|       set_bltouch_deployed(false); | ||||
|     #endif | ||||
|  | ||||
|     bool do_bed_cal = parser.boolval('B'), do_probe_cal = parser.boolval('P'); | ||||
|     if (!do_bed_cal && !do_probe_cal) do_bed_cal = do_probe_cal = true; | ||||
|  | ||||
|     // Synchronize with planner | ||||
|     planner.synchronize(); | ||||
|  | ||||
|     #ifndef PTC_PROBE_HEATING_OFFSET | ||||
|       #define PTC_PROBE_HEATING_OFFSET 0 | ||||
|     #endif | ||||
|     const xyz_pos_t parkpos = PTC_PARK_POS, | ||||
|               probe_pos_xyz = xyz_pos_t(PTC_PROBE_POS) + xyz_pos_t({ 0.0f, 0.0f, PTC_PROBE_HEATING_OFFSET }), | ||||
|                 noz_pos_xyz = probe_pos_xyz - probe.offset_xy;  // Nozzle position based on probe position | ||||
|  | ||||
|     if (do_bed_cal || do_probe_cal) { | ||||
|       // Ensure park position is reachable | ||||
|       bool reachable = position_is_reachable(parkpos) || WITHIN(parkpos.z, Z_MIN_POS - fslop, Z_MAX_POS + fslop); | ||||
|       if (!reachable) | ||||
|         SERIAL_ECHOLNPGM("!Park"); | ||||
|       else { | ||||
|         // Ensure probe position is reachable | ||||
|         reachable = probe.can_reach(probe_pos_xyz); | ||||
|         if (!reachable) SERIAL_ECHOLNPGM("!Probe"); | ||||
|       } | ||||
|  | ||||
|       if (!reachable) { | ||||
|         SERIAL_ECHOLNPGM(" position unreachable - aborting."); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       process_subcommands_now(FPSTR(G28_STR)); | ||||
|     } | ||||
|  | ||||
|     remember_feedrate_scaling_off(); | ||||
|  | ||||
|     /****************************************** | ||||
|      * Calibrate bed temperature offsets | ||||
|      ******************************************/ | ||||
|  | ||||
|     // Report temperatures every second and handle heating timeouts | ||||
|     millis_t next_temp_report = millis() + 1000; | ||||
|  | ||||
|     auto report_targets = [&](const celsius_t tb, const celsius_t tp) { | ||||
|       SERIAL_ECHOLNPGM("Target Bed:", tb, " Probe:", tp); | ||||
|     }; | ||||
|  | ||||
|     if (do_bed_cal) { | ||||
|  | ||||
|       celsius_t target_bed = PTC_BED_START, | ||||
|                 target_probe = PTC_PROBE_TEMP; | ||||
|  | ||||
|       say_waiting_for(); SERIAL_ECHOLNPGM(" cooling."); | ||||
|       while (thermalManager.wholeDegBed() > target_bed || thermalManager.wholeDegProbe() > target_probe) | ||||
|         report_temps(next_temp_report); | ||||
|  | ||||
|       // Disable leveling so it won't mess with us | ||||
|       TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); | ||||
|  | ||||
|       for (uint8_t idx = 0; idx <= PTC_BED_COUNT; idx++) { | ||||
|         thermalManager.setTargetBed(target_bed); | ||||
|  | ||||
|         report_targets(target_bed, target_probe); | ||||
|  | ||||
|         // Park nozzle | ||||
|         do_blocking_move_to(parkpos); | ||||
|  | ||||
|         // Wait for heatbed to reach target temp and probe to cool below target temp | ||||
|         if (wait_for_temps(target_bed, target_probe, next_temp_report, millis() + MIN_TO_MS(15))) { | ||||
|           SERIAL_ECHOLNPGM("!Bed heating timeout."); | ||||
|           break; | ||||
|         } | ||||
|  | ||||
|         // Move the nozzle to the probing point and wait for the probe to reach target temp | ||||
|         do_blocking_move_to(noz_pos_xyz); | ||||
|         say_waiting_for_probe_heating(); | ||||
|         SERIAL_EOL(); | ||||
|         while (thermalManager.wholeDegProbe() < target_probe) | ||||
|           report_temps(next_temp_report); | ||||
|  | ||||
|         const float measured_z = g76_probe(TSI_BED, target_bed, noz_pos_xyz); | ||||
|         if (isnan(measured_z) || target_bed > (BED_MAX_TARGET)) break; | ||||
|       } | ||||
|  | ||||
|       SERIAL_ECHOLNPGM("Retrieved measurements: ", ptc.get_index()); | ||||
|       if (ptc.finish_calibration(TSI_BED)) { | ||||
|         say_successfully_calibrated(); | ||||
|         SERIAL_ECHOLNPGM(" bed."); | ||||
|       } | ||||
|       else { | ||||
|         say_failed_to_calibrate(); | ||||
|         SERIAL_ECHOLNPGM(" bed. Values reset."); | ||||
|       } | ||||
|  | ||||
|       // Cleanup | ||||
|       thermalManager.setTargetBed(0); | ||||
|       TERN_(HAS_LEVELING, set_bed_leveling_enabled(true)); | ||||
|     } // do_bed_cal | ||||
|  | ||||
|     /******************************************** | ||||
|      * Calibrate probe temperature offsets | ||||
|      ********************************************/ | ||||
|  | ||||
|     if (do_probe_cal) { | ||||
|  | ||||
|       // Park nozzle | ||||
|       do_blocking_move_to(parkpos); | ||||
|  | ||||
|       // Initialize temperatures | ||||
|       const celsius_t target_bed = BED_MAX_TARGET; | ||||
|       thermalManager.setTargetBed(target_bed); | ||||
|  | ||||
|       celsius_t target_probe = PTC_PROBE_START; | ||||
|  | ||||
|       report_targets(target_bed, target_probe); | ||||
|  | ||||
|       // Wait for heatbed to reach target temp and probe to cool below target temp | ||||
|       wait_for_temps(target_bed, target_probe, next_temp_report); | ||||
|  | ||||
|       // Disable leveling so it won't mess with us | ||||
|       TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); | ||||
|  | ||||
|       bool timeout = false; | ||||
|       for (uint8_t idx = 0; idx <= PTC_PROBE_COUNT; idx++) { | ||||
|         // Move probe to probing point and wait for it to reach target temperature | ||||
|         do_blocking_move_to(noz_pos_xyz); | ||||
|  | ||||
|         say_waiting_for_probe_heating(); | ||||
|         SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe); | ||||
|         const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL); | ||||
|         while (thermalManager.degProbe() < target_probe) { | ||||
|           if (report_temps(next_temp_report, probe_timeout_ms)) { | ||||
|             SERIAL_ECHOLNPGM("!Probe heating timed out."); | ||||
|             timeout = true; | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|         if (timeout) break; | ||||
|  | ||||
|         const float measured_z = g76_probe(TSI_PROBE, target_probe, noz_pos_xyz); | ||||
|         if (isnan(measured_z)) break; | ||||
|       } | ||||
|  | ||||
|       SERIAL_ECHOLNPGM("Retrieved measurements: ", ptc.get_index()); | ||||
|       if (ptc.finish_calibration(TSI_PROBE)) | ||||
|         say_successfully_calibrated(); | ||||
|       else | ||||
|         say_failed_to_calibrate(); | ||||
|       SERIAL_ECHOLNPGM(" probe."); | ||||
|  | ||||
|       // Cleanup | ||||
|       thermalManager.setTargetBed(0); | ||||
|       TERN_(HAS_LEVELING, set_bed_leveling_enabled(true)); | ||||
|  | ||||
|       SERIAL_ECHOLNPGM("Final compensation values:"); | ||||
|       ptc.print_offsets(); | ||||
|     } // do_probe_cal | ||||
|  | ||||
|     restore_feedrate_and_scaling(); | ||||
|   } | ||||
|  | ||||
| #endif // PTC_PROBE && PTC_BED | ||||
|  | ||||
| /** | ||||
|  * M871: Report / reset temperature compensation offsets. | ||||
|  *       Note: This does not affect values in EEPROM until M500. | ||||
|  * | ||||
|  *   M871 [ R | B | P | E ] | ||||
|  * | ||||
|  *    No Parameters - Print current offset values. | ||||
|  * | ||||
|  * Select only one of these flags: | ||||
|  *    R - Reset all offsets to zero (i.e., disable compensation). | ||||
|  *    B - Manually set offset for bed | ||||
|  *    P - Manually set offset for probe | ||||
|  *    E - Manually set offset for extruder | ||||
|  * | ||||
|  * With B, P, or E: | ||||
|  *    I[index] - Index in the array | ||||
|  *    V[value] - Adjustment in µm | ||||
|  */ | ||||
| void GcodeSuite::M871() { | ||||
|  | ||||
|   if (parser.seen('R')) { | ||||
|     // Reset z-probe offsets to factory defaults | ||||
|     ptc.clear_all_offsets(); | ||||
|     SERIAL_ECHOLNPGM("Offsets reset to default."); | ||||
|   } | ||||
|   else if (parser.seen("BPE")) { | ||||
|     if (!parser.seenval('V')) return; | ||||
|     const int16_t offset_val = parser.value_int(); | ||||
|     if (!parser.seenval('I')) return; | ||||
|     const int16_t idx = parser.value_int(); | ||||
|     const TempSensorID mod = TERN_(PTC_BED,    parser.seen_test('B') ? TSI_BED   :) | ||||
|                              TERN_(PTC_HOTEND, parser.seen_test('E') ? TSI_EXT   :) | ||||
|                              TERN_(PTC_PROBE,  parser.seen_test('P') ? TSI_PROBE :) TSI_COUNT; | ||||
|     if (mod == TSI_COUNT) | ||||
|       SERIAL_ECHOLNPGM("!Invalid sensor."); | ||||
|     else if (idx > 0 && ptc.set_offset(mod, idx - 1, offset_val)) | ||||
|       SERIAL_ECHOLNPGM("Set value: ", offset_val); | ||||
|     else | ||||
|       SERIAL_ECHOLNPGM("!Invalid index. Failed to set value (note: value at index 0 is constant)."); | ||||
|   } | ||||
|   else // Print current Z-probe adjustments. Note: Values in EEPROM might differ. | ||||
|     ptc.print_offsets(); | ||||
| } | ||||
|  | ||||
| #endif // HAS_PTC | ||||
| @@ -424,7 +424,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { | ||||
|         case 61: G61(); break;                                    // G61:  Apply/restore saved coordinates. | ||||
|       #endif | ||||
|  | ||||
|       #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|       #if BOTH(PTC_PROBE, PTC_BED) | ||||
|         case 76: G76(); break;                                    // G76: Calibrate first layer compensation values | ||||
|       #endif | ||||
|  | ||||
| @@ -587,6 +587,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { | ||||
|         case 191: M191(); break;                                  // M191: Wait for chamber temperature to reach target | ||||
|       #endif | ||||
|  | ||||
|       #if HAS_TEMP_PROBE | ||||
|         case 192: M192(); break;                                  // M192: Wait for probe temp | ||||
|       #endif | ||||
|  | ||||
|       #if HAS_COOLER | ||||
|         case 143: M143(); break;                                  // M143: Set cooler temperature | ||||
|         case 193: M193(); break;                                  // M193: Wait for cooler temperature to reach target | ||||
| @@ -921,8 +925,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { | ||||
|         case 852: M852(); break;                                  // M852: Set Skew factors | ||||
|       #endif | ||||
|  | ||||
|       #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|         case 192: M192(); break;                                  // M192: Wait for probe temp | ||||
|       #if HAS_PTC | ||||
|         case 871: M871(); break;                                  // M871: Print/reset/clear first layer temperature offset values | ||||
|       #endif | ||||
|  | ||||
|   | ||||
| @@ -66,7 +66,7 @@ | ||||
|  * G42  - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) | ||||
|  * G60  - Save current position. (Requires SAVED_POSITIONS) | ||||
|  * G61  - Apply/restore saved coordinates. (Requires SAVED_POSITIONS) | ||||
|  * G76  - Calibrate first layer temperature offsets. (Requires PROBE_TEMP_COMPENSATION) | ||||
|  * G76  - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED) | ||||
|  * G80  - Cancel current motion mode (Requires GCODE_MOTION_MODES) | ||||
|  * G90  - Use Absolute Coordinates | ||||
|  * G91  - Use Relative Coordinates | ||||
| @@ -88,6 +88,8 @@ | ||||
|  * M16  - Expected printer check. (Requires EXPECTED_PRINTER_CHECK) | ||||
|  * M17  - Enable/Power all stepper motors | ||||
|  * M18  - Disable all stepper motors; same as M84 | ||||
|  * | ||||
|  *** Print from Media (SDSUPPORT) *** | ||||
|  * M20  - List SD card. (Requires SDSUPPORT) | ||||
|  * M21  - Init SD card. (Requires SDSUPPORT) | ||||
|  * M22  - Release SD card. (Requires SDSUPPORT) | ||||
| @@ -100,30 +102,36 @@ | ||||
|  *        OR, with 'C' get the current filename. | ||||
|  * M28  - Start SD write: "M28 /path/file.gco". (Requires SDSUPPORT) | ||||
|  * M29  - Stop SD write. (Requires SDSUPPORT) | ||||
|  * M30  - Delete file from SD: "M30 /path/file.gco" | ||||
|  * M30  - Delete file from SD: "M30 /path/file.gco" (Requires SDSUPPORT) | ||||
|  * M31  - Report time since last M109 or SD card start to serial. | ||||
|  * M32  - Select file and start SD print: "M32 [S<bytepos>] !/path/file.gco#". (Requires SDSUPPORT) | ||||
|  *        Use P to run other files as sub-programs: "M32 P !filename#" | ||||
|  *        The '#' is necessary when calling from within sd files, as it stops buffer prereading | ||||
|  * M33  - Get the longname version of a path. (Requires LONG_FILENAME_HOST_SUPPORT) | ||||
|  * M34  - Set SD Card sorting options. (Requires SDCARD_SORT_ALPHA) | ||||
|  * | ||||
|  * M42  - Change pin status via gcode: M42 P<pin> S<value>. LED pin assumed if P is omitted. (Requires DIRECT_PIN_CONTROL) | ||||
|  * M43  - Display pin status, watch pins for changes, watch endstops & toggle LED, Z servo probe test, toggle pins | ||||
|  * M43  - Display pin status, watch pins for changes, watch endstops & toggle LED, Z servo probe test, toggle pins (Requires PINS_DEBUGGING) | ||||
|  * M48  - Measure Z Probe repeatability: M48 P<points> X<pos> Y<pos> V<level> E<engage> L<legs> S<chizoid>. (Requires Z_MIN_PROBE_REPEATABILITY_TEST) | ||||
|  * | ||||
|  * M73  - Set the progress percentage. (Requires LCD_SET_PROGRESS_MANUALLY) | ||||
|  * M75  - Start the print job timer. | ||||
|  * M76  - Pause the print job timer. | ||||
|  * M77  - Stop the print job timer. | ||||
|  * M78  - Show statistical information about the print jobs. (Requires PRINTCOUNTER) | ||||
|  * | ||||
|  * M80  - Turn on Power Supply. (Requires PSU_CONTROL) | ||||
|  * M81  - Turn off Power Supply. (Requires PSU_CONTROL) | ||||
|  * | ||||
|  * M82  - Set E codes absolute (default). | ||||
|  * M83  - Set E codes relative while in Absolute (G90) mode. | ||||
|  * M84  - Disable steppers until next move, or use S<seconds> to specify an idle | ||||
|  *        duration after which steppers should turn off. S0 disables the timeout. | ||||
|  * M85  - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default) | ||||
|  * M92  - Set planner.settings.axis_steps_per_mm for one or more axes. | ||||
|  * | ||||
|  * M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER) | ||||
|  * | ||||
|  * M104 - Set extruder target temp. | ||||
|  * M105 - Report current temperatures. | ||||
|  * M106 - Set print fan speed. | ||||
| @@ -132,23 +140,29 @@ | ||||
|  * M109 - S<temp> Wait for extruder current temp to reach target temp. ** Wait only when heating! ** | ||||
|  *        R<temp> Wait for extruder current temp to reach target temp. ** Wait for heating or cooling. ** | ||||
|  *        If AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F | ||||
|  * | ||||
|  * M110 - Set the current line number. (Used by host printing) | ||||
|  * M111 - Set debug flags: "M111 S<flagbits>". See flag bits defined in enum.h. | ||||
|  * M112 - Full Shutdown. | ||||
|  * | ||||
|  * M113 - Get or set the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE) | ||||
|  * M114 - Report current position. | ||||
|  * M115 - Report capabilities. (Extended capabilities requires EXTENDED_CAPABILITIES_REPORT) | ||||
|  * M117 - Display a message on the controller screen. (Requires an LCD) | ||||
|  * M118 - Display a message in the host console. | ||||
|  * | ||||
|  * M119 - Report endstops status. | ||||
|  * M120 - Enable endstops detection. | ||||
|  * M121 - Disable endstops detection. | ||||
|  * | ||||
|  * M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660 or L6470) | ||||
|  * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) | ||||
|  * | ||||
|  * M126 - Solenoid Air Valve Open. (Requires BARICUDA) | ||||
|  * M127 - Solenoid Air Valve Closed. (Requires BARICUDA) | ||||
|  * M128 - EtoP Open. (Requires BARICUDA) | ||||
|  * M129 - EtoP Closed. (Requires BARICUDA) | ||||
|  * | ||||
|  * M140 - Set bed target temp. S<temp> | ||||
|  * M141 - Set heated chamber target temp. S<temp> (Requires a chamber heater) | ||||
|  * M143 - Set cooler target temp. S<temp> (Requires a laser cooling device) | ||||
| @@ -161,9 +175,9 @@ | ||||
|  * M164 - Commit the mix and save to a virtual tool (current, or as specified by 'S'). (Requires MIXING_EXTRUDER) | ||||
|  * M165 - Set the mix for the mixing extruder (and current virtual tool) with parameters ABCDHI. (Requires MIXING_EXTRUDER and DIRECT_MIXING_IN_G1) | ||||
|  * M166 - Set the Gradient Mix for the mixing extruder. (Requires GRADIENT_MIX) | ||||
|  * M190 - S<temp> Wait for bed current temp to reach target temp. ** Wait only when heating! ** | ||||
|  *        R<temp> Wait for bed current temp to reach target temp. ** Wait for heating or cooling. ** | ||||
|  * M193 - R<temp> Wait for cooler temp to reach target temp. ** Wait for cooling. ** | ||||
|  * M190 - Set bed target temperature and wait. R<temp> Set target temperature and wait. S<temp> Set, but only wait when heating. (Requires TEMP_SENSOR_BED) | ||||
|  * M192 - Wait for probe to reach target temperature. (Requires TEMP_SENSOR_PROBE) | ||||
|  * M193 - R<temp> Wait for cooler to reach target temp. ** Wait for cooling. ** | ||||
|  * M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.) | ||||
|  * M201 - Set max acceleration in units/s^2 for print moves: "M201 X<accel> Y<accel> Z<accel> E<accel>" | ||||
|  * M202 - Set max acceleration in units/s^2 for travel moves: "M202 X<accel> Y<accel> Z<accel> E<accel>" ** UNUSED IN MARLIN! ** | ||||
| @@ -183,7 +197,7 @@ | ||||
|  * M218 - Set/get a tool offset: "M218 T<index> X<offset> Y<offset>". (Requires 2 or more extruders) | ||||
|  * M220 - Set Feedrate Percentage: "M220 S<percent>" (i.e., "FR" on the LCD) | ||||
|  *        Use "M220 B" to back up the Feedrate Percentage and "M220 R" to restore it. (Requires an MMU_MODEL version 2 or 2S) | ||||
|  * M221 - Set Flow Percentage: "M221 S<percent>" | ||||
|  * M221 - Set Flow Percentage: "M221 S<percent>" (Requires an extruder) | ||||
|  * M226 - Wait until a pin is in a given state: "M226 P<pin> S<state>" (Requires DIRECT_PIN_CONTROL) | ||||
|  * M240 - Trigger a camera to take a photograph. (Requires PHOTO_GCODE) | ||||
|  * M250 - Set LCD contrast: "M250 C<contrast>" (0-63). (Requires LCD support) | ||||
| @@ -230,9 +244,9 @@ | ||||
|  * M502 - Revert to the default "factory settings". ** Does not write them to EEPROM! ** | ||||
|  * M503 - Print the current settings (in memory): "M503 S<verbose>". S0 specifies compact output. | ||||
|  * M504 - Validate EEPROM contents. (Requires EEPROM_SETTINGS) | ||||
|  * M510 - Lock Printer | ||||
|  * M511 - Unlock Printer | ||||
|  * M512 - Set/Change/Remove Password | ||||
|  * M510 - Lock Printer (Requires PASSWORD_FEATURE) | ||||
|  * M511 - Unlock Printer (Requires PASSWORD_UNLOCK_GCODE) | ||||
|  * M512 - Set/Change/Remove Password (Requires PASSWORD_CHANGE_GCODE) | ||||
|  * M524 - Abort the current SD print job started with M24. (Requires SDSUPPORT) | ||||
|  * M540 - Enable/disable SD card abort on endstop hit: "M540 S<state>". (Requires SD_ABORT_ON_ENDSTOP_HIT) | ||||
|  * M552 - Get or set IP address. Enable/disable network interface. (Requires enabled Ethernet port) | ||||
| @@ -252,7 +266,9 @@ | ||||
|  * M808 - Set or Goto a Repeat Marker (Requires GCODE_REPEAT_MARKERS) | ||||
|  * M810-M819 - Define/execute a G-code macro (Requires GCODE_MACROS) | ||||
|  * M851 - Set Z probe's XYZ offsets in current units. (Negative values: X=left, Y=front, Z=below) | ||||
|  * M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ) | ||||
|  * M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, plus SKEW_CORRECTION_FOR_Z for IJ) | ||||
|  * | ||||
|  *** I2C_POSITION_ENCODERS *** | ||||
|  * M860 - Report the position of position encoder modules. | ||||
|  * M861 - Report the status of position encoder modules. | ||||
|  * M862 - Perform an axis continuity test for position encoder modules. | ||||
| @@ -263,8 +279,8 @@ | ||||
|  * M867 - Enable/disable or toggle error correction for position encoder modules. | ||||
|  * M868 - Report or set position encoder module error correction threshold. | ||||
|  * M869 - Report position encoder module error. | ||||
|  * M871 - Print/reset/clear first layer temperature offset values. (Requires PROBE_TEMP_COMPENSATION) | ||||
|  * M192 - Wait for probe temp (Requires PROBE_TEMP_COMPENSATION) | ||||
|  * | ||||
|  * M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) | ||||
|  * M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER) | ||||
|  * M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE) | ||||
|  * M906 - Set or get motor current in milliamps using axis codes X, Y, Z, E. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660 or L6470) | ||||
| @@ -282,13 +298,14 @@ | ||||
|  * M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER) | ||||
|  * M7219 - Control Max7219 Matrix LEDs. (Requires MAX7219_GCODE) | ||||
|  * | ||||
|  *** SCARA *** | ||||
|  * M360 - SCARA calibration: Move to cal-position ThetaA (0 deg calibration) | ||||
|  * M361 - SCARA calibration: Move to cal-position ThetaB (90 deg calibration - steps per degree) | ||||
|  * M362 - SCARA calibration: Move to cal-position PsiA (0 deg calibration) | ||||
|  * M363 - SCARA calibration: Move to cal-position PsiB (90 deg calibration - steps per degree) | ||||
|  * M364 - SCARA calibration: Move to cal-position PSIC (90 deg to Theta calibration position) | ||||
|  * | ||||
|  * ************ Custom codes - This can change to suit future G-code regulations | ||||
|  *** Custom codes (can be changed to suit future G-code standards) *** | ||||
|  * G425 - Calibrate using a conductive object. (Requires CALIBRATION_GCODE) | ||||
|  * M928 - Start SD logging: "M928 filename.gco". Stop with M29. (Requires SDSUPPORT) | ||||
|  * M993 - Backup SPI Flash to SD | ||||
| @@ -296,10 +313,11 @@ | ||||
|  * M995 - Touch screen calibration for TFT display | ||||
|  * M997 - Perform in-application firmware update | ||||
|  * M999 - Restart after being stopped by error | ||||
|  * | ||||
|  * D... - Custom Development G-code. Add hooks to 'gcode_D.cpp' for developers to test features. (Requires MARLIN_DEV_MODE) | ||||
|  *        D576 - Set buffer monitoring options. (Requires BUFFER_MONITORING) | ||||
|  * | ||||
|  * "T" Codes | ||||
|  *** "T" Codes *** | ||||
|  * | ||||
|  * T0-T3 - Select an extruder (tool) by index: "T<n> F<units/min>" | ||||
|  */ | ||||
| @@ -551,7 +569,7 @@ private: | ||||
|     static void G59(); | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|   #if BOTH(PTC_PROBE, PTC_BED) | ||||
|     static void G76(); | ||||
|   #endif | ||||
|  | ||||
| @@ -744,6 +762,10 @@ private: | ||||
|     static void M191(); | ||||
|   #endif | ||||
|  | ||||
|   #if HAS_TEMP_PROBE | ||||
|     static void M192(); | ||||
|   #endif | ||||
|  | ||||
|   #if HAS_COOLER | ||||
|     static void M143(); | ||||
|     static void M193(); | ||||
| @@ -1087,8 +1109,7 @@ private: | ||||
|     FORCE_INLINE static void M869() { I2CPEM.M869(); } | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|     static void M192(); | ||||
|   #if HAS_PTC | ||||
|     static void M871(); | ||||
|   #endif | ||||
|  | ||||
|   | ||||
							
								
								
									
										56
									
								
								Marlin/src/gcode/temp/M192.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Marlin/src/gcode/temp/M192.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||||
|  * | ||||
|  * Based on Sprinter and grbl. | ||||
|  * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * M192.cpp - Wait for probe to reach temperature | ||||
|  */ | ||||
|  | ||||
| #include "../../inc/MarlinConfig.h" | ||||
|  | ||||
| #if HAS_TEMP_PROBE | ||||
|  | ||||
| #include "../gcode.h" | ||||
| #include "../../module/temperature.h" | ||||
| #include "../../lcd/marlinui.h" | ||||
|  | ||||
| /** | ||||
|  * M192: Wait for probe temperature sensor to reach a target | ||||
|  * | ||||
|  * Select only one of these flags: | ||||
|  *    R - Wait for heating or cooling | ||||
|  *    S - Wait only for heating | ||||
|  */ | ||||
| void GcodeSuite::M192() { | ||||
|   if (DEBUGGING(DRYRUN)) return; | ||||
|  | ||||
|   const bool no_wait_for_cooling = parser.seenval('S'); | ||||
|   if (!no_wait_for_cooling && !parser.seenval('R')) { | ||||
|     SERIAL_ERROR_MSG("No target temperature set."); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const celsius_t target_temp = parser.value_celsius(); | ||||
|   ui.set_status(thermalManager.isProbeBelowTemp(target_temp) ? GET_TEXT_F(MSG_PROBE_HEATING) : GET_TEXT_F(MSG_PROBE_COOLING)); | ||||
|   thermalManager.wait_for_probe(target_temp, no_wait_for_cooling); | ||||
| } | ||||
|  | ||||
| #endif // HAS_TEMP_PROBE | ||||
| @@ -550,6 +550,20 @@ | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| // Probe Temperature Compensation | ||||
| #if !TEMP_SENSOR_PROBE | ||||
|   #undef PTC_PROBE | ||||
| #endif | ||||
| #if !TEMP_SENSOR_BED | ||||
|   #undef PTC_BED | ||||
| #endif | ||||
| #if !HAS_EXTRUDERS | ||||
|   #undef PTC_HOTEND | ||||
| #endif | ||||
| #if ANY(PTC_PROBE, PTC_BED, PTC_HOTEND) | ||||
|   #define HAS_PTC 1 | ||||
| #endif | ||||
|  | ||||
| // Let SD_FINISHED_RELEASECOMMAND stand in for SD_FINISHED_STEPPERRELEASE | ||||
| #if ENABLED(SD_FINISHED_STEPPERRELEASE) | ||||
|   #ifndef SD_FINISHED_RELEASECOMMAND | ||||
|   | ||||
| @@ -597,6 +597,10 @@ | ||||
|   #error "SPINDLE_LASER_PWM (true) is now set with SPINDLE_LASER_USE_PWM (enabled)." | ||||
| #elif ANY(IS_RAMPS_EEB, IS_RAMPS_EEF, IS_RAMPS_EFB, IS_RAMPS_EFF, IS_RAMPS_SF) | ||||
|   #error "The IS_RAMPS_* conditionals (for heater/fan/bed pins) are now called FET_ORDER_*." | ||||
| #elif defined(PROBE_TEMP_COMPENSATION) | ||||
|   #error "PROBE_TEMP_COMPENSATION is now set using the PTC_PROBE, PTC_BED, PTC_HOTEND options." | ||||
| #elif defined(BTC_PROBE_TEMP) | ||||
|   #error "BTC_PROBE_TEMP is now PTC_PROBE_TEMP." | ||||
| #endif | ||||
|  | ||||
| #if MB(DUE3DOM_MINI) && PIN_EXISTS(TEMP_2) && DISABLED(TEMP_SENSOR_BOARD) | ||||
| @@ -611,60 +615,60 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L | ||||
| /** | ||||
|  * Probe temp compensation requirements | ||||
|  */ | ||||
|  | ||||
| #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|   #if defined(PTC_PARK_POS_X) || defined(PTC_PARK_POS_Y) || defined(PTC_PARK_POS_Z) | ||||
|     #error "PTC_PARK_POS_[XYZ] is now PTC_PARK_POS (array)." | ||||
|   #elif !defined(PTC_PARK_POS) | ||||
|     #error "PROBE_TEMP_COMPENSATION requires PTC_PARK_POS." | ||||
|   #elif defined(PTC_PROBE_POS_X) || defined(PTC_PROBE_POS_Y) | ||||
|     #error "PTC_PROBE_POS_[XY] is now PTC_PROBE_POS (array)." | ||||
|   #elif !defined(PTC_PROBE_POS) | ||||
|     #error "PROBE_TEMP_COMPENSATION requires PTC_PROBE_POS." | ||||
| #if HAS_PTC | ||||
|   #if TEMP_SENSOR_PROBE && TEMP_SENSOR_BED | ||||
|     #if defined(PTC_PARK_POS_X) || defined(PTC_PARK_POS_Y) || defined(PTC_PARK_POS_Z) | ||||
|       #error "PTC_PARK_POS_[XYZ] is now PTC_PARK_POS (array)." | ||||
|     #elif !defined(PTC_PARK_POS) | ||||
|       #error "PTC_PARK_POS is required for Probe Temperature Compensation." | ||||
|     #elif defined(PTC_PROBE_POS_X) || defined(PTC_PROBE_POS_Y) | ||||
|       #error "PTC_PROBE_POS_[XY] is now PTC_PROBE_POS (array)." | ||||
|     #elif !defined(PTC_PROBE_POS) | ||||
|       #error "PTC_PROBE_POS is required for Probe Temperature Compensation." | ||||
|     #endif | ||||
|   #endif | ||||
|  | ||||
|   #ifdef PTC_SAMPLE_START | ||||
|     constexpr auto _ptc_sample_start = PTC_SAMPLE_START; | ||||
|   #ifdef PTC_PROBE_START | ||||
|     constexpr auto _ptc_sample_start = PTC_PROBE_START; | ||||
|     constexpr decltype(_ptc_sample_start) _test_ptc_sample_start = 12.3f; | ||||
|     static_assert(_test_ptc_sample_start != 12.3f, "PTC_SAMPLE_START must be a whole number."); | ||||
|     static_assert(_test_ptc_sample_start != 12.3f, "PTC_PROBE_START must be a whole number."); | ||||
|   #endif | ||||
|   #ifdef PTC_SAMPLE_RES | ||||
|     constexpr auto _ptc_sample_res = PTC_SAMPLE_RES; | ||||
|   #ifdef PTC_PROBE_RES | ||||
|     constexpr auto _ptc_sample_res = PTC_PROBE_RES; | ||||
|     constexpr decltype(_ptc_sample_res) _test_ptc_sample_res = 12.3f; | ||||
|     static_assert(_test_ptc_sample_res != 12.3f, "PTC_SAMPLE_RES must be a whole number."); | ||||
|     static_assert(_test_ptc_sample_res != 12.3f, "PTC_PROBE_RES must be a whole number."); | ||||
|   #endif | ||||
|   #ifdef BTC_SAMPLE_START | ||||
|     constexpr auto _btc_sample_start = BTC_SAMPLE_START; | ||||
|   #ifdef PTC_BED_START | ||||
|     constexpr auto _btc_sample_start = PTC_BED_START; | ||||
|     constexpr decltype(_btc_sample_start) _test_btc_sample_start = 12.3f; | ||||
|     static_assert(_test_btc_sample_start != 12.3f, "BTC_SAMPLE_START must be a whole number."); | ||||
|     static_assert(_test_btc_sample_start != 12.3f, "PTC_BED_START must be a whole number."); | ||||
|   #endif | ||||
|   #ifdef BTC_SAMPLE_RES | ||||
|     constexpr auto _btc_sample_res = BTC_SAMPLE_RES; | ||||
|   #ifdef PTC_BED_RES | ||||
|     constexpr auto _btc_sample_res = PTC_BED_RES; | ||||
|     constexpr decltype(_btc_sample_res) _test_btc_sample_res = 12.3f; | ||||
|     static_assert(_test_btc_sample_res != 12.3f, "BTC_SAMPLE_RES must be a whole number."); | ||||
|     static_assert(_test_btc_sample_res != 12.3f, "PTC_BED_RES must be a whole number."); | ||||
|   #endif | ||||
|   #ifdef BTC_PROBE_TEMP | ||||
|     constexpr auto _btc_probe_temp = BTC_PROBE_TEMP; | ||||
|   #ifdef PTC_PROBE_TEMP | ||||
|     constexpr auto _btc_probe_temp = PTC_PROBE_TEMP; | ||||
|     constexpr decltype(_btc_probe_temp) _test_btc_probe_temp = 12.3f; | ||||
|     static_assert(_test_btc_probe_temp != 12.3f, "BTC_PROBE_TEMP must be a whole number."); | ||||
|     static_assert(_test_btc_probe_temp != 12.3f, "PTC_PROBE_TEMP must be a whole number."); | ||||
|   #endif | ||||
|   #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|     #ifdef ETC_SAMPLE_START | ||||
|       constexpr auto _etc_sample_start = ETC_SAMPLE_START; | ||||
|   #if ENABLED(PTC_HOTEND) | ||||
|     #if EXTRUDERS != 1 | ||||
|       #error "PTC_HOTEND only works with a single extruder." | ||||
|     #endif | ||||
|     #ifdef PTC_HOTEND_START | ||||
|       constexpr auto _etc_sample_start = PTC_HOTEND_START; | ||||
|       constexpr decltype(_etc_sample_start) _test_etc_sample_start = 12.3f; | ||||
|       static_assert(_test_etc_sample_start != 12.3f, "ETC_SAMPLE_START must be a whole number."); | ||||
|       static_assert(_test_etc_sample_start != 12.3f, "PTC_HOTEND_START must be a whole number."); | ||||
|     #endif | ||||
|     #ifdef ETC_SAMPLE_RES | ||||
|       constexpr auto _etc_sample_res = ETC_SAMPLE_RES; | ||||
|     #ifdef PTC_HOTEND_RES | ||||
|       constexpr auto _etc_sample_res = PTC_HOTEND_RES; | ||||
|       constexpr decltype(_etc_sample_res) _test_etc_sample_res = 12.3f; | ||||
|       static_assert(_test_etc_sample_res != 12.3f, "ETC_SAMPLE_RES must be a whole number."); | ||||
|       static_assert(_test_etc_sample_res != 12.3f, "PTC_HOTEND_RES must be a whole number."); | ||||
|     #endif | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(USE_TEMP_EXT_COMPENSATION) && EXTRUDERS != 1 | ||||
|     #error "USE_TEMP_EXT_COMPENSATION only works with a single extruder." | ||||
|   #endif | ||||
| #endif | ||||
| #endif // HAS_PTC | ||||
|  | ||||
| /** | ||||
|  * Marlin release, version and default string | ||||
|   | ||||
| @@ -128,7 +128,7 @@ | ||||
|   #include "../feature/tmc_util.h" | ||||
| #endif | ||||
|  | ||||
| #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
| #if HAS_PTC | ||||
|   #include "../feature/probe_temp_comp.h" | ||||
| #endif | ||||
|  | ||||
| @@ -264,13 +264,16 @@ typedef struct SettingsDataStruct { | ||||
|   // | ||||
|   // Temperature first layer compensation values | ||||
|   // | ||||
|   #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|     int16_t z_offsets_probe[COUNT(temp_comp.z_offsets_probe)], // M871 P I V | ||||
|             z_offsets_bed[COUNT(temp_comp.z_offsets_bed)]      // M871 B I V | ||||
|             #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|               , z_offsets_ext[COUNT(temp_comp.z_offsets_ext)]  // M871 E I V | ||||
|             #endif | ||||
|             ; | ||||
|   #if HAS_PTC | ||||
|     #if ENABLED(PTC_PROBE) | ||||
|       int16_t z_offsets_probe[COUNT(ptc.z_offsets_probe)]; // M871 P I V | ||||
|     #endif | ||||
|     #if ENABLED(PTC_BED) | ||||
|       int16_t z_offsets_bed[COUNT(ptc.z_offsets_bed)];     // M871 B I V | ||||
|     #endif | ||||
|     #if ENABLED(PTC_HOTEND) | ||||
|       int16_t z_offsets_hotend[COUNT(ptc.z_offsets_hotend)];     // M871 E I V | ||||
|     #endif | ||||
|   #endif | ||||
|  | ||||
|   // | ||||
| @@ -844,11 +847,15 @@ void MarlinSettings::postprocess() { | ||||
|     // | ||||
|     // Thermal first layer compensation values | ||||
|     // | ||||
|     #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|       EEPROM_WRITE(temp_comp.z_offsets_probe); | ||||
|       EEPROM_WRITE(temp_comp.z_offsets_bed); | ||||
|       #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|         EEPROM_WRITE(temp_comp.z_offsets_ext); | ||||
|     #if HAS_PTC | ||||
|       #if ENABLED(PTC_PROBE) | ||||
|         EEPROM_WRITE(ptc.z_offsets_probe); | ||||
|       #endif | ||||
|       #if ENABLED(PTC_BED) | ||||
|         EEPROM_WRITE(ptc.z_offsets_bed); | ||||
|       #endif | ||||
|       #if ENABLED(PTC_HOTEND) | ||||
|         EEPROM_WRITE(ptc.z_offsets_hotend); | ||||
|       #endif | ||||
|     #else | ||||
|       // No placeholder data for this feature | ||||
| @@ -1710,13 +1717,17 @@ void MarlinSettings::postprocess() { | ||||
|       // | ||||
|       // Thermal first layer compensation values | ||||
|       // | ||||
|       #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|         EEPROM_READ(temp_comp.z_offsets_probe); | ||||
|         EEPROM_READ(temp_comp.z_offsets_bed); | ||||
|         #if ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|           EEPROM_READ(temp_comp.z_offsets_ext); | ||||
|       #if HAS_PTC | ||||
|         #if ENABLED(PTC_PROBE) | ||||
|           EEPROM_READ(ptc.z_offsets_probe); | ||||
|         #endif | ||||
|         temp_comp.reset_index(); | ||||
|         # if ENABLED(PTC_BED) | ||||
|           EEPROM_READ(ptc.z_offsets_bed); | ||||
|         #endif | ||||
|         #if ENABLED(PTC_HOTEND) | ||||
|           EEPROM_READ(ptc.z_offsets_hotend); | ||||
|         #endif | ||||
|         ptc.reset_index(); | ||||
|       #else | ||||
|         // No placeholder data for this feature | ||||
|       #endif | ||||
| @@ -2728,6 +2739,11 @@ void MarlinSettings::reset() { | ||||
|   // | ||||
|   TERN_(EDITABLE_SERVO_ANGLES, COPY(servo_angles, base_servo_angles)); // When not editable only one copy of servo angles exists | ||||
|  | ||||
|   // | ||||
|   // Probe Temperature Compensation | ||||
|   // | ||||
|   TERN_(HAS_PTC, ptc.reset()); | ||||
|  | ||||
|   // | ||||
|   // BLTOUCH | ||||
|   // | ||||
|   | ||||
| @@ -18,7 +18,7 @@ opt_set MOTHERBOARD BOARD_RAMBO \ | ||||
|         FANMUX0_PIN 53 | ||||
| opt_disable Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN USE_WATCHDOG | ||||
| opt_enable USE_ZMAX_PLUG REPRAP_DISCOUNT_SMART_CONTROLLER LCD_PROGRESS_BAR LCD_PROGRESS_BAR_TEST \ | ||||
|            FIX_MOUNTED_PROBE CODEPENDENT_XY_HOMING PIDTEMPBED PROBE_TEMP_COMPENSATION \ | ||||
|            FIX_MOUNTED_PROBE CODEPENDENT_XY_HOMING PIDTEMPBED PTC_PROBE PTC_BED \ | ||||
|            PREHEAT_BEFORE_PROBING PROBING_HEATERS_OFF PROBING_FANS_OFF PROBING_STEPPERS_OFF WAIT_FOR_BED_HEATER \ | ||||
|            EEPROM_SETTINGS SDSUPPORT SD_REPRINT_LAST_SELECTED_FILE BINARY_FILE_TRANSFER \ | ||||
|            BLINKM PCA9533 PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \ | ||||
| @@ -61,16 +61,16 @@ opt_disable MIN_SOFTWARE_ENDSTOP_Z MAX_SOFTWARE_ENDSTOPS | ||||
| exec_test $1 $2 "Rambo CNC Configuration" "$3" | ||||
|  | ||||
| # | ||||
| # Rambo heated bed only | ||||
| # Rambo heated bed and probe temp sensor | ||||
| # | ||||
| restore_configs | ||||
| opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 \ | ||||
| opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 TEMP_SENSOR_PROBE 1 TEMP_PROBE_PIN 12 \ | ||||
|         DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \ | ||||
|         DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ | ||||
|         DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \ | ||||
|         MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \ | ||||
|         AXIS_RELATIVE_MODES '{ false, false, false }' | ||||
| opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER | ||||
| opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER FIX_MOUNTED_PROBE Z_SAFE_HOMING | ||||
| exec_test $1 $2 "Rambo heated bed only" "$3" | ||||
|  | ||||
| # | ||||
|   | ||||
| @@ -136,20 +136,20 @@ ADVANCED_PAUSE_FEATURE                 = src_filter=+<src/feature/pause.cpp> +<s | ||||
| PSU_CONTROL                            = src_filter=+<src/feature/power.cpp> | ||||
| HAS_POWER_MONITOR                      = src_filter=+<src/feature/power_monitor.cpp> +<src/gcode/feature/power_monitor> | ||||
| POWER_LOSS_RECOVERY                    = src_filter=+<src/feature/powerloss.cpp> +<src/gcode/feature/powerloss> | ||||
| PROBE_TEMP_COMPENSATION                = src_filter=+<src/feature/probe_temp_comp.cpp> +<src/gcode/calibrate/G76_M192_M871.cpp> | ||||
| HAS_PTC                                = src_filter=+<src/feature/probe_temp_comp.cpp> +<src/gcode/calibrate/G76_M871.cpp> | ||||
| HAS_FILAMENT_SENSOR                    = src_filter=+<src/feature/runout.cpp> +<src/gcode/feature/runout> | ||||
| (EXT|MANUAL)_SOLENOID.*                = src_filter=+<src/feature/solenoid.cpp> +<src/gcode/control/M380_M381.cpp> | ||||
| MK2_MULTIPLEXER                        = src_filter=+<src/feature/snmm.cpp> | ||||
| HAS_CUTTER                             = src_filter=+<src/feature/spindle_laser.cpp> +<src/gcode/control/M3-M5.cpp> | ||||
| HAS_DRIVER_SAFE_POWER_PROTECT          = src_filter=+<src/feature/stepper_driver_safety.cpp> | ||||
| EXPERIMENTAL_I2CBUS                    = src_filter=+<src/feature/twibus.cpp> +<src/gcode/feature/i2c> | ||||
| MECHANICAL_GANTRY_CAL.+                = src_filter=+<src/gcode/calibrate/G34.cpp> | ||||
| Z_MULTI_ENDSTOPS                       = src_filter=+<src/gcode/calibrate/G34_M422.cpp> | ||||
| Z_STEPPER_AUTO_ALIGN                   = src_filter=+<src/feature/z_stepper_align.cpp> +<src/gcode/calibrate/G34_M422.cpp> | ||||
| G26_MESH_VALIDATION                    = src_filter=+<src/gcode/bedlevel/G26.cpp> | ||||
| ASSISTED_TRAMMING                      = src_filter=+<src/feature/tramming.cpp> +<src/gcode/bedlevel/G35.cpp> | ||||
| HAS_MESH                               = src_filter=+<src/gcode/bedlevel/G42.cpp> | ||||
| HAS_LEVELING                           = src_filter=+<src/gcode/bedlevel/M420.cpp> +<src/feature/bedlevel/bedlevel.cpp> | ||||
| MECHANICAL_GANTRY_CAL.+                = src_filter=+<src/gcode/calibrate/G34.cpp> | ||||
| Z_MULTI_ENDSTOPS|Z_STEPPER_AUTO_ALIGN  = src_filter=+<src/gcode/calibrate/G34_M422.cpp> | ||||
| Z_STEPPER_AUTO_ALIGN                   = src_filter=+<src/feature/z_stepper_align.cpp> | ||||
| DELTA_AUTO_CALIBRATION                 = src_filter=+<src/gcode/calibrate/G33.cpp> | ||||
| CALIBRATION_GCODE                      = src_filter=+<src/gcode/calibrate/G425.cpp> | ||||
| Z_MIN_PROBE_REPEATABILITY_TEST         = src_filter=+<src/gcode/calibrate/M48.cpp> | ||||
| @@ -209,6 +209,7 @@ SDSUPPORT                              = src_filter=+<src/sd/cardreader.cpp> +<s | ||||
| HAS_MEDIA_SUBCALLS                     = src_filter=+<src/gcode/sd/M32.cpp> | ||||
| GCODE_REPEAT_MARKERS                   = src_filter=+<src/feature/repeat.cpp> +<src/gcode/sd/M808.cpp> | ||||
| HAS_EXTRUDERS                          = src_filter=+<src/gcode/units/M82_M83.cpp> +<src/gcode/temp/M104_M109.cpp> +<src/gcode/config/M221.cpp> | ||||
| HAS_TEMP_PROBE                         = src_filter=+<src/gcode/temp/M192.cpp> | ||||
| HAS_COOLER                             = src_filter=+<src/gcode/temp/M143_M193.cpp> | ||||
| HAS_COOLER|LASER_COOLANT_FLOW_METER    = src_filter=+<src/feature/cooler.cpp> | ||||
| AUTO_REPORT_TEMPERATURES               = src_filter=+<src/gcode/temp/M155.cpp> | ||||
|   | ||||
| @@ -152,7 +152,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared> | ||||
|   -<src/gcode/calibrate/G33.cpp> | ||||
|   -<src/gcode/calibrate/G34.cpp> | ||||
|   -<src/gcode/calibrate/G34_M422.cpp> | ||||
|   -<src/gcode/calibrate/G76_M192_M871.cpp> | ||||
|   -<src/gcode/calibrate/G76_M871.cpp> | ||||
|   -<src/gcode/calibrate/G425.cpp> | ||||
|   -<src/gcode/calibrate/M12.cpp> | ||||
|   -<src/gcode/calibrate/M48.cpp> | ||||
| @@ -229,6 +229,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared> | ||||
|   -<src/gcode/sd/M808.cpp> | ||||
|   -<src/gcode/temp/M104_M109.cpp> | ||||
|   -<src/gcode/temp/M155.cpp> | ||||
|   -<src/gcode/temp/M192.cpp> | ||||
|   -<src/gcode/units/G20_G21.cpp> | ||||
|   -<src/gcode/units/M82_M83.cpp> | ||||
|   -<src/gcode/units/M149.cpp> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user