Using PID library for heating element with SSR and max31855

Hi, I'm trying to understand the PID library and I'm a noob so its a little rough. I'm planning on using PID to control a heating element with SSR using MAX31855 as input.

I'm starting from scratch basically but with the library so I wanted to test out the relay output example included in the library. Here's my code:
Setpoint is 100 which is fine, as input is around 16 right now in my house! Heater is busted.... :frowning: I'm not worried about tuning or coding steps or anything else like that right now. just trying to get it to work and control the SSR.

Whats happening is when it starts the ssr actually pulses a bit but the higher the output the less it pulses until it stops? I'd think SSR would be on 100% when it starts and if I heat up the tc it should start pulsing to stop? Something is very wrong here lol and some help is greatly appreciated!

/********************************************************
 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   to connect them together we use "time proportioning
 * control"  it's essentially a really slow version of PWM.
 * first we decide on a window size (5000mS say.) we then 
 * set the pid to adjust its output between 0 and that window
 * size.  lastly, we add some logic that translates the PID
 * output into "Relay On Time" with the remainder of the 
 * window being "Relay Off Time"
 ********************************************************/
#include <Adafruit_MAX31855.h>
#include <PID_v1.h>
#define RelayPin 6

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

//31855 stuff
int thermoCLK = 53;
int thermoCS = 51;
int thermoDO = 49;
int backLight = 13;    // pin 13 will control the backlight
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);


void setup()
{
  Serial.begin(115200);
  windowStartTime = millis();
  
  //initialize the variables we're linked to
  Setpoint = 100;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  pinMode(RelayPin, OUTPUT);  
  Input = thermocouple.readCelsius();
  
  myPID.Compute();
  Serial.print("INPUT:");
  Serial.println(Input);
  Serial.print("OUTPUT:");
  Serial.print(Output);
  
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);  
  
  else digitalWrite(RelayPin,LOW);
     
     
  

}

Here's output:

OUTPUT:5000.00INPUT:16.25
OUTPUT:46.88INPUT:15.75
OUTPUT:46.88INPUT:15.50
OUTPUT:260.63INPUT:15.50
OUTPUT:260.63INPUT:15.00
OUTPUT:301.63INPUT:15.75
OUTPUT:301.63INPUT:15.75
OUTPUT:329.75INPUT:15.75
OUTPUT:329.75INPUT:16.00
OUTPUT:376.25INPUT:15.25
OUTPUT:376.25INPUT:15.25
OUTPUT:430.13INPUT:15.75
OUTPUT:430.13INPUT:15.00
OUTPUT:468.13INPUT:15.50
OUTPUT:468.13INPUT:16.50
OUTPUT:489.38INPUT:16.00
OUTPUT:489.38INPUT:16.00
OUTPUT:552.38INPUT:16.00
OUTPUT:552.38INPUT:15.00
OUTPUT:601.88INPUT:15.00
OUTPUT:601.88INPUT:15.75
OUTPUT:625.00INPUT:16.50
OUTPUT:625.00INPUT:15.25
OUTPUT:680.88INPUT:15.25
OUTPUT:680.88INPUT:16.00
OUTPUT:708.88INPUT:15.50
OUTPUT:708.88INPUT:16.50
OUTPUT:752.13INPUT:15.25
OUTPUT:752.13INPUT:15.25
OUTPUT:814.50INPUT:15.75
OUTPUT:814.50INPUT:15.75
OUTPUT:838.13INPUT:15.25
OUTPUT:838.13INPUT:15.75
OUTPUT:885.25INPUT:15.50
OUTPUT:885.25INPUT:15.50
OUTPUT:930.50INPUT:16.25
OUTPUT:930.50INPUT:15.75
OUTPUT:967.13INPUT:16.25
OUTPUT:967.13INPUT:15.50
OUTPUT:1014.88INPUT:15.50
OUTPUT:1014.88INPUT:15.50
OUTPUT:1054.63INPUT:16.50
OUTPUT:1054.63INPUT:15.75
OUTPUT:1093.75INPUT:15.50
OUTPUT:1093.75INPUT:16.00
OUTPUT:1135.25INPUT:16.25
OUTPUT:1135.25INPUT:16.25
OUTPUT:1176.63INPUT:16.50
OUTPUT:1176.63INPUT:16.00
OUTPUT:1224.13INPUT:15.50
OUTPUT:1224.13INPUT:16.75
OUTPUT:1254.25INPUT:15.75
OUTPUT:1254.25INPUT:15.75
OUTPUT:1315.88INPUT:16.00
OUTPUT:1315.88INPUT:16.75
OUTPUT:1335.50INPUT:15.75
OUTPUT:1335.50INPUT:16.00
OUTPUT:1396.50INPUT:16.75
OUTPUT:1396.50INPUT:16.25
OUTPUT:1427.88INPUT:16.25
OUTPUT:1427.88INPUT:16.50
OUTPUT:1469.13INPUT:16.00
OUTPUT:1469.13INPUT:16.25
OUTPUT:1516.50INPUT:16.00
OUTPUT:1516.50INPUT:16.50
OUTPUT:1552.75INPUT:16.50
OUTPUT:1552.75INPUT:16.25
OUTPUT:1600.13INPUT:16.75
OUTPUT:1600.13INPUT:16.00
OUTPUT:1642.63INPUT:15.75
OUTPUT:1642.63INPUT:15.75
OUTPUT:1685.25INPUT:16.50
OUTPUT:1685.25INPUT:16.00
OUTPUT:1721.75INPUT:16.25
OUTPUT:1721.75INPUT:16.50
OUTPUT:1760.00INPUT:16.25
OUTPUT:1760.00INPUT:16.75
OUTPUT:1803.63INPUT:16.75
OUTPUT:1803.63INPUT:16.75
OUTPUT:1847.75INPUT:16.25
OUTPUT:1847.75INPUT:16.00
OUTPUT:1898.75INPUT:16.50
OUTPUT:1898.75INPUT:16.00
OUTPUT:1933.25INPUT:15.75
OUTPUT:1933.25INPUT:16.25
OUTPUT:1972.13INPUT:16.00
OUTPUT:1972.13INPUT:16.00
OUTPUT:2019.63INPUT:16.00
OUTPUT:2019.63INPUT:16.00
OUTPUT:2059.12INPUT:16.00
OUTPUT:2059.12INPUT:16.50
OUTPUT:2094.87INPUT:16.25
OUTPUT:2094.87INPUT:16.00
OUTPUT:2147.87INPUT:16.25
OUTPUT:2147.87INPUT:16.75
OUTPUT:2175.50INPUT:16.25
OUTPUT:2175.50INPUT:16.00
OUTPUT:2234.00INPUT:15.25
OUTPUT:2234.00INPUT:16.25
OUTPUT:2265.37INPUT:17.00
OUTPUT:2265.37INPUT:16.25
OUTPUT:2309.75INPUT:16.00
OUTPUT:2309.75INPUT:16.00
OUTPUT:2354.75INPUT:16.25
OUTPUT:2354.75INPUT:16.75
OUTPUT:2384.87INPUT:16.50
OUTPUT:2384.87INPUT:16.25
OUTPUT:2440.25INPUT:16.50
OUTPUT:2440.25INPUT:16.25
OUTPUT:2477.12INPUT:17.00
OUTPUT:2477.12INPUT:17.00
OUTPUT:2509.62INPUT:16.00
OUTPUT:2509.62INPUT:17.00
OUTPUT:2558.62INPUT:17.25
OUTPUT:2558.62INPUT:17.25
OUTPUT:2597.00INPUT:16.00
OUTPUT:2597.00INPUT:16.50
OUTPUT:2650.25INPUT:16.75
OUTPUT:2650.25INPUT:16.50
OUTPUT:2684.50INPUT:16.50
OUTPUT:2684.50INPUT:16.25
OUTPUT:2729.37INPUT:16.00
OUTPUT:2729.37INPUT:15.50
OUTPUT:2778.12INPUT:15.50
OUTPUT:2778.12INPUT:16.50
OUTPUT:2800.37INPUT:16.25
OUTPUT:2800.37INPUT:16.25
OUTPUT:2855.25INPUT:16.00
OUTPUT:2855.25INPUT:16.00
OUTPUT:2897.75INPUT:16.25
OUTPUT:2897.75INPUT:16.25
OUTPUT:2934.12INPUT:16.50
OUTPUT:2934.12INPUT:17.00
OUTPUT:2969.12INPUT:16.75
OUTPUT:2969.12INPUT:15.75
OUTPUT:3033.75INPUT:16.25
OUTPUT:3033.75INPUT:16.75
OUTPUT:3050.87INPUT:17.00
OUTPUT:3050.87INPUT:16.75
OUTPUT:3102.50INPUT:16.75
OUTPUT:3102.50INPUT:17.00
OUTPUT:3141.00INPUT:16.75
OUTPUT:3141.00INPUT:16.25
OUTPUT:3194.37INPUT:16.25
OUTPUT:3194.37INPUT:16.50
OUTPUT:3225.62INPUT:16.50
OUTPUT:3225.62INPUT:17.00
OUTPUT:3263.62INPUT:16.25
OUTPUT:3263.62INPUT:16.00
OUTPUT:3322.62INPUT:16.75
OUTPUT:3322.62INPUT:16.25
OUTPUT:3351.50

I'll spare you the rest but output simply keeps raising until it hits WindowSize(5000). If I heat up the thermocouple the output does decrease but doesn't seem to do anything different with the RelayPin? Very odd. I have been searching around and trying to implement different bits of code from other sketches to no avail.

THANKS!

The output is ramping up so that's going in the right direction. Looks like it needs tuning.

I remember seeing a PID Auto-Tune library somewhere. Perhaps that will help.

The Proportional constant relates the error (100-16) to the output. I think if you want the heater full on if the temperature is 10 degrees low you probably want a P parameter of 500 instead of 2.

The Integral constant is saving you some. It adds up the errors over time to eliminate offset. If the output is not responding fast enough this boosts the output.

The Differential only takes action when the error value starts changing. It's there to try to keep the temperature from overshooting.

  pinMode(RelayPin, OUTPUT);

Are you planning to set the mode of the relay pin to INPUT later in loop, so you can read the state of the relay? Seems unlikely. This belongs in setup().

What, exactly, are Input and Output in terms of the temperature read from the thermocouple? It appears that you are using Output as though it were some sort of measure of time. It is not.

PaulS:
What, exactly, are Input and Output in terms of the temperature read from the thermocouple? It appears that you are using Output as though it were some sort of measure of time. It is not.

As far as the PID library is concerned Input and Setpoint are in the same units (so that an error term can be calculated) but the Output term doesn't need to be in the same units. It's a measure of how much you want to change the Input value. In this case it is a PWM value controlling the heater duty cycle.

In this case it is a PWM value controlling the heater duty cycle.

Doesn't look that way to me:

  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);  
  
  else digitalWrite(RelayPin,LOW);

Thanks for quick reply guys!

Thanks for tip on pinmode going in setup. :slight_smile: I know I read somewhere that pid library does that automatic but RelayPin doesn't do anything at all without it? I tried and same thing.
That's cool that you brought up reading the state of the ssr, as I may add that in later. For now simply understanding how this works would be perfect for me though haha! I'm planning on doing alot more with it but need to start at 1st grade level.

The very odd thing is even if output is zero(input > setpoint) in the start of the sketch the ssr still goes through the 'exact' same length and amount of pulses before it stops.

I'm really not sure what OUTPUT should be, as I simply copied the code over. If anyone has suggestions I'd love to hear them. I even went through osPID code and rocketscream code. Seems I need to do that again huh?

PaulS:

In this case it is a PWM value controlling the heater duty cycle.

Doesn't look that way to me:

  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);  

else digitalWrite(RelayPin,LOW);

Perhaps this equivalent code will make it clearer:

   unsigned long millisecondsOfOnTimePer5SecondWindow = Output;
   digitalWrite(RelayPin,(millis() - windowStartTime) < millisecondsOfOnTimePer5SecondWindow);

I'm messing with the PID values now but still to no avail. I need a break guys. If there's anything else anyone can add please let me know and thanks again.

Ok, I'm done for now but last thing... It seems to have a negative type effect. If I heat up the TC and output lowers the ssr comes on and seems to work right. Once the output reaches a certain point the ssr turns off. Little backwards huh?

Got it. It was backwards! Also needs to be tuned but I need actual heaters for that. Will be very soon.

example sketch has this:

if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);  
  
  else digitalWrite(RelayPin,LOW);

Changed to:

if(Output > millis() - windowStartTime) digitalWrite(RelayPin,HIGH);  
  
  else digitalWrite(RelayPin,LOW);

I know this thread is somewhat outdated... But would you mind telling me which SSR and Heating element you bought? I am trying to work on a project where I will need both of these and need some guidance in purchasing...

Hi, I've made a ton of progress on this since then. :slight_smile: I'm using a fotek 40amp ssr and only paid $7.00 or so shipped from china. I can't find the 40 amp ones that cheap anymore though. Here's a 25amp ssr like I have which might be fine with what you're doing depending on wattage of heaters and how many heaters etc.

http://www.ebay.com/itm/SSR-25-DA-Solid-State-Relay-PID-Temperature-Controller-25A-Output-24V-380V-/271092328688?_trksid=p2045573.m2102&_trkparms=aid%3D555001%26algo%3DPW.CURRENT%26ao%3D1%26asc%3D146%26meid%3D6411926506775367794%26pid%3D100034%26prg%3D1079%26rk%3D1%26sd%3D390195438437%26

I'm using halogen lamps but you can use different kinds of heating elements. I actually created a forum for DIY BGA guys but its not limited to that. Anything with heating elements and even more is welcome. Not much activity so far but people do check.

diybga.com

I'm even farther with it now but here's a video but not explained very well.

Cheers :slight_smile: