Compare commits

...

4 Commits

Author SHA1 Message Date
Chris Giacofei
23f5c79cf3 make variable names more specific.
It's possible multiple vessels will need to be controlled in the future.
2024-05-02 13:00:03 -04:00
Chris Giacofei
455d5cc89f Tracking down compile errors. 2024-05-01 16:13:59 -04:00
Chris Giacofei
ac157d2acb Switch over to PID control. 2024-05-01 15:46:02 -04:00
Chris Giacofei
9be0cabfe3 Heat all the way to the setpoint. 2024-05-01 15:44:29 -04:00
4 changed files with 56 additions and 64 deletions

View File

@ -8,23 +8,23 @@
#include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C. #include <LiquidMenu.h> // LiquidMenu_config.h needs to be modified to use I2C.
#include <MD_REncoder.h> #include <MD_REncoder.h>
#include <Adafruit_MAX31865.h> #include <Adafruit_MAX31865.h>
//#include <EEPROM-Storage.h> #include <EEPROM-Storage.h>
// My Includes // My Includes
#include "config.h" #include "config.h"
#include "src/button/button.h" #include "src/button/button.h"
#include "src/slowPWM/slowPWM.h" #include "src/slowPWM/slowPWM.h"
#include "src/thermoControl/thermoControl.h" //#include "src/thermoControl/thermoControl.h"
//#include "src/Arduino-PID-Library/PID_v1.h" #include "src/Arduino-PID-Library/PID_v1.h"
double KettleDuty = 0; double KettleDuty = 0;
double KettleSetpoint = 70; double KettleSetpoint = 70;
double CurrentTemp; double CurrentTemp;
bool tuning = false; bool tuning = false;
//EEPROMStorage<double> eepromKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum EEPROMStorage<double> kettleKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum
//EEPROMStorage<double> eepromKi(9, 5.0); // Initialize at zero. EEPROMStorage<double> kettleKi(9, 5.0);
//EEPROMStorage<double> eepromKd(18, 1.0); EEPROMStorage<double> kettleKd(18, 1.0);
// User I/O objects. // User I/O objects.
Button Enter; Button Enter;
@ -32,11 +32,7 @@ slowPWM boilPWM;
MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK); MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK);
LiquidCrystal_I2C lcd(0x27, 20, 4); LiquidCrystal_I2C lcd(0x27, 20, 4);
Adafruit_MAX31865 thermoRTD = Adafruit_MAX31865(KettleRTD); Adafruit_MAX31865 thermoRTD = Adafruit_MAX31865(KettleRTD);
thermoControl Controller(&CurrentTemp, &KettleSetpoint, &KettleDuty, AUTOMATIC); PID Controller(&CurrentTemp, &KettleDuty, &KettleSetpoint, kettleKp, kettleKi, kettleKd, P_ON_M, DIRECT);
//PID ControllerPID(&CurrentTemp, &KettleDuty, &KettleSetpoint, eepromKp, eepromKi, eepromKd, P_ON_M, DIRECT);
unsigned long lastRun = 0;
// Return a character array to represent the // Return a character array to represent the
// On/Off state of the kettle. // On/Off state of the kettle.
@ -74,6 +70,8 @@ LiquidMenu menu(lcd);
// Increases/decreases the kettle output to a max // Increases/decreases the kettle output to a max
// of 100% and minimum of 0%. // of 100% and minimum of 0%.
void doEncoder() { void doEncoder() {
if (tuning) return;
uint8_t result = rotary.read(); uint8_t result = rotary.read();
uint8_t inc = 1; uint8_t inc = 1;
@ -108,7 +106,6 @@ void doEncoder() {
void setup() { void setup() {
lastRun = millis() - UpdateInterval;
Serial.begin(115200); Serial.begin(115200);
rotary.begin(); rotary.begin();
thermoRTD.begin(MAX31865_3WIRE); thermoRTD.begin(MAX31865_3WIRE);
@ -116,7 +113,6 @@ void setup() {
attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE);
pinMode(encoderCLK, INPUT_PULLUP); pinMode(encoderCLK, INPUT_PULLUP);
pinMode(encoderDT, INPUT_PULLUP); pinMode(encoderDT, INPUT_PULLUP);
Enter.begin(encoderBTN); Enter.begin(encoderBTN);
@ -143,33 +139,48 @@ void run_kettle() {
Controller.Compute(); Controller.Compute();
} }
/*
void run_tuning() { void run_tuning() {
if (Enter.pressed()) { if (Enter.pressed()) {
stopAutoTune(); if(tuning) { //cancel autotune
Controller.Cancel();
Controller.Mode(OFF);
tuning=false;
}
return;
}
// Initial setup
if(!tuning) {
KettleDuty=50;
Controller.NoiseBand(0.5);
Controller.OutputStep(30);
Controller.LookbackSec(20);
Controller.Mode(AUTOMATIC);
tuning=true;
}
if (Controller.ComputeTune() != 0) {
tuning = false;
}
if(!tuning) {
//we're done, set the tuning parameters
Controller.SetTunings(Controller.TunedKp(),Controller.TunedKi(),Controller.TunedKd());
Controller.Mode(OFF);
} }
int result = ControllerPID.ComputeTune();
if (result!=0)
{
tuning = false;
}
if(!tuning)
{ //we're done, set the tuning parameters
ControllerPID.SetTunings(ControllerPID.TunedKp(),ControllerPID.TunedKi(),ControllerPID.TunedKd());
ControllerPID.Mode(OFF);
}
} }
*/
void loop() { void loop() {
unsigned long now = millis(); unsigned long now = millis();
static unsigned long lastTime=now-2000; static unsigned long lastTime=now-250;
unsigned long timeChange = (now - lastTime); unsigned long timeChange = (now - lastTime);
static byte lastoutput = LOW; static byte lastoutput = LOW;
static double lastKettleDuty = 0; static double lastKettleDuty = 0;
static double lastKettleSetpoint = 0; static double lastKettleSetpoint = 0;
static byte lastTemperature; static byte lastTemperature;
if(timeChange >= 2000) { if(timeChange >= 250) {
CurrentTemp = 32 + 1.8 * thermoRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE); CurrentTemp = 32 + 1.8 * thermoRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE);
lastTime = now; lastTime = now;
} }
@ -177,7 +188,7 @@ void loop() {
if (!tuning) { if (!tuning) {
run_kettle(); run_kettle();
} else { } else {
//run_tuning(); run_tuning();
} }
byte output = boilPWM.Compute(KettleDuty); byte output = boilPWM.Compute(KettleDuty);
@ -195,31 +206,11 @@ void loop() {
} }
} }
/*
void startAutoTune() {
if(!tuning) {
//Set the output to the desired starting frequency.
KettleDuty=50;
ControllerPID.SetNoiseBand(1);
ControllerPID.SetOutputStep(30);
ControllerPID.SetLookbackSec(20);
ControllerPID.Mode(AUTOMATIC);
tuning=true;
}
}
void stopAutoTune() {
if(tuning) { //cancel autotune
ControllerPID.Cancel();
ControllerPID.Mode(OFF);
tuning=false;
}
}
void SaveTunings() { void SaveTunings() {
eepromKp = ControllerPID.GetKp(); kettleKp = Controller.Kp();
eepromKi = ControllerPID.GetKi(); kettleKi = Controller.Ki();
eepromKd = ControllerPID.GetKd(); kettleKd = Controller.Kd();
} }
void SerialSend() void SerialSend()
@ -230,9 +221,9 @@ void SerialSend()
if(tuning){ if(tuning){
Serial.println("tuning mode"); Serial.println("tuning mode");
} else { } else {
Serial.print("kp: ");Serial.print(ControllerPID.GetKp());Serial.print(" "); Serial.print("kp: ");Serial.print(Controller.Kp());Serial.print(" ");
Serial.print("ki: ");Serial.print(ControllerPID.GetKi());Serial.print(" "); Serial.print("ki: ");Serial.print(Controller.Ki());Serial.print(" ");
Serial.print("kd: ");Serial.print(ControllerPID.GetKd());Serial.println(); Serial.print("kd: ");Serial.print(Controller.Kd());Serial.println();
} }
} }
@ -242,13 +233,10 @@ void SerialReceive()
String myinput; String myinput;
myinput = Serial.readString(); myinput = Serial.readString();
myinput.trim(); myinput.trim();
if(myinput=="start"){ if(myinput=="tune"){
startAutoTune(); tuning=true;
} else if(myinput=="stop") {
stopAutoTune();
} else if(myinput=="save") { } else if(myinput=="save") {
SaveTunings(); SaveTunings();
} }
} }
} }
*/

@ -1 +1 @@
Subproject commit 7787498eda8955288e99a18d02581a425203bac5 Subproject commit d565cded53094ac01a63078cd4c0f1295aad67b4

View File

@ -14,24 +14,27 @@ thermoControl::thermoControl(double* current_temp, double* setpoint, double* pow
actual_temp = current_temp; actual_temp = current_temp;
hysteresis = 1.0; hysteresis = 1.0;
max_pwr_threshold = 5.0; max_pwr_threshold = 5.0;
isheating=false;
Serial.println("Controller Started"); Serial.println("Controller Started");
} }
bool thermoControl::Compute() { bool thermoControl::Compute() {
unsigned long now = millis(); unsigned long now = millis();
unsigned long timeChange = (now - lastTime); unsigned long timeChange = (now - lastTime);
if(timeChange >= SampleInterval && OpMode == AUTOMATIC) { if(timeChange >= SampleInterval && OpMode == AUTOMATIC) {
double error = *control_temp - *actual_temp; double error = *control_temp - *actual_temp;
if (error >= max_pwr_threshold) { if (error >= max_pwr_threshold) {
*output_pwm = outMax; *output_pwm = outMax;
} else if (error > hysteresis) { isheating=true;
} else if (error > hysteresis || (error <= hysteresis && error > 0 && isheating)) {
*output_pwm = 100 * error / max_pwr_threshold; *output_pwm = 100 * error / max_pwr_threshold;
if (*output_pwm > 100) *output_pwm = 100; if (*output_pwm > 100) *output_pwm = 100;
if (*output_pwm < 0) *output_pwm = 0; isheating=true;
} else { } else {
*output_pwm = 0; *output_pwm = 0;
isheating=false;
} }
lastTime = now; lastTime = now;

View File

@ -17,6 +17,7 @@ class thermoControl {
int outMin; int outMin;
int SampleInterval; int SampleInterval;
unsigned long lastTime; unsigned long lastTime;
bool isheating;
modes OpMode; modes OpMode;
public: public: