From 2bf27c264d5a749472c963b9cb01b14217441da8 Mon Sep 17 00:00:00 2001
From: Jake
Date: Sun, 3 Aug 2025 14:15:59 +0800
Subject: [PATCH] implemented controls on bang bang simulator
---
LineFollowerSim.js | 102 ++++++++++++++++++++++++++++++++++++++++++---
index.html | 43 ++++++++++++++-----
2 files changed, 129 insertions(+), 16 deletions(-)
diff --git a/LineFollowerSim.js b/LineFollowerSim.js
index 7dd53ee..374a21b 100644
--- a/LineFollowerSim.js
+++ b/LineFollowerSim.js
@@ -16,34 +16,124 @@ export class LineFollowerSim {
this.lineTargetX = 250;
this.lineWidth = 12;
+
+ const bbThresholdSlider = document.getElementById("bbThresholdSlider");
+ const bbTurnSpeedSlider = document.getElementById("bbTurnSpeedSlider");
+ const bbThresholdValue = document.getElementById("bbThresholdValue");
+ const bbTurnSpeedValue = document.getElementById("bbTurnSpeedValue");
+ this.threshold = parseFloat(bbThresholdSlider.value);
+
+ const resetBtn = document.getElementById("resetBangBangBtn");
+ resetBtn.addEventListener("click", () => {
+ // Put the box instantly on the line
+ this.box.x = this.lineX;
+
+
+ });
+
+
+
+ this.lastUpdateTime = 0;
+ this.updateInterval = 50; // ms
+
+
this.updateBox = updateBoxFn || this.defaultUpdateBox.bind(this);
this.loop = this.loop.bind(this);
}
+ updateCodeBlock() {
+ this.code = `
+if left_color < ${this.threshold}:
+ motor(-${this.turnAmount}, ${this.turnAmount}) # Turn left
+elif right_color < ${this.threshold}:
+ motor(${this.turnAmount}, -${this.turnAmount}) # Turn right
+else:
+ motor(50, 50) # Go straight
+`
+ document.getElementById('code-block').textContent = this.code;
+ }
+
updateLine() {
if (Math.random() < 0.02) {
this.lineTargetX = 250 + (Math.random() - 0.5) * 200;
}
- this.lineX += (this.lineTargetX - this.lineX) * 0.005;
+ this.lineX += (this.lineTargetX - this.lineX) * 0.0025;
}
+ lineProximity(x, lineX) {
+ const distance = Math.abs(x - lineX);
+ const maxDistance = 20;
+ const maxValue = 1024;
+
+ if (distance > maxDistance) return 0;
+
+ // Reverse the falloff: closer = lower, farther = higher
+ const value = 100 + (distance / maxDistance) * (maxValue - 100);
+ return Math.round(value);
+ }
+
+
defaultUpdateBox() {
+
+ const now = performance.now();
+ if (now - this.lastUpdateTime < this.updateInterval) return;
+ this.lastUpdateTime = now;
+
+
+ const bbLeftColorValue = document.getElementById("leftColor");
+ const bbRightColorValue = document.getElementById("rightColor");
+
+ const bbThresh = parseFloat(bbThresholdSlider.value);
+ const bbTurnSpeed = parseFloat(bbTurnSpeedSlider.value);
+
+ bbThresholdValue.textContent = bbThresh.toFixed(0);
+ bbTurnSpeedValue.textContent = bbTurnSpeed.toFixed(2);
+ this.threshold = bbThresh.toFixed(0);
+ this.turnAmount = bbTurnSpeed.toFixed(0);
const leftSensor = this.box.x - this.box.width / 2;
const rightSensor = this.box.x + this.box.width / 2;
+ this.updateCodeBlock();
+
const onLine = x => x >= this.lineX - this.lineWidth / 2 && x <= this.lineX + this.lineWidth / 2;
+ let leftColor = this.lineProximity(leftSensor, this.lineX);
+ let rightColor = this.lineProximity(rightSensor, this.lineX);
+ if (leftColor == 0) {
+ leftColor = 1024; // No line detected
+ }
+ if (rightColor == 0) {
+ rightColor = 1024; // No line detected
+ }
+
+ bbLeftColorValue.textContent = leftColor;
+ bbRightColorValue.textContent = rightColor;
+
const leftOnLine = onLine(leftSensor);
const rightOnLine = onLine(rightSensor);
- if (leftOnLine && !rightOnLine) {
- this.box.dir = -1;
- } else if (rightOnLine && !leftOnLine) {
- this.box.dir = 1;
+ if (leftColor < bbThresh) {
+ this.box.dir -= (bbTurnSpeed * 0.01);
+ if (this.box.dir < -5) {
+ this.box.dir = -5; // Limit the turn speed
+ }
+ } else if (rightColor < bbThresh) {
+ this.box.dir += bbTurnSpeed * 0.01;
+ if (this.box.dir > 5) {
+ this.box.dir = 5; // Limit the turn speed
+ }
} else {
- //this.box.dir = 0;
+
+ if (this.box.dir > 1) {
+ this.box.dir -= 0.1;
+ } else if (this.box.dir < -1) {
+ this.box.dir += 0.1;
+ } else {
+ this.box.dir = 0;
+ }
}
+ console.log(this.box.dir);
this.box.x += this.box.dir * this.box.speed;
}
diff --git a/index.html b/index.html
index fcb0920..f187920 100644
--- a/index.html
+++ b/index.html
@@ -1119,6 +1119,24 @@ while True:
Bang-Bang Algorithm
+
+
Bang-Bang Controller Parameters
+
+
+
left_color: 0
+
right_color: 0
+
+
+
+
+
+
@@ -1129,30 +1147,32 @@ while True:
A PID algorithm on the other hand tries to always keep the robot exactly on the line.
First we have to change our two colour values, left_color and
- right_color into a single error value.
+ right_color into a single error value.
+
right_color - left_color = error
Now if we are on the line our error should be 0, with ot becoming positive if we move one way,
and negative if we move the other.
+
+ Try adjusting the Kp value to control how aggressively the robot will attempt to
+ drive towards the line.
@@ -1161,7 +1181,8 @@ while True:
Step 3: The Code
The pid.py library is simple, we initialize it with a P, I, and
- D.
+
D.
+
These stand for Proportional, Integral, and Derivative
@@ -1243,6 +1264,8 @@ while True:
import { LineFollowerSim } from './LineFollowerSim.js';
+
+
// Bang-Bang controller (default)
const canvas1 = document.getElementById('canvasBangBang');
const sim1 = new LineFollowerSim(canvas1);