fix overshoot

This commit is contained in:
Vincent van der Wal
2025-09-07 15:41:16 +02:00
parent 46cb96d26b
commit e4f93be75e
3 changed files with 121 additions and 44 deletions
+27 -22
View File
@@ -9,10 +9,7 @@
#include "secrets.h"
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");
// Json Variable to Hold Sensor Readings
@@ -30,19 +27,23 @@ int thermoCLK = 5;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
float temperature = 0;
int targetTemp = 300;
float setOverShoot = 15;
float setUnderShoot = 10;
float setOverShoot = 20;
float setUnderShoot = 20;
float derivedOverShoot = targetTemp;
float derivedUnderShoot = targetTemp;
unsigned long lastSwitch = 0;
unsigned long switchDelay = 30000; // 30s
unsigned long switchDelay = 30000; // 15s
bool autoSwitch = true;
// Get Sensor Readings and return JSON object
String getSensorReadings()
{
readings["temperature"] = thermocouple.readCelsius();
temperature = thermocouple.readCelsius();
readings["temperature"] = temperature;
if (digitalRead(relay) == HIGH)
{
readings["relais"] = 1;
@@ -51,6 +52,7 @@ String getSensorReadings()
{
readings["relais"] = 0;
}
readings["target_temp"] = targetTemp;
readings["derived_overshoot"] = derivedOverShoot;
readings["derived_undershoot"] = derivedUnderShoot;
@@ -161,23 +163,23 @@ void regulateRelais()
{
if (autoSwitch)
{
float sinceLastSwitch = millis() - lastSwitch;
float fiveMinutesInMillis = 5 * 60 * 1000;
float shootFactor = sinceLastSwitch / fiveMinutesInMillis;
float overshoot = setOverShoot * shootFactor; // derive over 5 mins -> 1 min eq. 3°C, 5mins eq. 15°C
float dirivedOvershoot = min(overshoot, setOverShoot);
float undershoot = setUnderShoot * shootFactor; // derive over 5 min -> 1 min eq. 3°C, 5mins eq. 15°C
float dirivedUndershoot = min(undershoot, setUnderShoot);
float overShootCorrectedTarget = derivedOverShoot = targetTemp - dirivedOvershoot;
float underShootCorrectedTarget = derivedUnderShoot = targetTemp + dirivedUndershoot;
if ((millis() - lastSwitch) > switchDelay)
{
float temperature = thermocouple.readCelsius();
float sinceLastSwitch = millis() - lastSwitch;
float fiveMinutesInMillis = 5 * 60 * 1000;
float shootFactor = sinceLastSwitch / fiveMinutesInMillis;
float overshoot = setOverShoot * shootFactor; // derive over 5 mins -> 1 min eq. 3°C, 5mins eq. 15°C
float dirivedOvershoot = min(overshoot, setOverShoot);
float undershoot = setUnderShoot * shootFactor; // derive over 5 min -> 1 min eq. 3°C, 5mins eq. 15°C
float dirivedUndershoot = min(undershoot, setUnderShoot);
float overShootCorrectedTarget = derivedOverShoot = targetTemp - dirivedOvershoot;
float underShootCorrectedTarget = derivedUnderShoot = targetTemp + dirivedUndershoot;
if (temperature > overShootCorrectedTarget) // > 285°C
if (temperature > overShootCorrectedTarget) // > 280°C
{
if (digitalRead(relay) == HIGH)
{
@@ -186,7 +188,10 @@ void regulateRelais()
resetDerivedValues();
}
}
else if (temperature < underShootCorrectedTarget) // < 310°C
}
if ((millis() - lastSwitch) > switchDelay)
{
if (temperature < underShootCorrectedTarget) // < 320°C
{
if (digitalRead(relay) == LOW)
{
+93 -21
View File
@@ -28,15 +28,23 @@ let relaisData = [
let temp = 300;
let targetTemp = 300
let setOverShoot = 30
let setUnderShoot = 30
let targetTempOverShoot = 300
let targetTempUnderShoot = 300
let lastSwitch = new Date()
let lastSwitchDuration = 0
const oven = document.querySelector('#oven')
const temperature = document.querySelector('#temperature')
const relaisSwitch = document.querySelector('#relais_switch')
const relaisSwitchInput: HTMLInputElement | null = document.querySelector('#relais_switch_input')
const targetTempInput: HTMLInputElement | null = document.querySelector('#target_temperature')
let spoofInterval = 10
let speedFactor = 250 / spoofInterval
const switchDelay = 60 / speedFactor * 1000
let maxValues = 4 * 60 * 60 // 60 minutes (4 values/sec)
let hs: Highcharts.StockChart;
@@ -91,10 +99,10 @@ const createChart = () => {
enabled: false
},
title: {
text: 'Temperature',
align: 'left',
},
// title: {
// text: 'Temperature',
// align: 'left',
// },
rangeSelector: {
enabled: false,
@@ -218,36 +226,95 @@ const onLoad = () => {
}
let d = new Date()
if (temp < 150) {
temp = temp + Math.random() * 4 - 1
} else if (temp < 20) {
temp = temp + Math.random() * 4 - 1.3
} else if (temp < targetTemp) {
temp = temp + Math.random() * 4 - 1.5
} else if (temp >= targetTemp) {
temp = temp + Math.random() * 3 - 1.6
}
if (relais) {
temp = temp + 0.2
if (temp < (targetTemp / 2)) {
temp = temp + Math.random() * 0.5 - 0.125
} else if (temp < (targetTemp / (3 / 2))) {
temp = temp + Math.random() * 0.5 - 0.15
} else {
temp = temp - 0.1
temp = temp + Math.random() * 0.5 - 0.25
}
let shootFactor = Math.min(((((d.getTime() - lastSwitch.getTime()) / speedFactor) - ((lastSwitchDuration * 0.5) / speedFactor))) / ((3 * 60 * 1000) / speedFactor), 1) // 5mins
shootFactor = shootFactor
if (relais == 0) {
temp = temp - 0.8 * shootFactor
} else {
temp = temp + 1 * shootFactor
}
let mod = temp % 0.25
if (mod > 0.125) {
temp = temp - mod + 0.25
} else {
temp = temp - mod
}
if (temperature)
temperature.innerHTML = temp.toFixed(2);
temperatureData.push([d.getTime(), temp])
relaisData.push([d.getTime(), relais])
temperatureData.push([d.getTime(), temp])
let derivedShootFactor = Math.min(((d.getTime() - lastSwitch.getTime()) / speedFactor) / ((3 * 60 * 1000) / speedFactor), 1) // 5mins
let overshoot = setOverShoot * derivedShootFactor; // derive over 5 mins -> 1 min eq. 3°C, 5mins eq. 15°C
let dirivedOvershoot = Math.min(overshoot, setOverShoot);
let undershoot = setUnderShoot * derivedShootFactor; // derive over 5 min -> 1 min eq. 3°C, 5mins eq. 15°C
let dirivedUndershoot = Math.min(undershoot, setUnderShoot);
targetTempOverShoot = targetTemp - dirivedOvershoot;
targetTempUnderShoot = targetTemp + dirivedUndershoot;
if ((d.getTime() - lastSwitch.getTime()) > switchDelay) {
if (temp > targetTempOverShoot) // > 270 °C
{
if (relais == 1) {
relais = 0;
oven?.classList.remove('on')
relaisSwitch?.classList.remove('on')
if (relaisSwitchInput)
relaisSwitchInput.checked = false
targetTempOverShoot = targetTemp
targetTempUnderShoot = targetTemp
lastSwitchDuration = d.getTime() - lastSwitch.getTime()
lastSwitch = new Date()
}
}
}
if ((d.getTime() - lastSwitch.getTime()) > switchDelay) {
if (temp < targetTempUnderShoot) // < 310°C
{
if (relais == 0) {
relais = 1;
oven?.classList.add('on')
relaisSwitch?.classList.add('on')
if (relaisSwitchInput)
relaisSwitchInput.checked = true
targetTempOverShoot = targetTemp
targetTempUnderShoot = targetTemp
lastSwitchDuration = d.getTime() - lastSwitch.getTime()
lastSwitch = new Date()
}
}
}
relaisData.push([d.getTime(), relais])
hs.xAxis[0].update({ plotBands: getRelaisBands() })
hs.yAxis[0].update({ plotLines: getTargetLines() })
hs.series[0].setData(temperatureData, true)
}, 250)
}, spoofInterval)
}
}
}
window.addEventListener('load', onLoad);
const getReadings = () => {
@@ -329,6 +396,9 @@ const switchRelais = () => {
ws.send("switchRelais");
} else {
// spoof some test data
let d = new Date()
lastSwitchDuration = d.getTime() - lastSwitch.getTime()
lastSwitch = new Date()
if (!relais) {
relais = 1
oven?.classList.add('on')
@@ -338,7 +408,6 @@ const switchRelais = () => {
} else {
relais = 0
oven?.classList.remove('on')
relaisSwitch?.classList.remove('on')
if (relaisSwitchInput)
relaisSwitchInput.checked = false
@@ -349,10 +418,13 @@ const switchRelais = () => {
const changeTargetTemp = (e: Event) => {
const target = e.target as HTMLTextAreaElement;
let value = Number(target?.value)
// targetTemp = value
console.log('Changed target temp to ' + value)
if (!import.meta.env.DEV) {
ws.send("setTargetTemp: " + pad(value, 3));
} else {
targetTemp = value
targetTempOverShoot = value
targetTempUnderShoot = value
}
}