I am attempting to hack an old vacuum oven by adding a PID control using a relay. (My code is based on this: Arduino Playground - PIDLibraryRelayOutputExample) The PID output is supposed to range between 0 and 5000, which corresponds to the time, within a 5000 ms window, for which the relay will turn on the oven. My issue is that no matter which constants I use, the PID output remains at 100% and stays on after the set temperature has been reached. The oven's temperature itself tends to coast an additional 10 or more degrees after the heating elements are turned off so, ideally, I'd think we'd want the output to decrease as we approach the setpoint. Any help would be appreciated, and the code is below.
#include <math.h>
#include <SPI.h>
#include <PID_v1.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
#define MAX6675_CS 10
#define MAX6675_SO 12
#define MAX6675_SCK 13
#define RelayPin 11
//Define Variables we'll be connecting to
double Set_temp, Input, Output;
double kp = 2;
double ki = 5;
double kd = 1;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Set_temp, kp, ki, kd, DIRECT);
int WindowSize = 5000;
unsigned long windowStartTime;
void setup()
{
lcd.begin(16,2);
Serial.begin(9600);
pinMode(RelayPin, OUTPUT);
windowStartTime = millis();
//initialize the variables we're linked to
Set_temp = 60;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
//For the normally open relay configuration, the oven is connected to the COM and NO pins of the relay. A HIGH signal will close the circuit and operate the oven.
//For the normally closed relay configurations, the oven is connected to the COM and NC pins of the relay. A LOW signal will close the circuit and operate the oven.
void loop() {
double temperature_read = readThermocouple();
Input = temperature_read;
myPID.Compute();
// /************************************************
// turn the output pin on/off based on pid output
// ************************************************/
lcd.setCursor(0,0);
lcd.print("TEMPERATURE");
lcd.setCursor(7,1);
lcd.print(temperature_read,1);
delay(1000);
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.print(millis());
Serial.print(",");
Serial.print(Input);
Serial.print(",");
Serial.print(Output);
Serial.print(",");
Serial.println();;
}
// make temperature adjustments here
double readThermocouple() {
uint16_t v;
pinMode(MAX6675_CS, OUTPUT);
pinMode(MAX6675_SO, INPUT);
pinMode(MAX6675_SCK, OUTPUT);
digitalWrite(MAX6675_CS, LOW);
delay(1);
// Read in 16 bits,
// 15 = 0 always
// 14..2 = 0.25 degree counts MSB First
// 2 = 1 if thermocouple is open circuit
// 1..0 = uninteresting status
v = shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
v <<= 8;
v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
digitalWrite(MAX6675_CS, HIGH);
if (v & 0x4)
{
// Bit 2 indicates if the thermocouple is disconnected
return NAN;
}
// The lower three bits (0,1,2) are discarded status bits
v >>= 3;
// The remaining bits are the number of 0.25 degree (C) counts
return v*0.25;
}