Open-source robot vacuum you build yourself.
Cleaning · Docking · Localization · ROS 2 Jazzy · Nav2 · Gazebo
Reference ROS 2 packages for the OOMWOO open-source robot vacuum — one home for the vacuum's ROS 2 packages instead of a repo per package. Behaviours like partition-and-clean, localization, docking and map-and-clean live here so they build, test and version together.
oomwoo_coverage— boustrophedon cell-decomposition coverage cleaning: drives a full-room sweep through Nav2 (or the reactive executor,executor:=reactive), with gap-fill and wedge recovery.oomwoo_nav_localize— kidnapped-robot relocalization (global correlative scan-match + AMCL) so the robot can recover its pose from any start position on a known map.oomwoo_sim_support— everything needed to run and measure the above headless in Gazebo: sim bring-up, a ground-truth pose publisher, the coverage meter, the kidnap injector, and the CLI regression runners.oomwoo_clean— cleaning-specific navigation, the home for the from-scratch cleaning-with-map rebuild. Ships the drive-to-goal behavior (cleaning.launch.py) and a nav-with-map launch (nav.launch.py); see Cleaning with a map below.oomwoo_clean_ui— RViz debug tooling for cleaning (cleaning_debug.launch.py): a ready-made layout with the coverage plan, robot, LiDAR, map and covered grid pre-added. Split out so itsrviz2dependency stays off the robot runtime.
Step-by-step guides on makerspet.com:
- Simulate OOMWOO-One in Gazebo with ROS 2 — bring up the simulation from scratch.
- Write your first OOMWOO ROS 2 package — a hello-world package in the dev image.
- Headless sim & coverage cleaning (for LLM agents) — run and measure cleaning with no display.
- The phantom obstacle: teaching OOMWOO to clean near walls — how the "wedges near furniture" bug was root-caused and fixed.
Run inside the makerspet/oomwoo:jazzy-dev container (each launch in its own
terminal). The default robot model is oomwoo_one.
# select the robot description
kaia config robot.model oomwoo_one
# start the Gazebo simulation
ros2 launch oomwoo_gazebo world.launch.py
# build a map with SLAM while you drive
ros2 launch oomwoo_bringup navigation.launch.py use_sim_time:=true slam:=True
# open RViz to watch the robot and map
ros2 launch oomwoo_bringup monitor_robot.launch.py use_sim_time:=true
# drive with the keyboard
ros2 run kaiaai_teleop teleop_keyboard
# watch the bumpers (contact-tolerant cleaning relies on these)
ros2 topic echo /bumper_left/contact
ros2 topic echo /bumper_right/contact
# save the map you built
ros2 run nav2_map_server map_saver_cli -f ~/maps/mapDrive-to-goal cleaning on a loaded map: drop a goal in RViz, watch the robot navigate there with Nav2, and (in sim) watch the floor marked clean wherever it goes. It is split into composable commands — one per terminal — so you see each one's logs live, and can swap any layer independently (a physical robot for the sim, or another behavior for cleaning).
# 1. robot source — Gazebo sim (GUI on, living_room by default).
# Swap for a real robot: ros2 launch oomwoo_bringup physical.launch.py
ros2 launch oomwoo_gazebo world.launch.py
# 2. navigation on the existing map (AMCL + Nav2). coverage:=true adds the
# sim-only ground-truth coverage meter (off by default).
ros2 launch oomwoo_clean nav.launch.py use_sim_time:=true coverage:=true
# 3. cleaning behavior — bridges RViz 2D Goal Pose to Nav2 and marks coverage.
# Swap for another behavior later (docking, ...).
ros2 launch oomwoo_clean cleaning.launch.py
# viewer — RViz with the covered grid and the goal/pose tools
ros2 launch oomwoo_clean_ui cleaning_debug.launch.pyIn RViz, drop a 2D Goal Pose — the robot drives there and the covered grid
fills in along its path. In sim the robot localizes itself at the spawn pose
(nav.launch.py seeds AMCL, auto_localize:=true by default), so no manual 2D
Pose Estimate is needed; keep the sim spawn pose and nav.launch.py's
x_pose/y_pose in sync so it lands in the right place.
The nav and cleaning commands are robot-agnostic; only command 1 changes between
sim and a real robot. On a real robot, pass auto_localize:=false (its pose is
unknown — seed it with RViz's 2D Pose Estimate) and leave coverage off:
coverage marking is ground-truth based, so it works in sim only (a real robot
needs a belief-based estimator, not built yet).
Copy-paste. Needs Docker on a native x86-64 Linux box (not ARM / not an M-series Mac, and not Docker Desktop on Windows — see the note at the bottom). Nothing else to install: these packages ship prebuilt in the dev image.
# ROS 2 Jazzy + Nav2 + Gazebo + oomwoo_one + these packages, ~9.5 GB
docker pull makerspet/oomwoo:jazzy-dev
# spin it up and get a bash prompt inside (same flow as the makerspet tutorials)
docker run -it --name oom makerspet/oomwoo:jazzy-devEverything below runs at the container's bash prompt. The packages are
already built and sourced — nothing to clone. (Editing them? Rebuild with
colcon build --symlink-install --packages-select oomwoo_coverage oomwoo_nav_localize oomwoo_sim_support oomwoo_clean oomwoo_clean_ui in
/ros_ws.)
bash /ros_ws/src/oomwoo-ros2-tools/deploy/run_reloc_regression.shTeleports the robot to 10 random spots and recovers each. Prints per-trial lines and a summary; exits 0 on pass. Expect:
RELOC_SUMMARY passed=10/10 success_rate=1.00 target=0.90 ... suite_pass=True
bash /ros_ws/src/oomwoo-ros2-tools/deploy/run_coverage_regression.shSweeps the room, then a gap-fill pass. Prints COVERAGE_REPORT lines and a
summary; exits 0 on pass.
bash /ros_ws/src/oomwoo-ros2-tools/deploy/run_coverage_livingroom.shSame harness on the cluttered stock living_room. The room is tight, so efficiency lands below the open test_room's by design. Note this suite is variable (~50–85 % across runs) and may not meet the 90 % gate the runner enforces — a known open item on this furniture-dense world (a hard under-furniture pocket where the robot intermittently wedges), not a regression failure.
Every simulation runs identically with or without the GUI — one switch:
ros2 launch oomwoo_sim_support coverage_regression.launch.py gui:=true(Headless is the default; gui:=true needs a display, e.g. docker run with
X11 forwarding as in the makerspet simulation tutorial.)
The launches follow the kaiaai convention: kaia config robot.model <package>
selects the robot description, or pass it explicitly:
ros2 launch oomwoo_sim_support coverage_regression.launch.py robot_model:=proscenic_m6proThe regression scripts pin oomwoo_one by default so results are reproducible.
RUNS=3 bash /ros_ws/src/oomwoo-ros2-tools/deploy/run_coverage_regression.shRuns the suite 3× and prints min/max/mean/stdev for each metric. Exit codes:
0 all pass, 1 a run missed its targets, 2 measurement invalid (the meter
detected ground-truth pose teleports — the sim is unstable on that host).
- Host requirement: the results assume a real x86-64 Linux host (or CI runner). Docker Desktop on Windows runs inside a WSL2 VM and ARM Macs emulate x86 — both destabilize Gazebo physics (the ground-truth pose can teleport). The regression detects that and reports "sim unstable" (exit 2) instead of garbage.
- Speed: on 4 vCPU the sim runs ~real-time. On fewer cores it's slower but the metrics are unaffected (they're measured in sim time).
- Reports: JSON lands at
/root/coverage_report.jsonand/root/reloc_report.json; live logs at/tmp/coverage_regression.log.1etc. - Clean up:
exitthe container, thendocker rm -f oomon the host.
Milestone design notes and the measured M1/M2 baselines are archived under docs/etc/.
The initial packages here were authored by Jayadev Rana, commissioned for OOMWOO's M1/M2 milestones — coverage cleaning, kidnapped-robot localization, a headless Gazebo regression harness, and a Raspberry Pi runtime baseline. Per-file copyright headers are preserved. Originally developed at jayadevrana/oomwoo-m1-ros2. Thank you, Jayadev.
New ROS 2 vacuum packages and improvements are welcome. See the OOMWOO requests for contributions and CONTRIBUTING. Say hi in the discussions or on Discord.