M872 wait for probe temperature (#19344)
This commit is contained in:
		| @@ -37,6 +37,17 @@ | ||||
| #include "../../module/probe.h" | ||||
| #include "../../feature/probe_temp_comp.h" | ||||
| 
 | ||||
| #include "../../lcd/ultralcd.h" | ||||
| #include "../../MarlinCore.h" // for wait_for_heatup and idle()
 | ||||
| 
 | ||||
| #if ENABLED(PRINTJOB_TIMER_AUTOSTART) | ||||
|   #include "../../module/printcounter.h" | ||||
| #endif | ||||
| 
 | ||||
| #if ENABLED(PRINTER_EVENTS_LEDS) | ||||
|   #include "../../feature/leds/leds.h" | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * G76: calibrate probe and/or bed temperature offsets | ||||
|  *  Notes: | ||||
| @@ -303,17 +314,17 @@ void GcodeSuite::M871() { | ||||
|   } | ||||
|   else if (parser.seen("BPE")) { | ||||
|     if (!parser.seenval('V')) return; | ||||
|     const int16_t val = parser.value_int(); | ||||
|     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 ENABLED(USE_TEMP_EXT_COMPENSATION) | ||||
|                                   parser.seen('E') ? TSI_EXT : | ||||
|                                 #endif | ||||
|                                 TSI_PROBE | ||||
|                               ); | ||||
|     if (idx > 0 && temp_comp.set_offset(mod, idx - 1, val)) | ||||
|       SERIAL_ECHOLNPAIR("Set value: ", val); | ||||
|     if (idx > 0 && temp_comp.set_offset(mod, idx - 1, offset_val)) | ||||
|       SERIAL_ECHOLNPAIR("Set value: ", offset_val); | ||||
|     else | ||||
|       SERIAL_ECHOLNPGM("!Invalid index. Failed to set value (note: value at index 0 is constant)."); | ||||
| 
 | ||||
| @@ -322,4 +333,25 @@ void GcodeSuite::M871() { | ||||
|     temp_comp.print_offsets(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * M872: 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::M872() { | ||||
|   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 float target_temp = parser.value_celsius(); | ||||
|   ui.set_status_P(thermalManager.isProbeBelowTemp(target_temp) ? GET_TEXT(MSG_PROBE_HEATING) : GET_TEXT(MSG_PROBE_COOLING)); | ||||
|   thermalManager.wait_for_probe(target_temp, no_wait_for_cooling); | ||||
| } | ||||
| 
 | ||||
| #endif // PROBE_TEMP_COMPENSATION
 | ||||
| @@ -819,6 +819,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { | ||||
|  | ||||
|       #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|         case 871: M871(); break;                                  // M871: Print/reset/clear first layer temperature offset values | ||||
|         case 872: M872(); break;                                  // M872: Wait for probe temp | ||||
|       #endif | ||||
|  | ||||
|       #if ENABLED(LIN_ADVANCE) | ||||
|   | ||||
| @@ -253,6 +253,7 @@ | ||||
|  * 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) | ||||
|  * M872 - Wait for probe temp (Requires PROBE_TEMP_COMPENSATION) | ||||
|  * 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) | ||||
| @@ -820,7 +821,10 @@ private: | ||||
|     FORCE_INLINE static void M869() { I2CPEM.M869(); } | ||||
|   #endif | ||||
|  | ||||
|   TERN_(PROBE_TEMP_COMPENSATION, static void M871()); | ||||
|   #if ENABLED(PROBE_TEMP_COMPENSATION) | ||||
|     static void M871(); | ||||
|     static void M872(); | ||||
|   #endif | ||||
|  | ||||
|   TERN_(LIN_ADVANCE, static void M900()); | ||||
|  | ||||
|   | ||||
| @@ -470,6 +470,8 @@ namespace Language_en { | ||||
|   PROGMEM Language_Str MSG_COOLING                         = _UxGT("Cooling..."); | ||||
|   PROGMEM Language_Str MSG_BED_HEATING                     = _UxGT("Bed Heating..."); | ||||
|   PROGMEM Language_Str MSG_BED_COOLING                     = _UxGT("Bed Cooling..."); | ||||
|   PROGMEM Language_Str MSG_PROBE_HEATING                   = _UxGT("Probe Heating..."); | ||||
|   PROGMEM Language_Str MSG_PROBE_COOLING                   = _UxGT("Probe Cooling..."); | ||||
|   PROGMEM Language_Str MSG_CHAMBER_HEATING                 = _UxGT("Chamber Heating..."); | ||||
|   PROGMEM Language_Str MSG_CHAMBER_COOLING                 = _UxGT("Chamber Cooling..."); | ||||
|   PROGMEM Language_Str MSG_DELTA_CALIBRATE                 = _UxGT("Delta Calibration"); | ||||
|   | ||||
| @@ -413,6 +413,8 @@ namespace Language_fr { | ||||
|   PROGMEM Language_Str MSG_COOLING                         = _UxGT("Refroidissement"); | ||||
|   PROGMEM Language_Str MSG_BED_HEATING                     = _UxGT("Lit en chauffe..."); | ||||
|   PROGMEM Language_Str MSG_BED_COOLING                     = _UxGT("Refroid. du lit..."); | ||||
|   PROGMEM Language_Str MSG_PROBE_HEATING                   = _UxGT("Probe en chauffe..."); | ||||
|   PROGMEM Language_Str MSG_PROBE_COOLING                   = _UxGT("Refroid. Probe..."); | ||||
|   PROGMEM Language_Str MSG_CHAMBER_HEATING                 = _UxGT("Chauffe caisson..."); | ||||
|   PROGMEM Language_Str MSG_CHAMBER_COOLING                 = _UxGT("Refroid. caisson..."); | ||||
|   PROGMEM Language_Str MSG_DELTA_CALIBRATE                 = _UxGT("Calibration Delta"); | ||||
|   | ||||
| @@ -440,7 +440,6 @@ volatile bool Temperature::raw_temps_ready = false; | ||||
|  | ||||
|     SHV(bias = d = (MAX_BED_POWER) >> 1, bias = d = (PID_MAX) >> 1); | ||||
|  | ||||
|     wait_for_heatup = true; // Can be interrupted with M108 | ||||
|     #if ENABLED(PRINTER_EVENT_LEDS) | ||||
|       const float start_temp = GHV(temp_bed.celsius, temp_hotend[heater].celsius); | ||||
|       LEDColor color = ONHEATINGSTART(); | ||||
| @@ -449,6 +448,7 @@ volatile bool Temperature::raw_temps_ready = false; | ||||
|     TERN_(NO_FAN_SLOWING_IN_PID_TUNING, adaptive_fan_slowing = false); | ||||
|  | ||||
|     // PID Tuning loop | ||||
|     wait_for_heatup = true; // Can be interrupted with M108 | ||||
|     while (wait_for_heatup) { | ||||
|  | ||||
|       const millis_t ms = millis(); | ||||
| @@ -632,6 +632,7 @@ volatile bool Temperature::raw_temps_ready = false; | ||||
|       } | ||||
|       TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); | ||||
|     } | ||||
|     wait_for_heatup = false; | ||||
|  | ||||
|     disable_all_heaters(); | ||||
|  | ||||
| @@ -3060,10 +3061,10 @@ void Temperature::tick() { | ||||
|         printerEventLEDs.onHotendHeatingStart(); | ||||
|       #endif | ||||
|  | ||||
|       float target_temp = -1.0, old_temp = 9999.0; | ||||
|       bool wants_to_cool = false; | ||||
|       wait_for_heatup = true; | ||||
|       float target_temp = -1.0, old_temp = 9999.0; | ||||
|       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0; | ||||
|       wait_for_heatup = true; | ||||
|       do { | ||||
|         // Target temperature might be changed during the loop | ||||
|         if (target_temp != degTargetHotend(target_extruder)) { | ||||
| @@ -3137,6 +3138,7 @@ void Temperature::tick() { | ||||
|       } while (wait_for_heatup && TEMP_CONDITIONS); | ||||
|  | ||||
|       if (wait_for_heatup) { | ||||
|         wait_for_heatup = false; | ||||
|         #if ENABLED(DWIN_CREALITY_LCD) | ||||
|           HMI_flag.heat_flag = 0; | ||||
|           duration_t elapsed = print_job_timer.duration();  // print timer | ||||
| @@ -3145,9 +3147,10 @@ void Temperature::tick() { | ||||
|           ui.reset_status(); | ||||
|         #endif | ||||
|         TERN_(PRINTER_EVENT_LEDS, printerEventLEDs.onHeatingDone()); | ||||
|         return true; | ||||
|       } | ||||
|  | ||||
|       return wait_for_heatup; | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|   #endif // HAS_TEMP_HOTEND | ||||
| @@ -3176,11 +3179,6 @@ void Temperature::tick() { | ||||
|         #define TEMP_BED_CONDITIONS (wants_to_cool ? isCoolingBed() : isHeatingBed()) | ||||
|       #endif | ||||
|  | ||||
|       float target_temp = -1, old_temp = 9999; | ||||
|       bool wants_to_cool = false; | ||||
|       wait_for_heatup = true; | ||||
|       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0; | ||||
|  | ||||
|       #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE) | ||||
|         KEEPALIVE_STATE(NOT_BUSY); | ||||
|       #endif | ||||
| @@ -3190,6 +3188,10 @@ void Temperature::tick() { | ||||
|         printerEventLEDs.onBedHeatingStart(); | ||||
|       #endif | ||||
|  | ||||
|       bool wants_to_cool = false; | ||||
|       float target_temp = -1, old_temp = 9999; | ||||
|       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0; | ||||
|       wait_for_heatup = true; | ||||
|       do { | ||||
|         // Target temperature might be changed during the loop | ||||
|         if (target_temp != degTargetBed()) { | ||||
| @@ -3264,9 +3266,13 @@ void Temperature::tick() { | ||||
|  | ||||
|       } while (wait_for_heatup && TEMP_BED_CONDITIONS); | ||||
|  | ||||
|       if (wait_for_heatup) ui.reset_status(); | ||||
|       if (wait_for_heatup) { | ||||
|         wait_for_heatup = false; | ||||
|         ui.reset_status(); | ||||
|         return true; | ||||
|       } | ||||
|  | ||||
|       return wait_for_heatup; | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     void Temperature::wait_for_bed_heating() { | ||||
| @@ -3280,6 +3286,77 @@ void Temperature::tick() { | ||||
|  | ||||
|   #endif // HAS_HEATED_BED | ||||
|  | ||||
|   #if HAS_TEMP_PROBE | ||||
|  | ||||
|     #ifndef MIN_DELTA_SLOPE_DEG_PROBE | ||||
|       #define MIN_DELTA_SLOPE_DEG_PROBE 1.0 | ||||
|     #endif | ||||
|     #ifndef MIN_DELTA_SLOPE_TIME_PROBE | ||||
|       #define MIN_DELTA_SLOPE_TIME_PROBE 600 | ||||
|     #endif | ||||
|  | ||||
|     bool Temperature::wait_for_probe(const float target_temp, bool no_wait_for_cooling/*=true*/) { | ||||
|  | ||||
|       const bool wants_to_cool = isProbeAboveTemp(target_temp); | ||||
|       const bool will_wait = !(wants_to_cool && no_wait_for_cooling); | ||||
|       if (will_wait) | ||||
|         SERIAL_ECHOLNPAIR("Waiting for probe to ", (wants_to_cool ? PSTR("cool down") : PSTR("heat up")), " to ", target_temp, " degrees."); | ||||
|  | ||||
|       #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE) | ||||
|         KEEPALIVE_STATE(NOT_BUSY); | ||||
|       #endif | ||||
|  | ||||
|       float old_temp = 9999; | ||||
|       millis_t next_temp_ms = 0, next_delta_check_ms = 0; | ||||
|       wait_for_heatup = true; | ||||
|       while (will_wait && wait_for_heatup) { | ||||
|  | ||||
|         // Print Temp Reading every 10 seconds while heating up. | ||||
|         millis_t now = millis(); | ||||
|         if (!next_temp_ms || ELAPSED(now, next_temp_ms)) { | ||||
|           next_temp_ms = now + 10000UL; | ||||
|           print_heater_states(active_extruder); | ||||
|           SERIAL_EOL(); | ||||
|         } | ||||
|  | ||||
|         idle(); | ||||
|         gcode.reset_stepper_timeout(); // Keep steppers powered | ||||
|  | ||||
|         // Break after MIN_DELTA_SLOPE_TIME_PROBE seconds if the temperature | ||||
|         // did not drop at least MIN_DELTA_SLOPE_DEG_PROBE. This avoids waiting | ||||
|         // forever as the probe is not actively heated. | ||||
|         if (!next_delta_check_ms || ELAPSED(now, next_delta_check_ms)) { | ||||
|           const float temp = degProbe(), | ||||
|                       delta_temp = old_temp > temp ? old_temp - temp : temp - old_temp; | ||||
|           if (delta_temp < float(MIN_DELTA_SLOPE_DEG_PROBE)) { | ||||
|             SERIAL_ECHOLNPGM("Timed out waiting for probe temperature."); | ||||
|             break; | ||||
|           } | ||||
|           next_delta_check_ms = now + 1000UL * MIN_DELTA_SLOPE_TIME_PROBE; | ||||
|           old_temp = temp; | ||||
|         } | ||||
|  | ||||
|         // Loop until the temperature is very close target | ||||
|         if (!(wants_to_cool ? isProbeAboveTemp(target_temp) : isProbeBelowTemp(target_temp))) { | ||||
|             SERIAL_ECHOLN(wants_to_cool ? PSTR("Cooldown") : PSTR("Heatup")); | ||||
|             SERIAL_ECHOLNPGM(" complete, target probe temperature reached."); | ||||
|             break; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (wait_for_heatup) { | ||||
|         wait_for_heatup = false; | ||||
|         ui.reset_status(); | ||||
|         return true; | ||||
|       } | ||||
|       else if (will_wait) | ||||
|         SERIAL_ECHOLNPGM("Canceled wait for probe temperature."); | ||||
|  | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|   #endif // HAS_TEMP_PROBE | ||||
|  | ||||
|   #if HAS_HEATED_CHAMBER | ||||
|  | ||||
|     #ifndef MIN_COOLING_SLOPE_DEG_CHAMBER | ||||
| @@ -3300,15 +3377,14 @@ void Temperature::tick() { | ||||
|         #define TEMP_CHAMBER_CONDITIONS (wants_to_cool ? isCoolingChamber() : isHeatingChamber()) | ||||
|       #endif | ||||
|  | ||||
|       float target_temp = -1, old_temp = 9999; | ||||
|       bool wants_to_cool = false; | ||||
|       wait_for_heatup = true; | ||||
|       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0; | ||||
|  | ||||
|       #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE) | ||||
|         KEEPALIVE_STATE(NOT_BUSY); | ||||
|       #endif | ||||
|  | ||||
|       bool wants_to_cool = false; | ||||
|       float target_temp = -1, old_temp = 9999; | ||||
|       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0; | ||||
|       wait_for_heatup = true; | ||||
|       do { | ||||
|         // Target temperature might be changed during the loop | ||||
|         if (target_temp != degTargetChamber()) { | ||||
| @@ -3367,9 +3443,13 @@ void Temperature::tick() { | ||||
|         } | ||||
|       } while (wait_for_heatup && TEMP_CHAMBER_CONDITIONS); | ||||
|  | ||||
|       if (wait_for_heatup) ui.reset_status(); | ||||
|       if (wait_for_heatup) { | ||||
|         wait_for_heatup = false; | ||||
|         ui.reset_status(); | ||||
|         return true; | ||||
|       } | ||||
|  | ||||
|       return wait_for_heatup; | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|   #endif // HAS_HEATED_CHAMBER | ||||
|   | ||||
| @@ -654,6 +654,9 @@ class Temperature { | ||||
|         FORCE_INLINE static int16_t rawProbeTemp()    { return temp_probe.raw; } | ||||
|       #endif | ||||
|       FORCE_INLINE static float degProbe()            { return temp_probe.celsius; } | ||||
|       FORCE_INLINE static bool isProbeBelowTemp(const float target_temp) { return temp_probe.celsius < target_temp; } | ||||
|       FORCE_INLINE static bool isProbeAboveTemp(const float target_temp) { return temp_probe.celsius > target_temp; } | ||||
|       static bool wait_for_probe(const float target_temp, bool no_wait_for_cooling=true); | ||||
|     #endif | ||||
|  | ||||
|     #if WATCH_PROBE | ||||
|   | ||||
		Reference in New Issue
	
	Block a user