void PID_autotune(float temp, int extruder, int ncycles) { float input = 0.0; int cycles = 0; bool heating = true; millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms; long t_high = 0, t_low = 0; long bias, d; float Ku, Tu; float Kp, Ki, Kd; float max = 0, min = 10000; #if HAS_AUTO_FAN millis_t next_auto_fan_check_ms = temp_ms + 2500; #endif if (extruder >= EXTRUDERS #if !HAS_TEMP_BED || extruder < 0 #endif ) { SERIAL_ECHOLN(MSG_PID_BAD_EXTRUDER_NUM); return; } SERIAL_ECHOLN(MSG_PID_AUTOTUNE_START); disable_heater(); // 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 (ms > next_auto_fan_check_ms) { checkExtruderAutoFans(); next_auto_fan_check_ms = ms + 2500; } #endif if (heating == true && input > temp) { if (ms - t2 > 5000) { 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 == false && input < temp) { if (ms - t1 > 5000) { 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); Kp = 0.6 * Ku; Ki = 2 * Kp / Tu; Kd = Kp * Tu / 8; SERIAL_PROTOCOLLNPGM(MSG_CLASSIC_PID); SERIAL_PROTOCOLPGM(MSG_KP); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(MSG_KI); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(MSG_KD); SERIAL_PROTOCOLLN(Kd); /* Kp = 0.33*Ku; Ki = Kp/Tu; Kd = Kp*Tu/3; SERIAL_PROTOCOLLNPGM(" Some overshoot "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); Kp = 0.2*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/3; SERIAL_PROTOCOLLNPGM(" No overshoot "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); */ } } if (extruder < 0) soft_pwm_bed = (bias + d) >> 1; else soft_pwm[extruder] = (bias + d) >> 1; cycles++; min = temp; }
void PID_autotune(float temp, int hotend, int ncycles) { float input = 0.0; int cycles = 0; bool heating = true; millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms; long t_high = 0, t_low = 0; long bias, d; float Ku, Tu; float Kp_temp, Ki_temp, Kd_temp; float max = 0, min = 10000; #if HAS_AUTO_FAN millis_t next_auto_fan_check_ms = temp_ms + 2500; #endif if (hotend >= HOTENDS #if !HAS_TEMP_BED || hotend < 0 #endif ) { ECHO_LM(ER, MSG_PID_BAD_EXTRUDER_NUM); return; } ECHO_LM(DB, MSG_PID_AUTOTUNE_START); if (hotend < 0) { ECHO_SM(DB, "BED"); } else { ECHO_SMV(DB, "Hotend: ", hotend); } ECHO_MV(" Temp: ", temp); ECHO_EMV(" Cycles: ", ncycles); disable_all_heaters(); // switch off all heaters. if (hotend < 0) soft_pwm_bed = bias = d = MAX_BED_POWER / 2; else soft_pwm[hotend] = bias = d = PID_MAX / 2; // PID Tuning loop for (;;) { millis_t ms = millis(); if (temp_meas_ready) { // temp sample ready updateTemperaturesFromRawValues(); input = (hotend<0)?current_temperature_bed:current_temperature[hotend]; max = max(max, input); min = min(min, input); #if HAS_AUTO_FAN if (ms > next_auto_fan_check_ms) { checkExtruderAutoFans(); next_auto_fan_check_ms = ms + 2500; } #endif if (heating && input > temp) { if (ms > t2 + 5000) { heating = false; if (hotend < 0) soft_pwm_bed = (bias - d) >> 1; else soft_pwm[hotend] = (bias - d) >> 1; t1 = ms; t_high = t1 - t2; max = temp; } } if (!heating && input < temp) { if (ms > t1 + 5000) { heating = true; t2 = ms; t_low = t2 - t1; if (cycles > 0) { long max_pow = hotend < 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; ECHO_MV(MSG_BIAS, bias); ECHO_MV(MSG_D, d); ECHO_MV(MSG_T_MIN, min); ECHO_MV(MSG_T_MAX, max); if (cycles > 2) { Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0); Tu = ((float)(t_low + t_high) / 1000.0); ECHO_MV(MSG_KU, Ku); ECHO_EMV(MSG_TU, Tu); Kp_temp = 0.6 * Ku; Ki_temp = 2 * Kp_temp / Tu; Kd_temp = Kp_temp * Tu / 8; ECHO_EM(MSG_CLASSIC_PID); ECHO_MV(MSG_KP, Kp_temp); ECHO_MV(MSG_KI, Ki_temp); ECHO_EMV(MSG_KD, Kd_temp); } else { ECHO_E; } } if (hotend < 0) soft_pwm_bed = (bias + d) >> 1; else soft_pwm[hotend] = (bias + d) >> 1; cycles++; min = temp; }