PID problem with Compute() function

I am building a reflow toaster oven using the Adafruit MAX31855 and the PID Library version 1.1.1 referenced in the Playground. I got some anomalous operation so I went looking for the problem and found something that I do not understand.

In short, the value "input" in the Compute() function is always zero. This makes the "error" in the function always equal to the Setpoint". The PID is always wrong. Here is the code for the oven so far...

*********************************************

Reflow_PID 
uses the Adafruit thermocouple MAX31855 and an SSR to
control the oven elements.
The code is adapted from the Adafruit library and the PID RelayOutput 
Example.

****************************************************/

#include <SPI.h>
#include <PID_v1.h>
#include <Adafruit_MAX31855.h>

// Default connection is using software SPI
// Software SPI declarations for MAX31855
#define MAXDO   2
#define MAXCS   3
#define MAXCLK  4

#define RELAY_PIN     5			// solid state relay pin

// initialize the Thermocouple
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

// PID declarations
double Setpoint, Input, Output;
double Kp = 2, Ki = 0, Kd = 0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
	pinMode(RELAY_PIN, OUTPUT);		// pin for solid state relay
	while (!Serial);				// wait for Serial Port to open
	Serial.begin(9600);
	delay(500);						// wait for MAX31855 to settle down

	// PID setup
	windowStartTime = millis();
	Setpoint = 70;
	myPID.SetOutputLimits(0, WindowSize);
	//turn the PID on
	myPID.SetMode(AUTOMATIC);
}

void loop() {

	double Input = thermocouple.readCelsius();		// get oven temp

	if (isnan(Input)){				// if we do not get a number from the '855
		Serial.println("Something wrong with thermocouple!");
		// Here is where we abort the cycle if the
		// Will need code to kill cycle here.
	}

	//*****************************************************************************
	Input = 20;			// here I set the Input value for troubleshooting purposes
	
	// do the PID calculations here
	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(RELAY_PIN, HIGH);

		// Debug information to serial port
		/*Serial.print("Set= ");
		Serial.print(Setpoint);
		Serial.print("  ");
		Serial.print("Input= ");
		Serial.print(Input);
		Serial.print("  ");
		Serial.print("Output= ");
		Serial.print(Output);
		Serial.print("  ");		
		Serial.print("millis - windowStartTime= ");
		Serial.print(millis() - windowStartTime);
		Serial.print("  ");
		Serial.println("        Pin= High ");
		*/
	}
	
	else {
		digitalWrite(RELAY_PIN, LOW);

		// Debug information to serial port
		/*Serial.print("Set= ");
		Serial.print(Setpoint);
		Serial.print("  ");
		Serial.print("Input= ");
		Serial.print(Input);
		Serial.print("  ");
		Serial.print("Output= ");
		Serial.print(Output);
		Serial.print("  ");
		Serial.print("millis - windowStartTime= ");
		Serial.print(millis() - windowStartTime);
		Serial.print("  ");
		Serial.println("  Pin= Low");*/
	}
}

I set the Setpoint and Input value for troubleshooting before calling the Compute() function.

In PID_v1.cpp below, I inserted some Serial.print lines in order to monitor the values being used inside the Compute() function. The line "double input = *myInput" is not passing the value of 20 along to the variable "input". I do not understand pointers well enough to interpret what is going on. I need advice on how to get the "Input" value in Reflow_PID.ino into the "input" value of the Compute() function.

/**********************************************************************************************
 * Arduino PID Library - Version 1.1.1
 * by Brett Beauregard <br3ttb@gmail.com> brettbeauregard.com
 *
 * This Library is licensed under a GPLv3 License
 **********************************************************************************************/

#if ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#include <PID_v1.h>

/*Constructor (...)*********************************************************
 *    The parameters specified here are those for for which we can't set up 
 *    reliable defaults, so we need to have the user set them.
 ***************************************************************************/
PID::PID(double *Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{
	
    myOutput = Output;
    myInput = Input;
    mySetpoint = Setpoint;
	inAuto = false;
	
	PID::SetOutputLimits(0, 255);				//default output limit corresponds to 
												//the arduino pwm limits

    SampleTime = 100;							//default Controller Sample Time is 0.1 seconds

    PID::SetControllerDirection(ControllerDirection);
    PID::SetTunings(Kp, Ki, Kd);

    lastTime = millis()-SampleTime;				
}
 
 
/* Compute() **********************************************************************
 *     This, as they say, is where the magic happens.  this function should be called
 *   every time "void loop()" executes.  the function will decide for itself whether a new
 *   pid Output needs to be computed.  returns true when the output is computed,
 *   false when nothing has been done.
 **********************************************************************************/ 
bool PID::Compute()
{
   if(!inAuto) return false;
   unsigned long now = millis();
   unsigned long timeChange = (now - lastTime);
   
   if(timeChange>=SampleTime)
   {
      /*Compute all the working error variables*/

	  double input = *myInput;	  
      double error = *mySetpoint - input;
	  
	  /* Here I insert some lines to see what values I have
	  - my "Setpoint" is 70, which I set in the .ino file
	  - my "Input" is 20, set just before the myPID.Compute() call
	    but the variable "input" is always zero
	  - this means that the "error" always equals the "Setpoint"
	  - the PID is always in error
	  */
	  Serial.print("Setpoint= ");
	  Serial.print(*mySetpoint);
	  Serial.print("  ");

	  Serial.print("input= ");
	  Serial.print(input);
	  Serial.print("  ");

	  Serial.print("error= ");
	  Serial.println(error);


      ITerm+= (ki * error);
      if(ITerm > outMax) ITerm= outMax;
      else if(ITerm < outMin) ITerm= outMin;
      double dInput = (input - lastInput);
 
      /*Compute PID Output*/
      double output = kp * error + ITerm- kd * dInput;
      
	  if(output > outMax) output = outMax;
      else if(output < outMin) output = outMin;
	  *myOutput = output;
	  
      /*Remember some variables for next time*/
      lastInput = input;
      lastTime = now;
	  return true;
   }
   else return false;
}

Has anyone else had this problem? I have spent the last few days reading and watching videos about PIDs and how they work. It all seems straightforward except that I do not understand pointers well enough. I need some advice badly.

I don't see anything wrong in that code. Does it also fail to work if you take out the Adafruit_MAX31855 library?

I remarked out the code relating to the thermocouple and made some minor changes and was able to produce output

/*********************************************

Reflow_PID 
uses the Adafruit thermocouple MAX31855 and an SSR to
control the oven elements.
The code is adapted from the Adafruit library and the PID RelayOutput 
Example.

****************************************************/

#include <SPI.h>
#include <PID_v1.h>
//#include <Adafruit_MAX31855.h>

// Default connection is using software SPI
// Software SPI declarations for MAX31855
#define MAXDO   2
#define MAXCS   3
#define MAXCLK  4

#define RELAY_PIN     5      // solid state relay pin

// initialize the Thermocouple
//Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

// PID declarations
double Setpoint, Input, Output;
double Kp = 2, Ki = 1, Kd = 0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
  pinMode(RELAY_PIN, OUTPUT);   // pin for solid state relay
  while (!Serial);        // wait for Serial Port to open
  Serial.begin(9600);
  Serial.println("test");
  delay(500);           // wait for MAX31855 to settle down

  // PID setup
  windowStartTime = millis();
  Setpoint = 70;
  myPID.SetOutputLimits(0, WindowSize);
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  Serial.println("test");
}

void loop() {

  static unsigned long _ATimer;
  if ((millis() - _ATimer) >= (100)) {
    _ATimer = millis();
  Serial.println(Output);


//  double Input = thermocouple.readCelsius();    // get oven temp

  if (isnan(Input)){        // if we do not get a number from the '855
    Serial.println("Something wrong with thermocouple!");
    // Here is where we abort the cycle if the
    // Will need code to kill cycle here.
  }

  //*****************************************************************************
  Input = 69.9;     // here I set the Input value for troubleshooting purposes
  
  // do the PID calculations here
  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(RELAY_PIN, HIGH);

    // Debug information to serial port
    /*Serial.print("Set= ");
    Serial.print(Setpoint);
    Serial.print("  ");
    Serial.print("Input= ");
    Serial.print(Input);
    Serial.print("  ");
    Serial.print("Output= ");
    Serial.print(Output);
    Serial.print("  ");   
    Serial.print("millis - windowStartTime= ");
    Serial.print(millis() - windowStartTime);
    Serial.print("  ");
    Serial.println("        Pin= High ");
    */
  }
  
  else {
    digitalWrite(RELAY_PIN, LOW);

    // Debug information to serial port
    /*Serial.print("Set= ");
    Serial.print(Setpoint);
    Serial.print("  ");
    Serial.print("Input= ");
    Serial.print(Input);
    Serial.print("  ");
    Serial.print("Output= ");
    Serial.print(Output);
    Serial.print("  ");
    Serial.print("millis - windowStartTime= ");
    Serial.print(millis() - windowStartTime);
    Serial.print("  ");
    Serial.println("  Pin= Low");*/
  }
    }
}

Attached is my reflow oven code. it has 2 stages of heat (Top Element and Bottom element) and a cooling fan I ducted the cooling air it through the bottom where you would remove the crumbs
I used 2 solid state relays pulsing them on.
I used a oven thermistor like the digital ones from walmart
and a simple mosfet switch to power the small cooling fan

I'm following the reflow curve for Amtech's SynTECH-n Solderpaste http://www.inventecusa.com/assets/syntech-n.pdf

Z

PID_RelayOutput_ReflowOvenControl_V2_1.ino (15.9 KB)

Yup, sure enough guys, it was the thermocouple. I would not have suspected a canned library from Adafruit in a million years. I will have to figure out what went wrong.

Many thanks and I will have a look at your reflow code as well. Bye for now.