Coverage Path Planning Simulator for Robot Vacuums
Compare random bounce, spiral and boustrophedon coverage in a browser lab that measures every strategy against the distance a perfect sweep would take.
- Category
- Autonomous Robots
- Time
- 20–40 min
- Platform
- Browser · Arduino · Raspberry Pi
01 / Start here
Introduction
Covering a floor is not the same problem as getting somewhere. A path planner finds one route to one goal; a coverage planner has to touch every reachable square, and the honest measure of it is distance travelled per square metre cleaned. This lab runs random bounce, an expanding spiral, and a planned serpentine sweep over the same room, and plots each against the theoretical best.
Live lab / Coverage path planning
Coverage path planning simulator
Three ways to cover a floor — random bounce, expanding spiral, and a planned boustrophedon sweep — measured against the one number that matters: the distance a perfect robot would need.
Shaded floor is covered. The thin line is where the robot has driven, the circle is its brush. Below, the same run plotted as coverage against distance — the dashed straight line is a perfect sweep, the dashed curve is the theory for random sweeping. Drag furniture to rebuild the room.
- Covered floor
- Furniture (drag it)
- Path driven
- Perfect sweep
- Covered
- 0%
- Distance
- 0.00× optimal
- Half the floor
- —
- 90% covered
- —
- 99% covered
- —
- Bumps
- 0
Keyboard: focus the room, then Space to run/pause, N to step, R to reset, M for a new room, F for full screen. Press 1–4 to pick a piece of furniture and the arrow keys to move it.
Controls
Strategy switches between the three. The room is rebuilt and the run restarts immediately, because a coverage number only means something next to the room it was measured in.
Drag any piece of furniture with the pointer, or press 1–4 to select one and move it with the arrow keys. The run restarts as you drag. Put a table in the middle of the floor and watch the planned sweep’s distance climb while its coverage falls.
New room scatters the furniture again. Run speed trades smoothness for patience — the random strategy needs several thousand moves to finish, so start it on fast.
Theory
A path planner answers how do I get there. A coverage planner answers how do I touch all of it, and the two have almost nothing in common.
The only honest yardstick is the distance a perfect robot would need. With a floor of area A and a brush of width w, sweeping every square once and never repeating takes:
d_optimal = A / w
Everything the lab reports is a multiple of that number. A strategy at 1.2× is spending 20% of its life going over floor it has already done; one at 8× is spending seven eighths of it.
Random bounce has a closed form, and it is not encouraging. A robot with no map covers new floor in proportion to how much is still uncovered, so uncovered area decays exponentially:
covered(d) ≈ 1 − e^(−d / d_optimal)
That is the dashed curve on the plot. Read three points off it: 63% of the floor after one optimal distance, 90% after 2.3, and 99% after 4.6. The last tenth of the room costs twice what the first three quarters did — the coupon collector’s problem, wearing a brush.
Systematic coverage is linear, so it finishes at 1× plus whatever overhead the row spacing and the turns cost. In this lab that overhead is about 35%.
The measured runs land close to the theory, and where they miss they miss in the direction you would expect: a real random walk revisits nearby floor rather than teleporting, so it does slightly worse than the independent-sampling curve suggests.
Algorithm
Random bounce. Drive straight. On a bump, pick a new heading at random and check it is clear. That is the whole thing, and it needs one bit of sensing and no memory at all.
Spiral, then relocate. Turn by an angle inversely proportional to how far you have travelled since the centre, which traces an expanding spiral. On a bump, dash in a straight line for a fixed distance and start a new spiral. Excellent on open floor — a spiral has almost no overlap — and helpless in a cluttered room, where every spiral is cut short after a few turns.
Planned serpentine. Three steps, and the second is the one people skip:
- Inflate. Grow every obstacle by the robot’s radius plus a safety margin. What is left is where the robot’s centre may go.
- Slice. Walk down the inflated map in rows one brush width apart. Each row becomes one or more free spans.
- Join. Visit the spans in serpentine order, and route between consecutive spans with a shortest path through the free space, so the robot drives around the sofa rather than into it.
Step 3 is where the distance overhead comes from, and it is why a cluttered room punishes a planner more than an empty one.
Source code
The random strategy is the one worth having on a real robot first, because it works with sensing you already have:
// Random-bounce coverage. Two bump switches, no map, no encoders.
const uint8_t BUMP_L = 2, BUMP_R = 3;
const uint16_t CRUISE = 170; // PWM
unsigned long turnUntil = 0;
int turnDir = 1;
void loop() {
bool left = digitalRead(BUMP_L) == LOW; // switches are active-low with pull-ups
bool right = digitalRead(BUMP_R) == LOW;
if (millis() < turnUntil) { // still executing a bounce
drive(turnDir * CRUISE, -turnDir * CRUISE);
return;
}
if (left || right) {
// Back off first — turning while wedged against a chair leg does nothing.
reverseFor(320);
// A random turn between 90 and 270 degrees. The randomness is what stops the
// robot tracing the same closed loop around the room forever.
turnDir = right ? -1 : 1;
turnUntil = millis() + random(420, 1250);
return;
}
drive(CRUISE, CRUISE);
}
The bounce angle has to be random. A fixed reflection turns the room into a billiard table, and a billiard ball on a rectangular table traces a closed path that misses most of the surface forever.
The planned sweep needs the inflate-slice-join pass above plus odometry good enough to hold a straight row, which is a different class of robot. Prototype it here, where position is exact by construction, before deciding whether your hardware can carry it.
Assumptions and hardware differences
The lab gives the robot perfect odometry, a perfectly known map, instant turns in place, and a brush that covers a clean circle. A real machine has none of those.
Wheel slip and gyro drift bend the rows apart within about ten of them, which is why commercial robots re-localise against walls, ceiling features or a beacon. Turns take time that this lab charges no distance for. And the brush does not cover a circle — it covers a rectangle behind the robot, so reversing over floor you have already done cleans nothing.
The gap between strategies survives all of it. If a planner beats random bounce by 3× here, it beats it by perhaps 2× on real hardware; the ordering does not change.
Circuit diagram
The sensing splits cleanly into three jobs, and only the first is required.
Bump. Two microswitches on a sprung front bumper, wired active-low to interrupt-capable pins with the internal pull-ups on. This is the sensing that makes random bounce possible and it is the last thing to fail.
Cliff. Downward reflectance sensors at the front corners, read every pass of the loop. A coverage run visits everywhere, which includes the top of the stairs — the arithmetic for how far the robot travels past the edge before it can stop is worked out here.
Position. Quadrature encoders on both wheels, and a gyro if you want rows that stay parallel. Only the planned strategy needs this, and needing it is the whole reason the other two exist.
For the coverage strategies as a build, see the room coverage robot; for the reactive layer underneath all of them, the obstacle avoidance simulator covers stop thresholds and scanning.
Hardware checklist
Components
- A differential-drive base whose brush width you can measure
- Bump sensing that survives being driven into furniture
- Encoders, if the robot is going to plan rather than wander
- A cliff sensor, because coverage runs end at stairs
Explore the graph
Where this simulator is used
The projects, learning paths, and tutorials that build on this lab.
Continue building
Download resources
Use these on-page references while working through the project. Downloadable project bundles will be added only after their source and version are published.
Common questions
Frequently asked questions
Why do cheap robot vacuums bounce around at random?
Because random bounce needs no map, no encoders, and no localisation — the entire strategy is drive straight, and turn a random amount when you hit something. That fits on an eight-bit microcontroller with two bump switches. The lab shows what it costs: the first half of the floor is covered just as fast as a planned sweep, but 90 percent takes about three times the ideal distance and 99 percent takes six or more. The robot gets there in the end, which is why the strategy survives — it just spends an hour doing twenty minutes of work.
Why is coverage so slow at the end and so fast at the start?
Because a robot sweeping without a map covers new floor in proportion to how much floor is still uncovered. Early on nearly everything it drives over is new; late on nearly everything is a repeat. That gives the classic exponential approach, coverage of about one minus e to the minus d over optimal, which the lab draws as a dashed reference curve. It is the same mathematics as the coupon collector problem, and it means the last tenth of a room costs more than the first three quarters.
If systematic sweeping is so much better, why does the lab stop it at 90 percent?
Because a planner has to keep the robot's body clear of everything, so it plans a path that stays a margin away from every wall and every table leg — and it never covers what it cannot drive to. In this lab 130 of the 133 squares the planned sweep misses are within two cells of a wall or a piece of furniture. That is exactly why real robot vacuums have a side brush that overhangs the chassis and why they follow the walls as a separate pass. Random bounce reaches those edges eventually, purely by luck.
What does the planned sweep need that the random one does not?
It needs to know where it is. A serpentine route only means anything if the robot can drive a straight line, turn a known angle, and step sideways by one brush width — which is odometry, and odometry drifts. The lab plans on a perfect map with a perfect robot, so treat its 1.35 times optimal as the floor of what a real machine achieves rather than a target. Add wheel slip and gyro drift and the rows stop being parallel within about ten of them.
How wide should the rows be?
One brush width, minus an overlap you choose deliberately. Space them exactly one width apart and any heading error at all leaves an uncleaned stripe between rows that no later pass will find. Overlap by 10 to 20 percent and the stripes close at the cost of that same percentage in distance. The lab spaces rows at the largest whole number of cells the brush covers, which is why the distance comes out at 1.35 times optimal rather than 1.0 — the overhead is real and every coverage robot pays some version of it.
Does this apply to anything other than vacuums?
It is the same problem for a robot lawnmower, a pool cleaner, a floor scrubber, a crop sprayer and a survey drone. All of them have a working width, a region to cover, and an energy budget that makes distance the thing to minimise. The strategies differ mostly in whether the machine can afford the sensing to know where it is — a survey drone has GPS and always plans; a pool cleaner has nothing and always wanders.
Further reading
References
Authoritative sources for going deeper than this simulator's bounded educational model.