max ki 70p, adjust kp ki

This commit is contained in:
Vincent van der Wal
2026-06-10 19:53:33 +02:00
parent c79559a82d
commit 5422ef1154
3 changed files with 23 additions and 12 deletions
+7 -4
View File
@@ -70,7 +70,7 @@ export class SpoofSocket {
pwm_off: 4000, pwm_off: 4000,
pid: 0, pid: 0,
kp: 0.6, kp: 0.6,
ki: 0.1, ki: 0.03,
kd: 0.0, kd: 0.0,
bake_phase: '', bake_phase: '',
bake_remaining: 0 bake_remaining: 0
@@ -127,14 +127,16 @@ export class SpoofSocket {
private applyMode(m: string): void { private applyMode(m: string): void {
const s = this.s; const s = this.s;
const wasPid = this.isPidMode(s.mode);
s.mode = m; s.mode = m;
if (m === 'baking') this.bakeStart = Date.now(); if (m === 'baking') this.bakeStart = Date.now();
if (m === 'manual') { if (m === 'manual') {
s.relais = 0; s.relais = 0;
this.lastSwitch = Date.now(); this.lastSwitch = Date.now();
} }
// Dump windup when the new target is below the current temp (e.g. -> pause) // Reset integral arriving from a non-PID mode (stale value) or when the
if (this.isPidMode(m) && this.activeSetpoint() < s.temperature) this.integral = 0; // new target is below the current temp (mirrors firmware applyMode).
if (this.isPidMode(m) && (!wasPid || this.activeSetpoint() < s.temperature)) this.integral = 0;
} }
private handle(cmd: string, value?: number | string): void { private handle(cmd: string, value?: number | string): void {
@@ -208,7 +210,8 @@ export class SpoofSocket {
const satHigh = output >= 100 && error > 0; const satHigh = output >= 100 && error > 0;
const satLow = output <= 0 && error < 0; const satLow = output <= 0 && error < 0;
if (!satHigh && !satLow) { if (!satHigh && !satLow) {
this.integral = Math.max(-100, Math.min(100, this.integral + s.ki * error * dt)); // integral clamped to ±70 to match the firmware (anti-overshoot)
this.integral = Math.max(-70, Math.min(70, this.integral + s.ki * error * dt));
} }
output = Math.max(0, Math.min(100, pTerm + this.integral)); output = Math.max(0, Math.min(100, pTerm + this.integral));
s.pid = output; s.pid = output;
+15 -7
View File
@@ -27,7 +27,7 @@ unsigned long lastWebSocket = 0;
const unsigned long WS_INTERVAL = 500; const unsigned long WS_INTERVAL = 500;
float temperature = 0; float temperature = 0;
float targetTemp = 370.0f; // default target temp for preheating, adjustable via UI float targetTemp = 350.0f; // default target temp for preheating, adjustable via UI
unsigned long lastSwitch = 0; unsigned long lastSwitch = 0;
float pwmSwitchDelayOn = 2000; // 2s float pwmSwitchDelayOn = 2000; // 2s
@@ -35,8 +35,8 @@ float pwmSwitchDelayOff = 4000; // 4s
float power = 100; float power = 100;
float kp = 0.55; float kp = 0.6;
float ki = 0.005; float ki = 0.03;
float kd = 0.0; float kd = 0.0;
// Heating modes. PREHEAT, PAUSE and BAKING are all PI-regulated and only // Heating modes. PREHEAT, PAUSE and BAKING are all PI-regulated and only
@@ -55,7 +55,11 @@ unsigned long bakeStart = 0; // millis() when BAKING was entered
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
PIDController pid(kp, ki, kd, 100.0, 0.0, 100.0); // Kp, Ki, Kd, max, min, max_integral // integral capped at 70 (not 100): near the setpoint P≈0, so the integral alone
// supplies the holding power. Letting it reach 100 means full power right as we
// hit the setpoint → big overshoot on this high-lag oven. 70 still covers the
// steady-state duty needed at high setpoints.
PIDController pid(kp, ki, kd, 100.0, 0.0, 70.0); // Kp, Ki, Kd, max, min, max_integral
static const char *modeToStr(Mode m) static const char *modeToStr(Mode m)
{ {
@@ -96,6 +100,7 @@ static float activeSetpoint()
// Centralised mode switch so every entry point stays consistent and safe. // Centralised mode switch so every entry point stays consistent and safe.
static void applyMode(Mode m) static void applyMode(Mode m)
{ {
Mode prev = mode;
mode = m; mode = m;
if (m == Mode::BAKING) if (m == Mode::BAKING)
@@ -110,9 +115,12 @@ static void applyMode(Mode m)
if (isPidMode(m)) if (isPidMode(m))
{ {
pid.setSetpoint(activeSetpoint()); pid.setSetpoint(activeSetpoint());
// Dump integral windup when the new target is below the current temp // Reset the integral when arriving from a non-PID mode (its value is stale
// (e.g. PREHEAT -> PAUSE) so we don't keep heating into an overshoot. // and would dump straight into an overshoot) or when the new target is
if (activeSetpoint() < temperature) // below the current temp (e.g. PREHEAT -> PAUSE, or BAKING -> PREHEAT).
// A PID -> PID hand-off at a higher target (e.g. PREHEAT -> BAKING) keeps
// the integral so the boost adds to the existing holding power.
if (!isPidMode(prev) || activeSetpoint() < temperature)
pid.reset(); pid.reset();
} }
+1 -1
View File
@@ -49,7 +49,7 @@
let pwmOff = $state(4); let pwmOff = $state(4);
let kp = $state(0.6); let kp = $state(0.6);
let ki = $state(0.1); let ki = $state(0.03);
let pauseGraphUpdate = $state(false); let pauseGraphUpdate = $state(false);
let darkMode = $state(true); let darkMode = $state(true);