Changes between Version 4 and Version 5 of HomeReflow


Ignore:
Timestamp:
Nov 11, 2010 2:27:00 AM (9 years ago)
Author:
sgk
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • HomeReflow

    v4 v5  
    55
    66== 状況 ==
    7  * 遅いけどリフローできた。すばらしい!ハンダごてがばからしくなります。
     7 * PIDライブラリを使わないようにしました。2011/11/10
    88
    99== 課題 ==
     
    3838 * PCをコンソールにするアプリが欲しい。
    3939
    40 == 外部ライブラリ ==
    41  * [http://www.arduino.cc/playground/Code/PIDLibrary PIDライブラリ]
    42 
    4340== `ReflowOven.pde` ==
    4441
     
    4845#!c
    4946#include <LiquidCrystal.h>
    50 #include "PID_Beta6.h"
    5147
    5248/*
     
    9692 */
    9793
    98 
    9994/* PID */
    100 double temperature, output, target;
    101 PID pid(&temperature, &output, &target, 75, 50, 0);
     95const double Kp = 300.0;
     96const double Ki = 200.0;
     97const double Kd = 0.0;
     98double previous, target, integral;
    10299
    103100/* Profile */
    104 const double Rstart = 3.0; // max ramp-up rate to Ts_min
    105 const double Rup = 3.0; // max ramp-up rate from Ts_max to Tpeak
    106 const double Rdown = 6.0; // max ramp-down rate from Tpeak to Ts_max
     101const double Rstart = 3.0;              // max ramp-up rate to Ts_min
     102const double Rup = 3.0;                 // max ramp-up rate from Ts_max to Tpeak
     103const double Rdown = -6.0;              // max ramp-down rate from Tpeak to Ts_max
    107104const double Ts_min = 150.0;
    108105const double Ts_max = 190.0;
    109 const int ts = 120; // pre-heat duration
     106const int ts = 120;                     // pre-heat duration
    110107const double Tpeak = 232.0;
    111108const double TL = 220.0;
    112 const int tL = 50; // keep above TL for tL
     109const int tL = 50;                      // keep above TL for tL
    113110const double Tend = 80.0;
    114111
     
    117114unsigned long nextOff, nextCheck, meltCount;
    118115double slope, destination;
     116int timer;
     117
     118/* Message string */
     119const char* messages[] = {
     120  /* 0 */ "Press to start",
     121  /* 1 */ "Ramp up",
     122  /* 2 */ "Pre-heat",
     123  /* 3 */ "Heat up",
     124  /* 4 */ "Melted",
     125  /* 5 */ "Cool down 1",
     126  /* 6 */ "Cool down 2"
     127};
     128
    119129
    120130void
     
    126136  pinMode(BUTTON, INPUT);
    127137
    128   Serial.begin(9600);
     138  Serial.begin(38400);
    129139  sensorSetup();
    130   pid.SetOutputLimits(0, 1000); // 1000 milliseconds
    131   pid.SetMode(AUTO);
    132140
    133141  lcd.begin(16, 2); // cols, rows
     
    135143  lcd.print("Reflow Oven");
    136144  delay(2000);
    137  
    138   state = nextOff = nextCheck = 0;
     145  lcd.clear();
     146  lcd.print(messages[0]);
     147
     148  state = 0;
     149  nextCheck = 0;
    139150}
    140151
     
    143154 * 1: ramp-up to 150, slope rate between 1.0/sec and 3.0/sec.
    144155 * 2: preheat to 190, for 60 and 120 seconds.
    145  * 3: heat to 232 and keep 232, over 220 for 30 to 60 seconds.
    146  * 5: cool down to under 50
    147  * 6: fail
     156 * 3: heat to 232
     157 * 4: keep 232, over 220 for 30 to 60 seconds.
     158 * 5: cool down to 190, slope rate less than 6.0/sec.
     159 * 6: cool down to under 50
    148160 */
    149161void
     
    151163{
    152164  unsigned long now;
    153   now = millis();
    154  
    155   /* state 0: wait for button presss. */
    156   if (digitalRead(BUTTON) == LOW) {
     165
     166  /* state 0: wait for the start button to be pressed. */
     167  if (state == 0) {
     168    if (digitalRead(BUTTON) == HIGH) {
     169      now = millis();
     170      if (now < nextCheck)
     171        return;
     172      nextCheck = now + 1000;
     173      lcd.clear();
     174      lcd.print(messages[state]);
     175      lcd.setCursor(0, 1);
     176      lcd.print(sensorValue());
     177      lcd.print(0xdf, BYTE);
     178      lcd.print('C');
     179      return;
     180    }
     181
     182    /* pressed */
     183    delay(100);
    157184    while (digitalRead(BUTTON) == LOW)
    158185      delay(100);
    159186    delay(100);
    160     if (state == 0)
    161       state = 9;
    162     else
    163       state = 0;
    164     nextOff = nextCheck = now;
    165   }
    166 
    167   /* Heater */
     187
     188    while ((previous = sensorValue()) == TEMP_ERROR)
     189      ;
     190    nextCheck = 0; // check immediately
     191    timer = 0;
     192  }
     193
     194  /* Current time */
     195  now = millis();
     196
     197  /*
     198   * Heater control until the next check.
     199   */
    168200  if (now < nextCheck) {
    169201    /* PWM on 1Hz */
    170     if (now < nextOff)
    171       digitalWrite(HEATER, true);
    172     else
    173       digitalWrite(HEATER, false);
    174   } else {
    175     /*
    176      * Check
    177      */
    178     nextCheck += 1000; // 1 second
    179     temperature = sensorValue();
     202    digitalWrite(HEATER, (now < nextOff));
     203    return;
     204  }
     205
     206  /*
     207   * Check once a second
     208   */
     209  ++timer;
     210  nextCheck += 1000; // 1 second
     211  double temperature = sensorValue();
     212  if (temperature == TEMP_ERROR)
     213    temperature = previous;
     214
     215  /* Check if the state should be changed. */
     216  switch (state) {
     217  case 0:
     218    state = 1;
     219    integral = 0;
     220    target = temperature;
     221    slope = Rstart;
     222    destination = Ts_min;
     223    break;
     224  case 1:
     225    // ramp-up to 150, slope rate between 1.0/sec and 3.0/sec.
     226    if (temperature >= Ts_min) {
     227      // preheat to 190, for 60 and 120 seconds.
     228      state = 2;
     229      integral = 0;
     230      target = temperature;
     231      slope = (Ts_max - Ts_min) / ts;
     232      destination = Ts_max;
     233    }
     234    break;
     235  case 2:
     236    // preheat to 190, for 60 and 120 seconds.
     237    if (temperature >= Ts_max) {
     238      // heat to 232
     239      state = 3;
     240      integral = 0;
     241      target = temperature;
     242      slope = Rup;
     243      destination = Tpeak;
     244    }
     245    break;
     246  case 3:
     247    // heat to 232
     248    if (temperature >= TL) {
     249      // keep 232 for 30 to 60 seconds.
     250      state = 4;
     251      integral = 0;
     252      target = destination = temperature;
     253      slope = 0;
     254      meltCount = 0;
     255    }
     256    break;
     257  case 4:
     258    // keep 232 for 30 to 60 seconds.
     259    if (++meltCount > tL) {
     260      // cool down to 190
     261      state = 5;
     262      integral = 0;
     263      target = temperature;
     264      slope = Rdown;
     265      destination = Ts_max;
     266    }
     267    break;
     268  case 5:
     269    // cool down to 190
     270    if (temperature <= Ts_max) {
     271      // cool down to under 50
     272      state = 6;
     273      integral = 0;
     274      target = destination = -273.0;
     275      slope = 0;
     276    }
     277    break;
     278  case 6:
     279    // cool down to under 50
     280    if (temperature <= Tend) {
     281      // done
     282      state = 0;
     283    }
     284    break;
     285  }
     286
     287  /* Next target */
     288  target += slope;
     289  if (slope > 0 ? (target > destination) : (target < destination))
     290    target = destination;
     291
     292  /* Heater control value */
     293  double error = target - temperature;
     294  integral += error;
     295  long MV = Kp * error + Ki * integral + Kd * (temperature - previous - slope);
     296  MV = min(max(0, MV), 1000);
     297  nextOff = now + MV;
     298  previous = temperature; // backup for the next calcuration.
     299
     300  /* LCD display */
     301  lcd.clear();
     302  lcd.print(messages[state]);
     303  lcd.setCursor(0, 1);
     304  lcd.print(timer);
     305  lcd.print(' ');
     306  lcd.print(MV);
     307  if (temperature != TEMP_ERROR) {
     308    lcd.print(' ');
     309    lcd.print(temperature);
     310    lcd.print(0xdf, BYTE);
     311    lcd.print('C');
     312  }
    180313 
    181     if (temperature == TEMP_ERROR)
    182       state = 6;
    183    
    184     /* Check if the state changes. */
    185     switch (state) {
    186     case 9:
    187       state = 1;
    188       pid.Reset();
    189       target = temperature;
    190       slope = Rstart;
    191       destination = Ts_min;
    192       break;
    193     case 1:
    194       if (temperature >= Ts_min) {
    195         state = 2;
    196         slope = (Ts_max - Ts_min) / ts;
    197         destination = Ts_max;
    198       }
    199       break;
    200     case 2:
    201       if (temperature >= Ts_max) {
    202         state = 3;
    203         slope = Rup;
    204         destination = Tpeak;
    205         meltCount = 0;
    206       }
    207       break;
    208     case 3:
    209       if (temperature >= TL) {
    210         state = 4;
    211         meltCount = 0;
    212       }
    213       break;
    214     case 4:
    215       if (++meltCount > tL) {
    216         state = 5;
    217         slope = Rdown;
    218         destination = -273.0;
    219       }
    220       break;
    221     case 5:
    222       if (temperature <= Tend)
    223         state = 0;
    224       break;
    225     }
    226  
    227     /* Next target */
    228     switch (state) {
    229     case 1:
    230     case 2:
    231     case 3:
    232       target += slope;
    233       if (target > destination)
    234         target = destination;
    235       break;
    236     case 5:
    237       target -= slope;
    238       if (target < destination)
    239         target = destination;
    240       break;
    241     }
    242    
    243     /* Heater control value */
    244     switch (state) {
    245     case 1:
    246     case 2:
    247     case 3:
    248     case 4:
    249     case 5:
    250       pid.Compute();
    251       nextOff = now + output;
    252       break;
    253      
    254     case 0:
    255     case 6:
    256     default:
    257       nextOff = 0;
    258     }
    259 
    260     /* LCD display */
    261     lcd.clear();
    262     switch (state) {
    263     case 0:
    264       lcd.print("Press to start");
    265       break;
    266     case 1:
    267       lcd.print("Ramp up");
    268       break;
    269     case 2:
    270       lcd.print("Pre-heat");
    271       break;
    272     case 3:
    273       lcd.print("Heat up");
    274       break;
    275     case 4:
    276       lcd.print("Melted");
    277       break;
    278     case 5:
    279       lcd.print("Cool down");
    280       break;
    281     case 6:
    282       lcd.print("Fail");
    283       break;
    284     }
    285     lcd.setCursor(0, 1);
    286     lcd.print(output);
    287     lcd.print(' ');
    288     if (temperature != TEMP_ERROR)
    289       lcd.print(temperature);
    290 
    291     SerialReceive();
    292     SerialSend();
    293   }
    294 }
    295 
    296 
    297 
    298 /********************************************
    299  * Serial Communication functions / helpers
    300  ********************************************/
    301 union {                // This Data structure lets
    302   byte asBytes[24];    // us take the byte array
    303   float asFloat[6];    // sent from processing and
    304 }                      // easily convert it to a
    305 foo;                   // float array
    306 
    307 // getting float values from processing into the arduino
    308 // was no small task.  the way this program does it is
    309 // as follows:
    310 //  * a float takes up 4 bytes.  in processing, convert
    311 //    the array of floats we want to send, into an array
    312 //    of bytes.
    313 //  * send the bytes to the arduino
    314 //  * use a data structure known as a union to convert
    315 //    the array of bytes back into an array of floats
    316 
    317 //  the bytes coming from the arduino follow the following
    318 //  format:
    319 //  0: 0=Manual, 1=Auto, else = ? error ?
    320 //  1-4: float setpoint
    321 //  5-8: float input
    322 //  9-12: float output 
    323 //  13-16: float P_Param
    324 //  17-20: float I_Param
    325 //  21-24: float D_Param
    326 void SerialReceive()
    327 {
    328   // read the bytes sent from Processing
    329   int index = 0;
    330   byte Auto_Man = -1;
    331   while (Serial.available() && index < 25) {
    332     if (index == 0)
    333       Auto_Man = Serial.read();
    334     else
    335       foo.asBytes[index-1] = Serial.read();
    336     index++;
    337   }
    338 
    339   // if the information we got was in the correct format,
    340   // read it into the system
    341   if (index == 25 && (Auto_Man == 0 || Auto_Man == 1)) {
    342     target = double(foo.asFloat[0]);
    343     if (Auto_Man == 0)                       // * only change the output if we are in
    344     {                                     //   manual mode.  otherwise we'll get an
    345       output = double(foo.asFloat[2]);      //   output blip, then the controller will
    346     }                                     //   overwrite.
    347 
    348     double p, i, d;                       // * read in and set the controller tunings
    349     p = double(foo.asFloat[3]);           //
    350     i = double(foo.asFloat[4]);           //
    351     d = double(foo.asFloat[5]);           //
    352     pid.SetTunings(p, i, d);            //
    353 
    354     if(Auto_Man==0)
    355       pid.SetMode(MANUAL);// * set the controller mode
    356     else
    357       pid.SetMode(AUTO);             //
    358   }
    359   Serial.flush();                         // * clear any random data from the serial buffer
    360 }
    361 
    362 // unlike our tiny microprocessor, the processing ap
    363 // has no problem converting strings into floats, so
    364 // we can just send strings.  much easier than getting
    365 // floats from processing to here no?
    366 void SerialSend()
    367 {
    368   Serial.print("PID ");
    369   Serial.print(target);   
    370   Serial.print(" ");
    371   Serial.print(temperature);   
    372   Serial.print(" ");
    373   Serial.print(output);
    374   Serial.print(" ");
    375   Serial.print(pid.GetP_Param());   
    376   Serial.print(" ");
    377   Serial.print(pid.GetI_Param());   
    378   Serial.print(" ");
    379   Serial.print(pid.GetD_Param());   
    380   Serial.print(" ");
    381   if (pid.GetMode() == AUTO)
    382     Serial.println("Automatic");
    383   else
    384     Serial.println("Manual"); 
    385 }
     314  /* Report to PC */
     315  Serial.print(millis() / 1000);
     316  Serial.print(",");
     317  Serial.print((int)(target * 100));
     318  Serial.print(",");
     319  Serial.print((int)(temperature * 100));
     320  Serial.println(",");
     321}
     322
    386323}}}
    387324