import {Vec2, Box, World} from "planck";
+import * as MENU from "./menu.js";
+import PIDController from "./pid-controller.js";
// Get the canvas element
const canvas = document.getElementById("area");
const ctx = canvas.getContext("2d");
-// Create a <link>Planck.js</link> world
const world = World(Vec2(0, 0));
+canvas.width = 500;
+canvas.height = 500;
+
+const PPM = 30;
+
+const targetX = 10;
+const targetY = -2.5;
+
// Define the box properties
-const boxWidth = 50;
-const boxHeight = 50;
+const boxWidth = 1;
+const boxHeight = 1;
// Create a dynamic body for the box
-const box = world.createDynamicBody(Vec2(200, 100));
+const box = world.createDynamicBody(Vec2(1, -2.5));
box.createFixture({
- shape: Box(boxWidth / 2, boxHeight / 2),
+ shape: Box(boxWidth, boxHeight),
density: 1.0,
});
+MENU.initMenu();
+const pid = new PIDController();
+
// Render the box on the canvas
function render() {
const position = box.getPosition();
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.fillStyle = "white";
+ ctx.fillRect(targetX * PPM, (-position.y * PPM), 30, 30);
// Draw the box
ctx.save();
- ctx.translate(position.x, position.y);
+ //ctx.translate(position.x * PPM, (-position.y * PPM));
ctx.rotate(angle);
- ctx.fillStyle = "#0095DD";
- ctx.fillRect(-boxWidth / 2, -boxHeight / 2, boxWidth, boxHeight);
+ ctx.fillStyle = "blue";
+ 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);
+ var force = {x: r, y: 0};
+ box.applyForce(force, box.getWorldCenter());
}
// Animation loop
--- /dev/null
+class PIDController {
+ //public enum DerivativeMeasurement {
+ // Velocity,
+ // ErrorRateOfChange
+ //}
+ constructor() {
+ this.PIDParams = {proportionalGain: 50, integralGain: 0.01, derivativeGain: 35, outputMin: -1, outputMax: 1, integralSaturation: false, derivativeInitialized: false};
+ this.valueLast;
+ this.errorLast;
+ this.integrationStored;
+ this.velocity;
+ }
+ Reset() {
+ this.derivativeInitialized = false;
+ }
+ Update(dt, currentValue, targetValue) {
+ if (dt <= 0) {
+ return;
+ }
+ var error = targetValue - currentValue;
+
+ 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;
+
+ var errorRateOfChange = (error - this.errorLast) / dt;
+ this.errorLast = error;
+
+ var valueRateOfChange = (currentValue - this.valueLast) / dt;
+ this.valueLast = currentValue;
+ this.velocity = valueRateOfChange;
+
+ var deriveMeasure = 0;
+
+ if (this.derivativeInitialized) {
+ //if (derivativeMeasurement == DerivativeMeasurement.Velocity) {
+ deriveMeasure = -valueRateOfChange;
+ //} else {
+ // deriveMeasure = errorRateOfChange;
+ //}
+ } else {
+ this.derivativeInitialized = true;
+ }
+
+ var D = this.PIDParams.derivativeGain * deriveMeasure;
+ var result = P + D;
+ return result;
+
+ //return Math.min(Math.max((result, this.outputMin), this.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;