🐛 Fix / refactor shared PID (#24673)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
Giuliano Zaro
2022-09-04 02:51:53 +02:00
committed by Scott Lahteine
parent e04e18a590
commit aa28358267
15 changed files with 323 additions and 266 deletions

View File

@ -364,18 +364,18 @@ typedef struct SettingsDataStruct {
//
// PIDTEMP
//
PIDCF_t hotendPID[HOTENDS]; // M301 En PIDCF / M303 En U
raw_pidcf_t hotendPID[HOTENDS]; // M301 En PIDCF / M303 En U
int16_t lpq_len; // M301 L
//
// PIDTEMPBED
//
PID_t bedPID; // M304 PID / M303 E-1 U
raw_pid_t bedPID; // M304 PID / M303 E-1 U
//
// PIDTEMPCHAMBER
//
PID_t chamberPID; // M309 PID / M303 E-2 U
raw_pid_t chamberPID; // M309 PID / M303 E-2 U
//
// User-defined Thermistors
@ -1052,27 +1052,20 @@ void MarlinSettings::postprocess() {
//
{
_FIELD_TEST(hotendPID);
#if DISABLED(PIDTEMP)
raw_pidcf_t pidcf = { NAN, NAN, NAN, NAN, NAN };
#endif
HOTEND_LOOP() {
PIDCF_t pidcf = {
#if DISABLED(PIDTEMP)
NAN, NAN, NAN,
NAN, NAN
#else
PID_PARAM(Kp, e),
unscalePID_i(PID_PARAM(Ki, e)),
unscalePID_d(PID_PARAM(Kd, e)),
PID_PARAM(Kc, e),
PID_PARAM(Kf, e)
#endif
};
#if ENABLED(PIDTEMP)
const hotend_pid_t &pid = thermalManager.temp_hotend[e].pid;
raw_pidcf_t pidcf = { pid.p(), pid.i(), pid.d(), pid.c(), pid.f() };
#endif
EEPROM_WRITE(pidcf);
}
_FIELD_TEST(lpq_len);
#if DISABLED(PID_EXTRUSION_SCALING)
const int16_t lpq_len = 20;
#endif
EEPROM_WRITE(TERN(PID_EXTRUSION_SCALING, thermalManager.lpq_len, lpq_len));
const int16_t lpq_len = TERN(PID_EXTRUSION_SCALING, thermalManager.lpq_len, 20);
EEPROM_WRITE(lpq_len);
}
//
@ -1080,17 +1073,12 @@ void MarlinSettings::postprocess() {
//
{
_FIELD_TEST(bedPID);
const PID_t bed_pid = {
#if DISABLED(PIDTEMPBED)
NAN, NAN, NAN
#else
// Store the unscaled PID values
thermalManager.temp_bed.pid.Kp,
unscalePID_i(thermalManager.temp_bed.pid.Ki),
unscalePID_d(thermalManager.temp_bed.pid.Kd)
#endif
};
#if ENABLED(PIDTEMPBED)
const PID_t &pid = thermalManager.temp_bed.pid;
const raw_pid_t bed_pid = { pid.p(), pid.i(), pid.d() };
#else
const raw_pid_t bed_pid = { NAN, NAN, NAN };
#endif
EEPROM_WRITE(bed_pid);
}
@ -1099,17 +1087,12 @@ void MarlinSettings::postprocess() {
//
{
_FIELD_TEST(chamberPID);
const PID_t chamber_pid = {
#if DISABLED(PIDTEMPCHAMBER)
NAN, NAN, NAN
#else
// Store the unscaled PID values
thermalManager.temp_chamber.pid.Kp,
unscalePID_i(thermalManager.temp_chamber.pid.Ki),
unscalePID_d(thermalManager.temp_chamber.pid.Kd)
#endif
};
#if ENABLED(PIDTEMPCHAMBER)
const PID_t &pid = thermalManager.temp_chamber.pid;
const raw_pid_t chamber_pid = { pid.p(), pid.i(), pid.d() };
#else
const raw_pid_t chamber_pid = { NAN, NAN, NAN };
#endif
EEPROM_WRITE(chamber_pid);
}
@ -1117,10 +1100,8 @@ void MarlinSettings::postprocess() {
// User-defined Thermistors
//
#if HAS_USER_THERMISTORS
{
_FIELD_TEST(user_thermistor);
EEPROM_WRITE(thermalManager.user_thermistor);
}
#endif
//
@ -2003,17 +1984,11 @@ void MarlinSettings::postprocess() {
//
{
HOTEND_LOOP() {
PIDCF_t pidcf;
raw_pidcf_t pidcf;
EEPROM_READ(pidcf);
#if ENABLED(PIDTEMP)
if (!validating && !isnan(pidcf.Kp)) {
// Scale PID values since EEPROM values are unscaled
PID_PARAM(Kp, e) = pidcf.Kp;
PID_PARAM(Ki, e) = scalePID_i(pidcf.Ki);
PID_PARAM(Kd, e) = scalePID_d(pidcf.Kd);
TERN_(PID_EXTRUSION_SCALING, PID_PARAM(Kc, e) = pidcf.Kc);
TERN_(PID_FAN_SCALING, PID_PARAM(Kf, e) = pidcf.Kf);
}
if (!validating && !isnan(pidcf.p))
thermalManager.temp_hotend[e].pid.set(pidcf);
#endif
}
}
@ -2035,15 +2010,11 @@ void MarlinSettings::postprocess() {
// Heated Bed PID
//
{
PID_t pid;
raw_pid_t pid;
EEPROM_READ(pid);
#if ENABLED(PIDTEMPBED)
if (!validating && !isnan(pid.Kp)) {
// Scale PID values since EEPROM values are unscaled
thermalManager.temp_bed.pid.Kp = pid.Kp;
thermalManager.temp_bed.pid.Ki = scalePID_i(pid.Ki);
thermalManager.temp_bed.pid.Kd = scalePID_d(pid.Kd);
}
if (!validating && !isnan(pid.p))
thermalManager.temp_bed.pid.set(pid);
#endif
}
@ -2051,15 +2022,11 @@ void MarlinSettings::postprocess() {
// Heated Chamber PID
//
{
PID_t pid;
raw_pid_t pid;
EEPROM_READ(pid);
#if ENABLED(PIDTEMPCHAMBER)
if (!validating && !isnan(pid.Kp)) {
// Scale PID values since EEPROM values are unscaled
thermalManager.temp_chamber.pid.Kp = pid.Kp;
thermalManager.temp_chamber.pid.Ki = scalePID_i(pid.Ki);
thermalManager.temp_chamber.pid.Kd = scalePID_d(pid.Kd);
}
if (!validating && !isnan(pid.p))
thermalManager.temp_chamber.pid.set(pid);
#endif
}
@ -3142,11 +3109,13 @@ void MarlinSettings::reset() {
#define PID_DEFAULT(N,E) DEFAULT_##N
#endif
HOTEND_LOOP() {
PID_PARAM(Kp, e) = float(PID_DEFAULT(Kp, ALIM(e, defKp)));
PID_PARAM(Ki, e) = scalePID_i(PID_DEFAULT(Ki, ALIM(e, defKi)));
PID_PARAM(Kd, e) = scalePID_d(PID_DEFAULT(Kd, ALIM(e, defKd)));
TERN_(PID_EXTRUSION_SCALING, PID_PARAM(Kc, e) = float(PID_DEFAULT(Kc, ALIM(e, defKc))));
TERN_(PID_FAN_SCALING, PID_PARAM(Kf, e) = float(PID_DEFAULT(Kf, ALIM(e, defKf))));
thermalManager.temp_hotend[e].pid.set(
PID_DEFAULT(Kp, ALIM(e, defKp)),
PID_DEFAULT(Ki, ALIM(e, defKi)),
PID_DEFAULT(Kd, ALIM(e, defKd))
OPTARG(PID_EXTRUSION_SCALING, PID_DEFAULT(Kc, ALIM(e, defKc)))
OPTARG(PID_FAN_SCALING, PID_DEFAULT(Kf, ALIM(e, defKf)))
);
}
#endif
@ -3160,9 +3129,7 @@ void MarlinSettings::reset() {
//
#if ENABLED(PIDTEMPBED)
thermalManager.temp_bed.pid.Kp = DEFAULT_bedKp;
thermalManager.temp_bed.pid.Ki = scalePID_i(DEFAULT_bedKi);
thermalManager.temp_bed.pid.Kd = scalePID_d(DEFAULT_bedKd);
thermalManager.temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd);
#endif
//
@ -3170,9 +3137,7 @@ void MarlinSettings::reset() {
//
#if ENABLED(PIDTEMPCHAMBER)
thermalManager.temp_chamber.pid.Kp = DEFAULT_chamberKp;
thermalManager.temp_chamber.pid.Ki = scalePID_i(DEFAULT_chamberKi);
thermalManager.temp_chamber.pid.Kd = scalePID_d(DEFAULT_chamberKd);
thermalManager.temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd);
#endif
//
@ -3342,14 +3307,15 @@ void MarlinSettings::reset() {
static_assert(COUNT(_filament_heat_capacity_permm) == HOTENDS, "FILAMENT_HEAT_CAPACITY_PERMM must have HOTENDS items.");
HOTEND_LOOP() {
thermalManager.temp_hotend[e].constants.heater_power = _mpc_heater_power[e];
thermalManager.temp_hotend[e].constants.block_heat_capacity = _mpc_block_heat_capacity[e];
thermalManager.temp_hotend[e].constants.sensor_responsiveness = _mpc_sensor_responsiveness[e];
thermalManager.temp_hotend[e].constants.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e];
MPC_t &constants = thermalManager.temp_hotend[e].constants;
constants.heater_power = _mpc_heater_power[e];
constants.block_heat_capacity = _mpc_block_heat_capacity[e];
constants.sensor_responsiveness = _mpc_sensor_responsiveness[e];
constants.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e];
#if ENABLED(MPC_INCLUDE_FAN)
thermalManager.temp_hotend[e].constants.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e];
constants.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e];
#endif
thermalManager.temp_hotend[e].constants.filament_heat_capacity_permm = _filament_heat_capacity_permm[e];
constants.filament_heat_capacity_permm = _filament_heat_capacity_permm[e];
}
#endif

View File

@ -597,7 +597,7 @@ volatile bool Temperature::raw_temps_ready = false;
millis_t next_temp_ms = millis(), t1 = next_temp_ms, t2 = next_temp_ms;
long t_high = 0, t_low = 0;
PID_t tune_pid = { 0, 0, 0 };
raw_pid_t tune_pid = { 0, 0, 0 };
celsius_float_t maxT = 0, minT = 10000;
const bool isbed = (heater_id == H_BED),
@ -716,16 +716,16 @@ volatile bool Temperature::raw_temps_ready = false;
pf = (ischamber || isbed) ? 0.2f : 0.6f,
df = (ischamber || isbed) ? 1.0f / 3.0f : 1.0f / 8.0f;
tune_pid.Kp = Ku * pf;
tune_pid.Ki = tune_pid.Kp * 2.0f / Tu;
tune_pid.Kd = tune_pid.Kp * Tu * df;
tune_pid.p = Ku * pf;
tune_pid.i = tune_pid.p * 2.0f / Tu;
tune_pid.d = tune_pid.p * Tu * df;
SERIAL_ECHOLNPGM(STR_KU, Ku, STR_TU, Tu);
if (ischamber || isbed)
SERIAL_ECHOLNPGM(" No overshoot");
else
SERIAL_ECHOLNPGM(STR_CLASSIC_PID);
SERIAL_ECHOLNPGM(STR_KP, tune_pid.Kp, STR_KI, tune_pid.Ki, STR_KD, tune_pid.Kd);
SERIAL_ECHOLNPGM(STR_KP, tune_pid.p, STR_KI, tune_pid.i, STR_KD, tune_pid.d);
}
}
SHV((bias + d) >> 1);
@ -795,39 +795,36 @@ volatile bool Temperature::raw_temps_ready = false;
#if EITHER(PIDTEMPBED, PIDTEMPCHAMBER)
FSTR_P const estring = GHV(F("chamber"), F("bed"), FPSTR(NUL_STR));
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Kp ", tune_pid.Kp);
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Ki ", tune_pid.Ki);
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Kd ", tune_pid.Kd);
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Kp ", tune_pid.p);
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Ki ", tune_pid.i);
say_default_(); SERIAL_ECHOF(estring); SERIAL_ECHOLNPGM("Kd ", tune_pid.d);
#else
say_default_(); SERIAL_ECHOLNPGM("Kp ", tune_pid.Kp);
say_default_(); SERIAL_ECHOLNPGM("Ki ", tune_pid.Ki);
say_default_(); SERIAL_ECHOLNPGM("Kd ", tune_pid.Kd);
say_default_(); SERIAL_ECHOLNPGM("Kp ", tune_pid.p);
say_default_(); SERIAL_ECHOLNPGM("Ki ", tune_pid.i);
say_default_(); SERIAL_ECHOLNPGM("Kd ", tune_pid.d);
#endif
auto _set_hotend_pid = [](const uint8_t e, const PID_t &in_pid) {
auto _set_hotend_pid = [](const uint8_t tool, const raw_pid_t &in_pid) {
#if ENABLED(PIDTEMP)
PID_PARAM(Kp, e) = in_pid.Kp;
PID_PARAM(Ki, e) = scalePID_i(in_pid.Ki);
PID_PARAM(Kd, e) = scalePID_d(in_pid.Kd);
#if ENABLED(PID_PARAMS_PER_HOTEND)
thermalManager.temp_hotend[tool].pid.set(in_pid);
#else
HOTEND_LOOP() thermalManager.temp_hotend[e].pid.set(in_pid);
#endif
updatePID();
#else
UNUSED(e); UNUSED(in_pid);
#endif
UNUSED(tool); UNUSED(in_pid);
};
#if ENABLED(PIDTEMPBED)
auto _set_bed_pid = [](const PID_t &in_pid) {
temp_bed.pid.Kp = in_pid.Kp;
temp_bed.pid.Ki = scalePID_i(in_pid.Ki);
temp_bed.pid.Kd = scalePID_d(in_pid.Kd);
auto _set_bed_pid = [](const raw_pid_t &in_pid) {
temp_bed.pid.set(in_pid);
};
#endif
#if ENABLED(PIDTEMPCHAMBER)
auto _set_chamber_pid = [](const PID_t &in_pid) {
temp_chamber.pid.Kp = in_pid.Kp;
temp_chamber.pid.Ki = scalePID_i(in_pid.Ki);
temp_chamber.pid.Kd = scalePID_d(in_pid.Kd);
auto _set_chamber_pid = [](const raw_pid_t &in_pid) {
temp_chamber.pid.set(in_pid);
};
#endif

View File

@ -60,53 +60,6 @@ typedef enum : int8_t {
H_NONE = -128
} heater_id_t;
// PID storage
typedef struct { float Kp, Ki, Kd; } PID_t;
typedef struct { float Kp, Ki, Kd, Kc; } PIDC_t;
typedef struct { float Kp, Ki, Kd, Kf; } PIDF_t;
typedef struct { float Kp, Ki, Kd, Kc, Kf; } PIDCF_t;
typedef
#if BOTH(PID_EXTRUSION_SCALING, PID_FAN_SCALING)
PIDCF_t
#elif ENABLED(PID_EXTRUSION_SCALING)
PIDC_t
#elif ENABLED(PID_FAN_SCALING)
PIDF_t
#else
PID_t
#endif
hotend_pid_t;
#if ENABLED(PID_EXTRUSION_SCALING)
typedef IF<(LPQ_MAX_LEN > 255), uint16_t, uint8_t>::type lpq_ptr_t;
#endif
#define PID_PARAM(F,H) _PID_##F(TERN(PID_PARAMS_PER_HOTEND, H, 0 & H)) // Always use 'H' to suppress warning
#define _PID_Kp(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Kp, NAN)
#define _PID_Ki(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Ki, NAN)
#define _PID_Kd(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Kd, NAN)
#if ENABLED(PIDTEMP)
#define _PID_Kc(H) TERN(PID_EXTRUSION_SCALING, Temperature::temp_hotend[H].pid.Kc, 1)
#define _PID_Kf(H) TERN(PID_FAN_SCALING, Temperature::temp_hotend[H].pid.Kf, 0)
#else
#define _PID_Kc(H) 1
#define _PID_Kf(H) 0
#endif
#if ENABLED(MPCTEMP)
typedef struct {
float heater_power; // M306 P
float block_heat_capacity; // M306 C
float sensor_responsiveness; // M306 R
float ambient_xfer_coeff_fan0; // M306 A
#if ENABLED(MPC_INCLUDE_FAN)
float fan255_adjustment; // M306 F
#endif
float filament_heat_capacity_permm; // M306 H
} MPC_t;
#endif
/**
* States for ADC reading in the ISR
*/
@ -188,7 +141,15 @@ enum ADCSensorState : char {
#define ACTUAL_ADC_SAMPLES _MAX(int(MIN_ADC_ISR_LOOPS), int(SensorsReady))
//
// PID
//
typedef struct { float p, i, d; } raw_pid_t;
typedef struct { float p, i, d, c, f; } raw_pidcf_t;
#if HAS_PID_HEATING
#define PID_K2 (1-float(PID_K1))
#define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY))
@ -197,10 +158,116 @@ enum ADCSensorState : char {
#define unscalePID_i(i) ( float(i) / PID_dT )
#define scalePID_d(d) ( float(d) / PID_dT )
#define unscalePID_d(d) ( float(d) * PID_dT )
typedef struct {
float Kp, Ki, Kd;
float p() const { return Kp; }
float i() const { return unscalePID_i(Ki); }
float d() const { return unscalePID_d(Kd); }
float c() const { return 1; }
float f() const { return 0; }
void set_Kp(float p) { Kp = p; }
void set_Ki(float i) { Ki = scalePID_i(i); }
void set_Kd(float d) { Kd = scalePID_d(d); }
void set_Kc(float) {}
void set_Kf(float) {}
void set(float p, float i, float d, float c=1, float f=0) { set_Kp(p); set_Ki(i); set_Kd(d); UNUSED(c); UNUSED(f); }
void set(const raw_pid_t &raw) { set(raw.p, raw.i, raw.d); }
void set(const raw_pidcf_t &raw) { set(raw.p, raw.i, raw.d); }
} PID_t;
#endif
#if ENABLED(MPCTEMP)
#if ENABLED(PIDTEMP)
typedef struct {
float Kp, Ki, Kd, Kc;
float p() const { return Kp; }
float i() const { return unscalePID_i(Ki); }
float d() const { return unscalePID_d(Kd); }
float c() const { return Kc; }
float f() const { return 0; }
void set_Kp(float p) { Kp = p; }
void set_Ki(float i) { Ki = scalePID_i(i); }
void set_Kd(float d) { Kd = scalePID_d(d); }
void set_Kc(float c) { Kc = c; }
void set_Kf(float) {}
void set(float p, float i, float d, float c=1, float f=0) { set_Kp(p); set_Ki(i); set_Kd(d); set_Kc(c); set_Kf(f); }
void set(const raw_pid_t &raw) { set(raw.p, raw.i, raw.d); }
void set(const raw_pidcf_t &raw) { set(raw.p, raw.i, raw.d, raw.c); }
} PIDC_t;
typedef struct {
float Kp, Ki, Kd, Kf;
float p() const { return Kp; }
float i() const { return unscalePID_i(Ki); }
float d() const { return unscalePID_d(Kd); }
float c() const { return 1; }
float f() const { return Kf; }
void set_Kp(float p) { Kp = p; }
void set_Ki(float i) { Ki = scalePID_i(i); }
void set_Kd(float d) { Kd = scalePID_d(d); }
void set_Kc(float) {}
void set_Kf(float f) { Kf = f; }
void set(float p, float i, float d, float c=1, float f=0) { set_Kp(p); set_Ki(i); set_Kd(d); set_Kf(f); }
void set(const raw_pid_t &raw) { set(raw.p, raw.i, raw.d); }
void set(const raw_pidcf_t &raw) { set(raw.p, raw.i, raw.d, raw.f); }
} PIDF_t;
typedef struct {
float Kp, Ki, Kd, Kc, Kf;
float p() const { return Kp; }
float i() const { return unscalePID_i(Ki); }
float d() const { return unscalePID_d(Kd); }
float c() const { return Kc; }
float f() const { return Kf; }
void set_Kp(float p) { Kp = p; }
void set_Ki(float i) { Ki = scalePID_i(i); }
void set_Kd(float d) { Kd = scalePID_d(d); }
void set_Kc(float c) { Kc = c; }
void set_Kf(float f) { Kf = f; }
void set(float p, float i, float d, float c=1, float f=0) { set_Kp(p); set_Ki(i); set_Kd(d); set_Kc(c); set_Kf(f); }
void set(const raw_pid_t &raw) { set(raw.p, raw.i, raw.d); }
void set(const raw_pidcf_t &raw) { set(raw.p, raw.i, raw.d, raw.c, raw.f); }
} PIDCF_t;
typedef
#if BOTH(PID_EXTRUSION_SCALING, PID_FAN_SCALING)
PIDCF_t
#elif ENABLED(PID_EXTRUSION_SCALING)
PIDC_t
#elif ENABLED(PID_FAN_SCALING)
PIDF_t
#else
PID_t
#endif
hotend_pid_t;
#if ENABLED(PID_EXTRUSION_SCALING)
typedef IF<(LPQ_MAX_LEN > 255), uint16_t, uint8_t>::type lpq_ptr_t;
#endif
#if ENABLED(PID_PARAMS_PER_HOTEND)
#define SET_HOTEND_PID(F,H,V) thermalManager.temp_hotend[H].pid.set_##F(V)
#else
#define SET_HOTEND_PID(F,_,V) do{ HOTEND_LOOP() thermalManager.temp_hotend[e].pid.set_##F(V); }while(0)
#endif
#elif ENABLED(MPCTEMP)
typedef struct {
float heater_power; // M306 P
float block_heat_capacity; // M306 C
float sensor_responsiveness; // M306 R
float ambient_xfer_coeff_fan0; // M306 A
#if ENABLED(MPC_INCLUDE_FAN)
float fan255_adjustment; // M306 F
#endif
float filament_heat_capacity_permm; // M306 H
} MPC_t;
#define MPC_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY))
#endif
#if ENABLED(G26_MESH_VALIDATION) && EITHER(HAS_MARLINUI_MENU, EXTENSIBLE_UI)
@ -218,7 +285,7 @@ public:
inline void sample(const raw_adc_t s) { acc += s; }
inline void update() { raw = acc; }
void setraw(const raw_adc_t r) { raw = r; }
raw_adc_t getraw() { return raw; }
raw_adc_t getraw() const { return raw; }
} temp_info_t;
#if HAS_TEMP_REDUNDANT
@ -393,6 +460,7 @@ class Temperature {
static const celsius_t hotend_maxtemp[HOTENDS];
static celsius_t hotend_max_target(const uint8_t e) { return hotend_maxtemp[e] - (HOTEND_OVERSHOOT); }
#endif
#if HAS_HEATED_BED
static bed_info_t temp_bed;
#endif
@ -965,12 +1033,16 @@ class Temperature {
static constexpr bool adaptive_fan_slowing = true;
#endif
/**
* Update the temp manager when PID values change
*/
// Update the temp manager when PID values change
#if ENABLED(PIDTEMP)
static void updatePID() {
TERN_(PID_EXTRUSION_SCALING, pes_e_position = 0);
static void updatePID() { TERN_(PID_EXTRUSION_SCALING, pes_e_position = 0); }
static void setPID(const uint8_t hotend, const_float_t p, const_float_t i, const_float_t d) {
#if ENABLED(PID_PARAMS_PER_HOTEND)
temp_hotend[hotend].pid.set(p, i, d);
#else
HOTEND_LOOP() temp_hotend[e].pid.set(p, i, d);
#endif
updatePID();
}
#endif