I've been cobbling together examples and other sketches to build a basic espresso machine controller.
The issue i have is that the relay controlling the heater does not turn off despite the output of the PID calc.
I have serial print debugging showing me the input value (temperature from an NTC) and the output of the PID and whether the relay is on.
Initially i get above zero output values and the heater is correctly on and the temperature approaches the setpoint, it then overshoots (by a lot, it's a thermoblock with minimal water in it), the output reduces to 0 but the heater relay stays on (i have to manually cut the power to keep it from boiling over.
I would appreciate some advice.
I've commented out some other experimental code, and i can clean it up/minimalise it properly if need be
// Thermistor Example #3 from the Adafruit Learning System guide on Thermistors
// https://learn.adafruit.com/thermistor/overview by Limor Fried, Adafruit Industries
// MIT License - please keep attribution and consider buying parts from Adafruit
// which analog pin to connect
#define THERMISTORPIN A0
// resistance at 25 degrees C
#define THERMISTORNOMINAL 100000
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 100000
#define HeaterPin 6
#define PumpPin 7
#define ButtonPin 8
unsigned long startTime;
int oldState;
long shotStart;
int samples[NUMSAMPLES];
// include the library code:
#include <LiquidCrystal.h>
#include <math.h>
#include <PID_v1.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//Define Variables we'll be connecting to
double Setpoint = 45, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, 2, 0, 0, DIRECT);
int WindowSize = 500;
unsigned long windowStartTime;
//int in1 = 7;
void setup(void) {
Serial.begin(9600);
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
analogReference(EXTERNAL);
pinMode(HeaterPin, OUTPUT);
pinMode(PumpPin, OUTPUT);
//pinMode(ButtonPin, INPUT); //no button as yet
digitalWrite(HeaterPin, HIGH); //heater off
digitalWrite(PumpPin, HIGH); //pump off
windowStartTime = millis();
//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(void) {
uint8_t i;
float average;
// take N samples in a row, with a slight delay
for (i = 0; i < NUMSAMPLES; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(10);
}
// average all the samples out
average = 0;
for (i = 0; i < NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
/* temp calculation debugging serial prints
Serial.print("Average analog reading ");
Serial.println(average);
*/
// convert the value to resistance
average = 1023 / average - 1;
average = SERIESRESISTOR / average;
/* temp calculation debugging serial prints
Serial.print("Thermistor resistance ");
Serial.println(average);
*/
//Calculates temp C from NTC resistance readings gather above
float temp;
temp = average / THERMISTORNOMINAL; // (R/Ro)
temp = log(temp); // ln(R/Ro)
temp /= BCOEFFICIENT; // 1/B * ln(R/Ro)
temp += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
temp = 1.0 / temp; // Invert
temp -= 273.15; // convert to C
//Prints calculated temperature to LCD and Serial
Serial.print("Temperature ");
Serial.print(temp);
Serial.println(" *C");
lcd.setCursor(0, 0);
lcd.print("Heating Water...");
lcd.setCursor(0, 1);
lcd.print("Temp "); lcd.print(temp); lcd.print(" "); lcd.print((char)223); lcd.print("C");
//PID
//Input = analogRead(0); //removed to add temperature as input below
Input = temp; //uses thermistor derived temperature reading as input for PID calc
Serial.print("Input: ");
Serial.println(Input); //debugging print
myPID.Compute();
Serial.print("Output: ");
Serial.println(Output); //debugging print
/************************************************
turn the output pin on/off based on pid output
************************************************/
unsigned long now = millis();
if (now - windowStartTime > WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if (Output > now - windowStartTime)
{
digitalWrite(HeaterPin, HIGH);
Serial.println("Heater Off"); //debugging print
}
else
{
digitalWrite(HeaterPin, LOW);
Serial.println("Heater On"); //debugging print
}
/* below is basic on/off code for initial relay/heater testing
//if(temp<Setpoint){
// digitalWrite(6, LOW);
// }
//if(temp>=Setpoint+0.5){ //Temperature greater than setpoint
// digitalWrite(6, HIGH);
*/
/* code for automatically starting an espresso shot once temperature is ready, and changing LCD to reflect this
digitalWrite(7, LOW); //starts a shot as soon as temperature is ready
shotStart = millis();
lcd.setCursor(0,0);
lcd.print("Pulling Shot...");
lcd.setCursor(0,1);
lcd.print("Temp "); lcd.print(temp); lcd.print(" "); lcd.print((char)223); lcd.print("C");*/
// }
/* if(millis() = shotStart + 23000){ //automatically stops shot at 23s, turns off both pump and heater
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
}
*/
/*Code to check for a button press to commence an espresso shot
int ButtonState = digitalRead(ButtonPin);
if (ButtonState == LOW) //inverted
{
if (oldState == HIGH)
{
Serial.println("Button Pushed");
digitalWrite(PumpPin, LOW); // turns the pump on
startTime = millis();
}
}
oldState = ButtonState;
if (digitalRead(PumpPin == LOW))
{
if (millis() - startTime >= 23000UL) //23s pump run
{
Serial.println("Shot Ready");
digitalWrite(PumpPin, HIGH);
}
}
*/
delay(500);
}