From bf2c923db57cf8d41a2d163a8ad691fc51d59635 Mon Sep 17 00:00:00 2001 From: grob6000 Date: Sun, 11 Jan 2015 13:50:17 +1100 Subject: [PATCH] Make multiple PID parameters a config option * Adds config parameter `PID_PARAMS_PER_EXTRUDER` - allows single PID parameters to be used where this would be preferable (e.g. dual identical extruders) * When disabled, will use `float Kp, Ki, Kd, Kc;` as before. Preprocessor macros used to switch between. * ultralcd.cpp defines extra menus for extra parameters only where required * M301 reports `e:xx` only if independent pid parameters enabled * EEPROM structure still leaves space for 3 extruders worth, when undef will save single parameter to all extruder positions, but only read the first * Switching off saves approx 330 B with no LCD enabled, 2634B with LCD (RRD) enabled: this is significant. * LCD modifications should be tested. --- Marlin/Configuration.h | 2 + Marlin/ConfigurationStore.cpp | 38 ++++++++++--------- Marlin/Marlin_main.cpp | 22 ++++++----- Marlin/temperature.cpp | 25 +++++++++---- Marlin/temperature.h | 9 ++++- Marlin/ultralcd.cpp | 70 ++++++++++++++++++----------------- 6 files changed, 96 insertions(+), 70 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index dfc1965e6..4e0786199 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -152,6 +152,8 @@ //#define PID_DEBUG // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay + //#define PID_PARAMS_PER_EXTRUDER // Uses separate PID parameters for each extruder (useful for mismatched extruders) + // Set/get with gcode: M301 E[extruder number, 0-2] #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature // is more then PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. #define PID_INTEGRAL_DRIVE_MAX PID_MAX //limit for the integral term diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index d0fdde75a..9a64d19f5 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -81,11 +81,11 @@ void Config_StoreSettings() { if (e < EXTRUDERS) { - EEPROM_WRITE_VAR(i,Kp[e]); - EEPROM_WRITE_VAR(i,Ki[e]); - EEPROM_WRITE_VAR(i,Kd[e]); + EEPROM_WRITE_VAR(i,PID_PARAM(Kp,e)); + EEPROM_WRITE_VAR(i,PID_PARAM(Ki,e)); + EEPROM_WRITE_VAR(i,PID_PARAM(Kd,e)); #ifdef PID_ADD_EXTRUSION_RATE - EEPROM_WRITE_VAR(i,Kc[e]); + EEPROM_WRITE_VAR(i,PID_PARAM(Kc,e)); #else//PID_ADD_EXTRUSION_RATE dummy = 1.0f; // 1.0 = default kc EEPROM_WRITE_VAR(dummmy); @@ -232,9 +232,9 @@ SERIAL_ECHOLNPGM("Scaling factors:"); SERIAL_ECHO_START; SERIAL_ECHOLNPGM("PID settings:"); SERIAL_ECHO_START; - SERIAL_ECHOPAIR(" M301 P", Kp[0]); // for compatibility with hosts, only echos values for E0 - SERIAL_ECHOPAIR(" I" ,unscalePID_i(Ki[0])); - SERIAL_ECHOPAIR(" D" ,unscalePID_d(Kd[0])); + SERIAL_ECHOPAIR(" M301 P", PID_PARAM(Kp,0)); // for compatibility with hosts, only echos values for E0 + SERIAL_ECHOPAIR(" I", unscalePID_i(PID_PARAM(Ki, 0))); + SERIAL_ECHOPAIR(" D", unscalePID_d(PID_PARAM(Kd, 0))); SERIAL_ECHOLN(""); #endif//PIDTEMP #ifdef FWRETRACT @@ -341,11 +341,11 @@ void Config_RetrieveSettings() if (e < EXTRUDERS) { // do not need to scale PID values as the values in EEPROM are already scaled - EEPROM_READ_VAR(i,Kp[e]); - EEPROM_READ_VAR(i,Ki[e]); - EEPROM_READ_VAR(i,Kd[e]); + EEPROM_READ_VAR(i,PID_PARAM(Kp,e)); + EEPROM_READ_VAR(i,PID_PARAM(Ki,e)); + EEPROM_READ_VAR(i,PID_PARAM(Kd,e)); #ifdef PID_ADD_EXTRUSION_RATE - EEPROM_READ_VAR(i,Kc[e]); + EEPROM_READ_VAR(i,PID_PARAM(Kc,e)); #else//PID_ADD_EXTRUSION_RATE EEPROM_READ_VAR(i,dummy); #endif//PID_ADD_EXTRUSION_RATE @@ -470,14 +470,18 @@ void Config_ResetDefault() lcd_contrast = DEFAULT_LCD_CONTRAST; #endif//DOGLCD #ifdef PIDTEMP +#ifdef PID_PARAMS_PER_EXTRUDER for (int e = 0; e < EXTRUDERS; e++) +#else // PID_PARAMS_PER_EXTRUDER + int e = 0; // only need to write once +#endif // PID_PARAMS_PER_EXTRUDER { - Kp[e] = DEFAULT_Kp; - Ki[e] = scalePID_i(DEFAULT_Ki); - Kd[e] = scalePID_d(DEFAULT_Kd); -#ifdef PID_ADD_EXTRUSION_RATE - Kc[e] = DEFAULT_Kc; -#endif//PID_ADD_EXTRUSION_RATE + PID_PARAM(Kp,e) = DEFAULT_Kp; + PID_PARAM(Ki,e) = scalePID_i(DEFAULT_Ki); + PID_PARAM(Kd,e) = scalePID_d(DEFAULT_Kd); + #ifdef PID_ADD_EXTRUSION_RATE + PID_PARAM(Kc,e) = DEFAULT_Kc; + #endif//PID_ADD_EXTRUSION_RATE } // call updatePID (similar to when we have processed M301) updatePID(); diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 203f52cb4..38af8cda9 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3209,27 +3209,29 @@ Sigma_Exit: if (e < EXTRUDERS) // catch bad input value { - if (code_seen('P')) Kp[e] = code_value(); - if (code_seen('I')) Ki[e] = scalePID_i(code_value()); - if (code_seen('D')) Kd[e] = scalePID_d(code_value()); + if (code_seen('P')) PID_PARAM(Kp,e) = code_value(); + if (code_seen('I')) PID_PARAM(Ki,e) = scalePID_i(code_value()); + if (code_seen('D')) PID_PARAM(Kd,e) = scalePID_d(code_value()); #ifdef PID_ADD_EXTRUSION_RATE - if (code_seen('C')) Kc[e] = code_value(); + if (code_seen('C')) PID_PARAM(Kc,e) = code_value(); #endif updatePID(); SERIAL_PROTOCOL(MSG_OK); - SERIAL_PROTOCOL(" e:"); // specify extruder in serial output - SERIAL_PROTOCOL(e); + #ifdef PID_PARAMS_PER_EXTRUDER + SERIAL_PROTOCOL(" e:"); // specify extruder in serial output + SERIAL_PROTOCOL(e); + #endif // PID_PARAMS_PER_EXTRUDER SERIAL_PROTOCOL(" p:"); - SERIAL_PROTOCOL(Kp[e]); + SERIAL_PROTOCOL(PID_PARAM(Kp,e)); SERIAL_PROTOCOL(" i:"); - SERIAL_PROTOCOL(unscalePID_i(Ki[e])); + SERIAL_PROTOCOL(unscalePID_i(PID_PARAM(Ki,e))); SERIAL_PROTOCOL(" d:"); - SERIAL_PROTOCOL(unscalePID_d(Kd[e])); + SERIAL_PROTOCOL(unscalePID_d(PID_PARAM(Kd,e))); #ifdef PID_ADD_EXTRUSION_RATE SERIAL_PROTOCOL(" c:"); //Kc does not have scaling applied above, or in resetting defaults - SERIAL_PROTOCOL(Kc[e]); + SERIAL_PROTOCOL(PID_PARAM(Kc,e)); #endif SERIAL_PROTOCOLLN(""); diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 6d6107a7c..f6eadaa48 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -126,12 +126,21 @@ static volatile bool temp_meas_ready = false; #endif #ifdef PIDTEMP +#ifdef PID_PARAMS_PER_EXTRUDER float Kp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(DEFAULT_Kp, DEFAULT_Kp, DEFAULT_Kp); float Ki[EXTRUDERS] = ARRAY_BY_EXTRUDERS(DEFAULT_Ki*PID_dT, DEFAULT_Ki*PID_dT, DEFAULT_Ki*PID_dT); float Kd[EXTRUDERS] = ARRAY_BY_EXTRUDERS(DEFAULT_Kd / PID_dT, DEFAULT_Kd / PID_dT, DEFAULT_Kd / PID_dT); -#ifdef PID_ADD_EXTRUSION_RATE - float Kc[EXTRUDERS] = ARRAY_BY_EXTRUDERS(DEFAULT_Kc, DEFAULT_Kc, DEFAULT_Kc); -#endif + #ifdef PID_ADD_EXTRUSION_RATE + float Kc[EXTRUDERS] = ARRAY_BY_EXTRUDERS(DEFAULT_Kc, DEFAULT_Kc, DEFAULT_Kc); + #endif // PID_ADD_EXTRUSION_RATE +#else //PID_PARAMS_PER_EXTRUDER + float Kp = DEFAULT_Kp; + float Ki = DEFAULT_Ki * PID_dT; + float Kd = DEFAULT_Kd / PID_dT; + #ifdef PID_ADD_EXTRUSION_RATE + float Kc = DEFAULT_Kc; + #endif // PID_ADD_EXTRUSION_RATE +#endif // PID_PARAMS_PER_EXTRUDER #endif //PIDTEMP // Init min and max temp with extreme values to prevent false errors during startup @@ -343,7 +352,7 @@ void updatePID() { #ifdef PIDTEMP for(int e = 0; e < EXTRUDERS; e++) { - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki[e]; + temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / PID_PARAM(Ki,e); } #endif #ifdef PIDTEMPBED @@ -464,14 +473,14 @@ void manage_heater() temp_iState[e] = 0.0; pid_reset[e] = false; } - pTerm[e] = Kp[e] * pid_error[e]; + pTerm[e] = PID_PARAM(Kp,e) * pid_error[e]; temp_iState[e] += pid_error[e]; temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); - iTerm[e] = Ki[e] * temp_iState[e]; + iTerm[e] = PID_PARAM(Ki,e) * temp_iState[e]; //K1 defined in Configuration.h in the PID settings #define K2 (1.0-K1) - dTerm[e] = (Kd[e] * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); + dTerm[e] = (PID_PARAM(Kd,e) * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); pid_output = pTerm[e] + iTerm[e] - dTerm[e]; if (pid_output > PID_MAX) { if (pid_error[e] > 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration @@ -811,7 +820,7 @@ void tp_init() maxttemp[e] = maxttemp[0]; #ifdef PIDTEMP temp_iState_min[e] = 0.0; - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki[e]; + temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / PID_PARAM(Ki,e); #endif //PIDTEMP #ifdef PIDTEMPBED temp_iState_min_bed = 0.0; diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 1c7601964..287b92b3b 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -58,7 +58,14 @@ extern float current_temperature_bed; #endif #ifdef PIDTEMP - extern float Kp[EXTRUDERS], Ki[EXTRUDERS], Kd[EXTRUDERS], Kc[EXTRUDERS]; + + #ifdef PID_PARAMS_PER_EXTRUDER + extern float Kp[EXTRUDERS], Ki[EXTRUDERS], Kd[EXTRUDERS], Kc[EXTRUDERS]; // one param per extruder + #define PID_PARAM(param,e) param[e] // use macro to point to array value + #else + extern float Kp, Ki, Kd, Kc; // one param per extruder - saves 20 or 36 bytes of ram (inc array pointer) + #define PID_PARAM(param, e) param // use macro to point directly to value + #endif // PID_PARAMS_PER_EXTRUDER float scalePID_i(float i); float scalePID_d(float d); float unscalePID_i(float i); diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index db9073e18..0f7645c87 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -790,41 +790,43 @@ static void lcd_control_temperature_menu() #ifdef PIDTEMP // set up temp variables - undo the default scaling pid_current_extruder = 0; - raw_Ki = unscalePID_i(Ki[0]); - raw_Kd = unscalePID_d(Kd[0]); - MENU_ITEM_EDIT(float52, MSG_PID_P, &Kp[0], 1, 9990); + raw_Ki = unscalePID_i(PID_PARAM(Ki,0)); + raw_Kd = unscalePID_d(PID_PARAM(Kd,0)); + MENU_ITEM_EDIT(float52, MSG_PID_P, &PID_PARAM(Kp,0), 1, 9990); // i is typically a small value so allows values below 1 MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d); -# ifdef PID_ADD_EXTRUSION_RATE - MENU_ITEM_EDIT(float3, MSG_PID_C, &Kc[0], 1, 9990); -# endif//PID_ADD_EXTRUSION_RATE -#if EXTRUDERS > 1 - // set up temp variables - undo the default scaling - pid_current_extruder = 1; - raw_Ki = unscalePID_i(Ki[1]); - raw_Kd = unscalePID_d(Kd[1]); - MENU_ITEM_EDIT(float52, MSG_PID_P1, &Kp[1], 1, 9990); - // i is typically a small value so allows values below 1 - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I1, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D1, &raw_Kd, 1, 9990, copy_and_scalePID_d); -# ifdef PID_ADD_EXTRUSION_RATE - MENU_ITEM_EDIT(float3, MSG_PID_C1, &Kc[1], 1, 9990); -# endif//PID_ADD_EXTRUSION_RATE -#endif//EXTRUDERS > 1 -#if EXTRUDERS > 2 - // set up temp variables - undo the default scaling - pid_current_extruder = 2; - raw_Ki = unscalePID_i(Ki[2]); - raw_Kd = unscalePID_d(Kd[2]); - MENU_ITEM_EDIT(float52, MSG_PID_P2, &Kp[2], 1, 9990); - // i is typically a small value so allows values below 1 - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I2, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D2, &raw_Kd, 1, 9990, copy_and_scalePID_d); -# ifdef PID_ADD_EXTRUSION_RATE - MENU_ITEM_EDIT(float3, MSG_PID_C2, &Kc[2], 1, 9990); -# endif//PID_ADD_EXTRUSION_RATE -#endif//EXTRUDERS > 2 + #ifdef PID_ADD_EXTRUSION_RATE + MENU_ITEM_EDIT(float3, MSG_PID_C, &PID_PARAM(Kc,0), 1, 9990); + #endif//PID_ADD_EXTRUSION_RATE +#ifdef PID_PARAMS_PER_EXTRUDER + #if EXTRUDERS > 1 + // set up temp variables - undo the default scaling + pid_current_extruder = 0; + raw_Ki = unscalePID_i(PID_PARAM(Ki,1)); + raw_Kd = unscalePID_d(PID_PARAM(Kd,1)); + MENU_ITEM_EDIT(float52, MSG_PID_P1, &PID_PARAM(Kp,1), 1, 9990); + // i is typically a small value so allows values below 1 + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I1, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D1, &raw_Kd, 1, 9990, copy_and_scalePID_d); + #ifdef PID_ADD_EXTRUSION_RATE + MENU_ITEM_EDIT(float3, MSG_PID_C1, &PID_PARAM(Kc,1), 1, 9990); + #endif//PID_ADD_EXTRUSION_RATE + #endif//EXTRUDERS > 1 + #if EXTRUDERS > 2 + // set up temp variables - undo the default scaling + pid_current_extruder = 0; + raw_Ki = unscalePID_i(PID_PARAM(Ki,2)); + raw_Kd = unscalePID_d(PID_PARAM(Kd,2)); + MENU_ITEM_EDIT(float52, MSG_PID_P2, &PID_PARAM(Kp,2), 1, 9990); + // i is typically a small value so allows values below 1 + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I2, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D2, &raw_Kd, 1, 9990, copy_and_scalePID_d); + #ifdef PID_ADD_EXTRUSION_RATE + MENU_ITEM_EDIT(float3, MSG_PID_C2, &PID_PARAM(Kc,2), 1, 9990); + #endif//PID_ADD_EXTRUSION_RATE + #endif//EXTRUDERS > 2 +#endif // PID_PARAMS_PER_EXTRUDER #endif//PIDTEMP MENU_ITEM(submenu, MSG_PREHEAT_PLA_SETTINGS, lcd_control_temperature_preheat_pla_settings_menu); MENU_ITEM(submenu, MSG_PREHEAT_ABS_SETTINGS, lcd_control_temperature_preheat_abs_settings_menu); @@ -1731,7 +1733,7 @@ char *ftostr52(const float &x) void copy_and_scalePID_i() { #ifdef PIDTEMP - Ki[pid_current_extruder] = scalePID_i(raw_Ki); + PID_PARAM(Ki, pid_current_extruder) = scalePID_i(raw_Ki); updatePID(); #endif } @@ -1741,7 +1743,7 @@ void copy_and_scalePID_i() void copy_and_scalePID_d() { #ifdef PIDTEMP - Kd[pid_current_extruder] = scalePID_d(raw_Kd); + PID_PARAM(Kd, pid_current_extruder) = scalePID_d(raw_Kd); updatePID(); #endif }