PID controller only works for first temp cycle then stops

I made a PID controller that uses a SSR to drive a resistive load (heating coil), a type K thermocupple with the adafruit max31855 breakout board. I'm using the adafruit max31855 lib with the arduino PID and PID front end libraries. I have the set point at 100*C, when I turn it on at room temp the realy LED comes on, i had a signal on my output (as seen in pid frontend), after it overshoots (tuning issue?) it cuts off, once the temp falls below the setpoint the SSR never comes back on. I don't know much C/C++, just enough basics to combine these different libraries and get it to compile. Any help would be appreciated, I'm not sure where to begin troubleshooting but I though the PID frontend could help.

You can see the output=nan after the overshoot, during heating this it was at a real value.

`````/*************************************************** 
  This is an example for the Adafruit Thermocouple Sensor w/MAX31855K

  Designed specifically to work with the Adafruit Thermocouple Sensor
  ----> https://www.adafruit.com/products/269

  These displays use SPI to communicate, 3 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include "Adafruit_MAX31855.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>

// set replay pin for PID
#define RelayPin 6

double Setpoint, Input, Output;

int thermoCLK = 5;
int thermoCS = 4;
int thermoDO = 3;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,53.2,10.5,2.12, DIRECT);

unsigned long serialTime; //this will help us know when to talk with processing

int WindowSize = 5000;
unsigned long windowStartTime;


// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);
// initialize the library and set the LCD address to 0x27 for a 16x2 line display
LiquidCrystal_I2C lcd(0x27,16,2);

  
void setup() {
 
  Serial.begin(9600);
  windowStartTime = millis();
  
 // inital setpoint before implementing control 
  Setpoint = 100;
  
  pinMode(RelayPin, OUTPUT);      // sets the digital pin as output
  
  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);
  
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  
  // set up the LCD's number of columns and rows: 
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.print("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);
}

void loop() {
  Input = thermocouple.readCelsius();
  
  myPID.Compute();

  /************************************************
   * 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);
  
  
  
  // basic readout test, just print the current temp
   lcd.setCursor(0, 0);
   lcd.print("Set Temp = ");
   lcd.println(Setpoint);
   lcd.print("  "); 
   lcd.setCursor(0, 1);
   if (isnan(Input)) 
   {
     lcd.print("T/C Problem");
   } 
   else 
   {
     lcd.print("C = "); 
     lcd.print(Input);
     lcd.print("  "); 
   }
   
     //send-receive with processing if it's time
  if(millis()>serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime+=500;
  }
 
} 


/********************************************
 * Serial Communication functions / helpers
 ********************************************/


union {                // This Data structure lets
  byte asBytes[24];    // us take the byte array
  float asFloat[6];    // sent from processing and
}                      // easily convert it to a
foo;                   // float array



// getting float values from processing into the arduino
// was no small task.  the way this program does it is
// as follows:
//  * a float takes up 4 bytes.  in processing, convert
//    the array of floats we want to send, into an array
//    of bytes.
//  * send the bytes to the arduino
//  * use a data structure known as a union to convert
//    the array of bytes back into an array of floats

//  the bytes coming from the arduino follow the following
//  format:
//  0: 0=Manual, 1=Auto, else = ? error ?
//  1: 0=Direct, 1=Reverse, else = ? error ?
//  2-5: float setpoint
//  6-9: float input
//  10-13: float output  
//  14-17: float P_Param
//  18-21: float I_Param
//  22-245: float D_Param
void SerialReceive()
{

  // read the bytes sent from Processing
  int index=0;
  byte Auto_Man = -1;
  byte Direct_Reverse = -1;
  while(Serial.available()&&index<26)
  {
    if(index==0) Auto_Man = Serial.read();
    else if(index==1) Direct_Reverse = Serial.read();
    else foo.asBytes[index-2] = Serial.read();
    index++;
  } 
  
  // if the information we got was in the correct format, 
  // read it into the system
  if(index==26  && (Auto_Man==0 || Auto_Man==1)&& (Direct_Reverse==0 || Direct_Reverse==1))
  {
    Setpoint=double(foo.asFloat[0]);
    //Input=double(foo.asFloat[1]);       // * the user has the ability to send the 
                                          //   value of "Input"  in most cases (as 
                                          //   in this one) this is not needed.
    if(Auto_Man==0)                       // * only change the output if we are in 
    {                                     //   manual mode.  otherwise we'll get an
      Output=double(foo.asFloat[2]);      //   output blip, then the controller will 
    }                                     //   overwrite.
    
    double p, i, d;                       // * read in and set the controller tunings
    p = double(foo.asFloat[3]);           //
    i = double(foo.asFloat[4]);           //
    d = double(foo.asFloat[5]);           //
    myPID.SetTunings(p, i, d);            //
    
    if(Auto_Man==0) myPID.SetMode(MANUAL);// * set the controller mode
    else myPID.SetMode(AUTOMATIC);             //
    
    if(Direct_Reverse==0) myPID.SetControllerDirection(DIRECT);// * set the controller Direction
    else myPID.SetControllerDirection(REVERSE);          //
  }
  Serial.flush();                         // * clear any random data from the serial buffer
}

// unlike our tiny microprocessor, the processing ap
// has no problem converting strings into floats, so
// we can just send strings.  much easier than getting
// floats from processing to here no?
void SerialSend()
{
  Serial.print("PID ");
  Serial.print(Setpoint);   
  Serial.print(" ");
  Serial.print(Input);   
  Serial.print(" ");
  Serial.print(Output);   
  Serial.print(" ");
  Serial.print(myPID.GetKp());   
  Serial.print(" ");
  Serial.print(myPID.GetKi());   
  Serial.print(" ");
  Serial.print(myPID.GetKd());   
  Serial.print(" ");
  if(myPID.GetMode()==AUTOMATIC) Serial.print("Automatic");
  else Serial.print("Manual");  
  Serial.print(" ");
  if(myPID.GetDirection()==DIRECT) Serial.println("Direct");
  else Serial.println("Reverse");
}

No PID expert, but it might be that the Kp is too high, which can cause overshoot.
Based upon - PID controller - Wikipedia - at 1/3 there are three pictures at the right

check this site - PID Theory -
especially the tuning part that might help to tune the values.

Wow! Those graphs make understanding the tuning parameters much easier, thanks! There's still the issue of PID control, regardless of tuning, after the overshoot it should come back on. Maybe the overshoot is taking so long, greater than the windowsize?, or something of that sort that is causing the PID logic to fail. Once it over shoots it takes a good 5min+ to cool down, in the image i had the coil/therm up against my wall AC unit on full.

Maybe the overshoot is taking so long, greater than the windowsize?,

Quite possible, (no expert disclaimer still applies :wink:
if overshoot is too large it can take quite some time to get at the setpoint, depends on the system - materials, physical properties etc.

Note there are systems in which overshoot is not an option. E.g. consider an system that heats biological samples for analysis. If the samples become too hot the proteins can get disrupted.

I also keep getting brief burts of "T/C problem" on my LCD, it seems like the max31855 is glitching out, i think it has to do with ground. When even i plug the ac cord into the wall the temp reading become less stable, and get loss of the sensor readings for short burts of time. But if the thermocouple was really connected to earth ground wouldn't it not work at all?

YOu might need a capacitor between the ADC and GND to dampen these gliches.