sal_murd:
I'm still not able to get the tuning appropriate. The way it is switching on and off would damage the heater. can you please help me understand how its actually working with pwm. my code is updated as below and the switching on and off is a bit faster for the heating element.
/********************************************************
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" Tt'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 <PID_v1.h>
#include <SPI.h>
#include "Adafruit_MAX31855.h"
#define RelayPin 8
// Example creating a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO 3
#define MAXCS 4
#define MAXCLK 5
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
double Kp = 5, Ki = 2, Kd = 0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
int WindowSize = 1000;
unsigned long windowStartTime;
void setup()
{
Serial.begin(9600);
while (!Serial) delay(1); // wait for Serial on Leonardo/Zero, etc
Serial.println("MAX31855 test");
// wait for MAX chip to stabilize
delay(500);
pinMode(RelayPin, OUTPUT);
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint = 30;
//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()
{
double c = thermocouple.readCelsius();
if (isnan(c)) {
Serial.println("Something wrong with thermocouple!");
} else {
Serial.print("C = ");
Serial.println(c);
}
delay(500);
Input = c;
myPID.Compute();
Serial.print("myPID.Compute() = ");
Serial.println(myPID.Compute());
/************************************************
turn the output pin on/off based on pid output
************************************************/
unsigned long now = millis();
Serial.println(windowStartTime);
if (now - windowStartTime > WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
Serial.print("Output = ");
Serial.println(Output);
Serial.print("Now = ");
Serial.println(now);
if (Output > now - windowStartTime) digitalWrite(RelayPin, HIGH);
else digitalWrite(RelayPin, LOW);
}
you will need to consider these changes I have documented in the modified code. sorry I couldn't compile and test, I am lacing one of the libraries you are using
/********************************************************
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" Tt'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 <PID_v1.h>
#include <SPI.h>
#include "Adafruit_MAX31855.h"
#define RelayPin 8
// Example creating a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO 3
#define MAXCS 4
#define MAXCLK 5
#define PIDSampleRate 100 //default is 100 miliseconds
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
double Kp = 5, Ki = 2, Kd = 0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
int WindowSize = 1000;
unsigned long windowStartTime;
void setup()
{
Serial.begin(9600);
while (!Serial) delay(1); // wait for Serial on Leonardo/Zero, etc
Serial.println("MAX31855 test");
// wait for MAX chip to stabilize
delay(500);
pinMode(RelayPin, OUTPUT);
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint = 30;
//tell the PID to range between 0 and the full window size
myPID.SetSampleTime(PIDSampleRate); //default is 100 miliseconds
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
static unsigned long timerDelay;
if ((millis() - timerDelay) >= (PIDSampleRate - 2)) {// lets get the temperature 2 miliseconds prior to the next PID calculation
timerDelay = millis(); //
double c = thermocouple.readCelsius();
if (isnan(c)) {
Serial.println("Something wrong with thermocouple!");
} else {
Serial.print("C = ");
Serial.println(c);
}
Input = c;
}
if (myPID.Compute()) { // Compute returns true when it actually does the calculation
timerDelay = millis(); // adjust the timer to match Compute delay timer
/************************************************
turn the output pin on/off based on pid output
************************************************/
unsigned long now = millis();
Serial.println(windowStartTime);
if (now - windowStartTime > WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
Serial.print("Output = ");
Serial.println(Output);
Serial.print("Now = ");
Serial.println(now);
if (Output > now - windowStartTime) digitalWrite(RelayPin, HIGH);
else digitalWrite(RelayPin, LOW);
}
}
The Compute has a built-in blink without delay timer which messes with your code.
also your delay(500); is corrupting your PID calculations.
Start tuning with Integral slowly increasing until you start to swing. then back down
now by adding a little proportional to the code will speed up the landing of the setpoint
Dirivitive is more for reacting to sudden changes either in setpoint or in the environment. derivative shouldn't be needed until fine-tuning for quick recovery after a change occurs
Hope this helps