Handle failures during calibration

Break out of the autotuning if a thermal error condition is detected and
attempt to restore a safe initial state irregardless of the error
handlers.

Also error out if the estimation fails to converge.
This commit is contained in:
Yuri D'Elia 2022-06-27 10:35:49 +02:00
parent cc96a47e7f
commit 47d2e9e61c

View file

@ -2632,23 +2632,33 @@ void waiting_handler()
void wait(unsigned ms) void wait(unsigned ms)
{ {
unsigned long mark = _millis() + ms; unsigned long mark = _millis() + ms;
while(_millis() < mark) while(_millis() < mark) {
if(temp_error_state.v) break;
waiting_handler(); waiting_handler();
}
} }
void wait_temp() void wait_temp()
{ {
while(current_temperature[0] < (target_temperature[0] - TEMP_HYSTERESIS)) while(current_temperature[0] < (target_temperature[0] - TEMP_HYSTERESIS)) {
if(temp_error_state.v) break;
waiting_handler(); waiting_handler();
}
} }
void cooldown(float temp) void cooldown(float temp)
{ {
float old_speed = fanSpeedSoftPwm; float old_speed = fanSpeedSoftPwm;
fanSpeedSoftPwm = 255; fanSpeedSoftPwm = 255;
while((current_temperature[0] >= temp) && while(current_temperature[0] >= temp) {
(current_temperature[0] >= (current_temperature_ambient + temp_model::data.Ta_corr + TEMP_HYSTERESIS))) if(temp_error_state.v) break;
float ambient = current_temperature_ambient + temp_model::data.Ta_corr;
if(current_temperature[0] < (ambient + TEMP_HYSTERESIS)) {
// do not get stuck waiting very close to ambient temperature
break;
}
waiting_handler(); waiting_handler();
}
fanSpeedSoftPwm = old_speed; fanSpeedSoftPwm = old_speed;
} }
@ -2670,6 +2680,10 @@ uint16_t record(uint16_t samples = REC_BUFFER_SIZE) {
adc_start_cycle(); adc_start_cycle();
temp_mgr_isr(); temp_mgr_isr();
// stop recording for an hard error condition
if(temp_error_state.v)
return 0;
// record a new entry // record a new entry
rec_entry& entry = rec_buffer[pos]; rec_entry& entry = rec_buffer[pos];
entry.temp = current_temperature_isr[0]; entry.temp = current_temperature_isr[0];
@ -2723,17 +2737,13 @@ float estimate(uint16_t samples, float* const var, float min, float max, float t
} }
SERIAL_ECHOLNPGM("TM estimation did not converge"); SERIAL_ECHOLNPGM("TM estimation did not converge");
return e; return NAN;
} }
void autotune(int16_t cal_temp) bool autotune(int16_t cal_temp)
{ {
SERIAL_ECHOLNPGM("TM: autotune start");
uint16_t samples; uint16_t samples;
float e;
// disable the model checking during self-calibration
bool was_enabled = temp_model::enabled;
temp_model_set_enabled(false);
// bootstrap C/R values without fan // bootstrap C/R values without fan
fanSpeedSoftPwm = 0; fanSpeedSoftPwm = 0;
@ -2755,9 +2765,14 @@ void autotune(int16_t cal_temp)
printf_P(PSTR("TM: %S C estimation\n"), verb); printf_P(PSTR("TM: %S C estimation\n"), verb);
target_temperature[0] = cal_temp; target_temperature[0] = cal_temp;
samples = record(); samples = record();
estimate(samples, &temp_model::data.C, if(temp_error_state.v || !samples)
return true;
e = estimate(samples, &temp_model::data.C,
TEMP_MODEL_Cl, TEMP_MODEL_Ch, TEMP_MODEL_C_thr, TEMP_MODEL_C_itr, TEMP_MODEL_Cl, TEMP_MODEL_Ch, TEMP_MODEL_C_thr, TEMP_MODEL_C_itr,
current_temperature_ambient); current_temperature_ambient);
if(isnan(e))
return true;
wait_temp(); wait_temp();
if(i) break; // we don't need to refine R if(i) break; // we don't need to refine R
@ -2765,9 +2780,14 @@ void autotune(int16_t cal_temp)
printf_P(PSTR("TM: %S R estimation @ %dC\n"), verb, cal_temp); printf_P(PSTR("TM: %S R estimation @ %dC\n"), verb, cal_temp);
samples = record(); samples = record();
estimate(samples, &temp_model::data.R[0], if(temp_error_state.v || !samples)
return true;
e = estimate(samples, &temp_model::data.R[0],
TEMP_MODEL_Rl, TEMP_MODEL_Rh, TEMP_MODEL_R_thr, TEMP_MODEL_R_itr, TEMP_MODEL_Rl, TEMP_MODEL_Rh, TEMP_MODEL_R_thr, TEMP_MODEL_R_itr,
current_temperature_ambient); current_temperature_ambient);
if(isnan(e))
return true;
} }
// Estimate fan losses at regular intervals, starting from full speed to avoid low-speed // Estimate fan losses at regular intervals, starting from full speed to avoid low-speed
@ -2783,9 +2803,14 @@ void autotune(int16_t cal_temp)
printf_P(PSTR("TM: R[%u] estimation\n"), (unsigned)soft_pwm_fan); printf_P(PSTR("TM: R[%u] estimation\n"), (unsigned)soft_pwm_fan);
samples = record(); samples = record();
estimate(samples, &temp_model::data.R[soft_pwm_fan], if(temp_error_state.v || !samples)
return true;
e = estimate(samples, &temp_model::data.R[soft_pwm_fan],
TEMP_MODEL_Rl, temp_model::data.R[0], TEMP_MODEL_R_thr, TEMP_MODEL_R_itr, TEMP_MODEL_Rl, temp_model::data.R[0], TEMP_MODEL_R_thr, TEMP_MODEL_R_itr,
current_temperature_ambient); current_temperature_ambient);
if(isnan(e))
return true;
} }
// interpolate remaining steps to speed-up calibration // interpolate remaining steps to speed-up calibration
@ -2802,10 +2827,7 @@ void autotune(int16_t cal_temp)
temp_model::data.R[i] = temp_model::data.R[prev] + d * f; temp_model::data.R[i] = temp_model::data.R[prev] + d * f;
} }
// restore the initial state return false;
fanSpeedSoftPwm = 0;
target_temperature[0] = 0;
temp_model_set_enabled(was_enabled);
} }
} // namespace temp_model_cal } // namespace temp_model_cal
@ -2814,8 +2836,26 @@ void temp_model_autotune(int16_t temp)
{ {
// TODO: ensure printer is idle/queue empty/buffer empty // TODO: ensure printer is idle/queue empty/buffer empty
KEEPALIVE_STATE(IN_PROCESS); KEEPALIVE_STATE(IN_PROCESS);
temp_model_cal::autotune(temp > 0 ? temp : TEMP_MODEL_CAL_Th);
temp_model_report_settings(); // disable the model checking during self-calibration
bool was_enabled = temp_model::enabled;
temp_model_set_enabled(false);
SERIAL_ECHOLNPGM("TM: autotune start");
bool err = temp_model_cal::autotune(temp > 0 ? temp : TEMP_MODEL_CAL_Th);
// always reset temperature
target_temperature[0] = 0;
if(err) {
SERIAL_ECHOLNPGM("TM: autotune failed");
if(temp_error_state.v)
fanSpeedSoftPwm = 255;
} else {
fanSpeedSoftPwm = 0;
temp_model_set_enabled(was_enabled);
temp_model_report_settings();
}
} }
#ifdef TEMP_MODEL_DEBUG #ifdef TEMP_MODEL_DEBUG