chiark / gitweb /
Added PID autotune. (experimental)
authorErik van der Zalm <erik@vdzalm.eu>
Thu, 8 Mar 2012 20:43:21 +0000 (21:43 +0100)
committerErik van der Zalm <erik@vdzalm.eu>
Thu, 8 Mar 2012 20:43:21 +0000 (21:43 +0100)
M303 Starts autotune. Wait till the Kp Ki and Kd constants are printed.
Put these values in Configuration.h

Marlin/Marlin.pde
Marlin/pins.h
Marlin/temperature.cpp
Marlin/temperature.h
Marlin/ultralcd.pde

index e82afabd48b69fbd377ee696ec09f37bd283eb5a..bdcb22afe9773a5de5beae6aa093cb967edddf8c 100644 (file)
 // 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.
 // M503 - print the current settings (from memory not from eeprom)
+// M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
 
 //Stepper Movement Variables
 
@@ -1197,6 +1198,13 @@ void process_commands()
       allow_cold_extrudes(true);
     }
     break;
+    case 303: // M303 PID autotune
+    {
+      float temp = 150.0;
+      if (code_seen('S')) temp=code_value();
+      PID_autotune(temp);
+    }
+    break;
     case 400: // finish all moves
     {
       st_synchronize();
index e1f9b842372fc51a403064cc80885c878630d999..bf0ce3e361c04e13b77a1c180725e092e190aab0 100644 (file)
     #define encrot2 3
     #define encrot3 1
 
-    
+    #define SDCARDDETECT -1
     //bits in the shift register that carry the buttons for:
     // left up center down right red
     #define BL_LE 7
index 77f9491abd2487b51d0583d30f5c68a9c87e7efa..da945ad0e9f5586f39beb68cc1214032a216a279 100644 (file)
@@ -62,7 +62,7 @@ int current_raw_bed = 0;
 //===========================================================================
 //=============================private variables============================
 //===========================================================================
-static bool temp_meas_ready = false;
+static volatile bool temp_meas_ready = false;
 
 static unsigned long  previous_millis_bed_heater;
 //static unsigned long previous_millis_heater;
@@ -132,7 +132,94 @@ static unsigned long  previous_millis_bed_heater;
 //===========================================================================
 //=============================   functions      ============================
 //===========================================================================
+
+void PID_autotune(float temp)
+{
+  float input;
+  int cycles=0;
+  bool heating = true;
+  soft_pwm[0] = 255>>1;
+
+  unsigned long temp_millis = millis();
+  unsigned long t1=temp_millis;
+  unsigned long t2=temp_millis;
+  long t_high;
+  long t_low;
+
+  long bias=127;
+  long d = 127;
+  float Ku, Tu;
+  float Kp, Ki, Kd;
+  float max, min;
   
+  SERIAL_ECHOLN("PID Autotune start");
+
+  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);
+      
+      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;
+          t1=millis();
+          t_high=t1 - t2;
+          max=temp;
+        }
+      }
+      if(heating == false && input < temp) {
+        if(millis() - t1 > 5000) {
+          heating=true;
+          t2=millis();
+          t_low=t2 - t1;
+          if(cycles > 0) {
+            bias += (d*(t_high - t_low))/(t_low + t_high);
+            bias = constrain(bias, 20 ,235);
+            if(bias > 127) d = 254 - bias;
+            else d = bias;
+
+            SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias);
+            SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d);
+            SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min);
+            SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max);
+            if(cycles > 2) {
+              Ku = (4.0*d)/(3.14159*(max-min)/2.0);
+              Tu = ((float)(t_low + t_high)/1000.0);
+              Kp = 0.6*Ku;
+              Ki = 2*Kp/Tu;
+              Kd = Kp*Tu/8;
+              SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
+              SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
+              SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
+            }
+          }
+          soft_pwm[0] = (bias + d) >> 1;
+          cycles++;
+          min=temp;
+        }
+      } 
+    }
+    if(input > (temp + 20)) {
+      SERIAL_PROTOCOLLNPGM("PID Autotune failed !!!, Temperature to high");
+      return;
+    }
+    if(millis() - temp_millis > 2000) {
+      temp_millis = millis();
+      SERIAL_PROTOCOLPGM("ok T:");
+      SERIAL_PROTOCOL(degHotend(0));   
+      SERIAL_PROTOCOLPGM(" @:");
+      SERIAL_PROTOCOLLN(getHeaterPower(0));       
+    }
+    LCD_STATUS;
+  }
+}
+
 void updatePID()
 {
 #ifdef PIDTEMP
index 80e68f78b45e0ba46e515d2f553dc04f279305ef..c7a457fa15cf52d08b721e63e4ceccad022f7a12 100644 (file)
-/*\r
-  temperature.h - temperature controller\r
-  Part of Marlin\r
-\r
-  Copyright (c) 2011 Erik van der Zalm\r
-\r
-  Grbl is free software: you can redistribute it and/or modify\r
-  it under the terms of the GNU General Public License as published by\r
-  the Free Software Foundation, either version 3 of the License, or\r
-  (at your option) any later version.\r
-\r
-  Grbl is distributed in the hope that it will be useful,\r
-  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  GNU General Public License for more details.\r
-\r
-  You should have received a copy of the GNU General Public License\r
-  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#ifndef temperature_h\r
-#define temperature_h \r
-\r
-#include "Marlin.h"\r
-#include "planner.h"\r
-#ifdef PID_ADD_EXTRUSION_RATE\r
-  #include "stepper.h"\r
-#endif\r
-\r
-// public functions\r
-void tp_init();  //initialise the heating\r
-void manage_heater(); //it is critical that this is called periodically.\r
-\r
-//low leven conversion routines\r
-// do not use this routines and variables outsie of temperature.cpp\r
-int temp2analog(int celsius, uint8_t e);\r
-int temp2analogBed(int celsius);\r
-float analog2temp(int raw, uint8_t e);\r
-float analog2tempBed(int raw);\r
-extern int target_raw[EXTRUDERS];  \r
-extern int heatingtarget_raw[EXTRUDERS];  \r
-extern int current_raw[EXTRUDERS];\r
-extern int target_raw_bed;\r
-extern int current_raw_bed;\r
-#ifdef BED_LIMIT_SWITCHING\r
-  extern int target_bed_low_temp ;  \r
-  extern int target_bed_high_temp ;\r
-#endif\r
-extern float Kp,Ki,Kd,Kc;\r
-\r
-#ifdef PIDTEMP\r
-  extern float pid_setpoint[EXTRUDERS];\r
-#endif\r
-  \r
-// #ifdef WATCHPERIOD\r
-  extern int watch_raw[EXTRUDERS] ;\r
-//   extern unsigned long watchmillis;\r
-// #endif\r
-\r
-\r
-//high level conversion routines, for use outside of temperature.cpp\r
-//inline so that there is no performance decrease.\r
-//deg=degreeCelsius\r
-\r
-FORCE_INLINE float degHotend(uint8_t extruder) {  \r
-  return analog2temp(current_raw[extruder], extruder);\r
-};\r
-\r
-FORCE_INLINE float degBed() {\r
-  return analog2tempBed(current_raw_bed);\r
-};\r
-\r
-FORCE_INLINE float degTargetHotend(uint8_t extruder) {  \r
-  return analog2temp(target_raw[extruder], extruder);\r
-};\r
-\r
-FORCE_INLINE float degTargetBed() {   \r
-  return analog2tempBed(target_raw_bed);\r
-};\r
-\r
-FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {  \r
-  target_raw[extruder] = temp2analog(celsius, extruder);\r
-#ifdef PIDTEMP\r
-  pid_setpoint[extruder] = celsius;\r
-#endif //PIDTEMP\r
-};\r
-\r
-FORCE_INLINE void setTargetBed(const float &celsius) {  \r
-  \r
-  target_raw_bed = temp2analogBed(celsius);\r
-  #ifdef BED_LIMIT_SWITCHING\r
-    if(celsius>BED_HYSTERESIS)\r
-    {\r
-    target_bed_low_temp= temp2analogBed(celsius-BED_HYSTERESIS);\r
-    target_bed_high_temp= temp2analogBed(celsius+BED_HYSTERESIS);\r
-    }\r
-    else\r
-    { \r
-      target_bed_low_temp=0;\r
-      target_bed_high_temp=0;\r
-    }\r
-  #endif\r
-};\r
-\r
-FORCE_INLINE bool isHeatingHotend(uint8_t extruder){  \r
-  return target_raw[extruder] > current_raw[extruder];\r
-};\r
-\r
-FORCE_INLINE bool isHeatingBed() {\r
-  return target_raw_bed > current_raw_bed;\r
-};\r
-\r
-FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {  \r
-  return target_raw[extruder] < current_raw[extruder];\r
-};\r
-\r
-FORCE_INLINE bool isCoolingBed() {\r
-  return target_raw_bed < current_raw_bed;\r
-};\r
-\r
-#define degHotend0() degHotend(0)\r
-#define degTargetHotend0() degTargetHotend(0)\r
-#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)\r
-#define isHeatingHotend0() isHeatingHotend(0)\r
-#define isCoolingHotend0() isCoolingHotend(0)\r
-#if EXTRUDERS > 1\r
-#define degHotend1() degHotend(1)\r
-#define degTargetHotend1() degTargetHotend(1)\r
-#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)\r
-#define isHeatingHotend1() isHeatingHotend(1)\r
-#define isCoolingHotend1() isCoolingHotend(1)\r
-#endif\r
-#if EXTRUDERS > 2\r
-#define degHotend2() degHotend(2)\r
-#define degTargetHotend2() degTargetHotend(2)\r
-#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)\r
-#define isHeatingHotend2() isHeatingHotend(2)\r
-#define isCoolingHotend2() isCoolingHotend(2)\r
-#endif\r
-#if EXTRUDERS > 3\r
-#error Invalid number of extruders\r
-#endif\r
-\r
-\r
-\r
-int getHeaterPower(int heater);\r
-void disable_heater();\r
-void setWatch();\r
-void updatePID();\r
-\r
-FORCE_INLINE void autotempShutdown(){\r
- #ifdef AUTOTEMP\r
- if(autotemp_enabled)\r
- {\r
-  autotemp_enabled=false;\r
-  if(degTargetHotend(ACTIVE_EXTRUDER)>autotemp_min)\r
-    setTargetHotend(0,ACTIVE_EXTRUDER);\r
- }\r
- #endif\r
-}\r
-#endif\r
+/*
+  temperature.h - temperature controller
+  Part of Marlin
+
+  Copyright (c) 2011 Erik van der Zalm
+
+  Grbl is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Grbl is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef temperature_h
+#define temperature_h 
+
+#include "Marlin.h"
+#include "planner.h"
+#ifdef PID_ADD_EXTRUSION_RATE
+  #include "stepper.h"
+#endif
+
+// public functions
+void tp_init();  //initialise the heating
+void manage_heater(); //it is critical that this is called periodically.
+
+//low leven conversion routines
+// do not use this routines and variables outsie of temperature.cpp
+int temp2analog(int celsius, uint8_t e);
+int temp2analogBed(int celsius);
+float analog2temp(int raw, uint8_t e);
+float analog2tempBed(int raw);
+extern int target_raw[EXTRUDERS];  
+extern int heatingtarget_raw[EXTRUDERS];  
+extern int current_raw[EXTRUDERS];
+extern int target_raw_bed;
+extern int current_raw_bed;
+#ifdef BED_LIMIT_SWITCHING
+  extern int target_bed_low_temp ;  
+  extern int target_bed_high_temp ;
+#endif
+extern float Kp,Ki,Kd,Kc;
+
+#ifdef PIDTEMP
+  extern float pid_setpoint[EXTRUDERS];
+#endif
+  
+// #ifdef WATCHPERIOD
+  extern int watch_raw[EXTRUDERS] ;
+//   extern unsigned long watchmillis;
+// #endif
+
+
+//high level conversion routines, for use outside of temperature.cpp
+//inline so that there is no performance decrease.
+//deg=degreeCelsius
+
+FORCE_INLINE float degHotend(uint8_t extruder) {  
+  return analog2temp(current_raw[extruder], extruder);
+};
+
+FORCE_INLINE float degBed() {
+  return analog2tempBed(current_raw_bed);
+};
+
+FORCE_INLINE float degTargetHotend(uint8_t extruder) {  
+  return analog2temp(target_raw[extruder], extruder);
+};
+
+FORCE_INLINE float degTargetBed() {   
+  return analog2tempBed(target_raw_bed);
+};
+
+FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {  
+  target_raw[extruder] = temp2analog(celsius, extruder);
+#ifdef PIDTEMP
+  pid_setpoint[extruder] = celsius;
+#endif //PIDTEMP
+};
+
+FORCE_INLINE void setTargetBed(const float &celsius) {  
+  
+  target_raw_bed = temp2analogBed(celsius);
+  #ifdef BED_LIMIT_SWITCHING
+    if(celsius>BED_HYSTERESIS)
+    {
+    target_bed_low_temp= temp2analogBed(celsius-BED_HYSTERESIS);
+    target_bed_high_temp= temp2analogBed(celsius+BED_HYSTERESIS);
+    }
+    else
+    { 
+      target_bed_low_temp=0;
+      target_bed_high_temp=0;
+    }
+  #endif
+};
+
+FORCE_INLINE bool isHeatingHotend(uint8_t extruder){  
+  return target_raw[extruder] > current_raw[extruder];
+};
+
+FORCE_INLINE bool isHeatingBed() {
+  return target_raw_bed > current_raw_bed;
+};
+
+FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {  
+  return target_raw[extruder] < current_raw[extruder];
+};
+
+FORCE_INLINE bool isCoolingBed() {
+  return target_raw_bed < current_raw_bed;
+};
+
+#define degHotend0() degHotend(0)
+#define degTargetHotend0() degTargetHotend(0)
+#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)
+#define isHeatingHotend0() isHeatingHotend(0)
+#define isCoolingHotend0() isCoolingHotend(0)
+#if EXTRUDERS > 1
+#define degHotend1() degHotend(1)
+#define degTargetHotend1() degTargetHotend(1)
+#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
+#define isHeatingHotend1() isHeatingHotend(1)
+#define isCoolingHotend1() isCoolingHotend(1)
+#endif
+#if EXTRUDERS > 2
+#define degHotend2() degHotend(2)
+#define degTargetHotend2() degTargetHotend(2)
+#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
+#define isHeatingHotend2() isHeatingHotend(2)
+#define isCoolingHotend2() isCoolingHotend(2)
+#endif
+#if EXTRUDERS > 3
+#error Invalid number of extruders
+#endif
+
+
+
+int getHeaterPower(int heater);
+void disable_heater();
+void setWatch();
+void updatePID();
+
+FORCE_INLINE void autotempShutdown(){
+ #ifdef AUTOTEMP
+ if(autotemp_enabled)
+ {
+  autotemp_enabled=false;
+  if(degTargetHotend(ACTIVE_EXTRUDER)>autotemp_min)
+    setTargetHotend(0,ACTIVE_EXTRUDER);
+ }
+ #endif
+}
+
+void PID_autotune(float temp);
+
+#endif
 \r
index 47dc2d5cc90f593f8c5c33863d1d91f6faa2a8ad..0f4861b131c16897b3e9d59ac2865a834ba55844 100644 (file)
@@ -315,19 +315,18 @@ void MainMenu::showStatus()
   static int olddegHotEnd0=-1;
   static int oldtargetHotEnd0=-1;
   //force_lcd_update=true;
-  if(force_lcd_update||feedmultiplychanged)  //initial display of content
+  if(force_lcd_update)  //initial display of content
   {
-    feedmultiplychanged=false;
     encoderpos=feedmultiply;
     clear();
-    lcd.setCursor(0,0);lcdprintPGM("\002123/567\001 ");
+    lcd.setCursor(0,0);lcdprintPGM("\002---/---\001 ");
     #if defined BED_USES_THERMISTOR || defined BED_USES_AD595 
-      lcd.setCursor(10,0);lcdprintPGM("B123/567\001 ");
+      lcd.setCursor(10,0);lcdprintPGM("B---/---\001 ");
     #endif
   }
     
   int tHotEnd0=intround(degHotend0());
-  if((abs(tHotEnd0-olddegHotEnd0)>1)||force_lcd_update) //>1 because otherwise the lcd is refreshed to often.
+  if((tHotEnd0!=olddegHotEnd0)||force_lcd_update)
   {
     lcd.setCursor(1,0);
     lcd.print(ftostr3(tHotEnd0));
@@ -379,8 +378,15 @@ void MainMenu::showStatus()
     lcdprintPGM("Z:");lcd.print(ftostr52(current_position[2]));
     oldzpos=currentz;
   }
+  
   static int oldfeedmultiply=0;
   int curfeedmultiply=feedmultiply;
+  
+  if(feedmultiplychanged == true) {
+    feedmultiplychanged == false;
+    encoderpos = curfeedmultiply;
+  }
+  
   if(encoderpos!=curfeedmultiply||force_lcd_update)
   {
    curfeedmultiply=encoderpos;
@@ -391,12 +397,14 @@ void MainMenu::showStatus()
    feedmultiply=curfeedmultiply;
    encoderpos=curfeedmultiply;
   }
+  
   if((curfeedmultiply!=oldfeedmultiply)||force_lcd_update)
   {
    oldfeedmultiply=curfeedmultiply;
    lcd.setCursor(0,2);
    lcd.print(itostr3(curfeedmultiply));lcdprintPGM("% ");
   }
+  
   if(messagetext[0]!='\0')
   {
     lcd.setCursor(0,LCD_HEIGHT-1);
@@ -404,7 +412,6 @@ void MainMenu::showStatus()
     uint8_t n=strlen(messagetext);
     for(int8_t i=0;i<LCD_WIDTH-n;i++)
       lcd.print(" ");
-    
     messagetext[0]='\0';
   }