Tutorial · Intermediate · 30 min

Coverage Path Planning: Sweep a Whole Floor

Getting somewhere and covering everywhere are different problems. Random, spiral and boustrophedon sweeps measured against a perfect one.

A different problem from getting there

A* finds one route to one goal. A coverage planner has to touch every reachable square, which changes the objective completely: there is no goal to be near, no heuristic to guide you, and success is not binary.

The measure that replaces it is distance per square metre swept. With floor area A and a tool of width w, a perfect robot sweeps each square once and never repeats:

d_optimal = A / w

A 20 m² room with a 250 mm brush needs 80 m. Every number below is a multiple of that, because a multiple is the only comparison that survives a change of room.

The law that governs sweeping without a map

A robot with no idea where it has been covers new floor in proportion to how much floor is still uncovered. That is a differential equation with one answer:

covered(d) ≈ 1 − e^(−d / d_optimal)

Read three points off it and the shape of the whole problem appears:

Coverage Distance
63% 1.0 × optimal
90% 2.3 × optimal
99% 4.6 × optimal

The last 9% costs more than the first 90%. This is the coupon collector’s problem with a brush attached, and it is the single fact that explains every robot vacuum you have ever watched.

What actually happens

Theory assumes each metre lands on floor chosen independently. A real robot drives in straight lines, so consecutive metres are correlated — it keeps re-sweeping the patch it is already standing on. Measured over five rooms in the coverage simulator:

Two stacked plots. The upper one shows floor covered as a percentage against distance travelled divided by a perfect sweep, for three measured strategies plus the dashed theoretical curve one minus e to the minus d. The planned sweep rises steepest and flattens at ninety percent; random bounce rises more slowly but keeps going past ninety-nine; the spiral is slowest of all. The lower plot is a horizontal bar chart of the distance each strategy needs to reach fifty, ninety and ninety-nine percent coverage, with the planned sweep marked never at ninety-nine percent.
Left half of the top panel: nothing separates the three strategies for the first half of the floor. The bottom panel is where the difference lives — 90% costs 1.3× planned, 2.9× random and 5.5× spiralling, and only the two unplanned ones ever reach 99%. Download SVG
Strategy 50% 90% 99% Finishes at
Planned sweep 0.75× 1.35× never 90.4%
Random bounce 0.91× 2.90× 6.76× 99.6%
Spiral + relocate 0.87× 5.54× 10.96× 99.5%

Three things in that table are worth more than the rest of this page.

For the first half of the floor, nothing matters. All three strategies are within 20% of each other at 50%. A robot with no sensing and no memory is genuinely as good as a planner for the first half of the job — which is exactly why the cheap approach is commercially viable and why casual observation never reveals the difference.

Random does worse than its own theory. 6.76× against a predicted 4.61× at 99%, because a straight-line bounce keeps revisiting floor it just did. Treat 1 − e^(−d) as the optimistic bound, not the estimate.

The planner never finishes. It stops at 90.4% and stays there, and this is not a bug.

Why the planner leaves a tenth of the floor

A coverage planner has to keep the robot’s body clear of every wall and every table leg, so it inflates each obstacle by the robot’s radius plus a margin and plans inside what is left. Whatever falls outside is floor the robot can never drive to.

In the measured run, 130 of the 133 squares the planner missed were within two cells of a wall or a piece of furniture. Only three were open floor. The misses are not scattered — they are a ring around every obstacle in the room.

Which explains two features of every commercial machine:

  • The side brush that overhangs the chassis. The brush is wider than the thing that collides, so it reaches floor the wheels can never get to.
  • The wall-following pass. It is a separate behaviour, run separately, because the systematic sweep structurally cannot do it.

Random bounce reaches those edges eventually, by luck, which is the one thing it does better.

Choosing rows

For a systematic sweep the only real parameter is row spacing.

Space rows exactly one brush width apart and any heading error at all leaves an uncleaned stripe between them — and nothing later will find it, because the plan believes that floor is done. Overlap by 10–20% and the stripes close, at a cost of exactly that percentage in distance.

That overlap, plus the transit distance around furniture, is where the planner’s 1.35× comes from. It is not waste; it is the price of a plan that survives contact with a real robot.

Two more choices that matter more than they look:

  • Run rows along the long axis of the room. Every turn costs time and covers no new floor, so halving the number of rows halves the turn overhead.
  • Route between spans, do not drive between them. When furniture splits a row into two spans, the robot has to go around. Planning that transit as a shortest path through free space is the difference between a plan and a wish.

The sensing each strategy demands

This is the real reason all three exist.

Random bounce needs one bit. Did I hit something. Two bump switches and a random number generator is the entire robot. No encoders, no map, no localisation, and nothing to drift.

Spiralling needs to know how far it has gone since the centre of the current spiral, which is a rough odometry — good enough to grow a radius, not good enough to close a loop.

A planned sweep needs to know where it is. Straight rows, known turn angles, and a sideways step of one brush width are all odometry claims, and odometry drifts. Ten rows in, the rows are no longer parallel. This is why commercial machines that plan also carry a gyro, a ceiling camera or a beacon — the planner is cheap and the localisation it assumes is not.

So the strategy is chosen by the sensing budget, not by the algorithm’s elegance. Build the random one first: it works, it is twenty lines, and it gives you a baseline the planner has to beat.

What it costs in minutes

Take that 20 m² room, a 250 mm brush and a robot cruising at 0.25 m/s:

Strategy Distance Time
Perfect sweep 80 m 5 min
Planned 108 m 7 min
Random, to 90% 232 m 15 min
Random, to 99% 541 m 36 min
Spiral, to 99% 877 m 58 min

A battery is a distance budget. A one-hour runtime at 0.25 m/s is 900 m, which comfortably covers one room at random and does not cover three — and that, rather than any algorithmic insight, is what pushed the market toward mapping robots.

When it goes wrong

Symptom Usually
Robot traces the same loop forever Bounce angle is deterministic — a fixed reflection on a rectangular floor is a closed path
Rows drift out of parallel Odometry, not the planner. Add a heading reference
Stripes of missed floor between rows Row spacing set to exactly the brush width with no overlap
Misses the edges of every room Working as designed — add a wall-following pass or a wider brush
Covers 90% fast, then appears to stop Also as designed. Watch the coverage curve, not the robot
Never finishes behind the sofa The transit between row spans was never planned
Battery dies mid-room Distance budget exceeded; measure coverage per metre, not per minute

Run all three against the same room in the coverage simulator — drag the furniture while it runs and the numbers move with it. Then build the room coverage robot, which starts with the strategy that needs nothing and adds sensing only where the measurement says it pays.

Explore the graph

Part of these builds

Projects and learning paths that include this tutorial.

Further reading

References