Hi, I am fairly unfamiliar with the Arduino PID library, I have just been going off of the few examples in the Arduino Library. However, I figured I would give it a try before making my own PID controller if I have to (which I’ve done before, just never with C++, I’ve used LabView in combination with Matlab and simulink to develop a temp controller). That being said I am having trouble with the output of this particular PID. I have run several tests with different Kp, Ki, and Kd values but no matter what I use the Output of the PID steadily climbs until it reaches its max where it sits until the programs is manually restarted (in my code this is currently set to 2000) despite how close the input is to the setpoint. This means that my relay eventually is on ~100% of the time which causes the system to go out of control and temperatures would just climb until either the heating element reaches max temp or burns out, or I stop the program from running. I will also note that this PID is controlling a SSR which is why the output ranges from 0-2000. The code is set up so that the relay will be on for a portion of the 2000 ms and off for the rest. If anyone can lend some insight or if my errors are glaringly obvious please point them out. My automatic controls skills are a little rusty to say the least.
Here is my current code:
#include <PID_v1.h>
#include <LiquidCrystal.h>
#include "Adafruit_MAX31855.h"
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,1,.1,.25, DIRECT);
int WindowSize = 2000;
unsigned long windowStartTime;
int RelayPin = 26; //sets relay to pin 6
int thermoCLK = 3;
int thermoCS = 4;
int thermoDO = 5;
int up_1 = 22; //sets switch to pin 22
int down_1 = 23; //sets switch to pin 23
//int up_10 = 24; //sets switch to pin 24
//int down_10 = 25; //sets switch to pin 25
int val_1 = 0; // variable for pin state
int val_2 = 0; // variable for pin state
//int val_3 = 0; // variable for pin state
//int val_4 = 0; // variable for pin state
int desired_temp = 200; // sets initial desired temp
int currentState_1 = 0;
int previousState_1 = 0;
int currentState_2 = 0;
int previousState_2 = 0;
//int currentState_3 = 0;
//int previousState_3 = 0;
//int currentState_4 = 0;
//int previousState_4 = 0;
// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
byte deg[8] = {
B1100, //binary code created at: http://www.quinapalus.com/hd44780udg.html
B10010, //set desired character and insert the binary code created by the website
B10010,
B1100,
B0,
B0,
B0,
};
void setup() {
windowStartTime = millis();
pinMode(up_1,INPUT); //sets up_1 as an input
pinMode(down_1,INPUT); //sets down_1 as an input
pinMode(RelayPin,OUTPUT); //sets RelayPin as an output
//pinMode(up_10,INPUT); //sets up_10 as an input
//pinMode(down_10,INPUT); //sets down_10 as an input
// starts serial communication at 9600 bits per second:
lcd.createChar(0, deg);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
Serial.begin(9600);
Setpoint = desired_temp;
Input = 60;
//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() {
long T_F = thermocouple.readFarenheit();
Setpoint = desired_temp;
val_1 = digitalRead(up_1); //reads input val of up_1
val_2 = digitalRead(down_1); //reads input val of down_1
//val_3 = digitalRead(up_10); //reads input val of up_10
//val_4 = digitalRead(down_10); //reads input val of down_10
if (val_1 == HIGH) {
currentState_1 = 1;
}
else {
currentState_1 = 0;
}
if(currentState_1 != previousState_1) {
if(currentState_1 == 1) {
desired_temp = desired_temp + 1;
delay(150);
}
}
if (val_2 == HIGH) {
currentState_2 = 1;
}
else {
currentState_2 = 0;
}
if(currentState_2 != previousState_2) {
if(currentState_2 == 1) {
desired_temp = desired_temp - 1;
delay (150);
}
}
// if (val_3 == HIGH) {
// currentState_3 = 1;
// }
// else {
// currentState_3 = 0;
// }
// if(currentState_3 != previousState_3) {
// if(currentState_3 == 1) {
// desired_temp = desired_temp + 10;
// }
// }
//
// if (val_4 == HIGH) {
// currentState_4 = 1;
// }
// else {
// currentState_4 = 0;
// }
// if(currentState_4 != previousState_4) {
// if(currentState_4 == 1) {
// desired_temp = desired_temp - 10;
// }
// }
// set the cursor to column 0, line 0
// (note: line 0 is the first row, since counting begins with 0):
lcd.setCursor(0, 0);
lcd.print("Set Temp");
// prints the current temp
lcd.print(desired_temp);
lcd.write(byte(0));
lcd.print("F ");
lcd.setCursor(0, 1);
lcd.print("Act Temp");
// prints the current temp
lcd.print(T_F);
lcd.write(byte(0));
lcd.print("F ");
double Input = T_F;
myPID.Compute();
unsigned long now = millis();
if(now - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if(Output > now - windowStartTime) {
digitalWrite(RelayPin,HIGH);
}
else {
digitalWrite(RelayPin,LOW);
}
Serial.println("output");
Serial.println(Output);
Serial.println("windowStartTime");
Serial.println(windowStartTime);
Serial.println("now");
Serial.println(now);
Serial.println("setpoint");
Serial.println(Setpoint);
}
Thank you in advance for any help provided.