mirror of
https://github.com/vincentvdwal/crust-craft.git
synced 2026-08-18 09:26:37 +02:00
remove Kd
This commit is contained in:
+41
-79
@@ -10,47 +10,52 @@
|
||||
#include "secrets.h"
|
||||
#include "pid.h"
|
||||
|
||||
// #define RELAY 21;
|
||||
// #define THERMO_DO 19;
|
||||
// #define THERMO_CS 23;
|
||||
// #define THERMO_CLK 5;
|
||||
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebSocket ws("/ws");
|
||||
|
||||
// Json Variable to Hold Sensor Readings
|
||||
JsonDocument readings;
|
||||
String jsonString;
|
||||
|
||||
// Timer variables
|
||||
unsigned long lastTime = 0;
|
||||
unsigned long timerDelay = 500;
|
||||
unsigned long lastSensor = 0;
|
||||
unsigned long SENSOR_INTERVAL = 100;
|
||||
|
||||
unsigned long lastWebSocket = 0;
|
||||
unsigned long WS_INTERVAL = 500;
|
||||
|
||||
int relay = 21;
|
||||
int thermoDO = 19;
|
||||
int thermoCS = 23;
|
||||
int thermoCLK = 5;
|
||||
|
||||
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
|
||||
|
||||
float temperature = 0;
|
||||
int targetTemp = 300;
|
||||
float setOverShoot = 20;
|
||||
float setUnderShoot = 20;
|
||||
float derivedOverShoot = targetTemp;
|
||||
float derivedUnderShoot = targetTemp;
|
||||
|
||||
unsigned long lastSwitch = 0;
|
||||
unsigned long autoSwitchDelay = 20000; // 20s
|
||||
float pwmSwitchDelayOn = 2000; // 4s
|
||||
float pwmSwitchDelayOff = 4000; // 7s
|
||||
float pwmSwitchDelayOn = 2000; // 2s
|
||||
float pwmSwitchDelayOff = 4000; // 4s
|
||||
|
||||
float power = 0;
|
||||
|
||||
float kp = 0.25;
|
||||
float ki = 0.25;
|
||||
float kd = 0.25;
|
||||
float kp = 0.540938;
|
||||
float ki = 0.000721;
|
||||
float kd = 0.0;
|
||||
|
||||
String mode = "off";
|
||||
|
||||
PIDController pid(kp, ki, kd, 100.0, 0.0, 50.0); // Kp, Ki, Kd, max, min, integ_max
|
||||
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
|
||||
|
||||
PIDController pid(kp, ki, kd, 100.0, 0.0, 100.0); // Kp, Ki, Kd, max, min, max_integral
|
||||
|
||||
// Get Sensor Readings and return JSON object
|
||||
String getSensorReadings()
|
||||
|
||||
{
|
||||
JsonDocument readings;
|
||||
String jsonString;
|
||||
|
||||
temperature = thermocouple.readCelsius();
|
||||
|
||||
readings["temperature"] = temperature;
|
||||
@@ -65,10 +70,10 @@ String getSensorReadings()
|
||||
}
|
||||
|
||||
readings["target_temp"] = targetTemp;
|
||||
readings["derived_overshoot"] = derivedOverShoot;
|
||||
readings["derived_undershoot"] = derivedUnderShoot;
|
||||
|
||||
readings["mode"] = mode;
|
||||
readings["pid"] = power;
|
||||
|
||||
readings["pwm_on"] = pwmSwitchDelayOn;
|
||||
readings["pwm_off"] = pwmSwitchDelayOff;
|
||||
|
||||
@@ -100,7 +105,8 @@ void initWiFi()
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.print('.');
|
||||
delay(1000);
|
||||
delay(SENSOR_INTERVAL);
|
||||
yield();
|
||||
}
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
@@ -110,12 +116,6 @@ void notifyClients(String sensorReadings)
|
||||
ws.textAll(sensorReadings);
|
||||
}
|
||||
|
||||
void resetDerivedValues()
|
||||
{
|
||||
derivedOverShoot = targetTemp;
|
||||
derivedUnderShoot = targetTemp;
|
||||
}
|
||||
|
||||
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
|
||||
{
|
||||
AwsFrameInfo *info = (AwsFrameInfo *)arg;
|
||||
@@ -142,7 +142,6 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
|
||||
digitalWrite(relay, HIGH);
|
||||
lastSwitch = millis();
|
||||
}
|
||||
resetDerivedValues();
|
||||
}
|
||||
if (message.startsWith("setTargetTemp"))
|
||||
{
|
||||
@@ -180,19 +179,19 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
|
||||
{
|
||||
String k = message.substring(6, 12);
|
||||
kp = k.toFloat();
|
||||
// pid.setSetKp(0.3);
|
||||
pid.setSetKp(kp);
|
||||
}
|
||||
if (message.startsWith("setKi"))
|
||||
{
|
||||
String k = message.substring(6, 12);
|
||||
ki = k.toFloat();
|
||||
// pid.setSetKp(0.3);
|
||||
pid.setSetKi(ki);
|
||||
}
|
||||
if (message.startsWith("setKd"))
|
||||
{
|
||||
String k = message.substring(6, 12);
|
||||
kd = k.toFloat();
|
||||
// pid.setSetKp(0.3);
|
||||
pid.setSetKd(kd);
|
||||
}
|
||||
if (message.startsWith("setPWMOn"))
|
||||
{
|
||||
@@ -241,48 +240,6 @@ void initWebSocket()
|
||||
|
||||
void regulateRelais()
|
||||
{
|
||||
if (mode == "auto_switch")
|
||||
{
|
||||
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) > autoSwitchDelay)
|
||||
{
|
||||
|
||||
if (temperature > overShootCorrectedTarget) // > 280°C
|
||||
{
|
||||
if (digitalRead(relay) == HIGH)
|
||||
{
|
||||
digitalWrite(relay, LOW);
|
||||
lastSwitch = millis();
|
||||
resetDerivedValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((millis() - lastSwitch) > autoSwitchDelay)
|
||||
{
|
||||
if (temperature < underShootCorrectedTarget) // < 320°C
|
||||
{
|
||||
if (digitalRead(relay) == LOW)
|
||||
{
|
||||
digitalWrite(relay, HIGH);
|
||||
lastSwitch = millis();
|
||||
resetDerivedValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == "pwm")
|
||||
{
|
||||
if ((millis() - lastSwitch) > pwmSwitchDelayOn)
|
||||
@@ -305,7 +262,7 @@ void regulateRelais()
|
||||
}
|
||||
if (mode == "pid")
|
||||
{
|
||||
// output = Kp×error + Ki×∫error×dt + Kd×(Δerror/Δt)`[^2][^5]
|
||||
// output = Kp×error + Ki×∫error×dt + Kd×(Δerror/Δt)
|
||||
power = pid.compute(temperature);
|
||||
pwmSwitchDelayOff = (pwmSwitchDelayOn / (power / 100)) - pwmSwitchDelayOn;
|
||||
|
||||
@@ -353,7 +310,7 @@ void setup()
|
||||
|
||||
// Create PID controller instance
|
||||
pid.setSetpoint(targetTemp);
|
||||
pid.setDt(2);
|
||||
pid.setDt(SENSOR_INTERVAL / 1000);
|
||||
|
||||
ElegantOTA.begin(&server);
|
||||
|
||||
@@ -363,12 +320,17 @@ void setup()
|
||||
|
||||
void loop()
|
||||
{
|
||||
if ((millis() - lastTime) > timerDelay)
|
||||
if ((millis() - lastSensor) > SENSOR_INTERVAL)
|
||||
{
|
||||
regulateRelais();
|
||||
lastSensor = millis();
|
||||
}
|
||||
|
||||
if ((millis() - lastWebSocket) > WS_INTERVAL)
|
||||
{
|
||||
String sensorReadings = getSensorReadings();
|
||||
notifyClients(sensorReadings);
|
||||
regulateRelais();
|
||||
lastTime = millis();
|
||||
lastWebSocket = millis();
|
||||
}
|
||||
|
||||
ws.cleanupClients();
|
||||
|
||||
+8
-8
@@ -51,16 +51,16 @@ double PIDController::compute(double current_temp)
|
||||
integral += ki * error * dt;
|
||||
integral = clamp(integral, -integral_max, integral_max);
|
||||
|
||||
// Derivative
|
||||
double d_term = 0.0;
|
||||
if (!first_run)
|
||||
{
|
||||
d_term = kd * (error - prev_error) / dt;
|
||||
}
|
||||
first_run = false;
|
||||
// // Derivative
|
||||
// double d_term = 0.0;
|
||||
// if (!first_run)
|
||||
// {
|
||||
// d_term = kd * (error - prev_error) / dt;
|
||||
// }
|
||||
// first_run = false;
|
||||
|
||||
// Output
|
||||
double output = p_term + integral + d_term;
|
||||
double output = p_term + integral; // d_term;
|
||||
output = clamp(output, min_output, max_output);
|
||||
|
||||
prev_error = error;
|
||||
|
||||
+249
-262
@@ -1,29 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import Chart from 'chart.js/auto';
|
||||
import 'chartjs-adapter-date-fns';
|
||||
|
||||
import annotationPlugin from 'chartjs-plugin-annotation';
|
||||
|
||||
import { nl } from 'date-fns/locale';
|
||||
|
||||
import { pad } from '$lib/utils';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let gateway = `ws://${page.url.host}/ws`;
|
||||
let ws: WebSocket;
|
||||
|
||||
const now = new Date();
|
||||
|
||||
let mode = $state('off');
|
||||
let temp = $state(300);
|
||||
let relais = $state(0);
|
||||
let targetTemp = $state(300);
|
||||
let setOverShoot = 20;
|
||||
let setUnderShoot = 20;
|
||||
let targetTempOverShoot = $state(targetTemp);
|
||||
let targetTempUnderShoot = $state(targetTemp);
|
||||
let calculatedPidOutput = $state(0);
|
||||
|
||||
let lastSwitch = new Date();
|
||||
@@ -34,7 +21,6 @@
|
||||
let pauseGraphUpdate = $state(false);
|
||||
let spoofInterval = 250;
|
||||
let speedFactor = 250 / spoofInterval;
|
||||
const switchDelay = (30 / speedFactor) * 1000;
|
||||
let pwmOn = $state(2);
|
||||
let pwmOnDelay = (2 / speedFactor) * 1000;
|
||||
let pwmOff = $state(4);
|
||||
@@ -44,260 +30,261 @@
|
||||
let ki = $state(0.25);
|
||||
let kd = $state(0.25);
|
||||
|
||||
let maxValues = 4 * 2 * 60 * 60; // 120 minutes (4 values/sec)
|
||||
let maxValues = 24 * 2 * 60 * 60; // 24h (2 values/sec)
|
||||
|
||||
let temperatureData: Array<[number, number]> = [];
|
||||
let relaisData: Array<[number, number]> = [];
|
||||
let powerData: Array<[number, number]> = [];
|
||||
|
||||
let downloadCSVButton: HTMLElement;
|
||||
let modeSpan: HTMLElement;
|
||||
|
||||
const getRelaisBands = () => {
|
||||
let relaisBands = {};
|
||||
let active = false;
|
||||
let count = 0;
|
||||
// const getRelaisBands = () => {
|
||||
// let relaisBands = {};
|
||||
// let active = false;
|
||||
// let count = 0;
|
||||
|
||||
for (let r of relaisData) {
|
||||
let key = 'relais' + count;
|
||||
if (r[1] === 1 && !active) {
|
||||
active = true;
|
||||
relaisBands[key] = {
|
||||
type: 'box',
|
||||
backgroundColor: 'rgba(255, 0, 0, 0.1)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 0, 0, 0.5)',
|
||||
drawTime: 'beforeDraw',
|
||||
// for (let r of relaisData) {
|
||||
// let key = 'relais' + count;
|
||||
// if (r[1] === 1 && !active) {
|
||||
// active = true;
|
||||
// relaisBands[key] = {
|
||||
// type: 'box',
|
||||
// backgroundColor: 'rgba(255, 0, 0, 0.1)',
|
||||
// borderWidth: 1,
|
||||
// borderColor: 'rgba(255, 0, 0, 0.5)',
|
||||
// drawTime: 'beforeDraw',
|
||||
|
||||
xMax: relaisData[relaisData.length - 1][0] + 10,
|
||||
xMin: r[0]
|
||||
};
|
||||
}
|
||||
if (r[1] === 0 && active) {
|
||||
relaisBands[key]['xMax'] = r[0];
|
||||
active = false;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return relaisBands;
|
||||
};
|
||||
// xMax: relaisData[relaisData.length - 1][0] + 10,
|
||||
// xMin: r[0]
|
||||
// };
|
||||
// }
|
||||
// if (r[1] === 0 && active) {
|
||||
// relaisBands[key]['xMax'] = r[0];
|
||||
// active = false;
|
||||
// count++;
|
||||
// }
|
||||
// }
|
||||
// return relaisBands;
|
||||
// };
|
||||
|
||||
const getAnnotations = () => {
|
||||
return {
|
||||
annotations: {
|
||||
limitGreen: {
|
||||
type: 'box',
|
||||
drawTime: 'beforeDraw',
|
||||
backgroundColor: 'rgba(0, 255, 133, 0.25)',
|
||||
borderWidth: 0,
|
||||
yMax: 0,
|
||||
yMin: 350
|
||||
},
|
||||
limitOrange: {
|
||||
type: 'box',
|
||||
drawTime: 'beforeDraw',
|
||||
backgroundColor: 'rgba(255, 138, 0 ,0.25)',
|
||||
borderWidth: 0,
|
||||
yMax: 350,
|
||||
yMin: 450
|
||||
},
|
||||
limitRed: {
|
||||
type: 'box',
|
||||
drawTime: 'beforeDraw',
|
||||
// const getAnnotations = () => {
|
||||
// return {
|
||||
// annotations: {
|
||||
// limitGreen: {
|
||||
// type: 'box',
|
||||
// drawTime: 'beforeDraw',
|
||||
// backgroundColor: 'rgba(0, 255, 133, 0.25)',
|
||||
// borderWidth: 0,
|
||||
// yMax: 0,
|
||||
// yMin: 350
|
||||
// },
|
||||
// limitOrange: {
|
||||
// type: 'box',
|
||||
// drawTime: 'beforeDraw',
|
||||
// backgroundColor: 'rgba(255, 138, 0 ,0.25)',
|
||||
// borderWidth: 0,
|
||||
// yMax: 350,
|
||||
// yMin: 450
|
||||
// },
|
||||
// limitRed: {
|
||||
// type: 'box',
|
||||
// drawTime: 'beforeDraw',
|
||||
|
||||
backgroundColor: 'rgba(255, 0, 0, 0.25)',
|
||||
borderWidth: 0,
|
||||
yMax: 450,
|
||||
yMin: 550
|
||||
},
|
||||
targetTemp: {
|
||||
type: 'line',
|
||||
drawTime: 'beforeDraw',
|
||||
borderColor: 'black',
|
||||
borderWidth: 2,
|
||||
scaleID: 'y',
|
||||
value: targetTemp,
|
||||
borderDash: [6, 6],
|
||||
borderDashOffset: 0,
|
||||
label: {
|
||||
backgroundColor: 'transparent',
|
||||
display: true,
|
||||
color: 'rgba(0,0,0, 1)',
|
||||
content: 'Target temp',
|
||||
position: 'center',
|
||||
yAdjust: -9
|
||||
}
|
||||
},
|
||||
...getRelaisBands()
|
||||
}
|
||||
};
|
||||
};
|
||||
// backgroundColor: 'rgba(255, 0, 0, 0.25)',
|
||||
// borderWidth: 0,
|
||||
// yMax: 450,
|
||||
// yMin: 550
|
||||
// },
|
||||
// targetTemp: {
|
||||
// type: 'line',
|
||||
// drawTime: 'beforeDraw',
|
||||
// borderColor: 'black',
|
||||
// borderWidth: 2,
|
||||
// scaleID: 'y',
|
||||
// value: targetTemp,
|
||||
// borderDash: [6, 6],
|
||||
// borderDashOffset: 0,
|
||||
// label: {
|
||||
// backgroundColor: 'transparent',
|
||||
// display: true,
|
||||
// color: 'rgba(0,0,0, 1)',
|
||||
// content: 'Target temp',
|
||||
// position: 'center',
|
||||
// yAdjust: -9
|
||||
// }
|
||||
// },
|
||||
// ...getRelaisBands()
|
||||
// }
|
||||
// };
|
||||
// };
|
||||
|
||||
let chart: Chart;
|
||||
Chart.register(annotationPlugin);
|
||||
// let chart: Chart;
|
||||
// Chart.register(annotationPlugin);
|
||||
|
||||
onMount(() => {
|
||||
initWebSocket();
|
||||
|
||||
chart = new Chart(canvas, {
|
||||
type: 'line',
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
mode: 'nearest',
|
||||
intersect: false,
|
||||
animation: false
|
||||
},
|
||||
annotation: getAnnotations()
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
tooltipFormat: 'HH:mm:ss',
|
||||
// chart = new Chart(canvas, {
|
||||
// type: 'line',
|
||||
// options: {
|
||||
// plugins: {
|
||||
// legend: {
|
||||
// display: false
|
||||
// },
|
||||
// tooltip: {
|
||||
// mode: 'nearest',
|
||||
// intersect: false,
|
||||
// animation: false
|
||||
// },
|
||||
// annotation: getAnnotations()
|
||||
// },
|
||||
// scales: {
|
||||
// x: {
|
||||
// type: 'time',
|
||||
// time: {
|
||||
// tooltipFormat: 'HH:mm:ss',
|
||||
|
||||
displayFormats: {
|
||||
millisecond: 'HH:mm:ss.S',
|
||||
second: 'HH:mm:ss',
|
||||
minute: 'HH:mm',
|
||||
hour: 'HH:mm'
|
||||
}
|
||||
},
|
||||
adapters: {
|
||||
date: {
|
||||
locale: nl
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
data: {
|
||||
labels: temperatureData.map((row) => row[0]),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Temperature',
|
||||
data: temperatureData.map((row) => row[1]),
|
||||
fill: true,
|
||||
tension: 0.25
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
// displayFormats: {
|
||||
// millisecond: 'HH:mm:ss.S',
|
||||
// second: 'HH:mm:ss',
|
||||
// minute: 'HH:mm',
|
||||
// hour: 'HH:mm'
|
||||
// }
|
||||
// },
|
||||
// adapters: {
|
||||
// date: {
|
||||
// locale: nl
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// y: {
|
||||
// min: 0
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// data: {
|
||||
// labels: temperatureData.map((row) => row[0]),
|
||||
// datasets: [
|
||||
// {
|
||||
// label: 'Temperature',
|
||||
// data: temperatureData.map((row) => row[1]),
|
||||
// fill: true,
|
||||
// tension: 0.25
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// });
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// spoof some test data
|
||||
setInterval(() => {
|
||||
if (temperatureData.length > maxValues) {
|
||||
temperatureData.shift();
|
||||
relaisData.shift();
|
||||
}
|
||||
let d = new Date();
|
||||
// if (import.meta.env.DEV) {
|
||||
// // spoof some test data
|
||||
// setInterval(() => {
|
||||
// if (temperatureData.length > maxValues) {
|
||||
// temperatureData.shift();
|
||||
// relaisData.shift();
|
||||
// }
|
||||
// let d = new Date();
|
||||
|
||||
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 + Math.random() * 0.5 - 0.25;
|
||||
}
|
||||
// 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 + Math.random() * 0.5 - 0.25;
|
||||
// }
|
||||
|
||||
let shootFactor = Math.min(
|
||||
((d.getTime() - lastSwitch.getTime()) / speedFactor -
|
||||
(lastSwitchDuration * 0.25) / speedFactor) /
|
||||
((3 * 60 * 1000) / speedFactor),
|
||||
1
|
||||
); // 5mins
|
||||
shootFactor = shootFactor;
|
||||
// let shootFactor = Math.min(
|
||||
// ((d.getTime() - lastSwitch.getTime()) / speedFactor -
|
||||
// (lastSwitchDuration * 0.25) / speedFactor) /
|
||||
// ((3 * 60 * 1000) / speedFactor),
|
||||
// 1
|
||||
// ); // 5mins
|
||||
// shootFactor = shootFactor;
|
||||
|
||||
if (relais == 0) {
|
||||
temp = temp - 0.3 * shootFactor;
|
||||
} else {
|
||||
temp = temp + 0.3 * shootFactor;
|
||||
}
|
||||
// if (relais == 0) {
|
||||
// temp = temp - 0.3 * shootFactor;
|
||||
// } else {
|
||||
// temp = temp + 0.3 * shootFactor;
|
||||
// }
|
||||
|
||||
let mod = temp % 0.25;
|
||||
if (mod > 0.125) {
|
||||
temp = temp - mod + 0.25;
|
||||
} else {
|
||||
temp = temp - mod;
|
||||
}
|
||||
// let mod = temp % 0.25;
|
||||
// if (mod > 0.125) {
|
||||
// temp = temp - mod + 0.25;
|
||||
// } else {
|
||||
// temp = temp - mod;
|
||||
// }
|
||||
|
||||
let derivedShootFactor = Math.min(
|
||||
(d.getTime() - lastSwitch.getTime()) / speedFactor / ((3 * 60 * 1000) / speedFactor),
|
||||
1
|
||||
); // 5mins
|
||||
// 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 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);
|
||||
// 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;
|
||||
// targetTempOverShoot = targetTemp - dirivedOvershoot;
|
||||
// targetTempUnderShoot = targetTemp + dirivedUndershoot;
|
||||
|
||||
if (mode === 'auto_switch') {
|
||||
if (d.getTime() - lastSwitch.getTime() > switchDelay) {
|
||||
if (temp > targetTempOverShoot) {
|
||||
// > 270 °C
|
||||
if (relais == 1) {
|
||||
relais = 0;
|
||||
// if (mode === 'auto_switch') {
|
||||
// if (d.getTime() - lastSwitch.getTime() > switchDelay) {
|
||||
// if (temp > targetTempOverShoot) {
|
||||
// // > 270 °C
|
||||
// if (relais == 1) {
|
||||
// relais = 0;
|
||||
|
||||
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;
|
||||
// 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;
|
||||
|
||||
targetTempOverShoot = targetTemp;
|
||||
targetTempUnderShoot = targetTemp;
|
||||
lastSwitchDuration = d.getTime() - lastSwitch.getTime();
|
||||
lastSwitch = new Date();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// targetTempOverShoot = targetTemp;
|
||||
// targetTempUnderShoot = targetTemp;
|
||||
// lastSwitchDuration = d.getTime() - lastSwitch.getTime();
|
||||
// lastSwitch = new Date();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (mode === 'pwm') {
|
||||
if (d.getTime() - lastSwitch.getTime() > pwmOnDelay) {
|
||||
if (relais) {
|
||||
relais = 0;
|
||||
lastSwitch = new Date();
|
||||
}
|
||||
}
|
||||
if (d.getTime() - lastSwitch.getTime() > pwmOffDelay) {
|
||||
if (!relais) {
|
||||
relais = 1;
|
||||
lastSwitch = new Date();
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (mode === 'pwm') {
|
||||
// if (d.getTime() - lastSwitch.getTime() > pwmOnDelay) {
|
||||
// if (relais) {
|
||||
// relais = 0;
|
||||
// lastSwitch = new Date();
|
||||
// }
|
||||
// }
|
||||
// if (d.getTime() - lastSwitch.getTime() > pwmOffDelay) {
|
||||
// if (!relais) {
|
||||
// relais = 1;
|
||||
// lastSwitch = new Date();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
temperatureData.push([d.getTime(), temp]);
|
||||
relaisData.push([d.getTime(), relais]);
|
||||
// temperatureData.push([d.getTime(), temp]);
|
||||
// relaisData.push([d.getTime(), relais]);
|
||||
|
||||
if (!pauseGraphUpdate) {
|
||||
chart.options.plugins.annotation = getAnnotations();
|
||||
chart.data.labels.push(d.getTime());
|
||||
chart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(temp);
|
||||
});
|
||||
chart.update('none');
|
||||
}
|
||||
}, spoofInterval);
|
||||
}
|
||||
// if (!pauseGraphUpdate) {
|
||||
// chart.options.plugins.annotation = getAnnotations();
|
||||
// chart.data.labels.push(d.getTime());
|
||||
// chart.data.datasets.forEach((dataset) => {
|
||||
// dataset.data.push(temp);
|
||||
// });
|
||||
// chart.update('none');
|
||||
// }
|
||||
// }, spoofInterval);
|
||||
// }
|
||||
});
|
||||
|
||||
const getReadings = () => {
|
||||
@@ -341,26 +328,26 @@
|
||||
if (temperatureData.length > maxValues) {
|
||||
temperatureData.shift();
|
||||
}
|
||||
temperatureData.push([d.getTime(), myObj[key]]);
|
||||
temp = myObj[key];
|
||||
temperatureData.push([d.getTime(), temp]);
|
||||
} else if (key === 'relais') {
|
||||
if (relaisData.length > maxValues) {
|
||||
relaisData.shift();
|
||||
}
|
||||
relaisData.push([d.getTime(), myObj[key]]);
|
||||
if (myObj[key]) {
|
||||
relais = 1;
|
||||
} else {
|
||||
relais = 0;
|
||||
}
|
||||
relaisData.push([d.getTime(), relais]);
|
||||
} else if (key === 'target_temp') {
|
||||
targetTemp = myObj[key];
|
||||
} else if (key === 'derived_overshoot') {
|
||||
targetTempOverShoot = myObj[key];
|
||||
} else if (key === 'derived_undershoot') {
|
||||
targetTempUnderShoot = myObj[key];
|
||||
} else if (key === 'pid') {
|
||||
if (powerData.length > maxValues) {
|
||||
powerData.shift();
|
||||
}
|
||||
calculatedPidOutput = myObj[key];
|
||||
powerData.push([d.getTime(), calculatedPidOutput]);
|
||||
} else if (key === 'pwm_on') {
|
||||
pwmOn = Number(myObj[key]) / 1000;
|
||||
} else if (key === 'pwm_off') {
|
||||
@@ -376,14 +363,14 @@
|
||||
modeSpan.innerText = mode;
|
||||
}
|
||||
|
||||
if (!pauseGraphUpdate) {
|
||||
chart.options.plugins.annotation = getAnnotations();
|
||||
chart.data.labels.push(d.getTime());
|
||||
chart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(temp);
|
||||
});
|
||||
chart.update('none');
|
||||
}
|
||||
// if (!pauseGraphUpdate) {
|
||||
// chart.options.plugins.annotation = getAnnotations();
|
||||
// chart.data.labels.push(d.getTime());
|
||||
// chart.data.datasets.forEach((dataset) => {
|
||||
// dataset.data.push(temp);
|
||||
// });
|
||||
// chart.update('none');
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -412,8 +399,6 @@
|
||||
ws.send('setTargetTemp: ' + pad(value, 3));
|
||||
} else {
|
||||
targetTemp = value;
|
||||
targetTempOverShoot = value;
|
||||
targetTempUnderShoot = value;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -464,10 +449,10 @@
|
||||
};
|
||||
|
||||
const prepareDownloadCSV = () => {
|
||||
let csvContent = 'Time,Temp,Relais\n';
|
||||
let csvContent = 'Time,Temp,Relais,Power\n';
|
||||
|
||||
for (let [i, temp] of temperatureData.entries()) {
|
||||
csvContent += `${temp[0]},${temp[1]},${relaisData[i] ? relaisData[i][1] : ''}\n`;
|
||||
csvContent += `${temp[0]},${temp[1]},${relaisData[i] ? relaisData[i][1] : ''},${powerData[i][1]}\n`;
|
||||
}
|
||||
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8,' });
|
||||
@@ -585,17 +570,19 @@
|
||||
{/if}
|
||||
{#if mode === 'pid'}
|
||||
<div class="mt-3 flex items-center gap-1">
|
||||
PID: {calculatedPidOutput.toFixed(0)}% {(calculatedPidOutput * 12).toFixed(0)}W
|
||||
PID: {calculatedPidOutput ? calculatedPidOutput.toFixed(0) : 0}% {calculatedPidOutput
|
||||
? (calculatedPidOutput * 12).toFixed(0)
|
||||
: 0}W
|
||||
</div>
|
||||
<div>ON:{pwmOn.toFixed(2)}s OFF:{pwmOff.toFixed(2)}s</div>
|
||||
<div class="mt-3 flex w-full justify-between px-9">
|
||||
<div>ON:{pwmOn.toFixed(2)}s OFF:{pwmOff ? pwmOff.toFixed(2) : 0}s</div>
|
||||
<div class="mt-3 flex w-full justify-between px-13">
|
||||
<div>Kp</div>
|
||||
<div>Ki</div>
|
||||
<div>Kd</div>
|
||||
<!-- <div>Kd</div> -->
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<input
|
||||
class="min-w-[85px] rounded"
|
||||
class="min-w-[120px] rounded"
|
||||
type="number"
|
||||
min="0"
|
||||
max="50"
|
||||
@@ -605,7 +592,7 @@
|
||||
onchange={(e) => changeKValue(e, 'p')}
|
||||
/>
|
||||
<input
|
||||
class="min-w-[85px] rounded"
|
||||
class="min-w-[120px] rounded"
|
||||
type="number"
|
||||
min="0"
|
||||
max="50"
|
||||
@@ -614,7 +601,7 @@
|
||||
id="target_temperature"
|
||||
onchange={(e) => changeKValue(e, 'i')}
|
||||
/>
|
||||
<input
|
||||
<!-- <input
|
||||
class="min-w-[85px] rounded"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -623,7 +610,7 @@
|
||||
value={kd}
|
||||
id="target_temperature"
|
||||
onchange={(e) => changeKValue(e, 'd')}
|
||||
/>
|
||||
/> -->
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user