Arduino PID Update

I wrote a post a few months back detailing my Arduino PID controller approach.  Based on some feedback, I realized the code in that post was overly complicated as well as had some errors in it.  I am now going to detail a much simpler approach.

Previously, I used a PID controller to schedule temperature over a fixed amount of time, such as to have precise ramp up time, hold time, and cool down time.  It is worth noting that a PID controller is also useful for indefinite time control, like a thermostat.  By varying the coefficients, you can customize how fast the system reacts and not damage any equipment (this is a consideration when using mechanical relays that don’t like fast switching).

Below is my Arduino C code for maintaining a set temperature like a thermostat with a PID controller.  The MAX31855 and the PID_v1 libraries can be found on my Github page.

#include "SPI.h"
#include "MAX31855.h"
#include "PID_v1.h"

//
//Arduino Pins
//
//CSB of MAX31855 thermocouple. By using separate CSBs, multiple devices can use the same SPI bus.
byte thermo1_csb = 7;
//Pin to control relay that switches the heating element
byte temp_relay0_Pin = 0;

//
//PID calculation parameters
//
//Value read by thermocouple sensor
double temp_read1;
//Temperature that system is currently maintaining
double temp_set1 = 95;
//Control value resulting from PID calculation
double Output_T1;

//
//Library Objects
//
MAX31855 thermo;
PID PID_temp1(&temp_read1, &Output_T1, &temp_set1, 1, 5, 0.5, DIRECT);

void setup()
{
   //Initiate thermocouple
   SPI.begin();
   thermo.setup(thermo1_csb);

   //Initiate heating element relay
   pinMode(temp_relay0_Pin, OUTPUT);
   digitalWrite(temp_relay0_Pin, LOW);
}

//This function reads the thermocouple sensor and translates the value into temp_read1
void read_sensors()
{
   thermo.read_temp();
   temp_read1 = thermo.thermocouple_temp*1.8+32;
}

//This function computes the output control value from the thermocouple reading and current set point
//and then turns the heating element on and off accordingly
void run_PID()
{
   uint16_t low_WindowSize = 0;
   uint16_t high_WindowSize = 1000;
   uint32_t windowStartTime = millis();

   //Specify the links and initial tuning parameters
   PID_temp1.SetOutputLimits(low_WindowSize, high_WindowSize);
   //PID_temp1.SetTunings(Kp, Ki, Kd);
   PID_temp1.SetMode(AUTOMATIC);

   PID_temp1.Compute();

   //This section controls the heating element
   while(millis() < (high_WindowSize-low_WindowSize) + windowStartTime) 
   {
       if(Output_T1 > (millis() - windowStartTime))
       {
          digitalWrite(temp_relay0_Pin, HIGH);
       }
       else
       {
         digitalWrite(temp_relay0_Pin, LOW);
       }
   }
}

void loop()
{
   read_sensors();
   run_PID();
}