Add overheat protection
This commit is contained in:
parent
53e3d47a04
commit
7bd0b44871
@ -9,13 +9,20 @@ PROJ=barista
|
|||||||
BUILD=build/$(subst :,.,$(FQBN))
|
BUILD=build/$(subst :,.,$(FQBN))
|
||||||
HEX=$(BUILD)/$(PROJ).ino.hex
|
HEX=$(BUILD)/$(PROJ).ino.hex
|
||||||
|
|
||||||
|
SRC=barista.ino \
|
||||||
|
ntc.c \
|
||||||
|
ntc.h \
|
||||||
|
pinout.h \
|
||||||
|
overheat.c \
|
||||||
|
overheat.h
|
||||||
|
|
||||||
# For host test programs
|
# For host test programs
|
||||||
CPPFLAGS=-I.
|
CPPFLAGS=-I.
|
||||||
LIBS=-lm
|
LIBS=-lm
|
||||||
|
|
||||||
all: $(HEX)
|
all: $(HEX)
|
||||||
|
|
||||||
$(HEX): barista.ino ntc.c ntc.h pinout.h
|
$(HEX): $(SRC)
|
||||||
arduino-cli compile $(OPTS) -e --fqbn $(FQBN)
|
arduino-cli compile $(OPTS) -e --fqbn $(FQBN)
|
||||||
|
|
||||||
upload: $(HEX)
|
upload: $(HEX)
|
||||||
@ -24,11 +31,14 @@ upload: $(HEX)
|
|||||||
serial:
|
serial:
|
||||||
picocom -b 9600 --lower-rts --lower-dtr /dev/ttyUSB0 --imap lfcrlf
|
picocom -b 9600 --lower-rts --lower-dtr /dev/ttyUSB0 --imap lfcrlf
|
||||||
|
|
||||||
test: test_ntc
|
test: test_ntc test_overheat
|
||||||
|
|
||||||
test_ntc: test/test_ntc.o ntc.o
|
test_ntc: test/test_ntc.o ntc.o
|
||||||
gcc $^ -o $@ $(LIBS)
|
gcc $^ -o $@ $(LIBS)
|
||||||
|
|
||||||
|
test_overheat: test/test_overheat.o overheat.o
|
||||||
|
gcc $^ -o $@ $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f test/test_ntc.o ntc.o
|
rm -f test/test_ntc.o ntc.o
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
#include "ntc.h"
|
#include "ntc.h"
|
||||||
|
#include "overheat.h"
|
||||||
#include "pinout.h"
|
#include "pinout.h"
|
||||||
#include <avr/wdt.h>
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ enum machine_state {
|
|||||||
HOT,
|
HOT,
|
||||||
BREWING,
|
BREWING,
|
||||||
COOLING,
|
COOLING,
|
||||||
|
PANIC_OVERHEAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
//int state = SLEEPING;
|
//int state = SLEEPING;
|
||||||
@ -83,6 +85,9 @@ struct state {
|
|||||||
struct btn btn[MAX_BTN];
|
struct btn btn[MAX_BTN];
|
||||||
enum buzz_state buzz_state;
|
enum buzz_state buzz_state;
|
||||||
unsigned long buzz_t0;
|
unsigned long buzz_t0;
|
||||||
|
|
||||||
|
struct overheat overheat;
|
||||||
|
unsigned long overheat_t0;
|
||||||
} g_st;
|
} g_st;
|
||||||
|
|
||||||
int read_input(int pin)
|
int read_input(int pin)
|
||||||
@ -133,6 +138,8 @@ void proc_ntc(struct state *state, const struct input *input)
|
|||||||
avg += state->ntc_array_T[i];
|
avg += state->ntc_array_T[i];
|
||||||
|
|
||||||
state->ntc_T = avg / MAX_SAMPLES;
|
state->ntc_T = avg / MAX_SAMPLES;
|
||||||
|
|
||||||
|
overheat_input(&state->overheat, millis(), state->ntc_T);
|
||||||
}
|
}
|
||||||
|
|
||||||
void proc_buttons(struct state *state, const struct input *input)
|
void proc_buttons(struct state *state, const struct input *input)
|
||||||
@ -169,10 +176,16 @@ void proc_buttons(struct state *state, const struct input *input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In PANIC_OVERHEAT state wait at least TIME_OVERHEAT_COOL and until the
|
||||||
|
* temperature goes below TIME_OVERHEAT_TEMP before doing anything. */
|
||||||
|
#define TIME_OVERHEAT_COOL 10000 /* ms */
|
||||||
|
#define TIME_OVERHEAT_TEMP 40.0 /* °C */
|
||||||
|
|
||||||
int red_min = 50;
|
int red_min = 50;
|
||||||
int red_state = red_min;
|
int red_state = red_min;
|
||||||
unsigned long brewing_time = 3000UL; /* 3 seconds */
|
unsigned long brewing_time = 3000UL; /* 3 seconds */
|
||||||
unsigned long cooling_time = 3000UL; /* 3 seconds */
|
unsigned long cooling_time = 3000UL; /* 3 seconds */
|
||||||
|
unsigned long overheat_time = 10000UL; /* 10 seconds */
|
||||||
unsigned long max_heating_time = 60000UL; /* 60 seconds */
|
unsigned long max_heating_time = 60000UL; /* 60 seconds */
|
||||||
unsigned long max_idle_time = 10000UL; /* 10 seconds */
|
unsigned long max_idle_time = 10000UL; /* 10 seconds */
|
||||||
|
|
||||||
@ -192,6 +205,13 @@ void proc_machine(struct state *st)
|
|||||||
Serial.print(temp);
|
Serial.print(temp);
|
||||||
Serial.println(" C");
|
Serial.println(" C");
|
||||||
|
|
||||||
|
/* If the machine is overheating */
|
||||||
|
if (overheat_panic(&st->overheat)) {
|
||||||
|
st->mstate = PANIC_OVERHEAT;
|
||||||
|
st->overheat_t0 = millis();
|
||||||
|
Serial.println("PANIC OVERHEATING");
|
||||||
|
}
|
||||||
|
|
||||||
/* Pressing ON cancels any operation */
|
/* Pressing ON cancels any operation */
|
||||||
if (st->mstate != SLEEPING && on) {
|
if (st->mstate != SLEEPING && on) {
|
||||||
st->mstate = SLEEPING;
|
st->mstate = SLEEPING;
|
||||||
@ -238,6 +258,13 @@ void proc_machine(struct state *st)
|
|||||||
st->heating_t0 = millis();
|
st->heating_t0 = millis();
|
||||||
Serial.println("heating");
|
Serial.println("heating");
|
||||||
}
|
}
|
||||||
|
} else if (st->mstate == PANIC_OVERHEAT) {
|
||||||
|
/* Wait until it cools down and enough time has passed */
|
||||||
|
if (st->ntc_T < TIME_OVERHEAT_TEMP &&
|
||||||
|
millis() - st->overheat_t0 > TIME_OVERHEAT_COOL) {
|
||||||
|
st->mstate = SLEEPING;
|
||||||
|
Serial.println("sleeping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,18 +305,21 @@ output_leds(const struct state *st)
|
|||||||
if (r >= 255)
|
if (r >= 255)
|
||||||
r = 0;
|
r = 0;
|
||||||
else
|
else
|
||||||
r += 3;
|
r += 5;
|
||||||
} else if (st->mstate == HOT) {
|
} else if (st->mstate == HOT) {
|
||||||
setled(PIN_LED_RED, 0);
|
setled(PIN_LED_RED, 0);
|
||||||
setled(PIN_LED_GREEN, 1);
|
setled(PIN_LED_GREEN, 1);
|
||||||
r = 0;
|
r = 0;
|
||||||
|
} else if (st->mstate == PANIC_OVERHEAT) {
|
||||||
|
setled(PIN_LED_RED, 1);
|
||||||
|
setled(PIN_LED_GREEN, 0);
|
||||||
} else if (st->mstate == BREWING) {
|
} else if (st->mstate == BREWING) {
|
||||||
setled(PIN_LED_RED, 0);
|
setled(PIN_LED_RED, 0);
|
||||||
analogWrite(PIN_LED_GREEN, g);
|
analogWrite(PIN_LED_GREEN, g);
|
||||||
if (g >= 255)
|
if (g >= 255)
|
||||||
g = 0;
|
g = 0;
|
||||||
else
|
else
|
||||||
g += 3;
|
g += 5;
|
||||||
} else {
|
} else {
|
||||||
setled(PIN_LED_RED, 0);
|
setled(PIN_LED_RED, 0);
|
||||||
setled(PIN_LED_GREEN, 0);
|
setled(PIN_LED_GREEN, 0);
|
||||||
@ -343,6 +373,8 @@ void setup()
|
|||||||
relay(PIN_HEAT, OFF);
|
relay(PIN_HEAT, OFF);
|
||||||
relay(PIN_PUMP, OFF);
|
relay(PIN_PUMP, OFF);
|
||||||
|
|
||||||
|
overheat_init(&g_st.overheat);
|
||||||
|
|
||||||
Serial.println("Ready");
|
Serial.println("Ready");
|
||||||
wdt_enable(WDTO_250MS);
|
wdt_enable(WDTO_250MS);
|
||||||
}
|
}
|
||||||
|
|||||||
1886
barista/data/dry-heat-50-C.csv
Normal file
1886
barista/data/dry-heat-50-C.csv
Normal file
File diff suppressed because it is too large
Load Diff
52
barista/overheat.c
Normal file
52
barista/overheat.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
|
#include "overheat.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
overheat_init(struct overheat *o)
|
||||||
|
{
|
||||||
|
memset(o, 0, sizeof(struct overheat));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
overheat_input(struct overheat *o, unsigned long t_ms, float temp)
|
||||||
|
{
|
||||||
|
unsigned long delta = t_ms - o->last_time;
|
||||||
|
|
||||||
|
if (delta < OVH_INTERVAL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
o->temp[o->next++] = temp;
|
||||||
|
if (o->next >= OVH_NSAMPLES)
|
||||||
|
o->next = 0;
|
||||||
|
if (o->n < OVH_NSAMPLES)
|
||||||
|
o->n++;
|
||||||
|
|
||||||
|
/* Recompute state */
|
||||||
|
float tmin = 10000.0, tmax = 0.0;
|
||||||
|
for (int i = 0; i < o->n; i++) {
|
||||||
|
if (o->temp[i] < tmin)
|
||||||
|
tmin = o->temp[i];
|
||||||
|
if (o->temp[i] > tmax)
|
||||||
|
tmax = o->temp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
o->delta = tmax - tmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
overheat_delta(struct overheat *o)
|
||||||
|
{
|
||||||
|
return o->delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
overheat_panic(struct overheat *o)
|
||||||
|
{
|
||||||
|
if (o->delta > OVH_THRESHOLD)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
barista/overheat.h
Normal file
32
barista/overheat.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
|
#ifndef BARISTA_OVERHEAT_H
|
||||||
|
#define BARISTA_OVERHEAT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OVH_NSAMPLES 20
|
||||||
|
#define OVH_INTERVAL 200 /* ms */
|
||||||
|
#define OVH_THRESHOLD 2.0 /* °C */
|
||||||
|
|
||||||
|
struct overheat {
|
||||||
|
unsigned long last_time;
|
||||||
|
float temp[OVH_NSAMPLES];
|
||||||
|
int next;
|
||||||
|
int n;
|
||||||
|
float delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
void overheat_init(struct overheat *o);
|
||||||
|
void overheat_input(struct overheat *o, unsigned long t_ms, float temp);
|
||||||
|
float overheat_delta(struct overheat *o);
|
||||||
|
int overheat_panic(struct overheat *o);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BARISTA_OVERHEAT_H */
|
||||||
@ -1,3 +1,6 @@
|
|||||||
|
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "ntc.h"
|
#include "ntc.h"
|
||||||
|
|
||||||
|
|||||||
36
barista/test/test_overheat.c
Normal file
36
barista/test/test_overheat.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "overheat.h"
|
||||||
|
|
||||||
|
/* Read a CSV from the stdin in the format
|
||||||
|
* <time_in_seconds> <state> <temp_in_C>
|
||||||
|
* skipping the first row (header).
|
||||||
|
*
|
||||||
|
* Outputs overheat state. */
|
||||||
|
|
||||||
|
#define MAX_LINE 1024
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
char buf[MAX_LINE];
|
||||||
|
fgets(buf, MAX_LINE, stdin);
|
||||||
|
|
||||||
|
float t, temp;
|
||||||
|
int st;
|
||||||
|
|
||||||
|
struct overheat ovh;
|
||||||
|
overheat_init(&ovh);
|
||||||
|
|
||||||
|
while (scanf("%f %d %f", &t, &st, &temp) == 3) {
|
||||||
|
|
||||||
|
overheat_input(&ovh, t * 1000.0, temp);
|
||||||
|
float delta = overheat_delta(&ovh);
|
||||||
|
int panic = overheat_panic(&ovh);
|
||||||
|
|
||||||
|
printf("%.3f %d %.2f %.1f %s\n", t, st, temp, delta, panic ? "PANIC" : "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user