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 <MD_REncoder.h>
#include <Adafruit_MAX31865.h>
//#include <EEPROM-Storage.h>
#include <EEPROM-Storage.h>
// My Includes
#include "config.h"
#include "src/button/button.h"
#include "src/slowPWM/slowPWM.h"
#include "src/thermoControl/thermoControl.h"
//#include "src/Arduino-PID-Library/PID_v1.h"
//#include "src/thermoControl/thermoControl.h"
#include "src/Arduino-PID-Library/PID_v1.h"
double KettleDuty = 0;
double KettleSetpoint = 70;
double CurrentTemp;
bool tuning = false;
//EEPROMStorage<double> eepromKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum
//EEPROMStorage<double> eepromKi(9, 5.0); // Initialize at zero.
//EEPROMStorage<double> eepromKd(18, 1.0);
EEPROMStorage<double> kettleKp(0, 2.0); // 9 bytes for doubles 8 + 1 for checksum
EEPROMStorage<double> kettleKi(9, 5.0);
EEPROMStorage<double> kettleKd(18, 1.0);
// User I/O objects.
Button Enter;
@ -32,11 +32,7 @@ slowPWM boilPWM;
MD_REncoder rotary = MD_REncoder(encoderDT, encoderCLK);
LiquidCrystal_I2C lcd(0x27, 20, 4);
Adafruit_MAX31865 thermoRTD = Adafruit_MAX31865(KettleRTD);
thermoControl Controller(&CurrentTemp, &KettleSetpoint, &KettleDuty, AUTOMATIC);
//PID ControllerPID(&CurrentTemp, &KettleDuty, &KettleSetpoint, eepromKp, eepromKi, eepromKd, P_ON_M, DIRECT);
unsigned long lastRun = 0;
PID Controller(&CurrentTemp, &KettleDuty, &KettleSetpoint, kettleKp, kettleKi, kettleKd, P_ON_M, DIRECT);
// Return a character array to represent the
// On/Off state of the kettle.
@ -74,6 +70,8 @@ LiquidMenu menu(lcd);
// Increases/decreases the kettle output to a max
// of 100% and minimum of 0%.
void doEncoder() {
if (tuning) return;
uint8_t result = rotary.read();
uint8_t inc = 1;
@ -108,7 +106,6 @@ void doEncoder() {
void setup() {
lastRun = millis() - UpdateInterval;
Serial.begin(115200);
rotary.begin();
thermoRTD.begin(MAX31865_3WIRE);
@ -116,7 +113,6 @@ void setup() {
attachInterrupt(digitalPinToInterrupt(encoderCLK), doEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderDT), doEncoder, CHANGE);
pinMode(encoderCLK, INPUT_PULLUP);
pinMode(encoderDT, INPUT_PULLUP);
Enter.begin(encoderBTN);
@ -143,33 +139,48 @@ void run_kettle() {
Controller.Compute();
}
/*
void run_tuning() {
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() {
unsigned long now = millis();
static unsigned long lastTime=now-2000;
static unsigned long lastTime=now-250;
unsigned long timeChange = (now - lastTime);
static byte lastoutput = LOW;
static double lastKettleDuty = 0;
static double lastKettleSetpoint = 0;
static byte lastTemperature;
if(timeChange >= 2000) {
if(timeChange >= 250) {
CurrentTemp = 32 + 1.8 * thermoRTD.temperature(RNOMINAL_KETTLE, RREF_KETTLE);
lastTime = now;
}
@ -177,7 +188,7 @@ void loop() {
if (!tuning) {
run_kettle();
} else {
//run_tuning();
run_tuning();
}
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() {
eepromKp = ControllerPID.GetKp();
eepromKi = ControllerPID.GetKi();
eepromKd = ControllerPID.GetKd();
kettleKp = Controller.Kp();
kettleKi = Controller.Ki();
kettleKd = Controller.Kd();
}
void SerialSend()
@ -230,9 +221,9 @@ void SerialSend()
if(tuning){
Serial.println("tuning mode");
} else {
Serial.print("kp: ");Serial.print(ControllerPID.GetKp());Serial.print(" ");
Serial.print("ki: ");Serial.print(ControllerPID.GetKi());Serial.print(" ");
Serial.print("kd: ");Serial.print(ControllerPID.GetKd());Serial.println();
Serial.print("kp: ");Serial.print(Controller.Kp());Serial.print(" ");
Serial.print("ki: ");Serial.print(Controller.Ki());Serial.print(" ");
Serial.print("kd: ");Serial.print(Controller.Kd());Serial.println();
}
}
@ -242,13 +233,10 @@ void SerialReceive()
String myinput;
myinput = Serial.readString();
myinput.trim();
if(myinput=="start"){
startAutoTune();
} else if(myinput=="stop") {
stopAutoTune();
if(myinput=="tune"){
tuning=true;
} else if(myinput=="save") {
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;
hysteresis = 1.0;
max_pwr_threshold = 5.0;
isheating=false;
Serial.println("Controller Started");
}
bool thermoControl::Compute() {
unsigned long now = millis();
unsigned long timeChange = (now - lastTime);
if(timeChange >= SampleInterval && OpMode == AUTOMATIC) {
double error = *control_temp - *actual_temp;
if (error >= max_pwr_threshold) {
*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;
if (*output_pwm > 100) *output_pwm = 100;
if (*output_pwm < 0) *output_pwm = 0;
isheating=true;
} else {
*output_pwm = 0;
isheating=false;
}
lastTime = now;

View File

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