summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormidopple <mdoppler@gmx.at>2012-05-04 09:40:45 +0200
committermidopple <mdoppler@gmx.at>2012-05-04 09:40:45 +0200
commitd2ccafcb779d337eee76b16186db82806cbdeedc (patch)
tree69a14b9a3d258b3dea8501678a5c73d1f0bbf07e
parent5a60fcd6f57d23dbaa1954546e5f869f223854db (diff)
Version 1.3.17T
- M303 - PID relay autotune possible - G4 Wait until last move is done
-rw-r--r--Sprinter/Configuration.h4
-rw-r--r--Sprinter/Sprinter.pde19
-rw-r--r--Sprinter/heater.cpp197
-rw-r--r--Sprinter/heater.h4
4 files changed, 222 insertions, 2 deletions
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<temperature> 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<temperature> 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();