Test naive bang-bang control algorithm for temperature

This commit is contained in:
2024-10-04 08:52:27 +02:00
parent ce6bc8a8a9
commit 334ce3fafb
2 changed files with 53 additions and 7 deletions

View File

@@ -102,12 +102,6 @@ void PWM_SetValue(int port, int value)
n = CLAMP(value, 100, 0) * PWM_CYCLE_TOP / 100.0f; 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) { switch (port) {
case PD4: OCR1B = n; break; case PD4: OCR1B = n; break;
case PD5: OCR1A = n; break; case PD5: OCR1A = n; break;

View File

@@ -6,6 +6,17 @@
#include <avr/interrupt.h> #include <avr/interrupt.h>
#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&section=ControlPID
// https://www.youtube.com/watch?v=wkfEZmsQqiA&list=PLn8PRpmsu08pQBgjxYFXSsODEF3Jqmm-y
enum state_e enum state_e
{ {
S_IDLE, S_IDLE,
@@ -121,6 +132,7 @@ static void Update(void)
{ {
char ch; char ch;
cmd_t cmd; cmd_t cmd;
float terr;
// Parse serial commands // Parse serial commands
while ((ch = UART_Getc()) >= 0) { while ((ch = UART_Getc()) >= 0) {
@@ -137,13 +149,48 @@ static void Update(void)
// Get latest sensor values // Get latest sensor values
FetchSensorValues(); 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 doesnt
// react.
state = S_IDLE;
terr = temp - temp_target;
if (terr < -HYSTERESIS) {
state = S_HEAT_UP;
}
if (terr > HYSTERESIS) {
state = S_COOL_DOWN;
}
switch (state) { switch (state) {
case S_IDLE: case S_IDLE:
MOS_Disable(MOS01);
MOS_Disable(MOS02);
PWM_SetValue(FAN01, 20);
PWM_SetValue(FAN02, 20);
PWM_SetValue(FAN03, 20);
break; break;
case S_HEAT_UP: case S_HEAT_UP:
MOS_Enable(MOS02);
MOS_Disable(MOS01);
PWM_SetValue(FAN01, 20);
PWM_SetValue(FAN02, 60);
PWM_SetValue(FAN03, 60);
break; break;
case S_COOL_DOWN: case S_COOL_DOWN:
MOS_Enable(MOS01);
MOS_Disable(MOS02);
PWM_SetValue(FAN01, 60);
PWM_SetValue(FAN02, 60);
PWM_SetValue(FAN03, 60);
break; break;
case S_DEHUMIDIFY: case S_DEHUMIDIFY:
break; 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("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_AVG=%.2fC, TD_AVG=%.2fC, RH_AVG=%.2f%%", temp, dewp, rhum);
Info("T_TAR=%.2fC, TD_TAR=%.2fC", temp_target, dewp_target); 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) int main(void)