diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0ec06316f8..2bcfc72833 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -95,10 +95,11 @@ // PID settings: // Comment the following line to disable PID and enable bang-bang. #define PIDTEMP +#define PIDTEMPBED #define PID_MAX 255 // limits current to nozzle; 255=full current #ifdef PIDTEMP //#define PID_DEBUG // Sends debug data to the serial port. - //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % + //#define PID_OPENLOOP 1 // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX #define PID_INTEGRAL_DRIVE_MAX 255 //limit for the integral term #define K1 0.95 //smoothing factor withing the PID #define PID_dT ((16.0 * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the @@ -114,6 +115,16 @@ // #define DEFAULT_Ki 0.1 // #define DEFAULT_Kd 12 +//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, argressive factor of .15 (vs .1, 1, 10) + #define DEFAULT_bedKp 10.00 + #define DEFAULT_bedKi .023 + #define DEFAULT_bedKd 305.4 + +//mark from pidautotune +// #define DEFAULT_bedKp 97.1 +// #define DEFAULT_bedKi 1.41 +// #define DEFAULT_bedKd 1675.16 + // Mendel Parts V9 on 12V // #define DEFAULT_Kp 63.0 // #define DEFAULT_Ki 2.25 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 5c46e7355f..91fbac52cd 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -113,6 +113,7 @@ // M221 S- set extrude factor override percentage // M240 - Trigger a camera to take a photograph // M301 - Set PID parameters P I and D +// M304 - Set bed PID parameters P I and D // M302 - Allow cold extrudes // M303 - PID relay autotune S sets the target temperature. (default target temperature = 150C) // M400 - Finish all moves @@ -1002,6 +1003,10 @@ void process_commands() #ifdef PIDTEMP SERIAL_PROTOCOLPGM(" @:"); SERIAL_PROTOCOL(getHeaterPower(tmp_extruder)); + #endif + #ifdef PIDTEMPBED + SERIAL_PROTOCOLPGM(" B@:"); + SERIAL_PROTOCOL(getHeaterPower(-1)); #endif SERIAL_PROTOCOLLN(""); return; @@ -1405,6 +1410,24 @@ void process_commands() } break; #endif //PIDTEMP + #ifdef PIDTEMPBED + case 304: // M304 + { + if(code_seen('P')) bedKp = code_value(); + if(code_seen('I')) bedKi = code_value()*PID_dT; + if(code_seen('D')) bedKd = code_value()/PID_dT; + updatePID(); + SERIAL_PROTOCOL(MSG_OK); + SERIAL_PROTOCOL(" p:"); + SERIAL_PROTOCOL(Kp); + SERIAL_PROTOCOL(" i:"); + SERIAL_PROTOCOL(Ki/PID_dT); + SERIAL_PROTOCOL(" d:"); + SERIAL_PROTOCOL(Kd*PID_dT); + SERIAL_PROTOCOLLN(""); + } + break; + #endif //PIDTEMP case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/ { #ifdef PHOTOGRAPH_PIN @@ -1437,8 +1460,14 @@ void process_commands() case 303: // M303 PID autotune { float temp = 150.0; + int e=0; + int c=5; + if (code_seen('E')) e=code_value(); + if (e<0) + temp=70; if (code_seen('S')) temp=code_value(); - PID_autotune(temp); + if (code_seen('C')) c=code_value(); + PID_autotune(temp, e, c); } break; case 400: // M400 finish all moves diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index a0413f710e..f31f84b260 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -57,6 +57,15 @@ int current_raw_bed = 0; float Kc=DEFAULT_Kc; #endif #endif //PIDTEMP + +#ifdef PIDTEMPBED + // used external + float pid_setpoint_bed = { 0.0 }; + + float bedKp=DEFAULT_bedKp; + float bedKi=(DEFAULT_bedKi*PID_dT); + float bedKd=(DEFAULT_bedKd/PID_dT); +#endif //PIDTEMPBED //=========================================================================== @@ -64,9 +73,6 @@ int current_raw_bed = 0; //=========================================================================== static volatile bool temp_meas_ready = false; -static unsigned long previous_millis_bed_heater; -//static unsigned long previous_millis_heater; - #ifdef PIDTEMP //static cannot be external: static float temp_iState[EXTRUDERS] = { 0 }; @@ -82,7 +88,20 @@ static unsigned long previous_millis_bed_heater; // static float pid_output[EXTRUDERS]; static bool pid_reset[EXTRUDERS]; #endif //PIDTEMP +#ifdef PIDTEMPBED + //static cannot be external: + static float temp_iState_bed = { 0 }; + static float temp_dState_bed = { 0 }; + static float pTerm_bed; + static float iTerm_bed; + static float dTerm_bed; + //int output; + static float pid_error_bed; + static float temp_iState_min_bed; + static float temp_iState_max_bed; +#endif //PIDTEMPBED static unsigned char soft_pwm[EXTRUDERS]; + static unsigned char soft_pwm_bed; #ifdef WATCHPERIOD int watch_raw[EXTRUDERS] = { -1000 }; // the first value used for all @@ -122,7 +141,7 @@ static unsigned long previous_millis_bed_heater; //============================= functions ============================ //=========================================================================== -void PID_autotune(float temp) +void PID_autotune(float temp, int extruder, int ncycles) { float input; int cycles=0; @@ -139,27 +158,45 @@ void PID_autotune(float temp) float Ku, Tu; float Kp, Ki, Kd; float max, min; - + + if ((extruder > EXTRUDERS) + #if (TEMP_BED_PIN <= -1) + ||(extruder < 0) + #endif + ){ + SERIAL_ECHOLN("PID Autotune failed. Bad extruder number."); + return; + } + SERIAL_ECHOLN("PID Autotune start"); disable_heater(); // switch off all heaters. - - soft_pwm[0] = PID_MAX/2; - - for(;;) { + + if (extruder<0) + soft_pwm_bed = PID_MAX/2; + else + soft_pwm[extruder] = PID_MAX/2; + + + + + for(;;) { if(temp_meas_ready == true) { // temp sample ready CRITICAL_SECTION_START; temp_meas_ready = false; CRITICAL_SECTION_END; - input = analog2temp(current_raw[0], 0); - + input = (extruder<0)?analog2tempBed(current_raw_bed):analog2temp(current_raw[extruder], extruder); + max=max(max,input); min=min(min,input); if(heating == true && input > temp) { if(millis() - t2 > 5000) { heating=false; - soft_pwm[0] = (bias - d) >> 1; + if (extruder<0) + soft_pwm_bed = (bias - d) >> 1; + else + soft_pwm[extruder] = (bias - d) >> 1; t1=millis(); t_high=t1 - t2; max=temp; @@ -210,7 +247,10 @@ void PID_autotune(float temp) */ } } - soft_pwm[0] = (bias + d) >> 1; + if (extruder<0) + soft_pwm_bed = (bias + d) >> 1; + else + soft_pwm[extruder] = (bias + d) >> 1; cycles++; min=temp; } @@ -221,17 +261,26 @@ void PID_autotune(float temp) return; } if(millis() - temp_millis > 2000) { - temp_millis = millis(); - SERIAL_PROTOCOLPGM("ok T:"); - SERIAL_PROTOCOL(degHotend(0)); + int p; + if (extruder<0){ + p=soft_pwm_bed; + SERIAL_PROTOCOLPGM("ok B:"); + }else{ + p=soft_pwm[extruder]; + SERIAL_PROTOCOLPGM("ok T:"); + } + + SERIAL_PROTOCOL(input); SERIAL_PROTOCOLPGM(" @:"); - SERIAL_PROTOCOLLN(getHeaterPower(0)); + SERIAL_PROTOCOLLN(p); + + temp_millis = millis(); } if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout"); return; } - if(cycles > 5) { + if(cycles > ncycles) { SERIAL_PROTOCOLLNPGM("PID Autotune finished ! Place the Kp, Ki and Kd constants in the configuration.h"); return; } @@ -245,19 +294,18 @@ void updatePID() for(int e = 0; e < EXTRUDERS; e++) { temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki; } + temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi; #endif } int getHeaterPower(int heater) { + if (heater<0) + return soft_pwm_bed; return soft_pwm[heater]; } void manage_heater() { -#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER - static int bed_needs_heating=0; - static int bed_is_on=0; -#endif #ifdef USE_WATCHDOG wd_reset(); @@ -298,12 +346,16 @@ void manage_heater() temp_iState[e] += pid_error[e]; temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); iTerm[e] = Ki * temp_iState[e]; + //K1 defined in Configuration.h in the PID settings #define K2 (1.0-K1) dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); temp_dState[e] = pid_input; + pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e], 0, PID_MAX); } + #else + pid_output = constrain(pid_setpoint[e], 0, PID_MAX); #endif //PID_OPENLOOP #ifdef PID_DEBUG SERIAL_ECHOLN(" PIDDEBUG "< -1 - - #ifdef HEATER_BED_DUTY_CYCLE_DIVIDER - bed_needs_heating=0; #endif - #ifndef BED_LIMIT_SWITCHING + #if TEMP_BED_PIN > -1 + + #ifdef PIDTEMPBED + pid_input = analog2tempBed(current_raw_bed); + + #ifndef PID_OPENLOOP + pid_error_bed = pid_setpoint_bed - pid_input; + pTerm_bed = bedKp * pid_error_bed; + temp_iState_bed += pid_error_bed; + temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed); + iTerm_bed = bedKi * temp_iState_bed; + + //K1 defined in Configuration.h in the PID settings + #define K2 (1.0-K1) + dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed); + temp_dState_bed = pid_input; + + pid_output = constrain(pTerm_bed + iTerm_bed - dTerm_bed, 0, PID_MAX); + + #else + pid_output = constrain(pid_setpoint_bed, 0, PID_MAX); + #endif //PID_OPENLOOP + + if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) + { + soft_pwm_bed = (int)pid_output >> 1; + } + else { + soft_pwm_bed = 0; + } + + #elif not defined BED_LIMIT_SWITCHING // Check if temperature is within the correct range if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) { if(current_raw_bed >= target_raw_bed) { - WRITE(HEATER_BED_PIN,LOW); + soft_pwm_bed = 0; } else { - #ifdef HEATER_BED_DUTY_CYCLE_DIVIDER - bed_needs_heating=1; - #endif - WRITE(HEATER_BED_PIN,HIGH); + soft_pwm_bed = 100; } } else { + soft_pwm_bed = 0; WRITE(HEATER_BED_PIN,LOW); } #else //#ifdef BED_LIMIT_SWITCHING @@ -381,18 +449,16 @@ void manage_heater() if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) { if(current_raw_bed > target_bed_high_temp) { - WRITE(HEATER_BED_PIN,LOW); + soft_pwm_bed = 0; } else if(current_raw_bed <= target_bed_low_temp) { - #ifdef HEATER_BED_DUTY_CYCLE_DIVIDER - bed_needs_heating=1; - #endif - WRITE(HEATER_BED_PIN,HIGH); + soft_pwm_bed = 100; } } else { + soft_pwm_bed = 0; WRITE(HEATER_BED_PIN,LOW); } #endif @@ -567,6 +633,8 @@ void tp_init() #ifdef PIDTEMP temp_iState_min[e] = 0.0; temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki; + temp_iState_min_bed = 0.0; + temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi; #endif //PIDTEMP } @@ -728,6 +796,7 @@ void disable_heater() #if TEMP_BED_PIN > -1 target_raw_bed=0; + soft_pwm_bed=0; #if HEATER_BED_PIN > -1 WRITE(HEATER_BED_PIN,LOW); #endif @@ -832,6 +901,7 @@ ISR(TIMER0_COMPB_vect) static unsigned char soft_pwm_0; static unsigned char soft_pwm_1; static unsigned char soft_pwm_2; + static unsigned char soft_pwm_b; if(pwm_count == 0){ soft_pwm_0 = soft_pwm[0]; @@ -844,6 +914,10 @@ ISR(TIMER0_COMPB_vect) soft_pwm_2 = soft_pwm[2]; if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); #endif + #if HEATER_BED_PIN > -1 + soft_pwm_b = soft_pwm_bed; + if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); + #endif } if(soft_pwm_0 <= pwm_count) WRITE(HEATER_0_PIN,0); #if EXTRUDERS > 1 @@ -852,6 +926,9 @@ ISR(TIMER0_COMPB_vect) #if EXTRUDERS > 2 if(soft_pwm_2 <= pwm_count) WRITE(HEATER_2_PIN,0); #endif + #if HEATER_BED_PIN > -1 + if(soft_pwm_b <= pwm_count) WRITE(HEATER_BED_PIN,0); + #endif pwm_count++; pwm_count &= 0x7f; diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 1848c703dd..ae289de41f 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -46,11 +46,15 @@ extern int current_raw_bed; extern int target_bed_low_temp ; extern int target_bed_high_temp ; #endif -extern float Kp,Ki,Kd,Kc; #ifdef PIDTEMP + extern float Kp,Ki,Kd,Kc; extern float pid_setpoint[EXTRUDERS]; #endif +#ifdef PIDTEMPBED + extern float bedKp,bedKi,bedKd; + extern float pid_setpoint_bed; +#endif // #ifdef WATCHPERIOD extern int watch_raw[EXTRUDERS] ; @@ -88,7 +92,9 @@ FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) { FORCE_INLINE void setTargetBed(const float &celsius) { target_raw_bed = temp2analogBed(celsius); - #ifdef BED_LIMIT_SWITCHING + #ifdef PIDTEMPBED + pid_setpoint_bed = celsius; + #elif defined BED_LIMIT_SWITCHING if(celsius>BED_HYSTERESIS) { target_bed_low_temp= temp2analogBed(celsius-BED_HYSTERESIS); @@ -163,7 +169,7 @@ FORCE_INLINE void autotempShutdown(){ #endif } -void PID_autotune(float temp); +void PID_autotune(float temp, int extruder, int ncycles); #endif - +