|
@ -638,6 +638,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(isbed ? PID_BED_START : PID_EXTR_START)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(isbed ? PID_BED_START : PID_EXTR_START)); |
|
|
|
|
|
|
|
|
if (target > GHV(CHAMBER_MAX_TARGET, BED_MAX_TARGET, temp_range[heater_id].maxtemp - (HOTEND_OVERSHOOT))) { |
|
|
if (target > GHV(CHAMBER_MAX_TARGET, BED_MAX_TARGET, temp_range[heater_id].maxtemp - (HOTEND_OVERSHOOT))) { |
|
|
|
|
|
SERIAL_ECHOPGM(STR_PID_AUTOTUNE); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); |
|
@ -645,6 +646,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SERIAL_ECHOPGM(STR_PID_AUTOTUNE); |
|
|
SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_START); |
|
|
SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_START); |
|
|
|
|
|
|
|
|
disable_all_heaters(); |
|
|
disable_all_heaters(); |
|
@ -660,10 +662,11 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
|
|
|
|
|
|
TERN_(NO_FAN_SLOWING_IN_PID_TUNING, adaptive_fan_slowing = false); |
|
|
TERN_(NO_FAN_SLOWING_IN_PID_TUNING, adaptive_fan_slowing = false); |
|
|
|
|
|
|
|
|
// PID Tuning loop
|
|
|
|
|
|
wait_for_heatup = true; // Can be interrupted with M108
|
|
|
|
|
|
LCD_MESSAGE(MSG_HEATING); |
|
|
LCD_MESSAGE(MSG_HEATING); |
|
|
while (wait_for_heatup) { |
|
|
|
|
|
|
|
|
// PID Tuning loop
|
|
|
|
|
|
wait_for_heatup = true; |
|
|
|
|
|
while (wait_for_heatup) { // Can be interrupted with M108
|
|
|
|
|
|
|
|
|
const millis_t ms = millis(); |
|
|
const millis_t ms = millis(); |
|
|
|
|
|
|
|
@ -729,6 +732,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
#define MAX_OVERSHOOT_PID_AUTOTUNE 30 |
|
|
#define MAX_OVERSHOOT_PID_AUTOTUNE 30 |
|
|
#endif |
|
|
#endif |
|
|
if (current_temp > target + MAX_OVERSHOOT_PID_AUTOTUNE) { |
|
|
if (current_temp > target + MAX_OVERSHOOT_PID_AUTOTUNE) { |
|
|
|
|
|
SERIAL_ECHOPGM(STR_PID_AUTOTUNE); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); |
|
@ -771,11 +775,13 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TUNING_TIMEOUT)); |
|
|
TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TUNING_TIMEOUT)); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TUNING_TIMEOUT)); |
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TUNING_TIMEOUT)); |
|
|
TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TIMEOUT))); |
|
|
TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TIMEOUT))); |
|
|
|
|
|
SERIAL_ECHOPGM(STR_PID_AUTOTUNE); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TIMEOUT); |
|
|
SERIAL_ECHOLNPGM(STR_PID_TIMEOUT); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (cycles > ncycles && cycles > 2) { |
|
|
if (cycles > ncycles && cycles > 2) { |
|
|
|
|
|
SERIAL_ECHOPGM(STR_PID_AUTOTUNE); |
|
|
SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_FINISHED); |
|
|
SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_FINISHED); |
|
|
TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE))); |
|
|
TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE))); |
|
|
|
|
|
|
|
@ -875,7 +881,6 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
MPC_t& constants = hotend.constants; |
|
|
MPC_t& constants = hotend.constants; |
|
|
|
|
|
|
|
|
// move to center of bed, just above bed height and cool with max fan
|
|
|
// move to center of bed, just above bed height and cool with max fan
|
|
|
SERIAL_ECHOLNPGM("Moving to tuning position"); |
|
|
|
|
|
TERN_(HAS_FAN, zero_fan_speeds()); |
|
|
TERN_(HAS_FAN, zero_fan_speeds()); |
|
|
disable_all_heaters(); |
|
|
disable_all_heaters(); |
|
|
TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255)); |
|
|
TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255)); |
|
@ -902,6 +907,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
next_test_ms += 10000UL; |
|
|
next_test_ms += 10000UL; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 0)); |
|
|
TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 0)); |
|
|
TERN_(HAS_FAN, planner.sync_fan_speeds(fan_speed)); |
|
|
TERN_(HAS_FAN, planner.sync_fan_speeds(fan_speed)); |
|
|
|
|
|
|
|
@ -909,8 +915,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
|
|
|
|
|
|
SERIAL_ECHOLNPGM("Heating to 200C"); |
|
|
SERIAL_ECHOLNPGM("Heating to 200C"); |
|
|
hotend.soft_pwm_amount = MPC_MAX >> 1; |
|
|
hotend.soft_pwm_amount = MPC_MAX >> 1; |
|
|
const millis_t heat_start_time = ms; |
|
|
const millis_t heat_start_time = next_test_ms = ms; |
|
|
next_test_ms = ms; |
|
|
|
|
|
celsius_float_t temp_samples[16]; |
|
|
celsius_float_t temp_samples[16]; |
|
|
uint8_t sample_count = 0; |
|
|
uint8_t sample_count = 0; |
|
|
uint16_t sample_distance = 1; |
|
|
uint16_t sample_distance = 1; |
|
@ -941,7 +946,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
} |
|
|
} |
|
|
hotend.soft_pwm_amount = 0; |
|
|
hotend.soft_pwm_amount = 0; |
|
|
|
|
|
|
|
|
// calculate physical constants from three equally spaced samples
|
|
|
// Calculate physical constants from three equally-spaced samples
|
|
|
sample_count = (sample_count + 1) / 2 * 2 - 1; |
|
|
sample_count = (sample_count + 1) / 2 * 2 - 1; |
|
|
const float t1 = temp_samples[0], |
|
|
const float t1 = temp_samples[0], |
|
|
t2 = temp_samples[(sample_count - 1) >> 1], |
|
|
t2 = temp_samples[(sample_count - 1) >> 1], |
|
@ -957,14 +962,13 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); |
|
|
hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); |
|
|
hotend.modeled_sensor_temp = current_temp; |
|
|
hotend.modeled_sensor_temp = current_temp; |
|
|
|
|
|
|
|
|
// let the system stabilise under MPC control then get a better measure of ambient loss without and with fan
|
|
|
// Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan
|
|
|
SERIAL_ECHOLNPGM("Measuring ambient heatloss at target ", hotend.modeled_block_temp); |
|
|
SERIAL_ECHOLNPGM("Measuring ambient heatloss at target ", hotend.modeled_block_temp); |
|
|
hotend.target = hotend.modeled_block_temp; |
|
|
hotend.target = hotend.modeled_block_temp; |
|
|
next_test_ms = ms + MPC_dT * 1000; |
|
|
next_test_ms = ms + MPC_dT * 1000; |
|
|
constexpr millis_t settle_time = 20000UL, |
|
|
constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; |
|
|
test_length = 20000UL; |
|
|
|
|
|
millis_t settle_end_ms = ms + settle_time, |
|
|
millis_t settle_end_ms = ms + settle_time, |
|
|
test_end_ms = settle_end_ms + test_length; |
|
|
test_end_ms = settle_end_ms + test_duration; |
|
|
float total_energy_fan0 = 0.0f; |
|
|
float total_energy_fan0 = 0.0f; |
|
|
#if HAS_FAN |
|
|
#if HAS_FAN |
|
|
bool fan0_done = false; |
|
|
bool fan0_done = false; |
|
@ -987,7 +991,7 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255); |
|
|
set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255); |
|
|
planner.sync_fan_speeds(fan_speed); |
|
|
planner.sync_fan_speeds(fan_speed); |
|
|
settle_end_ms = ms + settle_time; |
|
|
settle_end_ms = ms + settle_time; |
|
|
test_end_ms = settle_end_ms + test_length; |
|
|
test_end_ms = settle_end_ms + test_duration; |
|
|
fan0_done = true; |
|
|
fan0_done = true; |
|
|
} |
|
|
} |
|
|
else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) |
|
|
else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) |
|
@ -1005,11 +1009,11 @@ volatile bool Temperature::raw_temps_ready = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const float power_fan0 = total_energy_fan0 * 1000 / test_length; |
|
|
const float power_fan0 = total_energy_fan0 * 1000 / test_duration; |
|
|
constants.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); |
|
|
constants.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); |
|
|
|
|
|
|
|
|
#if HAS_FAN |
|
|
#if HAS_FAN |
|
|
const float power_fan255 = total_energy_fan255 * 1000 / test_length, |
|
|
const float power_fan255 = total_energy_fan255 * 1000 / test_duration, |
|
|
ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); |
|
|
ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); |
|
|
constants.fan255_adjustment = ambient_xfer_coeff_fan255 - constants.ambient_xfer_coeff_fan0; |
|
|
constants.fan255_adjustment = ambient_xfer_coeff_fan255 - constants.ambient_xfer_coeff_fan0; |
|
|
#endif |
|
|
#endif |
|
|