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:
left_color: 0
+ right_color: 0 +
+
+
+
+
+ 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.
The pid.py library is simple, we initialize it with a P, I, and
- D.
D.
+
These stand for Proportional, Integral, and Derivative