How it is built
Architecture overview
A robot vacuum is a small mobile robot with three computers and one cloud. A microcontroller runs the reflexes at a fixed rate: wheels, brushes, fan, cliff and bump sensors. An application processor runs the slow, heavy parts: it builds a map from a lidar or a camera, plans a route that covers every room, recognises obstacles and talks to the cloud. The dock charges the robot and empties its bin. The cloud and app hold the user's maps, schedules and the update pipeline. The idea that makes it work is a strict split by deadline: anything that can hurt the robot (a drop, a stall, a lost command link) is handled on the microcontroller without asking the application processor, and anything that needs the map is allowed to be late. The map is the shared object: a probabilistic grid that SLAM writes, room segmentation labels, the planner reads and the app displays.
Parts:
- Base control — wheel, brush and fan loops, reflex sensing, safe stop — Fixed-rate control loop, PID controller, Fault detection, isolation and recovery (no page yet)
- State estimation — pose from wheels, gyro and scan matching — Kalman filter, Extended Kalman filter, Sensor fusion (no page yet)
- Mapping — lidar or visual SLAM into a grid — SLAM (no page yet), Point-cloud registration (ICP) (no page yet), Occupancy grid (no page yet), Bundle adjustment (no page yet), ORB feature detection (no page yet)
- Map understanding — rooms, doors, user zones —
mathematical-morphology-watershed(no page yet), Voronoi diagrams (no page yet) - Planning and driving — coverage routes, point-to-point paths, path tracking — Coverage path planning (no page yet), A* search, Motion planning (no page yet), Pure-pursuit path tracking (no page yet)
- Perception — what is on the floor — Structured light depth (no page yet), Weight quantization
- Docking — find the dock and align — Fiducial marker localization (no page yet)
- Cloud link — commands, state and maps between robot and app — MQTT protocol (no page yet), Device shadow state sync (no page yet), Mutual TLS
- Updates — new firmware that cannot brick the robot — A/B partition updates
- Operations — on-robot supervision and cloud resilience — Process supervision, Graceful draining, Point-in-time recovery, Primary-backup replication, HDR histogram (no page yet), Deterministic simulation testing, Coverage-guided fuzzing
┌───────────────────────── robot ─────────────────────────────┐
│ MCU (hard real time) application SoC (Linux) │
│ wheels/PID, brush, fan lidar/camera ─► SLAM ─► grid map ─► rooms
│ cliff, bump, current ◄─v,ω──── planner ─► tracker │ │
│ gyro, encoders ──odometry─────► fusion (EKF) ◄─ scan match │ ▼
│ watchdog, reflex stop perception (NPU) ─► obstacles │ coverage plan
└───────▲──────────────────────────────┬──────────────────────────┘
│ charge/empty/IR beacon │ MQTT over mutual TLS
dock ▼
cloud: shadow (desired/reported), map store,
OTA service ──► app (phone)
How the parts fit together
Base control
The microcontroller runs a Fixed-rate control loop: read encoders, gyro and the cliff, bump and motor-current sensors, run the controllers, write the PWM outputs, every period, against absolute deadlines so jitter does not accumulate. Wheel speed is a PID controller per wheel; the brush and fan loops are simpler current or speed loops. The application processor never touches the motors. It sends (v, ω) setpoints (forward speed and turn rate) with a short expiry, and the microcontroller converts them to wheel speeds. If the setpoint expires, the robot stops: a hung Linux process cannot leave a robot driving. The microcontroller itself is guarded by a Watchdog timer.
Reflexes run here, in the same loop that reads the sensor. A cliff sensor that reads "no floor" stops the wheels in the same tick and only then tells the application processor. This is Fault detection, isolation and recovery (no page yet) in its simplest form: a table of monitors (cliff, bump, wheel stall, brush overcurrent, battery temperature) and fixed responses (stop, back off, reverse the brush, enter safe mode). The modes themselves (docked, cleaning, returning, paused, error) are a Hierarchical state machine: "lifted off the floor" and "low battery" are handled once on the parent state and inherited by every cleaning substate, rather than repeated in each.
Contract to the application processor: a framed serial link with sequence numbers and a checksum, a heartbeat both ways, odometry and gyro packets at a steady rate, and events (cliff, bump) sent as soon as they happen. The link is lossy, so every frame must stand alone.
State estimation
Wheel odometry alone drifts: carpet and wheel slip bias it, and a turn error becomes a position error. The estimator fuses the wheels with a gyro in a Kalman filter; because the motion and measurement models are nonlinear, the Extended Kalman filter is the usual form; Sensor fusion (no page yet) adds time alignment between the sensors and the frame tree that says where the lidar sits relative to the wheels. The scan matcher's pose is a measurement that pulls the estimate back. A SPSC ring buffer carries the sensor packets from the I/O thread to the fusion thread without locks.
Mapping
SLAM (no page yet) turns the stream of range scans (or images) into a pose graph and a map. Each new lidar scan is aligned to the previous scans or the local map by Point-cloud registration (ICP) (no page yet), which gives the relative motion; a loop closure adds an edge when the robot returns to a known place, and optimising the graph pulls drift out. The map is an Occupancy grid (no page yet): each cell holds a log-odds value updated from the scans, so free, occupied and unknown are three different states and noise averages out.
A lidar gives range directly and works in the dark; a camera needs light and texture. Camera-based robots instead run visual SLAM with ORB feature detection (no page yet) features for tracking and relocalisation and Bundle adjustment (no page yet) to refine poses and points. ORB-SLAM3 is the open reference for that route (source: Campos et al.). Many designs use the lidar for the map and the camera for obstacle recognition.
Contract: the map is a grid with a fixed resolution (order of a few centimetres per cell), an origin and a version number. SLAM is the only writer while mapping; afterwards the map is read-only until the next run, so the planner and the app never see a half-updated map.
Map understanding
A grid is not what the user thinks in: the app shows rooms. Segmentation cuts the free space into rooms at doorways. Open-source implementations include a morphological method, a distance-transform method, a Voronoi-graph method and a trained semantic one (source: ipa_room_segmentation code, Bormann et al. 2016). The first two use mathematical-morphology-watershed (no page yet): shrink the free space until doorways separate rooms, then grow labels back. Voronoi diagrams (no page yet) find the skeleton of the free space and cut it at narrow points. After segmentation the user can merge, split and name rooms and draw no-go zones; those edits live next to the grid, keyed by the map version.
Planning and driving
A cleaning job is a list of rooms. For each room, Coverage path planning (no page yet) covers the free space with parallel passes (boustrophedon, "ox-turning" lanes), with the lane width matched to the brush, cells split where an obstacle breaks a lane (source: Galceran and Carreras, survey). Between rooms, and back to the dock, the robot needs ordinary shortest paths on the grid with inflated obstacles: A* search over the grid is enough at this scale. Motion planning (no page yet) covers the local layer: avoid a chair leg that was not in the map.
The path is a list of points; Pure-pursuit path tracking (no page yet) steers to a point a fixed look-ahead distance along it and outputs (v, ω), which is the contract to the base. Pure pursuit beats a model-predictive controller here because a differential-drive robot at low speed does not need one; the tracker is a few lines run at the planner's rate (order of 10 Hz).
Perception
Cliffs and bumpers sense contact; the obstacle layer senses things before contact. A line laser or time-of-flight sensor gives depth from Structured light depth (no page yet), and a camera plus a small classifier names what is ahead (cable, sock, pet mess) so the planner chooses a margin for each class instead of one distance for everything. The classifier runs on an accelerator in the application processor; Weight quantization to 8-bit integers lets it fit the memory and power budget, and the cost is a small accuracy loss that must be measured on floor-level images before shipping. Contract to planning: a list of obstacles with position, class and confidence, merged into the grid as temporary cells with a time-to-live, so a moved shoe does not stay a wall.
Docking
The robot finds the dock first from the map, then, close in, from a marker or infrared beacon pattern with Fiducial marker localization (no page yet), fused with odometry. A marker gives the dock's pose relative to the robot, which is more accurate than the map at the last half metre. Contact is detected on the charging pins by the microcontroller. The dock does the self-emptying as a sequence on its own controller; the robot only reports "docked" and "bin full" and waits.
Cloud link
The robot holds a long-lived MQTT protocol (no page yet) connection: topics, a keep-alive, a last-will message so the cloud knows when the robot drops, and QoS 1 for commands (source: MQTT v5 spec). State is a shadow, Device shadow state sync (no page yet): the app writes a desired document ("clean the kitchen, quiet mode"), the robot writes reported, and the difference is delivered as a delta; versions on the document reject an update made from a stale copy (source: AWS IoT Device Shadow docs). This beats request/response because the robot is often asleep or off Wi-Fi: the intent waits in the cloud and is applied on reconnect. Large objects (maps, logs) go by presigned upload to object storage; the shadow holds only the map version.
The connection uses Mutual TLS, so every robot has a provisioned certificate and a stolen account password cannot command it. Valetudo shows the cloud can be replaced by a local MQTT and REST bridge (source: Valetudo README).
Updates
Firmware updates use A/B partition updates: write the new image to the idle slot, boot it once, and fall back to the old slot unless it reports healthy. Health here means "reached the cleaning state, connected to the cloud and the microcontroller link works", not just "booted". The update runs while the robot is docked and charged; the microcontroller has its own image, and the pair must stay version-compatible.
Operations
On the robot, Process supervision restarts mapping, perception and the cloud client independently; losing perception must not stop cleaning. In the cloud, Graceful draining lets a broker restart without a reconnect storm from the fleet; Point-in-time recovery protects the map store (a corrupted map is a lost evening of mapping) and Primary-backup replication keeps the shadow store available. HDR histogram (no page yet) records latency for command-to-motion across the fleet. The planner and the state machine run in Deterministic simulation testing on recorded floor plans, and Coverage-guided fuzzing hits the parsers that take outside input: serial frames, MQTT payloads, map uploads.
Data and control flow
A cleaning job from the app:
- The app writes
desired: {rooms: [kitchen], mode: quiet}to the shadow; the cloud delivers the delta over MQTT when the robot is online. - The robot's state machine leaves docked; the application processor loads the map and relocalises: the first scans are matched against the saved grid, and if matching fails the robot drives a short path to gather more.
- The planner builds a coverage route for each requested room and the A* paths between them.
- The tracker sends
(v, ω)to the base. The base obeys, publishes odometry, and stops on its own at cliffs or bumps. - Perception adds temporary obstacles; the local planner re-routes around them; unreachable cells are marked skipped.
- When the battery nears a reserve, the planner switches to "go to dock"; after charging it resumes the remaining coverage from the saved plan.
- The robot reports progress and the final coverage into the shadow; the map and the cleaning log go to object storage.
One control tick on the base (the part that never waits): read sensors, check reflex table, run PID, write PWM, kick the watchdog, publish a packet. If an application setpoint has expired, the target velocity is zero.
An update: the cloud marks the robot's desired firmware version; when docked and charged the robot downloads and verifies the image, writes the idle slot, reboots into it, runs health checks, and reports. Unhealthy means the bootloader returns to the old slot by itself.
Scaling
- Compute and memory on the robot come first: the application processor is small and the map grows with the home. Levers: coarser grid resolution, local map windows with a global pose graph, quantised perception models, and splitting work across cores with ring buffers.
- Coverage quality (missed corners, double passes): improve room decomposition and edge-following before adding sensors.
- Battery limits area per run; lever: fewer turns, resume after charging.
- Fleet size is a cloud problem: connection count per broker, reconnect storms after an outage, map storage. Levers: shard brokers by device id, jittered reconnect, map upload only on change, expiry for old logs.
- Release safety limits how fast you can improve: staged rollouts, A/B fallback, and simulation on a library of floor plans.
Failure modes
| Failure | Symptom | Cause | Fix |
|---|---|---|---|
| Kidnapping | robot cleans the wrong room, map "slides" | picked up and moved, pose no longer matches | detect lift (wheel drop, gyro), relocalise globally before moving |
| Odometry drift on carpet | map walls double or smear | wheel slip, bias on turns | fuse the gyro, weight scan matching higher, check loop closure |
| False loop closure | map folds onto itself | two similar corridors | verify with a second check; reject closures with a robust cost |
| Dark floor read as cliff | robot refuses to enter an area | infrared absorbed by the surface | per-sensor calibration, debounce, user-defined override zone |
| Mirror and glass | lidar sees a phantom room or passes a window | specular or transparent surface | bumper contact marks the obstacle; user-drawn barrier |
| Dock miss | circles near the dock, runs out of battery | marker not seen, map drift near dock | beacon fallback, dock pose re-estimated each docking |
| Stale desired state | app shows "cleaning", robot idle | disconnected robot, update from an old copy | versioned shadow, reported timestamps, retry on reconnect |
| Bad update | robot does not boot or loops | firmware bug in the new slot | A/B with health-confirm, staged rollout |
| Planner stuck | spins in place | goal inside inflated obstacle, oscillating replans | recovery behaviours in order: wait, back off, re-plan with smaller inflation, give up and report |
Real implementations
| name | what it is | repo | licence | notes |
|---|---|---|---|---|
| Valetudo | local cloud replacement for vacuum robots, REST and MQTT | Hypfer/Valetudo | Apache-2.0 | reuses the vendor firmware, "not a custom firmware" |
| Nav2 | ROS 2 navigation stack: planners, controllers, costmaps | ros-navigation/navigation2 | per package (LGPL-2.1-or-later, Apache-2.0, BSD-3-Clause) | pattern of the planner and tracker layers; written for larger robots |
| SLAM Toolbox | 2D lidar SLAM with pose-graph, lifelong mapping | SteveMacenski/slam_toolbox | LGPL-2.1 | |
| Cartographer | 2D and 3D SLAM with loop closure | cartographer-project/cartographer | Apache-2.0 | |
| ORB-SLAM3 | visual and visual-inertial SLAM | UZ-SLAMLab/ORB_SLAM3 | GPL-3.0 | the visual route |
| ipa_coverage_planning | room segmentation and coverage path planning | ipa320/ipa_coverage_planning | LGPL for academic and non-commercial use (package.xml) | companion to the Bormann et al. papers |
Commercial robots (Roborock, iRobot Roomba, Ecovacs, Dreame) have closed firmware and clouds; the split above is the common design, not a documented one of any vendor.
Sources
- R. Bormann, F. Jordan, W. Li, J. Hampp, M. Hägele, Room Segmentation: Survey, Implementation, and Analysis, ICRA 2016. IEEE
- R. Bormann et al., Indoor coverage path planning: Survey, implementation, analysis, ICRA 2018. IEEE
- E. Galceran, M. Carreras, A survey on coverage path planning for robotics, Robotics and Autonomous Systems, 2013. DOI
- C. Campos et al., ORB-SLAM3: An Accurate Open-Source Library for Visual, Visual-Inertial and Multi-Map SLAM. arXiv
- W. Hess et al., Real-Time Loop Closure in 2D LIDAR SLAM, ICRA 2016 (the Cartographer paper). paper
- AWS IoT Core, Device Shadow service and shadow documents.
- OASIS, MQTT version 5.0.
- Valetudo docs and README; Nav2.