Pid temperature sensor code

Hello,
I am using the code below to heat up a yoghurt maker. My heater is an 8 ohm 25 watt resistor (on a pc heat-sink). The thermometer used is a DS18b20. I got the code off the internet (http://www.instructables.com/id/Cheap-Arduino-Controled-Yogurt-Maker/) and it works fine. The only problem is that I would like to adjust the parameters to have a more steady temperature (43 degrees Celsius) but I don't know what the 3 PID variables (Kp, Ki, Kd) are responsible for. I asked the person who made it, but I found his answer wasn't precise... Could somebody precisely tell me what they do?

// Include necessary libraries
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SD.h>
#include <PID_v1.h>

// Setup vars
long intervalTemp = 1000; // interval between temperature measurements / PID computation
int minOn = 1; // minimum time for the relay to be on
int maxOn = 60; // maximum time for the relay to be on, IE, one cicle
long intervalSD = 5000; // interval between saving data on the SD card
double Setpoint = 43; // temperature to be manteined
int relayPin = 3; // pin where the relay is connected
const int chipSelect = 10; // pin CS (SD card) (optional)
int led1 = 4;
int led2 = 5;

// Internal vars (don't change)
long previousMillisTemp = 0;
long previousMillisSD = 0;
unsigned long windowStartTime;
float tempAtual = 0; // current temp
int stat = 0; // 0 = relay off / 1 = relay on
static char tempBuff[15];
File datafile;

// PID parameters (input, output, setpoint, Kp, Ki, Kd, direction)
double Input, Output;
PID myPID(&Input, &Output, &Setpoint,35,30,5, DIRECT);

// Configures thermometer
OneWire oneWire(2); // pin where the themometer is connected
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;

void setup() {
  sensors.begin();
  sensors.getAddress(insideThermometer, 0);
  //sensors.setResolution(insideThermometer, 11); //set thermometer do max resolution
  pinMode(relayPin, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(led1, OUTPUT); 
  pinMode(led2, OUTPUT);  

  
  // PID
  windowStartTime = ceil(millis()/1000);
  myPID.SetOutputLimits(minOn, maxOn);
  myPID.SetMode(AUTOMATIC);
     
  Serial.begin(9600);
 
  if (!SD.begin(chipSelect)) {
  
    Serial.println("SD card initialized.");
    
    // Create a new file
    char filename[] = "DATA00.TXT";
    for (uint8_t i = 0; i < 100; i++) {
      filename[4] = i/10 + '0';
      filename[5] = i%10 + '0';
      if (! SD.exists(filename)) {
        // only open a new file if it doesn't exist
        datafile = SD.open(filename, FILE_WRITE); 
        break;  // leave the loop!
      }
    }
  
    if (! datafile) {
      Serial.print("Logging to: ");
      Serial.println(filename);
    }
  }
  
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" thermometers.");
  Serial.print("Device 0 Resolution: ");
  Serial.println(sensors.getResolution(insideThermometer), DEC); 
  
  Serial.print("Set temperature: ");
  Serial.println(Setpoint);
  Serial.println("##################");
  
  
}

void loop() {
  unsigned long currentMillis = millis();
  
  // Checks current temp and prints it on serial
  if((currentMillis - previousMillisTemp > intervalTemp)||(currentMillis - previousMillisTemp < 0)) {
    
    // Updates previous millis
    previousMillisTemp = currentMillis;
    
    // Gets temperature
    sensors.requestTemperatures();
    tempAtual = sensors.getTempCByIndex(0);
    
    // Computes PID
    Input = tempAtual;
    myPID.Compute();
      
    // Controls relay
    unsigned long now = ceil(millis()/1000);
    if(now - windowStartTime > maxOn) { // maximumOn reached
      windowStartTime += maxOn;
    }
    if(Output >= now - windowStartTime) { // output defines how much of the time >minOn and <maxOn the relay will be on, the remaining time it will be off.
      digitalWrite(relayPin, HIGH);
      digitalWrite(led1, HIGH);
      digitalWrite(led2, LOW);
      stat = 1;
    } else {
      digitalWrite(relayPin, LOW);
      digitalWrite(led2, HIGH);
      digitalWrite(led1, LOW);
      stat = 0;
    }
    
    // Prints current temperature on serial
    Serial.print("Temp: ");
    Serial.print(sensors.getTempCByIndex(0));
    Serial.print("C | Output: ");
    Serial.print(Output);
    Serial.print(" | Heat: ");
    if(stat == 0) {
      Serial.println("off");
    } else {
      Serial.println("on");
    }
      
  }
  
  // Saves data on the SD card
  if((currentMillis - previousMillisSD > intervalSD)||(currentMillis - previousMillisSD < 0)) {
    
    // Updates previous millis
    previousMillisSD = currentMillis;
    
    // Creates string to save on file
    String dataString = "";
    dtostrf(tempAtual, 5, 2, tempBuff);
    dataString.concat(tempBuff);
    dataString.concat(","); 
    dataString.concat(stat); 
  
    // If the file is available, write to it:
    if (datafile) {
      datafile.println(dataString);
      datafile.flush();
    }  
    
  
    
  }     
}

/* Code ends here! */

Thanks!

double Kp = 3;  //Determines how aggressively the PID reacts to the current amount of error (Proportional)
double Ki = 2;  //Determines how aggressively the PID reacts to error over time (Integral)
double Kd = 1;  //Determines how aggressively the PID reacts to the change in error (Derivative)

Ok... So what would that mean in this case...

This influence the way the regulator react to the error.

Proportional is basicly what is say: for the "process reading" (in this case the actual temps) compare the the "set point" (the tempeture you want to have) give you the "error"

now you have the decide how fast you want to correct the error. for that you adjust the "gain".

if we resume the math, the output = (process reading - set point) x gain.

for a heating loop, generaly you need only the proportional mode because it is not a really fast reaction and the regulator does'nt have to react with to much precision.

it is mostly the gain variable that will have the best impact for your process. there is no good value. you have to do some physical test to obtain the best time of response and the best stability .

that page resume, Kp shoul be the "gain"

http://playground.arduino.cc/Code/PIDLibraryConstructor

Thank you so much for the precise answer! I will go try that out.

It kinda worked... It reduced the temperature gap from 1.5 degrees to about 0.75 degrees... But how could i get the relay to turn on when the temperature is just below 43?

Temp: 43.00C | Output: 1.00 | Heat: off
Temp: 42.94C | Output: 4.00 | Heat: off
Temp: 42.94C | Output: 3.56 | Heat: off
Temp: 42.88C | Output: 6.75 | Heat: off
Temp: 42.94C | Output: 3.50 | Heat: off
Temp: 42.94C | Output: 4.31 | Heat: off
Temp: 42.88C | Output: 7.50 | Heat: off
Temp: 42.88C | Output: 7.25 | Heat: off
Temp: 42.88C | Output: 7.63 | Heat: off
Temp: 42.88C | Output: 8.00 | Heat: off
Temp: 42.88C | Output: 8.38 | Heat: off
Temp: 42.81C | Output: 11.75 | Heat: off
Temp: 42.81C | Output: 11.69 | Heat: off
Temp: 42.75C | Output: 15.25 | Heat: off
Temp: 42.75C | Output: 15.38 | Heat: off
Temp: 42.75C | Output: 16.12 | Heat: off
Temp: 42.69C | Output: 19.87 | Heat: off
Temp: 42.69C | Output: 20.19 | Heat: off
Temp: 42.69C | Output: 21.12 | Heat: off
Temp: 42.69C | Output: 22.06 | Heat: off
Temp: 42.69C | Output: 23.00 | Heat: off
Temp: 42.69C | Output: 23.94 | Heat: off
Temp: 42.63C | Output: 27.87 | Heat: off
Temp: 42.56C | Output: 31.37 | Heat: off
Temp: 42.56C | Output: 32.06 | Heat: off
Temp: 42.56C | Output: 33.38 | Heat: off
Temp: 42.50C | Output: 37.69 | Heat: off
Temp: 42.50C | Output: 38.56 | Heat: off
Temp: 42.50C | Output: 40.06 | Heat: off
Temp: 42.44C | Output: 44.56 | Heat: off
Temp: 42.44C | Output: 45.63 | Heat: off
Temp: 42.44C | Output: 47.31 | Heat: off
Temp: 42.38C | Output: 52.00 | Heat: on

But how could i get the relay to turn on when the temperature is just below 43?

Without seeing your new code? We'd only be guessing.

I don't konw how the library have been program. I'm talking about industrial PID regulator.

There's an output treshold option in the library:

http://playground.arduino.cc/Code/PIDLibrarySetTunings

It's supposer to be set 0-255 by default but it could have explain it.

On the other way, for what I'm reading from your result, you've got a gap of +/-0.5 C. I Don't know you application but it seem good.
specially if your working with a magnetic relay. it have mechanical part and have a limited number of activation. It less matter with solid state relay.

Finally, look for a gap of time if the temp is keep in a good range, if not, you can increment the gain, it will rise more faster. if it rise to fast, it will start and stop too often. the more stable the process if, the best are you're configuration.

If you want more precise temperature with faster response, maybe peltier with MOSFET transistor control would be better option, but it's little out of the your question :wink: