|
@@ -219,8 +219,8 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
219
|
219
|
* Alternately heat and cool the nozzle, observing its behavior to
|
220
|
220
|
* determine the best PID values to achieve a stable temperature.
|
221
|
221
|
*/
|
222
|
|
- void Temperature::PID_autotune(const float temp, const int8_t hotend, const int8_t ncycles, const bool set_result/*=false*/) {
|
223
|
|
- float input = 0.0;
|
|
222
|
+ void Temperature::PID_autotune(const float &target, const int8_t hotend, const int8_t ncycles, const bool set_result/*=false*/) {
|
|
223
|
+ float current = 0.0;
|
224
|
224
|
int cycles = 0;
|
225
|
225
|
bool heating = true;
|
226
|
226
|
|
|
@@ -232,34 +232,19 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
232
|
232
|
workKp = 0, workKi = 0, workKd = 0,
|
233
|
233
|
max = 0, min = 10000;
|
234
|
234
|
|
|
235
|
+ #define HAS_TP_BED (ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED))
|
|
236
|
+ #if HAS_TP_BED && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP)
|
|
237
|
+ #define TV(B,H) (hotend < 0 ? (B) : (H))
|
|
238
|
+ #elif HAS_TP_BED
|
|
239
|
+ #define TV(B,H) (B)
|
|
240
|
+ #else
|
|
241
|
+ #define TV(B,H) (H)
|
|
242
|
+ #endif
|
|
243
|
+
|
235
|
244
|
#if WATCH_THE_BED || WATCH_HOTENDS
|
236
|
|
- const float watch_temp_target = temp -
|
237
|
|
- #if ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED) && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP)
|
238
|
|
- (hotend < 0 ? (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1) : (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1))
|
239
|
|
- #elif ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED)
|
240
|
|
- (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1)
|
241
|
|
- #else
|
242
|
|
- (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1)
|
243
|
|
- #endif
|
244
|
|
- ;
|
245
|
|
- const int8_t watch_temp_period =
|
246
|
|
- #if ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED) && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP)
|
247
|
|
- hotend < 0 ? WATCH_BED_TEMP_PERIOD : WATCH_TEMP_PERIOD
|
248
|
|
- #elif ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED)
|
249
|
|
- WATCH_BED_TEMP_PERIOD
|
250
|
|
- #else
|
251
|
|
- WATCH_TEMP_PERIOD
|
252
|
|
- #endif
|
253
|
|
- ;
|
254
|
|
- const int8_t watch_temp_increase =
|
255
|
|
- #if ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED) && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP)
|
256
|
|
- hotend < 0 ? WATCH_BED_TEMP_INCREASE : WATCH_TEMP_INCREASE
|
257
|
|
- #elif ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED)
|
258
|
|
- WATCH_BED_TEMP_INCREASE
|
259
|
|
- #else
|
260
|
|
- WATCH_TEMP_INCREASE
|
261
|
|
- #endif
|
262
|
|
- ;
|
|
245
|
+ const int8_t watch_temp_period = TV(WATCH_BED_TEMP_PERIOD, WATCH_TEMP_PERIOD),
|
|
246
|
+ watch_temp_increase = TV(WATCH_BED_TEMP_INCREASE, WATCH_TEMP_INCREASE);
|
|
247
|
+ const float watch_temp_target = target - float(watch_temp_increase + TV(TEMP_BED_HYSTERESIS, TEMP_HYSTERESIS) + 1);
|
263
|
248
|
millis_t temp_change_ms = next_temp_ms + watch_temp_period * 1000UL;
|
264
|
249
|
float next_watch_temp = 0.0;
|
265
|
250
|
bool heated = false;
|
|
@@ -300,7 +285,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
300
|
285
|
soft_pwm_amount_bed = bias = d = (MAX_BED_POWER) >> 1;
|
301
|
286
|
#endif
|
302
|
287
|
|
303
|
|
- wait_for_heatup = true;
|
|
288
|
+ wait_for_heatup = true; // Can be interrupted with M108
|
304
|
289
|
|
305
|
290
|
// PID Tuning loop
|
306
|
291
|
while (wait_for_heatup) {
|
|
@@ -310,7 +295,8 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
310
|
295
|
if (temp_meas_ready) { // temp sample ready
|
311
|
296
|
updateTemperaturesFromRawValues();
|
312
|
297
|
|
313
|
|
- input =
|
|
298
|
+ // Get the current temperature and constrain it
|
|
299
|
+ current =
|
314
|
300
|
#if HAS_PID_FOR_BOTH
|
315
|
301
|
hotend < 0 ? current_temperature_bed : current_temperature[hotend]
|
316
|
302
|
#elif ENABLED(PIDTEMP)
|
|
@@ -319,9 +305,8 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
319
|
305
|
current_temperature_bed
|
320
|
306
|
#endif
|
321
|
307
|
;
|
322
|
|
-
|
323
|
|
- NOLESS(max, input);
|
324
|
|
- NOMORE(min, input);
|
|
308
|
+ NOLESS(max, current);
|
|
309
|
+ NOMORE(min, current);
|
325
|
310
|
|
326
|
311
|
#if HAS_AUTO_FAN
|
327
|
312
|
if (ELAPSED(ms, next_auto_fan_check_ms)) {
|
|
@@ -330,7 +315,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
330
|
315
|
}
|
331
|
316
|
#endif
|
332
|
317
|
|
333
|
|
- if (heating && input > temp) {
|
|
318
|
+ if (heating && current > target) {
|
334
|
319
|
if (ELAPSED(ms, t2 + 5000UL)) {
|
335
|
320
|
heating = false;
|
336
|
321
|
#if HAS_PID_FOR_BOTH
|
|
@@ -345,11 +330,11 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
345
|
330
|
#endif
|
346
|
331
|
t1 = ms;
|
347
|
332
|
t_high = t1 - t2;
|
348
|
|
- max = temp;
|
|
333
|
+ max = target;
|
349
|
334
|
}
|
350
|
335
|
}
|
351
|
336
|
|
352
|
|
- if (!heating && input < temp) {
|
|
337
|
+ if (!heating && current < target) {
|
353
|
338
|
if (ELAPSED(ms, t1 + 5000UL)) {
|
354
|
339
|
heating = true;
|
355
|
340
|
t2 = ms;
|
|
@@ -373,7 +358,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
373
|
358
|
SERIAL_PROTOCOLPAIR(MSG_T_MIN, min);
|
374
|
359
|
SERIAL_PROTOCOLPAIR(MSG_T_MAX, max);
|
375
|
360
|
if (cycles > 2) {
|
376
|
|
- Ku = (4.0 * d) / (M_PI * (max - min) * 0.5); // i.e., CIRCLE_CIRC((max - min) * 0.25)
|
|
361
|
+ Ku = (4.0 * d) / (M_PI * (max - min) * 0.5);
|
377
|
362
|
Tu = ((float)(t_low + t_high) * 0.001);
|
378
|
363
|
SERIAL_PROTOCOLPAIR(MSG_KU, Ku);
|
379
|
364
|
SERIAL_PROTOCOLPAIR(MSG_TU, Tu);
|
|
@@ -413,41 +398,48 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS],
|
413
|
398
|
soft_pwm_amount_bed = (bias + d) >> 1;
|
414
|
399
|
#endif
|
415
|
400
|
cycles++;
|
416
|
|
- min = temp;
|
|
401
|
+ min = target;
|
417
|
402
|
}
|
418
|
403
|
}
|
419
|
404
|
}
|
|
405
|
+
|
|
406
|
+ // Did the temperature overshoot very far?
|
420
|
407
|
#define MAX_OVERSHOOT_PID_AUTOTUNE 20
|
421
|
|
- if (input > temp + MAX_OVERSHOOT_PID_AUTOTUNE) {
|
|
408
|
+ if (current > target + MAX_OVERSHOOT_PID_AUTOTUNE) {
|
422
|
409
|
SERIAL_PROTOCOLLNPGM(MSG_PID_TEMP_TOO_HIGH);
|
423
|
410
|
break;
|
424
|
411
|
}
|
425
|
|
- // Every 2 seconds...
|
|
412
|
+
|
|
413
|
+ // Report heater states every 2 seconds
|
426
|
414
|
if (ELAPSED(ms, next_temp_ms)) {
|
427
|
415
|
#if HAS_TEMP_HOTEND || HAS_TEMP_BED
|
428
|
416
|
print_heaterstates();
|
429
|
417
|
SERIAL_EOL();
|
430
|
418
|
#endif
|
431
|
|
-
|
432
|
419
|
next_temp_ms = ms + 2000UL;
|
433
|
420
|
|
|
421
|
+ // Make sure heating is actually working
|
434
|
422
|
#if WATCH_THE_BED || WATCH_HOTENDS
|
435
|
|
- if (!heated && input > next_watch_temp) {
|
436
|
|
- if (input > watch_temp_target) heated = true;
|
437
|
|
- next_watch_temp = input + watch_temp_increase;
|
438
|
|
- temp_change_ms = ms + watch_temp_period * 1000UL;
|
|
423
|
+ if (!heated) { // If not yet reached target...
|
|
424
|
+ if (current > next_watch_temp) { // Over the watch temp?
|
|
425
|
+ next_watch_temp = current + watch_temp_increase; // - set the next temp to watch for
|
|
426
|
+ temp_change_ms = ms + watch_temp_period * 1000UL; // - move the expiration timer up
|
|
427
|
+ if (current > watch_temp_target) heated = true; // - Flag if target temperature reached
|
|
428
|
+ }
|
|
429
|
+ else if (ELAPSED(ms, temp_change_ms)) // Watch timer expired
|
|
430
|
+ _temp_error(hotend, PSTR(MSG_T_HEATING_FAILED), PSTR(MSG_HEATING_FAILED_LCD));
|
439
|
431
|
}
|
440
|
|
- else if (!heated && ELAPSED(ms, temp_change_ms))
|
441
|
|
- _temp_error(hotend, PSTR(MSG_T_HEATING_FAILED), PSTR(MSG_HEATING_FAILED_LCD));
|
442
|
|
- else if (heated && input < temp - MAX_OVERSHOOT_PID_AUTOTUNE)
|
|
432
|
+ else if (current < target - (MAX_OVERSHOOT_PID_AUTOTUNE)) // Heated, then temperature fell too far?
|
443
|
433
|
_temp_error(hotend, PSTR(MSG_T_THERMAL_RUNAWAY), PSTR(MSG_THERMAL_RUNAWAY));
|
444
|
434
|
#endif
|
445
|
435
|
} // every 2 seconds
|
|
436
|
+
|
446
|
437
|
// Timeout after 20 minutes since the last undershoot/overshoot cycle
|
447
|
438
|
if (((ms - t1) + (ms - t2)) > (20L * 60L * 1000L)) {
|
448
|
439
|
SERIAL_PROTOCOLLNPGM(MSG_PID_TIMEOUT);
|
449
|
440
|
break;
|
450
|
441
|
}
|
|
442
|
+
|
451
|
443
|
if (cycles > ncycles) {
|
452
|
444
|
SERIAL_PROTOCOLLNPGM(MSG_PID_AUTOTUNE_FINISHED);
|
453
|
445
|
|