What you are building
This is a differential-drive robot: two powered wheels share an axle and a castor supports the other end. Changing the two wheel speeds lets the robot travel straight, follow a curve, or turn in place. A microcontroller reads wheel encoders and controls both motors.
You need a two-wheel chassis, geared motors with encoders, a motor driver, suitable power supplies, jumper wires, chalk, and a tape measure. Check the voltage and current ratings of the motors, driver, regulator, and microcontroller before connecting them. You can test the control ideas in the Robotics labs before using the real robot, but you still need floor tests to measure friction, wheel size, slip, and battery effects.
Teal entries are build milestones. Magenta entries explain a problem that needs another idea before you continue, with links to the relevant lesson. Most of the work is in position estimation, closed-loop stopping, and path following.
Drive the route in a virtual room first
Make a model in Webots before powering the motors on the floor. Give it two wheel motors and two encoder sensors, then enter the measured wheel radius and distance between the wheels. Keep the controller behind the same wheel-command and encoder interfaces that the physical robot will use.
- Begin with ideal motion. Check a straight line, a circle, a turn in place and five target points while plotting simulated ground truth beside encoder odometry.
- Add measured mass, motor response, encoder resolution and floor friction. Then vary wheel size, slip, sensor noise and delay across a saved set of test cases.
- Require the controller to stop on stale encoders, impossible jumps and an obstacle inside its stopping distance. Record the final error and every safety stop.
The real floor is still part of the project. Measure wheel diameter, axle spacing, deadband, battery sag and slip on the physical robot, put those values back into the model, and rerun the same cases. Start the first floor tests at low speed with the chassis supported or in a clear bounded area. See Simulating Physical Systems for the model, scenario and transfer workflow.
Project milestones
-
Control one wheel in both directions.
Support the chassis so the wheel cannot move the robot. Use a PWM output for speed and the motor driver's direction inputs for forward and reverse. Start with a low duty cycle, then confirm that zero, forward, reverse, and stop all behave as intended.
-
Diagnose resets when the motors start.
If the program restarts as a motor starts, log the reset cause if the chip provides one and measure the supply rail with an oscilloscope if available. A short voltage drop points to a power problem rather than a control-flow bug.
What you needDo not power a motor from a microcontroller pin. Use an H-bridge driver rated for the motor's supply voltage and stall current. Motors draw their largest current while starting or stalled, which can pull the supply below the controller's minimum voltage and cause a brownout reset. Use short power wiring, the decoupling capacitors recommended by each datasheet, and a motor supply path that can handle the peak current. If logic and motor supplies are separate, connect their grounds unless the driver provides electrical isolation.
step 8Spin a motor both ways without killing a transistor step 22Give the board power that does not sag when a motor starts -
Run both wheels without resets.
Test forward, reverse, starting, stopping, and a brief blocked-wheel case at a safe current limit. Then put the robot on the floor and compare the wheel speeds at the same command. Small motor and gearbox differences are normal, so record them now.
-
Convert forward speed and turn rate into wheel speeds.
Equal and opposite wheel commands should produce a turn in place, but open-loop PWM values rarely produce equal wheel speeds. Work in physical units so that the command describes millimetres per second and degrees per second rather than two unrelated duty cycles.
What you needA differential-drive model converts the robot's forward speed and angular speed into left and right wheel speeds. The calculation uses the track width, measured between the two tyre contact lines. Write and unit-test both conversions. Use radians per second inside the equations, even if the user interface displays degrees per second.
step 1Drive a straight line, a circle and a spin with two wheel speeds step 2Work out the turn from the two speeds and the track width -
Test a line, a measured circle, and a turn in place.
Mark a circle on the floor and command the matching radius. Measure the cross-track error at several points. The difference includes wheel calibration, track-width error, tyre deformation, slip, and unequal speed response.
-
Measure wheel travel with encoders.
Run the same timed motor command on a smooth floor, on carpet, and at two battery charge levels. The distances will differ because PWM and time do not measure motion. Encoders give the controller a direct measurement of shaft rotation.
What you needAn encoder produces counts as its shaft turns. Convert the change in each wheel's count into distance using the measured wheel circumference and the encoder counts per wheel revolution. Sample both totals at a fixed interval, then use those two distances to update the robot's position and heading. This is wheel odometry, a form of dead reckoning. Count edges with a hardware counter or interrupts so the main loop cannot miss them. A quadrature encoder also reports direction.
step 3Count the slots on a wheel and turn a count into millimetres step 4Add up small steps until they become a position step 12Catch a press while the program is busy -
Calibrate distance per encoder count.
Print x, y, and heading. Drive a straight two-metre test several times, in both directions, and compare encoder distance with the tape measure. Adjust millimetres per count from the average result. Repeating the run shows whether the remaining error is a consistent scale error or random variation.
-
Measure odometry drift with five square runs.
Command four two-metre sides with 90-degree turns. After each run, mark the actual axle centre and measure its distance and heading relative to the start. Compare those measurements with the final odometry estimate.
What you needOdometry adds many small motion estimates, so wheel-size, track-width, missed-count, and slip errors accumulate as drift. A two per cent diameter difference makes the robot curve even when the encoder counts match. Heading error is especially costly because its sideways position error grows with later travel. For small angles, one degree produces about 52 millimetres of sideways error after three metres and about 175 millimetres after ten metres.
step 5Make one wheel two per cent bigger, and lose the robot step 6A degree of heading costs more than a per cent of distance -
Record position and heading error.
For each square run, record the reported finish and the measured finish. Keep position error and heading error as separate values. The mean shows repeatable calibration bias; the spread shows run-to-run uncertainty. Use both when choosing a target tolerance.
-
Express the target in the robot's coordinate frame.
The target and robot pose are stored in floor coordinates, but steering uses forward and left distances relative to the chassis. First subtract the robot position from the target. Then rotate that difference by the negative robot heading. Reversing those operations gives the wrong result.
What you needUse a two-dimensional rotation matrix built from sine and cosine. Translation and rotation are different operations in this form, and their order matters. Put the complete floor-to-robot conversion in one function. Test easy cases on paper: zero heading, a target directly ahead, and headings of plus and minus 90 degrees.
step 3Move every point at once step 5Do two moves, and then swap the order step 12Turn a character, shrink a picture, rank the pages -
Check the live target coordinates.
Print the target's forward and left coordinates while moving the robot by hand. Moving it toward the target should reduce the forward value. Turning the chassis should change both values in a predictable way. Fix sign or angle mistakes before enabling the motors; the printed values make them much easier to isolate.
-
Reduce overshoot at the target.
A full-speed command followed by zero at the target ignores braking distance. The robot crosses the target before friction slows it. A permanently low speed avoids much of the overshoot but makes long moves unnecessarily slow.
What you needWith proportional control, commanded speed is the remaining distance multiplied by a gain, then limited to a safe range. Add a derivative term if the robot still approaches too quickly: it responds to how fast the error changes and provides damping. Measure the loop interval because both derivative and integral calculations depend on time.
step 3Push harder when you are further away step 5React to how fast the error is changing step 11Hold a position, where the brake has to be the controller -
Measure the remaining steady-state error.
Watch the final part of the approach. As the position error shrinks, the proportional output may fall below the motor and gearbox's deadband. The robot then stops a repeatable distance short even though the controller still requests a small correction.
-
Remove steady-state error without restoring overshoot.
Increasing the proportional gain may overcome the deadband near the target, but it also raises the speed farther away and can bring the overshoot back. Use a separate term for error that persists over time.
What you needThe integral term accumulates error multiplied by the loop interval. A small error that remains for several updates therefore produces a growing correction until the robot moves. Limit the stored integral to prevent windup, and reset or condition it when a new target is selected. Log the proportional, integral, and derivative contributions separately.
step 4Close the last gap with a running total step 6Read the three terms separately at any moment of a run -
Verify the controller at five target points.
Measure final position error, overshoot, and settling time for five targets approached from different directions. Inspect the three logged terms for one run. Large or noisy derivative spikes and a saturated integral indicate tuning or measurement problems.
-
Follow a sequence of points and a curved path.
A waypoint sequence needs a clear rule for advancing to the next point. A very small tolerance makes the robot waste time correcting at each corner; a large one cuts corners. Curved paths also need a local steering target rather than the final endpoint.
What you needChoose a waypoint tolerance using the measured odometry uncertainty and the task's required accuracy. Track cross-track error, the shortest sideways distance to the intended path. A pure pursuit follower selects a point a fixed look-ahead distance along the path and commands the arc that reaches it. Short look-ahead distances follow tight curves but can cause oscillation; longer ones are smoother but cut corners.
step 8Take four corners in order, and decide what close enough means step 9Steer by the distance to the line, not the angle to it step 10Aim at a point further down the path -
Run the complete path-following test.
Mark a path with straight and curved sections. Run it from several starting poses and record maximum cross-track error, final position error, time, and any safety stops. Save the controller gains, calibration values, surface, and battery state with the results so another person can reproduce the test.
Review the robot in four passes
Once the basic path follower works, repeat the tests with four different goals. Keep the same code and hardware so you can compare results.
Make it work
Confirm the basic requirements: commands use physical units, odometry updates continuously, the robot stops within its tolerance, and the path follower completes the marked route.
Make it correct
With the motors disabled, test stale or impossible sensor inputs in software. On a guarded bench, briefly lift the drive wheels or block the route with a light object. Check that the controller limits stored error and stops safely instead of commanding a sudden lunge.
Make it fast
Run the same move five times. Record travel time, settling time, overshoot, final error, and peak motor command. Change one gain at a time, repeat the trials, and compare all of the measurements rather than choosing only the fastest run.
Make it survive
Test encoder loss by injecting a missing-count fault or disconnecting a sensor while the motors are disabled. Test slip at low speed in a clear area. The robot should detect implausible motion, stop, and report the fault. Add an external position or heading sensor before relying on recovery from large odometry errors.
Course links for each pass
Use these lessons when a test exposes the matching failure mode.
-
Prevent integral windup.
Make it correct
When the robot cannot move, the position error remains and the integral term can keep growing even though the motor command is already limited. When motion becomes possible, that stored value causes a large command. This is integral windup. Clamp the integral or pause its update while the output is saturated in the same direction as the error.
step 8Spot a stored total that grew too large, and limit it -
Tune the three controller gains.
Make it fast
Controller gains depend on the robot and the required behaviour. Define measurements before tuning: settling time, overshoot, final error, and motor effort. Use repeated runs, adjust one term at a time, and keep the best settings with the test conditions. A combined score is useful only if its weighting matches the task.
step 7Tune a controller yourself, against a measured score -
Detect unreliable odometry.
Make it survive
Wheel odometry assumes that measured wheel rotation matches motion across the floor. Slip, skidding, a lifted wheel, or external movement breaks that assumption. Compare the estimate with another source such as an inertial sensor, camera, beacon, or map observation. Track uncertainty so the robot can slow or stop when localisation is no longer reliable.
step 11Four ways to move a robot without turning a wheel
Optional extension: camera instructions and learned actions
Keep the encoder, odometry, path follower and stopping controller as the baseline. Add a camera and learned model one layer above them. The model may propose a target or short action chunk; checked code remains responsible for workspace limits, obstacles, speed and stopping.
- Record time-aligned camera, pose, command and intervention data.
Mark the coordinate frame and acquisition time of every value. Split by run and room, not by neighbouring frames. Include failed approaches, recoveries and cases where the instruction is ambiguous.
- Begin with perception or waypoint proposals in shadow mode.
Compare proposed objects, masks or targets with held-out labels while the original controller drives. Do not let a visual answer command motors until its latency, failure slices and uncertainty response have been measured.
- Validate every proposal against a stopping envelope.
Reject targets outside the mapped workspace, action values outside limits and paths without adequate clearance. Execute a short prefix, re-observe and stop when localisation, perception or the model output becomes invalid.
- Report autonomous, shielded and human-assisted trials separately.
Use new rooms, objects and phrasings. Record success, minimum clearance, collisions, interventions, latency and energy across repeated starts. A safety override is a prevented failure, not an autonomous success.
Relevant lessons: image-text models, vision evaluation, vision-language-action models, and staged physical evidence.
Related projects and courses
This project covers differential-drive kinematics, wheel odometry, position control, and path following. Larger mobile robots use the same ideas but add stronger localisation, obstacle detection, route planning, fault handling, and safety-rated stopping systems.
All builds or read Robotics, Control Systems and Linear Algebra for the complete lesson sequences.