0

I am making a system of regulation of the temperature using PID. I want to keep my temperature in 37 celsius. in order to understand the stability of my system easily, I want to see the fuction of temperature in terms of time. I found a function pulseIn() who Read a pulse (either HIGH or LOW) on a pin. But I don't know how to do it into my program. this is the program of my PID system:

#include <PID_v1.h>
#include "math.h" 
int c=0;
int  i=0, output2 = 0, output3 = 0; 
double val=0.0;
double val2 = 0.0;
//Define Variables we'll be connecting to
double Setpoint, Input, Input2, Output=0;
double tOnMax = 50.0;

//Specify the links and initial tuning parameters
PID myPID( &Input, &Output, &Setpoint,10,20,20, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Setpoint = 37; //temperature a reguler 

  //turn the PID on
  pinMode(9, OUTPUT);
  myPID.SetOutputLimits(-100, 100);
  myPID.SetMode(AUTOMATIC);
  Serial.begin(19200);
  while (!Serial); 
}

void loop()
{
  // phase haute
  digitalWrite(9,HIGH);
  delay(output2);
  // phase basse
  digitalWrite(9,LOW);

  for (i = 0; i < 64;i++)
      val += analogRead(0);
  val /= 64.;

 for (i = 0; i < 64;i++)
      val2 += analogRead(1);
  val2 /=64.;

  float mv = round (( val/1024.0)*5000);
  float mv2 = round (( val2/1024.0)*5000);
  Input = mv/10;
  Input2 = mv2/10;
//  Serial.println(Input);
  myPID.Compute();
  output2 = map(Output, -100, 100, 0, tOnMax);
  output3 = map(Output, -100, 100, 0, tOnMax);
//  Serial.print("output is :");
//  Serial.println(output2); 
//  Serial.print("Input: ");
for (c=0; c < 500; c++) {}
Serial.println(Input);

}

thnak you in advance

user3704293
  • 471
  • 7
  • 19
zakaria
  • 47
  • 1
  • 3
  • 9
  • pulseIn() returns the number of microseconds that a digital signal is in a specific state. I fail to see what that has to do with measuring temperature. – Majenko Jan 07 '16 at 14:06
  • well! is there any way to see the temperature in terms of TIME? – zakaria Jan 07 '16 at 14:13
  • Temperature is temperature, time is time. I don't understand what you are asking. – Majenko Jan 07 '16 at 14:15
  • There is a problem in that the timebase for the looping/PID sampling is variable, with the on pulse being delay(output2) milliseconds and the off time being whatever the calculation/printing time of the rest of the loop. As is, with low, but non-zero, output2 it will just loop() faster and might not add less energy to the heated system. Add a delay(tOnMax - output2); in phase basse to fix that and get a more stable timebase. – Dave X Jan 07 '16 at 14:57
  • @Majenko I want to see the evolution of the function tempertaure (t), in other words, i want to see in my screenfor exemple: 24.1C -> 20ms ; 25C-> 200ms; 26 -> 500ms .... – zakaria Jan 07 '16 at 15:02
  • Second, With a Setpoint of '37' for the PID, and using Input=mv/10, then Input is temperature. Your output of the PID is a bit odd, as -100 to 100 mapped to (0,tOnMax) (you could skip the map() and SetOutputLimits(0,tOnMax) directly) and the (mapped) output value is what the PID is trying to drive. You can treat that as TIME or output2/tOnMax as a duty cycle or percent of power if you correct the off-time as above. – Dave X Jan 07 '16 at 15:07
  • Third, Physics-wise, the time-temperature relation depends on how fast energy leaks out of your heated system, and depends on the ambient temperature. If you know the wattage of your heater, you could multiply it by the duty cycle to give you a power in, and your question might evolve to be more about mapping wattage to temperature, and that you'd have full watts with a large error, and a steady-state wattage when you reach temp. How many watts is your heater and at full power, how long would it take to get half-way from ambient to 37C? – Dave X Jan 07 '16 at 15:14
  • @Dave X thank you very much for your comments. actually, the heater has 10 watts... and it takes around 30 mn to reach to the value 37 – zakaria Jan 07 '16 at 15:17
  • OK, with such a slow heater as compared to the calculation time of the arduino, you likely want to use a much longer sampling time. You could disconnect the PWM time and the sampling time from the loop() time by replacing the delay() with millis() as in http://arduino.stackexchange.com/questions/17918/using-arduino-for-simultaneous-lighting-effects/17929#17929 , and with a sampling time of 1s or 1minute, the parameters of the PID could start making sense. i.e. the D term would conform to watts/(degreeError/minute), the I term to Watts/(degreeError*minutes) and P to watts/degreeError. – Dave X Jan 07 '16 at 15:41
  • I don't want to edit your code, but for a quick fix, set tOnMax=6000, add the delay(tOnMax-output2), and drop the for loop. This will set your timebase to 10s. And then reconsider your PID settings. PID myPID( &Input, &Output, &Setpoint,10,0,0, DIRECT); would start to proportionally turn it off at 37-6000/(10*200)=34C, which might be good enough. – Dave X Jan 07 '16 at 15:56
  • Also, add a 'val=0.0; val2=0.0;' to initialize them within the loop. Otherwise they will grow unbounded, overestimate the temp and turn things off. – Dave X Jan 07 '16 at 16:04
  • Is your question still about pulseIn()? or would a title like "Reporting PID heater system output" be more descriptive? – Dave X Jan 10 '16 at 06:03
  • sorry to be late for the answer, my title will be more descriptive if I rename it ''Reporting PID heater system output''. and actually, I followed your advice and my system works correctly, thank you very much Dave X :) – zakaria Jan 14 '16 at 13:30

2 Answers2

1

I want to see the evolution of the function tempertaure (t), in other words, i want to see in my screen for exemple: 24.1C -> 20ms ; 25C-> 200ms; 26 -> 500ms

Quite apart from managing the heater, it sounds as if you need to sample the temperature at a constant rate, compare its value to any of several temperature-intervals, and, when it moves out of one interval into another, report the time it spent within the previous one. This will require saving which interval the temperature was last observed in, and the time it entered that interval, re-saving both when it moves into a new one. You may need to apply some smoothing to the temperature data to if there is any noise in the temperature data to prevent it appearing to jitter back and forth between intervals during interval edge crossings.

JRobert
  • 15,246
  • 3
  • 23
  • 51
1

OK, with such a slow heater as compared to the calculation time of the arduino, you likely want to use a much longer sampling time. One could disconnect the PWM time and the sampling time from the loop() time by replacing the delay() with millis() as in Using Arduino for simultaneous lighting effects and below, and with a sampling time of 1s, 10s or 60s, the parameters of the PID and the integral and derivative terms could start making sense. i.e. the D term would conform to watts/(degreeError/minute), the I term to Watts/(degreeError*minutes) and P to watts/degreeError.

One nice way to think of a PID controller is that it converts process errors into a control variable. If you want to convert "degrees below setpoint" into "milliseconds of heat per tOnMax second cycle", set that directly:

// Tuned for full power (1000ms/sec) up to 35C: P=1000/2 
PID myPID( &Degrees, &millisecondsOn, &Setpoint,500,0,0, DIRECT);
myPID.SetOutputLimits(0, tOnMax);
...

Or "duty cycle of heater"

// Tuned for full power (100%) up to 35C: P=1.0/2 
PID myPID( &Degrees, &millisecondsOn, &Setpoint,0.5,0,0, DIRECT);
myPID.SetOutputLimits(0, 1.0);
...

I didn't want to edit your code too much, but went for a 1s PWM frequency, 10s sampling or PID cycle time. The 1sec PWM/cycle time is the minimum most commercial PID controllers work with (typically 1s-999s to handle a range from solid-state-relay controlled resistive heating elements to relay controlled mechanical systems like pilot light heaters or fan/pump systems) and should be plenty fast enough for your system. Slower PWM times are better for mechanical systems, and faster times are better for thermal cycling of resistive elements.

The 10s cycle time is ~200x slower than your initial code looks like it is sampling, but the 10s time might be more in keeping with the physical changes in your system as compared to your resolution. I can't tell the temperature resolution of your sensor for your code, but assuming it is 0.1C, taken with a (37C-20C)/30m=0.0094C/s rate of change, it would take about 10s to make 1 bit of detectable change. If you sample faster than that, all you will be getting is noise or no change. Sampling significantly faster than the physical process changes can serve to confuse a PID in the integral and derivative terms--Derivative because the derivative of error is mostly zeros or noise, and Integral because the integral accumulator can wind up before the system even begins to move. Looking at the Arduino PID library code at https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.cpp#L57 with a I=20, output limits of (-100,100), a t0=20C, a setpoint of 37, sampling time of 50ms, and a temperature rate of change of 0.0094C/s, the Iterm accumulator would be wound up to 100 in just 0.300 seconds. The wound-up integral would guarantee an overshoot until the integral accumulator erodes afterwards (For example: 37.5C for 10s? 37.1C for 100s? ???)

With a 1000ms PWM and 10s sampling time base, you would need to reconsider your PID settings. In particular, the I and D terms strongly sensitive to the sampling time and the output range. As a start, PID myPID( &Input, &Output, &Setpoint,500,0,0, DIRECT); would start to proportionally turn the heater off at 37-1000/500)=35C, which might be good enough for your needs. If that isn't close enough, you could increase P more to tighten the proportional band. ("Proportional band" is error band where the P*error term of the PID doesn't saturate the output limits, i.e., PropBand = +/-(tOnMax/P) ) Alternately, you could fiddle with the I term to completely eliminate the droop.

#include <PID_v1.h>
#include "math.h" 
int c=0;
int  i=0, output2 = 0, output3 = 0; 
double val=0.0;
double val2 = 0.0;
//Define Variables we'll be connecting to
double Setpoint, Input, Input2, Output=0;
double tOnMax = 1000.0; // 1 second PWM controlling 10w heater
unsigned long sampleTime, heaterTime;

//Specify the links and initial tuning parameters
// Process takes 30m to come to 37C from 17C at 10W
// Proportional: Full power to setpoint-2C, then proportional taper: P= tOnMax/2
// Integral: 30m = 300 samples, so area under curve = 20*300/2=3000
// so for integral to roll up to 50% power (1/2 tOnMax) in 30m:
// I = tOnMax/2/3000 = 1000/2/3000 = 0.15
// Derivative: Max slew rate of 20C/30m = 20C/300 10sSamples = 0.067C/sample
// Ignore the derivative for now to avoid potential noise problems, 
// but D=tOnMax/0.067=15000 would anticipate and counteract the maximum slewing rate
PID myPID( &Input, &Output, &Setpoint,tOnMax/2,0.15,0, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Setpoint = 37; //temperature a reguler 

  //turn the PID on
  pinMode(9, OUTPUT);
  myPID.SetOutputLimits(0, tOnMax);
  myPID.SetMode(AUTOMATIC);
  Serial.begin(19200);
  while (!Serial); 
  heaterTime=sampletime=millis();
}

void loop()
{
  unsigned long now = millis();
  if(heaterTime < now){
     if(digitalRead(9)) {// phase haute -> basse
        heaterTime += tOnMax-output2; // schedule on 
        digitalWrite(9,LOW);}
     } else {  // phase basse -> haute
       heaterTime += output2);  // schedule off
       digitalWrite(9,HIGH);
     }
  if (sampleTime < now ) {
      sampleTime = sampleTime + 10000;  // every 10 seconds
      val=0=val2=0;
      for (i = 0; i < 64;i++)
          val += analogRead(0);
      val /= 64.;

      float mv = round (( val/1024.0)*5000); // convert to degrees*10?
      Input = mv/10;        // degrees
      myPID.Compute();
      output2 = Output;
      Serial.print(Input);
      Serial.print("C -> ");
      Serial.print(output2); 
      Serial.print("ms / "); 
      Serial.println(tOnMax); 
   } // end sample
}
Dave X
  • 2,332
  • 14
  • 28
  • thank you again for your response I really appreciate your help. I still have a question about what you said ''but went for a 1s PWM frequency, 10s sampling or PID cycle time. With a 1000ms PWM and 10s sampling time base, you would need to reconsider your PID settings.'' actually can you give me some details about the 1s PWM frequency and 10 s sampling time ... i failed to understand it, thank you in advance – zakaria Jan 08 '16 at 09:33
  • The 1s PWM frequency is set in my edit by the tOnMax of 1000 ms, and the PID chooses a duty cycle within with an on-time of output2 and an off time of tOnMax-output2. The sampling time is how often one would take a measurement. Since your process seems slow (assuming 20C to 37C in 30 minutes at full power, or about 0.5C per minute = 0.0094C/sec), fast sampling times won't detect much, so I chose 10s sampling time. At that rate, the most the process will change is 0.09C/sample, which might(??) be significantly less than your sensor resolution. – Dave X Jan 10 '16 at 04:40
  • I added some to my answer about my choice of times. – Dave X Jan 10 '16 at 06:00