From ef4635af0fc5998cf735d32ea59a5ad63fb474f4 Mon Sep 17 00:00:00 2001 From: Robin Krens Date: Tue, 23 Jan 2024 21:28:11 +0100 Subject: [PATCH] pid controller configurable through menu --- package.json | 6 ++--- src/app.js | 16 +++++++++----- src/menu.js | 27 +++++++++++++++++++---- src/menu.js.bak | 15 +++++++++++++ src/pid-controller.js | 61 +++++++++------------------------------------------ src/styles.css | 4 ++-- 6 files changed, 64 insertions(+), 65 deletions(-) create mode 100644 src/menu.js.bak diff --git a/package.json b/package.json index 4405128..4345c99 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "author": "Robin Krens", "license": "ISC", "dependencies": { - "planck": "^1.0.0" + "planck": "^1.0.0", + "tweakpane": "^3.1.4" }, "devDependencies": { "eslint": "^8.56.0", - "parcel": "^2.11.0", - "tweakpane": "^4.0.3" + "parcel": "^2.11.0" } } diff --git a/src/app.js b/src/app.js index 49b3bb8..816d89d 100644 --- a/src/app.js +++ b/src/app.js @@ -8,12 +8,12 @@ const ctx = canvas.getContext("2d"); const world = World(Vec2(0, 0)); -canvas.width = 500; -canvas.height = 500; +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; const PPM = 30; -const targetX = 10; +var targetX = 10; const targetY = -2.5; // Define the box properties @@ -25,10 +25,16 @@ const box = world.createDynamicBody(Vec2(1, -2.5)); box.createFixture({ shape: Box(boxWidth, boxHeight), density: 1.0, + friction: 0.01, }); -MENU.initMenu(); const pid = new PIDController(); +MENU.initMenu(pid); + +canvas.addEventListener("click", function(event) { + targetX = (event.clientX - canvas.getBoundingClientRect().left) / PPM; + console.log("Updated targetX:", targetX); +}); // Render the box on the canvas function render() { @@ -48,7 +54,7 @@ function render() { ctx.fillRect(position.x * PPM, (-position.y * PPM), boxWidth * PPM, boxHeight * PPM); ctx.restore(); var r = pid.Update(1/60, position.x, targetX); - console.log(r); + //console.log(r); var force = {x: r, y: 0}; box.applyForce(force, box.getWorldCenter()); } diff --git a/src/menu.js b/src/menu.js index 0e4e0b4..f78a5be 100644 --- a/src/menu.js +++ b/src/menu.js @@ -1,12 +1,31 @@ import {Pane} from "tweakpane"; -function initMenu() +function initMenu(pid) { const pane = new Pane(); - const tab = pane.addTab({ - pages: [{title: "Creative Mode"}, {title: "Preset"}] + const pidSettings = pane.addFolder({ + title: "PID settings" + }); + pidSettings.addInput( + pid.PIDParams, "proportionalGain", + {min: 0, max: 10, step: 0.1} + ); + + pidSettings.addInput( + pid.PIDParams, "derivativeGain", + {min: 0, max: 10, step: 0.1} + ); + + pidSettings.addInput( + pid.PIDParams, "integralGain", + {min: 0, max: 10, step: 0.1} + ); + pane.addMonitor(pid.PIDParams, "force", { + title: "Force (N)", + view: "graph", + min: -10000, + max: +10000, }); - } export {initMenu}; diff --git a/src/menu.js.bak b/src/menu.js.bak new file mode 100644 index 0000000..946cf2b --- /dev/null +++ b/src/menu.js.bak @@ -0,0 +1,15 @@ +import {Pane} from "tweakpane"; + +function initMenu(pid) +{ + const pane = new Pane(); + const pidSettings = pane.addFolder({ + title: "PID settings" + }); + pidSettings.addInput( + pid.PIDParams, "proportionalGain", + {min: 0, max: 100, step: 1} + ); +} + +export {initMenu}; diff --git a/src/pid-controller.js b/src/pid-controller.js index 2ec15d2..31240a5 100644 --- a/src/pid-controller.js +++ b/src/pid-controller.js @@ -4,10 +4,10 @@ class PIDController { // ErrorRateOfChange //} constructor() { - this.PIDParams = {proportionalGain: 50, integralGain: 0.01, derivativeGain: 35, outputMin: -1, outputMax: 1, integralSaturation: false, derivativeInitialized: false}; + this.PIDParams = {proportionalGain: 2, integralGain: 0.0, derivativeGain: 2, iMin: -1, iMax: 1, integralSaturation: false, derivativeInitialized: false, outputMax: 1, outputMin: -1, magnitude: 10, force: 0}; this.valueLast; this.errorLast; - this.integrationStored; + this.integrationStored = 0; this.velocity; } Reset() { @@ -21,8 +21,8 @@ class PIDController { var P = this.PIDParams.proportionalGain * error; - this.integrationStored = Math.min(Math.max(this.integrationStored + (error * dt), -this.integralSaturation), -this.integralSaturation); - var I = this.integralGain * this.integrationStored; + this.integrationStored = Math.min(Math.max(this.integrationStored + (error * dt), this.PIDParams.iMin), this.PIDParams.iMax); + var I = this.PIDParams.integralGain * this.integrationStored; var errorRateOfChange = (error - this.errorLast) / dt; this.errorLast = error; @@ -42,56 +42,15 @@ class PIDController { } else { this.derivativeInitialized = true; } - var D = this.PIDParams.derivativeGain * deriveMeasure; - var result = P + D; - return result; + var result = P + I + D; + result *= this.PIDParams.magnitude; + this.PIDParams.force = result * 60; /* this routine is called ~60seconds */ - //return Math.min(Math.max((result, this.outputMin), this.outputMax)); + //console.log(result*60 + " N"); + return result; + //return Math.min(Math.max((result, this.PIDParams.outputMin), this.PIDParams.outputMax)); } - - // float AngleDifference(float a, float b) { - // return (a - b + 540) % 360 - 180; //calculate modular difference, and remap to [-180, 180] - // } - - // public float UpdateAngle(float dt, float currentAngle, float targetAngle) { - // if (dt <= 0) throw new ArgumentOutOfRangeException(nameof(dt)); - // float error = AngleDifference(targetAngle, currentAngle); - - // //calculate P term - // float P = proportionalGain * error; - - // //calculate I term - // integrationStored = Mathf.Clamp(integrationStored + (error * dt), -integralSaturation, integralSaturation); - // float I = integralGain * integrationStored; - - // //calculate both D terms - // float errorRateOfChange = AngleDifference(error, errorLast) / dt; - // errorLast = error; - - // float valueRateOfChange = AngleDifference(currentAngle, valueLast) / dt; - // valueLast = currentAngle; - // velocity = valueRateOfChange; - - // //choose D term to use - // float deriveMeasure = 0; - - // if (derivativeInitialized) { - // if (derivativeMeasurement == DerivativeMeasurement.Velocity) { - // deriveMeasure = -valueRateOfChange; - // } else { - // deriveMeasure = errorRateOfChange; - // } - // } else { - // derivativeInitialized = true; - // } - - // float D = derivativeGain * deriveMeasure; - - // float result = P + I + D; - - // return Mathf.Clamp(result, outputMin, outputMax); - // } } export default PIDController; diff --git a/src/styles.css b/src/styles.css index 3ec4728..3b84f96 100644 --- a/src/styles.css +++ b/src/styles.css @@ -8,8 +8,8 @@ body, html { margin: 0; padding: 0; display: block; - width: 500px; - height: 500px; + width: 100%; + height: 100%; background: #ccc; } -- 2.7.4