From d2ccafcb779d337eee76b16186db82806cbdeedc Mon Sep 17 00:00:00 2001 From: midopple Date: Fri, 4 May 2012 09:40:45 +0200 Subject: Version 1.3.17T - M303 - PID relay autotune possible - G4 Wait until last move is done --- Sprinter/Configuration.h | 4 + Sprinter/Sprinter.pde | 19 ++++- Sprinter/heater.cpp | 197 +++++++++++++++++++++++++++++++++++++++++++++++ Sprinter/heater.h | 4 + 4 files changed, 222 insertions(+), 2 deletions(-) (limited to 'Sprinter') diff --git a/Sprinter/Configuration.h b/Sprinter/Configuration.h index 9f76861..3cb9644 100644 --- a/Sprinter/Configuration.h +++ b/Sprinter/Configuration.h @@ -287,6 +287,10 @@ const int dropsegments=5; //everything with less than this number of steps will //Command M601 / Command M602 Reset the MIN/MAX Value //#define DEBUG_HEATER_TEMP +// M303 - PID relay autotune S sets the target temperature. +// (default target temperature = 150C) +#define PID_AUTOTUNE + //PID Controler Settings #define PID_INTEGRAL_DRIVE_MAX 80 // too big, and heater will lag after changing temperature, too small and it might not compensate enough for long-term errors #define PID_PGAIN 2560 //256 is 1.0 // value of X means that error of 1 degree is changing PWM duty by X, probably no need to go over 25 diff --git a/Sprinter/Sprinter.pde b/Sprinter/Sprinter.pde index b5d0489..e3c146c 100644 --- a/Sprinter/Sprinter.pde +++ b/Sprinter/Sprinter.pde @@ -116,6 +116,10 @@ Version 1.3.16T - Extra Max Feedrate for Retract (MAX_RETRACT_FEEDRATE) + Version 1.3.17T +- M303 - PID relay autotune possible +- G4 Wait until last move is done + */ @@ -207,6 +211,8 @@ void __cxa_pure_virtual(){}; // M220 - set speed factor override percentage S:factor in percent // M221 - set extruder multiply factor S100 --> original Extrude Speed +// M303 - PID relay autotune S sets the target temperature. (default target temperature = 150C) + // M500 - stores paramters in EEPROM // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. @@ -218,7 +224,7 @@ void __cxa_pure_virtual(){}; // M603 - Show Free Ram -#define _VERSION_TEXT "1.3.16T / 24.04.2012" +#define _VERSION_TEXT "1.3.17T / 04.05.2012" //Stepper Movement Variables char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; @@ -1121,6 +1127,7 @@ FORCE_INLINE void process_commands() if(code_seen('P')) codenum = code_value(); // milliseconds to wait if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait codenum += millis(); // keep track of when we started waiting + st_synchronize(); // wait for all movements to finish while(millis() < codenum ){ manage_heater(); } @@ -1795,7 +1802,15 @@ FORCE_INLINE void process_commands() } } break; - +#ifdef PID_AUTOTUNE + case 303: // M303 PID autotune + { + float help_temp = 150.0; + if (code_seen('S')) help_temp=code_value(); + PID_autotune(help_temp); + } + break; +#endif #ifdef USE_EEPROM_SETTINGS case 500: // Store settings in EEPROM { diff --git a/Sprinter/heater.cpp b/Sprinter/heater.cpp index 6d980ff..ebab2a5 100644 --- a/Sprinter/heater.cpp +++ b/Sprinter/heater.cpp @@ -295,6 +295,203 @@ ISR(TIMER2_OVF_vect) #endif //--------------------END SOFT PWM--------------------------- +//-------------------- START PID AUTOTUNE --------------------------- +// Based on PID relay test +// Thanks to Erik van der Zalm for this idea to use it for Marlin +// Some information see: +// http://brettbeauregard.com/blog/2012/01/arduino-pid-autotune-library/ +//------------------------------------------------------------------ +#ifdef PID_AUTOTUNE +void PID_autotune(int PIDAT_test_temp) +{ + float PIDAT_input = 0; + int PIDAT_input_help = 0; + unsigned char PIDAT_count_input = 0; + + float PIDAT_max, PIDAT_min; + + unsigned char PIDAT_PWM_val = 255; + + unsigned char PIDAT_cycles=0; + bool PIDAT_heating = true; + + unsigned long PIDAT_temp_millis = millis(); + unsigned long PIDAT_t1=PIDAT_temp_millis; + unsigned long PIDAT_t2=PIDAT_temp_millis; + unsigned long PIDAT_T_check_AI_val = PIDAT_temp_millis; + + unsigned char PIDAT_cycle_cnt = 0; + + long PIDAT_t_high; + long PIDAT_t_low; + + long PIDAT_bias= 127; + long PIDAT_d = 127; + + float PIDAT_Ku, PIDAT_Tu; + float PIDAT_Kp, PIDAT_Ki, PIDAT_Kd; + + #define PIDAT_TIME_FACTOR ((HEATER_CHECK_INTERVAL*256.0) / 1000.0) + + showString(PSTR("PID Autotune start\r\n")); + + target_temp = PIDAT_test_temp; + + #ifdef BED_USES_THERMISTOR + WRITE(HEATER_1_PIN,LOW); + #endif + + for(;;) + { + + if((millis() - PIDAT_T_check_AI_val) > 100 ) + { + PIDAT_T_check_AI_val = millis(); + PIDAT_cycle_cnt++; + + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + current_raw = 1023 - current_raw; + PIDAT_input_help += analog2temp(current_raw); + PIDAT_count_input++; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + PIDAT_input_help += analog2temp(current_raw); + PIDAT_count_input++; + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + PIDAT_input_help += analog2temp(current_raw); + PIDAT_count_input++; + #endif + } + + if(PIDAT_cycle_cnt >= 10 ) + { + + PIDAT_cycle_cnt = 0; + + PIDAT_input = (float)PIDAT_input_help / (float)PIDAT_count_input; + PIDAT_input_help = 0; + PIDAT_count_input = 0; + + PIDAT_max=max(PIDAT_max,PIDAT_input); + PIDAT_min=min(PIDAT_min,PIDAT_input); + + if(PIDAT_heating == true && PIDAT_input > PIDAT_test_temp) + { + if(millis() - PIDAT_t2 > 5000) + { + PIDAT_heating = false; + PIDAT_PWM_val = (PIDAT_bias - PIDAT_d); + PIDAT_t1 = millis(); + PIDAT_t_high = PIDAT_t1 - PIDAT_t2; + PIDAT_max = PIDAT_test_temp; + } + } + + if(PIDAT_heating == false && PIDAT_input < PIDAT_test_temp) + { + if(millis() - PIDAT_t1 > 5000) + { + PIDAT_heating = true; + PIDAT_t2 = millis(); + PIDAT_t_low = PIDAT_t2 - PIDAT_t1; + + if(PIDAT_cycles > 0) + { + PIDAT_bias += (PIDAT_d*(PIDAT_t_high - PIDAT_t_low))/(PIDAT_t_low + PIDAT_t_high); + PIDAT_bias = constrain(PIDAT_bias, 20 ,235); + if(PIDAT_bias > 127) PIDAT_d = 254 - PIDAT_bias; + else PIDAT_d = PIDAT_bias; + + showString(PSTR(" bias: ")); Serial.print(PIDAT_bias); + showString(PSTR(" d: ")); Serial.print(PIDAT_d); + showString(PSTR(" min: ")); Serial.print(PIDAT_min); + showString(PSTR(" max: ")); Serial.println(PIDAT_max); + + if(PIDAT_cycles > 2) + { + PIDAT_Ku = (4.0*PIDAT_d)/(3.14159*(PIDAT_max-PIDAT_min)); + PIDAT_Tu = ((float)(PIDAT_t_low + PIDAT_t_high)/1000.0); + + showString(PSTR(" Ku: ")); Serial.print(PIDAT_Ku); + showString(PSTR(" Tu: ")); Serial.println(PIDAT_Tu); + + PIDAT_Kp = 0.60*PIDAT_Ku; + PIDAT_Ki = 2*PIDAT_Kp/PIDAT_Tu; + PIDAT_Kd = PIDAT_Kp*PIDAT_Tu/8; + showString(PSTR(" Clasic PID \r\n")); + //showString(PSTR(" Kp: ")); Serial.println(PIDAT_Kp); + //showString(PSTR(" Ki: ")); Serial.println(PIDAT_Ki); + //showString(PSTR(" Kd: ")); Serial.println(PIDAT_Kd); + showString(PSTR(" CFG Kp: ")); Serial.println((unsigned int)(PIDAT_Kp*256)); + showString(PSTR(" CFG Ki: ")); Serial.println((unsigned int)(PIDAT_Ki*PIDAT_TIME_FACTOR)); + showString(PSTR(" CFG Kd: ")); Serial.println((unsigned int)(PIDAT_Kd*PIDAT_TIME_FACTOR)); + + PIDAT_Kp = 0.30*PIDAT_Ku; + PIDAT_Ki = PIDAT_Kp/PIDAT_Tu; + PIDAT_Kd = PIDAT_Kp*PIDAT_Tu/3; + showString(PSTR(" Some overshoot \r\n")); + showString(PSTR(" CFG Kp: ")); Serial.println((unsigned int)(PIDAT_Kp*256)); + showString(PSTR(" CFG Ki: ")); Serial.println((unsigned int)(PIDAT_Ki*PIDAT_TIME_FACTOR)); + showString(PSTR(" CFG Kd: ")); Serial.println((unsigned int)(PIDAT_Kd*PIDAT_TIME_FACTOR)); + /* + PIDAT_Kp = 0.20*PIDAT_Ku; + PIDAT_Ki = 2*PIDAT_Kp/PIDAT_Tu; + PIDAT_Kd = PIDAT_Kp*PIDAT_Tu/3; + showString(PSTR(" No overshoot \r\n")); + showString(PSTR(" CFG Kp: ")); Serial.println((unsigned int)(PIDAT_Kp*256)); + showString(PSTR(" CFG Ki: ")); Serial.println((unsigned int)(PIDAT_Ki*PIDAT_TIME_FACTOR)); + showString(PSTR(" CFG Kd: ")); Serial.println((unsigned int)(PIDAT_Kd*PIDAT_TIME_FACTOR)); + */ + } + } + PIDAT_PWM_val = (PIDAT_bias + PIDAT_d); + PIDAT_cycles++; + PIDAT_min = PIDAT_test_temp; + } + } + + #ifdef PID_SOFT_PWM + g_heater_pwm_val = PIDAT_PWM_val; + #else + analogWrite_check(HEATER_0_PIN, PIDAT_PWM_val); + #if LED_PIN>-1 + analogWrite_check(LED_PIN, PIDAT_PWM_val); + #endif + #endif + } + + if(PIDAT_input > (PIDAT_test_temp + 20)) + { + showString(PSTR("PID Autotune failed! Temperature to high\r\n")); + return; + } + + if(millis() - PIDAT_temp_millis > 2000) + { + PIDAT_temp_millis = millis(); + showString(PSTR("ok T:")); + Serial.print(PIDAT_input); + showString(PSTR(" @:")); + Serial.println((unsigned char)PIDAT_PWM_val*1); + } + + if(((millis() - PIDAT_t1) + (millis() - PIDAT_t2)) > (10L*60L*1000L*2L)) + { + showString(PSTR("PID Autotune failed! timeout\r\n")); + return; + } + + if(PIDAT_cycles > 5) + { + showString(PSTR("PID Autotune finished ! Place the Kp, Ki and Kd constants in the configuration.h\r\n")); + return; + } + } +} +#endif +//---------------- END AUTOTUNE PID ------------------------------ void manage_heater() { diff --git a/Sprinter/heater.h b/Sprinter/heater.h index 6e00a37..87b6b4d 100644 --- a/Sprinter/heater.h +++ b/Sprinter/heater.h @@ -119,4 +119,8 @@ extern unsigned char manage_monitor; void init_Timer2_softpwm(void); #endif +#ifdef PID_AUTOTUNE + void PID_autotune(int PIDAT_test_temp); +#endif + void manage_heater(); -- cgit v1.2.1