From 334ce3fafb74be978c7c60159b122e2885d11464 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Fri, 4 Oct 2024 08:52:27 +0200 Subject: [PATCH] Test naive bang-bang control algorithm for temperature --- src/bus/pwm.c | 6 ------ src/main.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/bus/pwm.c b/src/bus/pwm.c index 5a8b0af..5d6cc91 100644 --- a/src/bus/pwm.c +++ b/src/bus/pwm.c @@ -102,12 +102,6 @@ void PWM_SetValue(int port, int value) n = CLAMP(value, 100, 0) * PWM_CYCLE_TOP / 100.0f; - Info("Setting duty cycle for %s to %d/%d...", - (port == FAN01) ? "FAN01" : - (port == FAN02) ? "FAN02" : - (port == FAN03) ? "FAN03" : - "UNKNOWN", n, PWM_CYCLE_TOP); - switch (port) { case PD4: OCR1B = n; break; case PD5: OCR1A = n; break; diff --git a/src/main.c b/src/main.c index b572f0c..f839522 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,17 @@ #include +#define HYSTERESIS 1.0f + +// https://en.wikipedia.org/wiki/Bang%E2%80%93bang_control +// https://support.75f.io/hc/en-us/articles/360044956794-Deadband-and-Hysteresis +// https://www.elotech.de/fileadmin/user_upload/PID-Regelungsgrundlagen.pdf +// https://thomasfermi.github.io/Algorithms-for-Automated-Driving/Control/PID.html +// https://www.ni.com/en/shop/labview/pid-theory-explained.html +// https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller +// https://ctms.engin.umich.edu/CTMS/index.php?example=Introduction§ion=ControlPID +// https://www.youtube.com/watch?v=wkfEZmsQqiA&list=PLn8PRpmsu08pQBgjxYFXSsODEF3Jqmm-y + enum state_e { S_IDLE, @@ -121,6 +132,7 @@ static void Update(void) { char ch; cmd_t cmd; + float terr; // Parse serial commands while ((ch = UART_Getc()) >= 0) { @@ -137,13 +149,48 @@ static void Update(void) // Get latest sensor values FetchSensorValues(); - // Handle state + // Two-step (bang-bang) controller testing + + // TODO: Sanity check setpoint! + // TODO: Check thermistor for overheating! + // TODO: PID control for fan pulse-width modulation? + + // The dead band represents the lower and upper limits + // of the error between which the controller doesn’t + // react. + + state = S_IDLE; + terr = temp - temp_target; + + if (terr < -HYSTERESIS) { + state = S_HEAT_UP; + } + + if (terr > HYSTERESIS) { + state = S_COOL_DOWN; + } + switch (state) { case S_IDLE: + MOS_Disable(MOS01); + MOS_Disable(MOS02); + PWM_SetValue(FAN01, 20); + PWM_SetValue(FAN02, 20); + PWM_SetValue(FAN03, 20); break; case S_HEAT_UP: + MOS_Enable(MOS02); + MOS_Disable(MOS01); + PWM_SetValue(FAN01, 20); + PWM_SetValue(FAN02, 60); + PWM_SetValue(FAN03, 60); break; case S_COOL_DOWN: + MOS_Enable(MOS01); + MOS_Disable(MOS02); + PWM_SetValue(FAN01, 60); + PWM_SetValue(FAN02, 60); + PWM_SetValue(FAN03, 60); break; case S_DEHUMIDIFY: break; @@ -213,6 +260,11 @@ static void FetchSensorValues(void) Info("T3=%.2fC, TD3=%.2fC, RH3=%.2f%%, NT3=%.2fC", t[2], td[2], rh[2], t[5]); Info("T_AVG=%.2fC, TD_AVG=%.2fC, RH_AVG=%.2f%%", temp, dewp, rhum); Info("T_TAR=%.2fC, TD_TAR=%.2fC", temp_target, dewp_target); + Info("STATE=%s", (state == S_IDLE) ? "S_IDLE" : + (state == S_HEAT_UP) ? "S_HEAT_UP" : + (state == S_COOL_DOWN) ? "S_COOL_DOWN" : + (state == S_DEHUMIDIFY) ? "S_DEHUMIDIFY" : + "UNKNOWN"); } int main(void)