|
@@ -350,11 +350,13 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
350
|
350
|
PID_t tune_pid = { 0, 0, 0 };
|
351
|
351
|
float max = 0, min = 10000;
|
352
|
352
|
|
|
353
|
+ const bool isbed = (heater < 0);
|
|
354
|
+
|
353
|
355
|
#if HAS_PID_FOR_BOTH
|
354
|
|
- #define GHV(B,H) (heater < 0 ? (B) : (H))
|
355
|
|
- #define SHV(B,H) do{ if (heater < 0) temp_bed.soft_pwm_amount = B; else temp_hotend[heater].soft_pwm_amount = H; }while(0)
|
356
|
|
- #define ONHEATINGSTART() (heater < 0 ? printerEventLEDs.onBedHeatingStart() : printerEventLEDs.onHotendHeatingStart())
|
357
|
|
- #define ONHEATING(S,C,T) do{ if (heater < 0) printerEventLEDs.onBedHeating(S,C,T); else printerEventLEDs.onHotendHeating(S,C,T); }while(0)
|
|
356
|
+ #define GHV(B,H) (isbed ? (B) : (H))
|
|
357
|
+ #define SHV(B,H) do{ if (isbed) temp_bed.soft_pwm_amount = B; else temp_hotend[heater].soft_pwm_amount = H; }while(0)
|
|
358
|
+ #define ONHEATINGSTART() (isbed ? printerEventLEDs.onBedHeatingStart() : printerEventLEDs.onHotendHeatingStart())
|
|
359
|
+ #define ONHEATING(S,C,T) (isbed ? printerEventLEDs.onBedHeating(S,C,T) : printerEventLEDs.onHotendHeating(S,C,T))
|
358
|
360
|
#elif ENABLED(PIDTEMPBED)
|
359
|
361
|
#define GHV(B,H) B
|
360
|
362
|
#define SHV(B,H) (temp_bed.soft_pwm_amount = B)
|
|
@@ -370,7 +372,7 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
370
|
372
|
#if WATCH_BED || WATCH_HOTENDS
|
371
|
373
|
#define HAS_TP_BED BOTH(THERMAL_PROTECTION_BED, PIDTEMPBED)
|
372
|
374
|
#if HAS_TP_BED && BOTH(THERMAL_PROTECTION_HOTENDS, PIDTEMP)
|
373
|
|
- #define GTV(B,H) (heater < 0 ? (B) : (H))
|
|
375
|
+ #define GTV(B,H) (isbed ? (B) : (H))
|
374
|
376
|
#elif HAS_TP_BED
|
375
|
377
|
#define GTV(B,H) (B)
|
376
|
378
|
#else
|
|
@@ -456,23 +458,25 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
456
|
458
|
|
457
|
459
|
SERIAL_ECHOPAIR(MSG_BIAS, bias, MSG_D, d, MSG_T_MIN, min, MSG_T_MAX, max);
|
458
|
460
|
if (cycles > 2) {
|
459
|
|
- float Ku = (4.0f * d) / (float(M_PI) * (max - min) * 0.5f),
|
460
|
|
- Tu = ((float)(t_low + t_high) * 0.001f);
|
461
|
|
- tune_pid.Kp = 0.6f * Ku;
|
|
461
|
+ const float Ku = (4.0f * d) / (float(M_PI) * (max - min) * 0.5f),
|
|
462
|
+ Tu = float(t_low + t_high) * 0.001f,
|
|
463
|
+ pf = isbed ? 0.2f : 0.6f,
|
|
464
|
+ df = isbed ? 1.0f / 3.0f : 1.0f / 8.0f;
|
|
465
|
+ tune_pid.Kp = Ku * pf;
|
|
466
|
+ tune_pid.Kd = tune_pid.Kp * Tu * df;
|
462
|
467
|
tune_pid.Ki = 2 * tune_pid.Kp / Tu;
|
463
|
|
- tune_pid.Kd = tune_pid.Kp * Tu * 0.125f;
|
464
|
468
|
SERIAL_ECHOPAIR(MSG_KU, Ku, MSG_TU, Tu);
|
465
|
469
|
SERIAL_ECHOLNPGM("\n" MSG_CLASSIC_PID);
|
466
|
470
|
SERIAL_ECHOLNPAIR(MSG_KP, tune_pid.Kp, MSG_KI, tune_pid.Ki, MSG_KD, tune_pid.Kd);
|
467
|
471
|
/**
|
468
|
|
- tune_pid.Kp = 0.33*Ku;
|
469
|
|
- tune_pid.Ki = tune_pid.Kp/Tu;
|
470
|
|
- tune_pid.Kd = tune_pid.Kp*Tu/3;
|
|
472
|
+ tune_pid.Kp = 0.33 * Ku;
|
|
473
|
+ tune_pid.Ki = tune_pid.Kp / Tu;
|
|
474
|
+ tune_pid.Kd = tune_pid.Kp * Tu / 3;
|
471
|
475
|
SERIAL_ECHOLNPGM(" Some overshoot");
|
472
|
476
|
SERIAL_ECHOLNPAIR(" Kp: ", tune_pid.Kp, " Ki: ", tune_pid.Ki, " Kd: ", tune_pid.Kd, " No overshoot");
|
473
|
|
- tune_pid.Kp = 0.2*Ku;
|
474
|
|
- tune_pid.Ki = 2*tune_pid.Kp/Tu;
|
475
|
|
- tune_pid.Kd = tune_pid.Kp*Tu/3;
|
|
477
|
+ tune_pid.Kp = 0.2 * Ku;
|
|
478
|
+ tune_pid.Ki = 2 * tune_pid.Kp / Tu;
|
|
479
|
+ tune_pid.Kd = tune_pid.Kp * Tu / 3;
|
476
|
480
|
SERIAL_ECHOPAIR(" Kp: ", tune_pid.Kp, " Ki: ", tune_pid.Ki, " Kd: ", tune_pid.Kd);
|
477
|
481
|
*/
|
478
|
482
|
}
|
|
@@ -496,7 +500,7 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
496
|
500
|
// Report heater states every 2 seconds
|
497
|
501
|
if (ELAPSED(ms, next_temp_ms)) {
|
498
|
502
|
#if HAS_TEMP_SENSOR
|
499
|
|
- print_heater_states(heater >= 0 ? heater : active_extruder);
|
|
503
|
+ print_heater_states(isbed ? active_extruder : heater);
|
500
|
504
|
SERIAL_EOL();
|
501
|
505
|
#endif
|
502
|
506
|
next_temp_ms = ms + 2000UL;
|
|
@@ -507,9 +511,9 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
507
|
511
|
#if WATCH_BED && WATCH_HOTENDS
|
508
|
512
|
true
|
509
|
513
|
#elif WATCH_HOTENDS
|
510
|
|
- heater >= 0
|
|
514
|
+ !isbed
|
511
|
515
|
#else
|
512
|
|
- heater < 0
|
|
516
|
+ isbed
|
513
|
517
|
#endif
|
514
|
518
|
) {
|
515
|
519
|
if (!heated) { // If not yet reached target...
|
|
@@ -569,7 +573,7 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
|
569
|
573
|
// Use the result? (As with "M303 U1")
|
570
|
574
|
if (set_result) {
|
571
|
575
|
#if HAS_PID_FOR_BOTH
|
572
|
|
- if (heater < 0) _SET_BED_PID(); else _SET_EXTRUDER_PID();
|
|
576
|
+ if (isbed) _SET_BED_PID(); else _SET_EXTRUDER_PID();
|
573
|
577
|
#elif ENABLED(PIDTEMP)
|
574
|
578
|
_SET_EXTRUDER_PID();
|
575
|
579
|
#else
|
|
@@ -805,9 +809,7 @@ float Temperature::get_pid_output(const int8_t e) {
|
805
|
809
|
static float temp_iState[HOTENDS] = { 0 },
|
806
|
810
|
temp_dState[HOTENDS] = { 0 };
|
807
|
811
|
static bool pid_reset[HOTENDS] = { false };
|
808
|
|
- float pid_error = temp_hotend[HOTEND_INDEX].target - temp_hotend[HOTEND_INDEX].current;
|
809
|
|
- work_pid[HOTEND_INDEX].Kd = PID_K2 * PID_PARAM(Kd, HOTEND_INDEX) * (temp_hotend[HOTEND_INDEX].current - temp_dState[HOTEND_INDEX]) + float(PID_K1) * work_pid[HOTEND_INDEX].Kd;
|
810
|
|
- temp_dState[HOTEND_INDEX] = temp_hotend[HOTEND_INDEX].current;
|
|
812
|
+ const float pid_error = temp_hotend[HOTEND_INDEX].target - temp_hotend[HOTEND_INDEX].current;
|
811
|
813
|
|
812
|
814
|
if (temp_hotend[HOTEND_INDEX].target == 0
|
813
|
815
|
|| pid_error < -(PID_FUNCTIONAL_RANGE)
|
|
@@ -825,13 +827,17 @@ float Temperature::get_pid_output(const int8_t e) {
|
825
|
827
|
else {
|
826
|
828
|
if (pid_reset[HOTEND_INDEX]) {
|
827
|
829
|
temp_iState[HOTEND_INDEX] = 0.0;
|
|
830
|
+ work_pid[HOTEND_INDEX].Kd = 0.0;
|
828
|
831
|
pid_reset[HOTEND_INDEX] = false;
|
829
|
832
|
}
|
830
|
|
- temp_iState[HOTEND_INDEX] += pid_error;
|
|
833
|
+
|
|
834
|
+ work_pid[HOTEND_INDEX].Kd = work_pid[HOTEND_INDEX].Kd + PID_K2 * (PID_PARAM(Kd, HOTEND_INDEX) * (temp_dState[HOTEND_INDEX] - temp_hotend[HOTEND_INDEX].current) - work_pid[HOTEND_INDEX].Kd);
|
|
835
|
+ const float max_power_over_i_gain = (float)PID_MAX / PID_PARAM(Ki, HOTEND_INDEX);
|
|
836
|
+ temp_iState[HOTEND_INDEX] = constrain(temp_iState[HOTEND_INDEX] + pid_error, 0, max_power_over_i_gain);
|
831
|
837
|
work_pid[HOTEND_INDEX].Kp = PID_PARAM(Kp, HOTEND_INDEX) * pid_error;
|
832
|
838
|
work_pid[HOTEND_INDEX].Ki = PID_PARAM(Ki, HOTEND_INDEX) * temp_iState[HOTEND_INDEX];
|
833
|
839
|
|
834
|
|
- pid_output = work_pid[HOTEND_INDEX].Kp + work_pid[HOTEND_INDEX].Ki - work_pid[HOTEND_INDEX].Kd;
|
|
840
|
+ pid_output = work_pid[HOTEND_INDEX].Kp + work_pid[HOTEND_INDEX].Ki + work_pid[HOTEND_INDEX].Kd;
|
835
|
841
|
|
836
|
842
|
#if ENABLED(PID_EXTRUSION_SCALING)
|
837
|
843
|
work_pid[HOTEND_INDEX].Kc = 0;
|
|
@@ -850,15 +856,9 @@ float Temperature::get_pid_output(const int8_t e) {
|
850
|
856
|
}
|
851
|
857
|
#endif // PID_EXTRUSION_SCALING
|
852
|
858
|
|
853
|
|
- if (pid_output > PID_MAX) {
|
854
|
|
- if (pid_error > 0) temp_iState[HOTEND_INDEX] -= pid_error; // conditional un-integration
|
855
|
|
- pid_output = PID_MAX;
|
856
|
|
- }
|
857
|
|
- else if (pid_output < 0) {
|
858
|
|
- if (pid_error < 0) temp_iState[HOTEND_INDEX] -= pid_error; // conditional un-integration
|
859
|
|
- pid_output = 0;
|
860
|
|
- }
|
|
859
|
+ pid_output = constrain(pid_output, 0, PID_MAX);
|
861
|
860
|
}
|
|
861
|
+ temp_dState[HOTEND_INDEX] = temp_hotend[HOTEND_INDEX].current;
|
862
|
862
|
|
863
|
863
|
#else // PID_OPENLOOP
|
864
|
864
|
|
|
@@ -908,23 +908,18 @@ float Temperature::get_pid_output(const int8_t e) {
|
908
|
908
|
static PID_t work_pid = { 0 };
|
909
|
909
|
static float temp_iState = 0, temp_dState = 0;
|
910
|
910
|
|
911
|
|
- float pid_error = temp_bed.target - temp_bed.current;
|
912
|
|
- temp_iState += pid_error;
|
|
911
|
+ const float max_power_over_i_gain = (float)MAX_BED_POWER / temp_bed.pid.Ki,
|
|
912
|
+ pid_error = temp_bed.target - temp_bed.current;
|
|
913
|
+
|
|
914
|
+ temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
|
|
915
|
+
|
913
|
916
|
work_pid.Kp = temp_bed.pid.Kp * pid_error;
|
914
|
917
|
work_pid.Ki = temp_bed.pid.Ki * temp_iState;
|
915
|
|
- work_pid.Kd = PID_K2 * temp_bed.pid.Kd * (temp_bed.current - temp_dState) + PID_K1 * work_pid.Kd;
|
|
918
|
+ work_pid.Kd = work_pid.Kd + PID_K2 * (temp_bed.pid.Kd * (temp_dState - temp_bed.current) - work_pid.Kd);
|
916
|
919
|
|
917
|
920
|
temp_dState = temp_bed.current;
|
918
|
921
|
|
919
|
|
- float pid_output = work_pid.Kp + work_pid.Ki - work_pid.Kd;
|
920
|
|
- if (pid_output > MAX_BED_POWER) {
|
921
|
|
- if (pid_error > 0) temp_iState -= pid_error; // conditional un-integration
|
922
|
|
- pid_output = MAX_BED_POWER;
|
923
|
|
- }
|
924
|
|
- else if (pid_output < 0) {
|
925
|
|
- if (pid_error < 0) temp_iState -= pid_error; // conditional un-integration
|
926
|
|
- pid_output = 0;
|
927
|
|
- }
|
|
922
|
+ const float pid_output = constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd, 0, MAX_BED_POWER);
|
928
|
923
|
|
929
|
924
|
#else // PID_OPENLOOP
|
930
|
925
|
|