Bang-bang wall following, and the sensor angle that skewed every reading
A tracked robot holding a fixed distance from a wall with on/off control, and why the biggest error came from geometry rather than the controller.
Rayhan M. Project: May 2024 Written 3 min read Source on GitHub
This was my first closed-loop control project: a tracked Makeblock robot that drives along a wall and holds a fixed distance from it using a single ultrasonic sensor. It was a six-person, ten-week project for EE195 Robotics Systems at Maynooth, in first year. I chaired the team.
The code, test data and reports are on GitHub.

The control problem
The setpoint was 40.5 cm from the wall, with an acceptable band of 39 to 42 cm. A sensor on the right side reads the wall distance continuously, and the controller steers by giving the two tracks different power. No human input once it starts.
Three states, no maths
We used bang-bang (on/off) control with three states:
| Reading | Effect |
|---|---|
| Inside the band | Gentle drift toward the wall |
| Too far | Steer in |
| Too close | Steer out |
The firmware was built in mBlock’s visual editor and exported to Arduino C++. The core of the loop:
if (ultrasonic_6.distanceCm() < 52) {
if (ultrasonic_6.distanceCm() > 49) {
Encoder_1.setTarPWM(100 / 100.0 * 255); // in band
Encoder_2.setTarPWM(-1 * (84 / 100.0 * 255));
} else {
Encoder_1.setTarPWM(100 / 100.0 * 255); // too close: steer out
Encoder_2.setTarPWM(-1 * (90.7 / 100.0 * 255));
}
} else {
Encoder_1.setTarPWM(89.2 / 100.0 * 255); // too far: steer in
Encoder_2.setTarPWM(-1 * (100 / 100.0 * 255));
}
Two details are worth pointing out. The second motor’s PWM is negative because the two motors are mounted mirror-image, so “forward” is the opposite rotation on each side. And the thresholds in the exported code are 49 and 52 cm of raw sensor reading, not the 39–42 cm band in our design, which the report never explains. If I picked this project up again, documenting that offset is the first thing I’d do.
We chose bang-bang over PID because it was much quicker to tune in the time we had, and the band was wide enough for it to work.
Results
Over a 30-second straight run, the robot stayed inside the band about 85% of the time. The readings swung between 37.4 cm and 44.8 cm, which is 7.65% below and 10.62% above the setpoint.

Some of that oscillation is built into bang-bang control. With no proportional term, the controller only reacts once the robot has already left the band, so it always overshoots before correcting.
The error that wasn’t the controller’s fault
When we plotted the sensor’s reported distance against the actual measured distance, the sensor consistently read high. The cause was geometry.
The sensor was fixed rigidly to the robot. Every time the robot turned to correct its course, the sensor turned too, so it was no longer pointing straight at the wall. The pulse then travelled a longer, angled path. If the sensor is tilted by an angle θ from perpendicular, it measures roughly d / cos θ instead of d:
- At 10° of tilt, a true 40.5 cm reads as about 41.1 cm.
- At 25° of tilt, it reads as about 44.7 cm, close to the worst reading we recorded.
So the controller was correcting against a distorted signal, and its own corrections made the distortion worse. That explains a good share of the overshoot beyond the programmed thresholds.
What I’d do differently
- Fix the sensor geometry before tuning. We spent most of our effort adjusting the control band when the dominant error was the mounting. Two sensors spaced along the side would measure both distance and angle to the wall, and correct for the tilt.
- Use proportional control. The oscillation is structural, not a tuning problem. A proportional term steers harder the further the robot is from the setpoint, so it corrects smoothly instead of switching. Something like this (not part of the project code):
float error = setpoint - distance;
float correction = Kp * error;
setLeft(base - correction);
setRight(base + correction);
- Be honest about corners. One sensor can’t tell “the wall is getting further away” from “the wall just ended at a corner”, so we restricted testing to straight runs. That was a limitation, not a solved problem.
- #control-systems
- #robotics
- #ultrasonic-sensor
- #arduino