diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 0714072e93..7b232e56bd 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -5559,20 +5559,25 @@ inline void gcode_M226() { * U with a non-zero value will apply the result to current settings */ inline void gcode_M303() { - int e = code_seen('E') ? code_value_short() : 0; - int c = code_seen('C') ? code_value_short() : 5; - bool u = code_seen('U') && code_value_short() != 0; + #if ENABLED(PIDTEMP) + int e = code_seen('E') ? code_value_short() : 0; + int c = code_seen('C') ? code_value_short() : 5; + bool u = code_seen('U') && code_value_short() != 0; - float temp = code_seen('S') ? code_value() : (e < 0 ? 70.0 : 150.0); + float temp = code_seen('S') ? code_value() : (e < 0 ? 70.0 : 150.0); - if (e >= 0 && e < EXTRUDERS) - target_extruder = e; + if (e >= 0 && e < EXTRUDERS) + target_extruder = e; - KEEPALIVE_STATE(NOT_BUSY); // don't send "busy: processing" messages during autotune output + KEEPALIVE_STATE(NOT_BUSY); // don't send "busy: processing" messages during autotune output - PID_autotune(temp, e, c, u); + PID_autotune(temp, e, c, u); - KEEPALIVE_STATE(IN_HANDLER); + KEEPALIVE_STATE(IN_HANDLER); + #else + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM(MSG_ERR_M303_DISABLED); + #endif } #if ENABLED(SCARA) diff --git a/Marlin/language.h b/Marlin/language.h index 9085a6a85f..0bbae448b3 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -159,6 +159,7 @@ #define MSG_ERR_M421_REQUIRES_XYZ "M421 requires XYZ parameters" #define MSG_ERR_MESH_INDEX_OOB "Mesh XY index is out of bounds" #define MSG_ERR_M428_TOO_FAR "Too far from reference point" +#define MSG_ERR_M303_DISABLED "PIDTEMP disabled" #define MSG_M119_REPORT "Reporting endstop status" #define MSG_ENDSTOP_HIT "TRIGGERED" #define MSG_ENDSTOP_OPEN "open" diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 3fad457cb9..bfbadc6cbe 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -221,176 +221,180 @@ static void updateTemperaturesFromRawValues(); //================================ Functions ================================ //=========================================================================== -void PID_autotune(float temp, int extruder, int ncycles, bool set_result/*=false*/) { - float input = 0.0; - int cycles = 0; - bool heating = true; +#if ENABLED(PIDTEMP) - millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms; - long t_high = 0, t_low = 0; + void PID_autotune(float temp, int extruder, int ncycles, bool set_result/*=false*/) { + float input = 0.0; + int cycles = 0; + bool heating = true; - long bias, d; - float Ku, Tu; - float workKp = 0, workKi = 0, workKd = 0; - float max = 0, min = 10000; + millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms; + long t_high = 0, t_low = 0; - #if HAS_AUTO_FAN - millis_t next_auto_fan_check_ms = temp_ms + 2500UL; - #endif + long bias, d; + float Ku, Tu; + float workKp = 0, workKi = 0, workKd = 0; + float max = 0, min = 10000; - if (extruder >= EXTRUDERS - #if !HAS_TEMP_BED - || extruder < 0 + #if HAS_AUTO_FAN + millis_t next_auto_fan_check_ms = temp_ms + 2500UL; #endif - ) { - SERIAL_ECHOLN(MSG_PID_BAD_EXTRUDER_NUM); - return; - } - SERIAL_ECHOLN(MSG_PID_AUTOTUNE_START); - - disable_all_heaters(); // switch off all heaters. - - if (extruder < 0) - soft_pwm_bed = bias = d = (MAX_BED_POWER) / 2; - else - soft_pwm[extruder] = bias = d = (PID_MAX) / 2; - - // PID Tuning loop - for (;;) { - - millis_t ms = millis(); - - if (temp_meas_ready) { // temp sample ready - updateTemperaturesFromRawValues(); - - input = (extruder < 0) ? current_temperature_bed : current_temperature[extruder]; - - max = max(max, input); - min = min(min, input); - - #if HAS_AUTO_FAN - if (ELAPSED(ms, next_auto_fan_check_ms)) { - checkExtruderAutoFans(); - next_auto_fan_check_ms = ms + 2500UL; - } + if (extruder >= EXTRUDERS + #if !HAS_TEMP_BED + || extruder < 0 #endif + ) { + SERIAL_ECHOLN(MSG_PID_BAD_EXTRUDER_NUM); + return; + } - if (heating && input > temp) { - if (ELAPSED(ms, t2 + 5000UL)) { - heating = false; - if (extruder < 0) - soft_pwm_bed = (bias - d) >> 1; - else - soft_pwm[extruder] = (bias - d) >> 1; - t1 = ms; - t_high = t1 - t2; - max = temp; - } - } + SERIAL_ECHOLN(MSG_PID_AUTOTUNE_START); - if (!heating && input < temp) { - if (ELAPSED(ms, t1 + 5000UL)) { - heating = true; - t2 = ms; - t_low = t2 - t1; - if (cycles > 0) { - long max_pow = extruder < 0 ? MAX_BED_POWER : PID_MAX; - bias += (d * (t_high - t_low)) / (t_low + t_high); - bias = constrain(bias, 20, max_pow - 20); - d = (bias > max_pow / 2) ? max_pow - 1 - bias : bias; + disable_all_heaters(); // switch off all heaters. - SERIAL_PROTOCOLPGM(MSG_BIAS); SERIAL_PROTOCOL(bias); - SERIAL_PROTOCOLPGM(MSG_D); SERIAL_PROTOCOL(d); - SERIAL_PROTOCOLPGM(MSG_T_MIN); SERIAL_PROTOCOL(min); - SERIAL_PROTOCOLPGM(MSG_T_MAX); SERIAL_PROTOCOLLN(max); - if (cycles > 2) { - Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0); - Tu = ((float)(t_low + t_high) / 1000.0); - SERIAL_PROTOCOLPGM(MSG_KU); SERIAL_PROTOCOL(Ku); - SERIAL_PROTOCOLPGM(MSG_TU); SERIAL_PROTOCOLLN(Tu); - workKp = 0.6 * Ku; - workKi = 2 * workKp / Tu; - workKd = workKp * Tu / 8; - SERIAL_PROTOCOLLNPGM(MSG_CLASSIC_PID); - SERIAL_PROTOCOLPGM(MSG_KP); SERIAL_PROTOCOLLN(workKp); - SERIAL_PROTOCOLPGM(MSG_KI); SERIAL_PROTOCOLLN(workKi); - SERIAL_PROTOCOLPGM(MSG_KD); SERIAL_PROTOCOLLN(workKd); - /** - workKp = 0.33*Ku; - workKi = workKp/Tu; - workKd = workKp*Tu/3; - SERIAL_PROTOCOLLNPGM(" Some overshoot "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(workKp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(workKi); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(workKd); - workKp = 0.2*Ku; - workKi = 2*workKp/Tu; - workKd = workKp*Tu/3; - SERIAL_PROTOCOLLNPGM(" No overshoot "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(workKp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(workKi); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(workKd); - */ - } + if (extruder < 0) + soft_pwm_bed = bias = d = (MAX_BED_POWER) / 2; + else + soft_pwm[extruder] = bias = d = (PID_MAX) / 2; + + // PID Tuning loop + for (;;) { + + millis_t ms = millis(); + + if (temp_meas_ready) { // temp sample ready + updateTemperaturesFromRawValues(); + + input = (extruder < 0) ? current_temperature_bed : current_temperature[extruder]; + + max = max(max, input); + min = min(min, input); + + #if HAS_AUTO_FAN + if (ELAPSED(ms, next_auto_fan_check_ms)) { + checkExtruderAutoFans(); + next_auto_fan_check_ms = ms + 2500UL; + } + #endif + + if (heating && input > temp) { + if (ELAPSED(ms, t2 + 5000UL)) { + heating = false; + if (extruder < 0) + soft_pwm_bed = (bias - d) >> 1; + else + soft_pwm[extruder] = (bias - d) >> 1; + t1 = ms; + t_high = t1 - t2; + max = temp; + } + } + + if (!heating && input < temp) { + if (ELAPSED(ms, t1 + 5000UL)) { + heating = true; + t2 = ms; + t_low = t2 - t1; + if (cycles > 0) { + long max_pow = extruder < 0 ? MAX_BED_POWER : PID_MAX; + bias += (d * (t_high - t_low)) / (t_low + t_high); + bias = constrain(bias, 20, max_pow - 20); + d = (bias > max_pow / 2) ? max_pow - 1 - bias : bias; + + SERIAL_PROTOCOLPGM(MSG_BIAS); SERIAL_PROTOCOL(bias); + SERIAL_PROTOCOLPGM(MSG_D); SERIAL_PROTOCOL(d); + SERIAL_PROTOCOLPGM(MSG_T_MIN); SERIAL_PROTOCOL(min); + SERIAL_PROTOCOLPGM(MSG_T_MAX); SERIAL_PROTOCOLLN(max); + if (cycles > 2) { + Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0); + Tu = ((float)(t_low + t_high) / 1000.0); + SERIAL_PROTOCOLPGM(MSG_KU); SERIAL_PROTOCOL(Ku); + SERIAL_PROTOCOLPGM(MSG_TU); SERIAL_PROTOCOLLN(Tu); + workKp = 0.6 * Ku; + workKi = 2 * workKp / Tu; + workKd = workKp * Tu / 8; + SERIAL_PROTOCOLLNPGM(MSG_CLASSIC_PID); + SERIAL_PROTOCOLPGM(MSG_KP); SERIAL_PROTOCOLLN(workKp); + SERIAL_PROTOCOLPGM(MSG_KI); SERIAL_PROTOCOLLN(workKi); + SERIAL_PROTOCOLPGM(MSG_KD); SERIAL_PROTOCOLLN(workKd); + /** + workKp = 0.33*Ku; + workKi = workKp/Tu; + workKd = workKp*Tu/3; + SERIAL_PROTOCOLLNPGM(" Some overshoot "); + SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(workKp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(workKi); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(workKd); + workKp = 0.2*Ku; + workKi = 2*workKp/Tu; + workKd = workKp*Tu/3; + SERIAL_PROTOCOLLNPGM(" No overshoot "); + SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(workKp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(workKi); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(workKd); + */ + } + } + if (extruder < 0) + soft_pwm_bed = (bias + d) >> 1; + else + soft_pwm[extruder] = (bias + d) >> 1; + cycles++; + min = temp; } - if (extruder < 0) - soft_pwm_bed = (bias + d) >> 1; - else - soft_pwm[extruder] = (bias + d) >> 1; - cycles++; - min = temp; } } - } - #define MAX_OVERSHOOT_PID_AUTOTUNE 20 - if (input > temp + MAX_OVERSHOOT_PID_AUTOTUNE) { - SERIAL_PROTOCOLLNPGM(MSG_PID_TEMP_TOO_HIGH); - return; - } - // Every 2 seconds... - if (ELAPSED(ms, temp_ms + 2000UL)) { - #if HAS_TEMP_HOTEND || HAS_TEMP_BED - print_heaterstates(); - SERIAL_EOL; - #endif + #define MAX_OVERSHOOT_PID_AUTOTUNE 20 + if (input > temp + MAX_OVERSHOOT_PID_AUTOTUNE) { + SERIAL_PROTOCOLLNPGM(MSG_PID_TEMP_TOO_HIGH); + return; + } + // Every 2 seconds... + if (ELAPSED(ms, temp_ms + 2000UL)) { + #if HAS_TEMP_HOTEND || HAS_TEMP_BED + print_heaterstates(); + SERIAL_EOL; + #endif - temp_ms = ms; - } // every 2 seconds - // Over 2 minutes? - if (((ms - t1) + (ms - t2)) > (10L * 60L * 1000L * 2L)) { - SERIAL_PROTOCOLLNPGM(MSG_PID_TIMEOUT); - return; - } - if (cycles > ncycles) { - SERIAL_PROTOCOLLNPGM(MSG_PID_AUTOTUNE_FINISHED); - const char* estring = extruder < 0 ? "bed" : ""; - SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kp "); SERIAL_PROTOCOLLN(workKp); - SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Ki "); SERIAL_PROTOCOLLN(workKi); - SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kd "); SERIAL_PROTOCOLLN(workKd); + temp_ms = ms; + } // every 2 seconds + // Over 2 minutes? + if (((ms - t1) + (ms - t2)) > (10L * 60L * 1000L * 2L)) { + SERIAL_PROTOCOLLNPGM(MSG_PID_TIMEOUT); + return; + } + if (cycles > ncycles) { + SERIAL_PROTOCOLLNPGM(MSG_PID_AUTOTUNE_FINISHED); + const char* estring = extruder < 0 ? "bed" : ""; + SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kp "); SERIAL_PROTOCOLLN(workKp); + SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Ki "); SERIAL_PROTOCOLLN(workKi); + SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kd "); SERIAL_PROTOCOLLN(workKd); - // Use the result? (As with "M303 U1") - if (set_result) { - if (extruder < 0) { - #if ENABLED(PIDTEMPBED) - bedKp = workKp; - bedKi = scalePID_i(workKi); - bedKd = scalePID_d(workKd); + // Use the result? (As with "M303 U1") + if (set_result) { + if (extruder < 0) { + #if ENABLED(PIDTEMPBED) + bedKp = workKp; + bedKi = scalePID_i(workKi); + bedKd = scalePID_d(workKd); + updatePID(); + #endif + } + else { + PID_PARAM(Kp, extruder) = workKp; + PID_PARAM(Ki, extruder) = scalePID_i(workKi); + PID_PARAM(Kd, extruder) = scalePID_d(workKd); updatePID(); - #endif - } - else { - PID_PARAM(Kp, extruder) = workKp; - PID_PARAM(Ki, extruder) = scalePID_i(workKi); - PID_PARAM(Kd, extruder) = scalePID_d(workKd); - updatePID(); + } } + return; } - return; + lcd_update(); } - lcd_update(); } -} + +#endif // PIDTEMP void updatePID() { #if ENABLED(PIDTEMP) diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 9747d07acb..c49f2c46a5 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -169,7 +169,9 @@ int getHeaterPower(int heater); void disable_all_heaters(); void updatePID(); -void PID_autotune(float temp, int extruder, int ncycles, bool set_result=false); +#if ENABLED(PIDTEMP) + void PID_autotune(float temp, int extruder, int ncycles, bool set_result=false); +#endif void setExtruderAutoFanState(int pin, bool state); void checkExtruderAutoFans();