TL;DR:
Driving a square is four straight runs and four 90 degree turns, each computed from wheel size and track width.
Dead reckoning adds up small moves and never checks the result, so errors pile up.
Timing alone is fragile; counting wheel ticks with encoders is far better.
Tell a robot to go forward half a meter, turn right, and repeat four times, and you expect it to end where it began. It almost never does. The gap between where it ends and where it started is one of the best first lessons in robotics, because it shows what a robot actually knows about its own position.
What you will build
You will program a two-wheel differential-drive robot to trace a square, 500 mm per side, then measure how far it misses. The same program works with a timed motor or with wheel encoders, so you can compare the two.
Parts and tools
A two-wheel robot with a caster, a motor driver and a microcontroller board (the same base as a line follower).
Optionally, wheel encoders that count ticks as each wheel turns.
Masking tape, a tape measure and a marker to mark the start corner and heading.
A flat, smooth floor with room for a 0.5 m square plus a margin.
Wiring and assembly
Nothing new: the motor driver takes two direction pins and a speed pin per motor, the battery feeds the driver, and all grounds are joined. If you have encoders, connect each one's signal wire to an input pin that can detect changes. Test that both wheels spin forward before you place the robot on the floor, and swap a motor's wires if one runs backward.
The numbers: how far to turn each wheel
Say the wheels are 65 mm in diameter and the distance between their contact points (the track width) is 120 mm. These are example values, so measure your own robot with a ruler.
Wheel circumference:
π × 65 mm ≈ 204.2 mm.One side is 500 mm, so each wheel must turn
500 / 204.2 ≈ 2.45revolutions.For a 90° pivot turn, the wheels spin in opposite directions and each travels a quarter of the circle whose diameter is the track width:
π × 120 / 4 ≈ 94.2 mm.That is
94.2 / 204.2 ≈ 0.46of a wheel revolution.If an encoder gives 20 ticks per wheel revolution, a side is
2.45 × 20 ≈ 49ticks and a turn is0.46 × 20 ≈ 9.2ticks.
Notice that 9.2 ticks cannot be done exactly. Rounding to 9 ticks means a turn of 9 / 20 × 204.2 / 94.2 × 90° ≈ 87.9°, which is already about two degrees short.
The code, step by step
Write two functions, driveForward(mm) and turnRight(degrees), and call them four times each. The idea is the same whether you count ticks or time.
const float WHEEL_MM = 204.2; // circumference
const int TICKS_PER_REV = 20;
const float TRACK_MM = 120.0;
long ticksForDistance(float mm) {
return lround(mm / WHEEL_MM * TICKS_PER_REV);
}
long ticksForTurn(float degrees) {
float arc = 3.14159 * TRACK_MM * degrees / 360.0;
return lround(arc / WHEEL_MM * TICKS_PER_REV);
}
void loop() {
for (int i = 0; i < 4; i++) {
driveTicks(ticksForDistance(500));
turnTicks(ticksForTurn(90));
}
while (true) {} // stop
}driveTicks and turnTicks run the motors until the encoder counts reach the target, then stop. Without encoders, replace them with timed runs, for example drive for a measured number of milliseconds, using a speed you timed against a tape measure.
Test, measure and fix
Mark the start corner and the direction the robot faces. Run the program and mark where it stops. Measure the gap from the start and the angle it ended up facing.
Now see why. Suppose each turn is 2° short. Over a 500 mm side, a 2° heading error moves the path sideways by 500 × sin 2° ≈ 17.5 mm. After four sides the heading is off by 8° and the errors have added up, so the robot ends well away from the start. Wheel slip, wheel diameters that differ slightly and a drifting battery make it worse.
Re-measure the wheel diameter and track width, since small errors scale into every move.
Lower the speed for turns so the wheels slip less.
Calibrate: run a single 90° turn ten times, find the average error and adjust the track width value until it matches.
Why the square does not close
Dead reckoning means estimating position by adding up your own movements from a known start. It has no way to notice a mistake, so every error stays forever and grows. Timing makes it worse than encoders, because the same time gives a different distance as the battery drains. Encoders count what the wheels did, but they cannot see a wheel slipping.
Robots fix this by checking against the world: a gyroscope for heading, walls or a line, or a LiDAR. That is the point of sensor fusion, and it is why real robots rarely rely on odometry alone.
Make it better
Try a gyroscope to measure the turn angle directly, a triangle or a hexagon (the turn is then 120° or 60°, with the same code), or have the robot print its estimated position after each side so you can compare with a tape measure.
Stay safe
Before you run it: Use low-voltage battery packs only, and run the robot on a clear floor away from stairs and table edges. Keep fingers out of the wheels and switch off before changing wires.
Frequently asked questions
Why use encoders instead of time?
Time depends on battery charge and floor friction. Counting wheel ticks measures what the wheel actually did.
Will a better robot close the square exactly?
No. You can shrink the gap with calibration and extra sensors, but dead reckoning alone always drifts.
