1. Project Overview & Quickstart (makerspet/oomwoo)
File: README.md
OOMWOO is an open-source home robot vacuum you can build yourself, built using
Raspberry Pi, 3D-printing, Home Assistant, Arduino and ROS2. It uses an
affordable 2D LiDAR to map your home and navigate on its own. Local, no
cloud required for regular functionality, no vendor lock-in. Follow us building in public
Discord | X | Instagram | Facebook | Reddit | newsletter | YouTube | oomwoo.com | Tutorials
Early build instructions will be available in Fall 2026.
Reference design images - this is approximately how the finished design will look:
Goals
- Affordable, fully open hardware, software and firmware
- Home appliance product quality - not a throwaway build
- Easy to build, with step-by-step zero-to-hero instructions
- 2D LiDAR mapping and autonomous navigation (ROS2 / Nav2)
- Native Home Assistant integration for local control
- 3D-printable, documented, and hackable chassis
- Buildable from parts you source yourself
- Local, no cloud required for regular functionality
- Optional extra functionality when connected cloud
- Apps on top of ROS2 to customize vacuum operation
- Stretch goal: App store
- Stretch goal: LeRobot integration, OpenClaw
v0 target: bare-bones build:
- 3D-printed chassis (browse)
- ROS2 Gazebo sim (install)
- Basic cleaning, mapping
- Raspberry Pi CM4/CM5 running ROS2 (install)
Open Source Deliverables:
- Software development environment, robot description package and tutorials (ROS2)
- Placeholder real vacuum cleaner and tutorials (temporary while OOMWOO is being designed)
- Bill of materials (BoM) (rough version available)
- 3D-scanned sourced parts
- 3D-printable files
- Raspberry Pi software
- Motor drivers, sensors PCB boards
- I/O PCB firmware
- Build, setup, bringup and troubleshooting instructions
- Demo video(s)
Contributing
Would you like to contribute? See CONTRIBUTING for the full guide.
OOMWOO is organized to built by the community, massively in parallel.
The vacuum and its software are subdivided into modules, see list below.
A volunteer picks whatever module she wants and works on it whenever she wants.
For code and simulation modules she builds her package in her own repo and sends
a short PR linking it from the module; for docs and specs she contributes files
in-tree under contributions/module-name/<her-github-username>. See
CONTRIBUTING for how this works.
Multiple developers are welcome to work on the same module.
The best solution for each module surfaces over time, with the project master having the last call.
- Pick a contribution from the list below.
- Let us know you're working on it and your progress.
- Check ARCHITECTURE.md and
SOFTWARE_INTERFACES.md for the system design
and ROS2 interfaces.
Requests for Contributions
Every module below is actionable now โ build it against the Gazebo simulation
(oomwoo-one) or a real placeholder robot
(a Proscenic M6 Pro connected to ROS2),
until OOMWOO hardware is ready. Pick one, tell us in
Discussions, build it in your own
repo (docs and specs go in-tree), and send a short PR linking it from the module.
| Module | ID | Status | Notes |
|---|---|---|---|
| ROS2 URDF + Gazebo sim | urdf-gazebo-sim | Mostly complete | Placeholder URDF + Gazebo sim (reference: oomwoo-one; @alvarosamudio featured), refined when hardware lands |
| First clean: coverage + mapping + exploration | clean-and-map | In progress | Coverage cleaning while SLAM-mapping and exploring |
| Auto cleaning | In progress | Clean the entire room using an existing map (using coverage path planning) | |
| Regression tests | In progress | Set up simulatior regression test framework (auto cleaning in Gazebo) | |
| Localization & navigation on a known map | nav-localize | In progress | Nav2 nav, AMCL localization, relocalize when lost, resume map |
| Dock cycle: undock, dock, recharge | dock-cycle | Ready to start work | Undock, return-to-dock, precise docking, station services, find dock when lost |
| Recovery behaviors & safety | recovery-safety | Ready to start work | Recovery ladder, escalation, pause-and-alert, safety sensors, status reporting |
| Stack health monitor & software watchdog | health-monitor | In progress | Per-component alive-and-well heartbeats + a roster-aware aggregator that feeds the MCU deadman; stops the robot when any critical node crashes / hangs / is missing โ the soft-fault layer above the MCU's hard reflexes |
| Near-field obstacle avoidance (camera + ToF) | obstacle-avoidance | In progress | v2 "never gets stuck": front stereo camera + 2x VL53L7CX ToF detect below-LiDAR obstacles (cables, socks); detect-then-classify |
| Compute benchmark & memory reduction | compute-benchmark | In progress | Measure ROS2/Nav2/SLAM memory, compare composable nodes, and track the 4 GB -> 2 GB target |
| Floor-surface handling & edge cleaning | floor-care | In progress | Wall/edge following, carpet vs hardwood, mop lift/lower |
| Cleaning modes, zones & job orchestration | cleaning-jobs | Ready to start work | Modes (regular/spot), virtual walls, room segmentation, job splitting + resume |
| Control app & UX (design-first) | control-app | Ready to start work | Local-first control app/UI โ a client of the ROS2 stack + Home Assistant; design-led (welcomes designers): prioritize features, concept the MVP surface (start/stop, live map, status, zones) |
| Live robot bring-up & validation | live-robot-bringup | Ready to start work | Connect the placeholder Proscenic M6 Pro to ROS2, re-run sim tests on hardware |
| Source 3D models (STEP) for BOM parts | source-3d-models | Mostly complete | Obtain / measure / model STEP files of off-the-shelf parts (wheels, fans, casterโฆ) so mounts fit |
| Procure part specs & datasheets | part-specs | In progress | Find/measure/reverse-engineer specs (pinouts, encoder PPR, torque, how to drive fansโฆ) for sourced parts |
| I/O + motor-driver PCB | io-pcb | In progress | I/O board with CM4/CM5 socket, STM32 MCU - motors, sensors, 4S2P charging, safety, FreeRTOS, custom serial to CM4/CM5, 2D LiDAR header, IMU, audio serial/amp/speaker, MIPI camera(s) i/f; KiCad, JLCPCB |
| I/O board software interface | io-board-interface | Ready to start work | CPU/MCU serial contract, ROS2 bridge mapping, safety watchdog behavior, hardware signal ownership, and bringup validation |
| MCU I/O board firmware | mcu-io-firmware | In progress | STM32G473 firmware: Arduino (STM32duino) API + FreeRTOS + a HAL/ISR real-time safety core; motors, sensors, charging, custom serial to the CPU; repo |
| Fit software into 2GB RAM | compute-benchmark | 2GB achieved | ROS2 node composition, Rust; remove Gazebo, desktop UI |
Planned and on-hold modules (mechanical design, later-phase software) live in the
RFC backlog.
Source code reference
- OOMWOO ROS2 and Ubuntu installation source code
- OOMWOO ROS2 URDF package and config source code
- remakeai reference vacuum teardown โ a consumer LiDAR vacuum with a basic dock and stationary mop.
Related prior art
- Valetudo โ cloud-free firmware replacement for commercial vacuums (local app-level control, not ROS2)
- codetiger/VacuumTiger - 3irobotix CRL-200-based vacuum low-level control reverse engineered
- kaiaai/LDS, kaiaai/lds2d โ open-source 2D LiDAR libraries (C++, Python) supporting 23+ LiDAR models
- remakeai/vacuum_ros2_bridge โ ROS2 bridge for a 3irobotix CRL-200-based vacuum (Proscenic), full ROS2 control
- Dennis Giese / robotinfo.dev โ teardowns and rootability of commercial robot vacuums.
- Build a ROS2/LiDAR robot crash course - watch this if you have no robotics experience
- Open Mower - open-source outdoor lawn mower
- AlieksieievYurii/vacuum-cleaner โ a DIY 3D-printed robot vacuum (Raspberry
Pi Zero W, gyroscope-based, Fusion 360, Android control app, no dock)
User requirements & Design research
Anecdotal prospective user requirements - collected mostly in r/RobotVacuums, r/ROS and as announcement post comments:
- open-source
- 3D printed first
- cleans well, a first-class appliance, not a throwaway build
- never gets stuck
- hair tangle-free
- modern capabilities - no legacy drag mop; dual-spinning rotary mop or better/roller
- bagless
- hackable, DIY fixable, upgrade-able
- examples: vacuum-only version, mop-only version
- Raspberry Pi
- Home Assistant integration
- operates without cloud
- later: ability to retrofit existing legacy vacuum cleaner robots
About
The project name "OOMWOO" is a rotational ambigram - it reads the same flipped 180ยฐ, like the robot itself, roaming your floor in every direction.
The project is sponsored by makerspet.com and remake.ai. We are reusing their open-source solutions.
- If you'd rather skip the parts hunt, a kit (motors, PCB, brushes, gaskets, LiDAR) will be available at makerspet.com, from the same maker behind this project. The kit is a convenience, never a requirement. Everything here stays open.
- When we get to apps, remake.ai will be providing its robot apps platform and app store. Using the app store will be entirely optional. The vacuum will always support cloud-free, local operation for regular functionality out-of-the-box.
License
Code is released under the Apache License 2.0.
Hardware design files, once added, to be released under an open hardware
license (TBD).
File: contributions/vacuum-fan/README.md
Blower Fan Assembly (mechanical module)
On hold. Fan options are already sourced โ see the suction-fan rows in
BOM.md (multiple Pa/price options: Dreame, Nidec, Roborock-family blowers).
The project has also moved away from the old teardown reference vacuum (its parts are
hard to source vs. big names like Roborock/Dreame/Xiaomi). This module resumes once enough
components are sourced and a 3D reference design with the key parts is sketched, so the
housing can be designed to fit real parts.Useful upstream work now: model the sourced fans in
source-3d-models, and gather fan specs / how to drive them in
part-specs. Those unblock this design.
The vacuum fan assembly provides air suction to the main brush and streams air into the dust bin.
It consists of:
- a high-speed BLDC blower motor + impeller (already sourced โ see BOM)
- a blower housing (volute) โ to be designed
- a blower exhaust gasket
- blower housing rubber mounts
Design research note: real-world cleaning does not track raw suction (Pa) โ
mid-range sealed motors match flagships. Prioritise a well-sealed airflow path
(no leaks at the bin / fan / brush seams) and a good brush over chasing maximum Pa.
See design research.
Request for Contribution โ Instructions (resumes when off hold)
When this reopens, the task is to design a 3D-printable volute housing + gasket around a
sourced BLDC blower (chosen from the BOM) that mates cleanly with the dust
bin and the chassis. Design goals:
- 3D-printable (assume PETG); ideally no supports; reliably reproducible
- sliced part fits ~20 ร 25 cm, 20 cm height (split if needed)
- well-sealed airflow path (no leaks); mates with the dust bin + chassis
- low vibration; secure motor mounting
- gasket: find an off-the-shelf one, else print TPU
- submit STEP + native CAD + 3MF/STL + a sub-component BoM + docs/photos/video to
contributions/vacuum-fan/<your-github-username>/
Acceptance criteria (when it resumes)
- Fits the (forthcoming) chassis + dust-bin interfaces without forcing changes to other modules
- Well-sealed, reasonably quiet, low-vibration, strong suction with the chosen sourced blower
- 3D-printable and reliably reproducible by someone else
- Documented; STEP + native CAD source provided
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple attempts
are welcome and useful even if not selected โ modules are swappable, and a non-selected
design is still a valid learning exercise and a fallback.
File: contributions/urdf-gazebo-sim/README.md
oomwoo URDF + Gazebo Simulation
Self-hosted package: github.com/alvarosamudio/oomwoo_gazebo
ROS2 package with URDF model, Gazebo simulation worlds, bump recovery node, and Nav2/SLAM configuration for the OOMWOO robot vacuum. Built against the ROS2 Software Interfaces contract.
See the repo above for full documentation, setup instructions, and usage.
File: contributions/source-3d-models/README.md
Source 3D Models (STEP) for Off-the-Shelf BOM Parts (procurement)
To design printed mounts and the chassis that fit real sourced parts, we need accurate
3D models (STEP) of the off-the-shelf components in the BOM โ the
drive-wheel assembly, the suction fan/blower (several candidate models), the caster wheel,
the side-brush motor, and more. Manufacturers rarely publish these, so the community needs
to obtain, measure, and model them. Every printed mount and the chassis references this
geometry โ see ARCHITECTURE.md ยง5.2 (mechanical interface
standard). Missing models block or force guesswork on the mechanical modules.
This is a great first contribution for anyone with CAD skills and calipers โ no
robotics or programming needed, and the modules can be modeled in parallel.
Please check the STEP models library before you pick a part.
STEP models live in the makerspet/oomwoo-one-cad repo, in thelibfolder.
Request for Contribution - Instructions
- Pick a part from the BOM and claim it in
Project Discussions or
Discord so two people don't model the same thing. Post progress too.- Please consider submitting a PR (pull request) to
makerspet/oomwooincontributions/source-3d-models/<your-GitHub-username>/README.md
with a brief description of which part you have picked, relevant links (to your repo containing the part) and files if any.
- Please consider submitting a PR (pull request) to
- Get an accurate model โ three paths:
- Find an existing STEP (manufacturer site, GrabCAD, etc.) and verify it against the
real part (dimensions match). Fastest โ but confirm it's the same model/revision. - Model it yourself: order the exact part (AliExpress links are in the BOM), measure
with calipers, optionally use a 3D scanner and build an accurate STEP. - 3D scan the part, convert the mesh into a STEP file. As an example, I use Creality Raptor.
- Find an existing STEP (manufacturer site, GrabCAD, etc.) and verify it against the
- Capture the interface-relevant geometry (external only โ internal detail is not needed):
- Overall bounding envelope (so it fits the chassis space / height budget)
- Mounting features: holes, bosses, clips, bolt pattern โ and their exact positions
- Functional interfaces: axle/shaft position + axis, wheel contact plane, fan air
inlet/outlet, connector / wire-exit locations - Mating faces where other modules attach
- Note the key overall dimensions
- Record provenance โ the exact vendor + link + which model/revision you measured. Parts
vary between sellers and revisions; say which one this model represents. - Submit a PR to
contributions/source-3d-models/<your-github-username>//:- the STEP file (primary deliverable) + native CAD source (Fusion/SolidWorks/etc.) if you modeled it
- a photo of the real part
- the source link (AliExpress/vendor) and key dimensions
- notes on tolerances and how you measured - if any
- announce it in Project Discussions
- Iterate with review.
- TBD, expect the RFC to evolve.
(*) If you have a strong reason to model a different variant than the BOM lists, post your
rationale in discussions first.
Acceptance criteria
Objective, measurable. Examples:
- Accurate STEP of the specified part โ bounding envelope, mounting features, and
functional interfaces match the measured real part (within a stated tolerance) - Includes the exact source link, key dimensions, and a photo of the real part
- Please make sure the model is licensed as open-source
- Verifiable/reproducible by someone else who buys the same part
- STEP provided (+ native CAD source if self-modeled)
- Documented well enough that a mount designer can build against it with confidence
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple attempts
are welcome and useful even if not selected โ models are swappable, and a non-selected
model is still a valid reference and a fallback.
File: contributions/recovery-safety/xbattlax/README.md
Recovery Safety Prototype by xbattlax
This contribution provides a first ROS2 recovery-and-safety package for the
OOMWOO recovery-safety RFC. It is deliberately small, deterministic, and
simulation-first:
- a bounded recovery ladder for bumper, wedged, no-path, and lost-localization
situations - immediate safe stop for e-stop, cliff, wheel-drop, and pickup events
- pause-and-alert when the ladder is exhausted
- a structured JSON status topic suitable for later Home Assistant integration
- unit tests for guaranteed termination and safety responses
The core ladder lives in pure Python, so it can be regression-tested without a
running ROS graph. The ROS2 node is a thin adapter around that core.
Package
oomwoo_recovery_safety
Location:
contributions/recovery-safety/xbattlax/oomwoo_recovery_safetyInterfaces
Subscribed topics
| Topic | Type | Purpose |
|---|---|---|
/bumper_left |
ros_gz_interfaces/msg/Contacts |
Trigger left-bumper recovery after filtering ground-plane contacts. |
/bumper_right |
ros_gz_interfaces/msg/Contacts |
Trigger right-bumper recovery after filtering ground-plane contacts. |
/oomwoo/recovery/event |
std_msgs/msg/String |
Manual/test trigger. Payload examples: wedged, no_valid_path, localization_lost, bumper_front. |
/oomwoo/recovery/behavior_result |
std_msgs/msg/String |
Optional external result for the current behavior: succeeded, failed, or JSON {"outcome":"succeeded"}. |
/oomwoo/safety/e_stop |
std_msgs/msg/Bool |
Immediate non-recoverable pause. |
/oomwoo/safety/cliff |
std_msgs/msg/Bool |
Immediate safety pause. |
/oomwoo/safety/wheel_drop |
std_msgs/msg/Bool |
Immediate safety pause. |
/oomwoo/safety/pickup |
std_msgs/msg/Bool |
Immediate safety pause for pickup/kidnap handoff. |
/oomwoo/recovery/reset |
std_msgs/msg/Bool |
Reset a paused/recovered controller when true. |
Published topics
| Topic | Type | Purpose |
|---|---|---|
/cmd_vel |
geometry_msgs/msg/Twist |
Short bounded motion commands for recovery. |
/oomwoo/status |
std_msgs/msg/String |
JSON status with state, reason_code, message, recoverable, source, and recovery metadata. |
/oomwoo/recovery/command |
std_msgs/msg/String |
JSON command for non-motion actions such as clear_costmap. |
Build
From the OOMWOO ROS2 container:
source /opt/ros/jazzy/setup.bash
cd /workspace
colcon build \
--base-paths contributions/recovery-safety/xbattlax/oomwoo_recovery_safety \
--packages-select oomwoo_recovery_safetyTest
source /opt/ros/jazzy/setup.bash
cd /workspace
colcon test \
--base-paths contributions/recovery-safety/xbattlax/oomwoo_recovery_safety \
--packages-select oomwoo_recovery_safety
colcon test-result --verboseThe tests cover:
- bounded escalation to pause-and-alert
- successful recovery stopping the ladder
- e-stop and safety events entering safe pause
- ignored duplicate triggers while already recovering
- JSON status shape
- held
/cmd_velpublishing so motion recoveries outlive base watchdog timeouts - a separate completion timeout for delegated commands such as
clear_costmap
Run
source /opt/ros/jazzy/setup.bash
source install/setup.bash
ros2 launch oomwoo_recovery_safety recovery_safety.launch.pyManual trigger example:
ros2 topic pub --once /oomwoo/recovery/event std_msgs/msg/String "{data: bumper_front}"Mark the current behavior as successful:
ros2 topic pub --once /oomwoo/recovery/behavior_result std_msgs/msg/String "{data: succeeded}"Trigger e-stop:
ros2 topic pub --once /oomwoo/safety/e_stop std_msgs/msg/Bool "{data: true}"Current limitations
- This is a first integration scaffold, not a full Nav2 behavior-server plugin.
clear_costmapis published as an intent on/oomwoo/recovery/command; a
future adapter should call Nav2 costmap clear services directly.- Success detection is external for now. If no
succeededresult arrives before
a behavior's timeout, the node escalates to the next behavior and eventually
pauses. Twist motions use their motion duration as the timeout; delegated
commands can use a longer completion timeout. - Cliff, wheel-drop, and pickup are represented as boolean topics until the
hardware/simulation message contract is finalized.
File: contributions/recovery-safety/README.md
Recovery Behaviors & Safety (ROS2 package)
Keep the robot unstuck and safe. This package provides a recovery ladder
(back up, wiggle, shake free, rotate, nudge, clear costmap, try an alternate path),
escalation when a recovery attempt fails, and a final pause-and-alert state
when everything fails. It also covers safety: cliff / wheel-drop / pickup
detection, an e-stop, and status / error reporting so a human knows what
happened. Because the physical robot isn't built yet, this is a Gazebo
simulation; it is later re-validated on hardware in the
live-robot-bringup RFC.
Status โ ready to start work. No need to wait for OOMWOO hardware โ develop it in the
Gazebo sim (urdf-gazebo-sim) or on the real
placeholder Proscenic M6 Pro.
Say so in the discussions so we can coordinate.
Design direction: reactive, contact-aware recovery (recommended)
Prior art is unanimous: real robot vacuums do not escape wedges with
navigation-stack recoveries. Nav2's spin / backup are collision-averse โ they
check the costmap and refuse to move into the very cells the robot is wedged
against, so they stall exactly when needed (OOMWOO's own coverage planner already
documents "spin/backup recoveries refuse to move there"). A vacuum is
contact-tolerant: it has a bumper and is meant to touch walls and furniture. The
recovery it needs is a small reactive, bumper-driven behavior layer that runs
open-loop and ignores the costmap, layered under the planner and overriding it
while in contact (subsumption โ Brooks, 1986). Coverage plans the open floor; this
handles near-obstacle. If it grows, this reactive layer can later be split into its
own reactive-control module.
Proven escape heuristics โ a starting point from iRobot's multi-mode coverage
patents; tune the thresholds in sim. All are keyed on the bumper pattern, not the
costmap:
- Wedge โ bumper held. If a bumper stays pressed for ~5 s, rotate away from the
pressed side (a "panic turn") and retry; repeat until it releases. Back off and
turn toward the free side โ not a blind straight reverse. - Confined pocket โ frequent bumps. Track the running distance between bumps; when
it drops below a threshold the robot is boxed in โ switch to bumper
edge-following (touch, small turns into-and-away) to worm out; below a lower
threshold, panic-turn. - Stuck / wheels spinning โ no bumps. If the robot travels a long distance with no
bump at all, assume it is high-centered / spinning โ spiral, then panic-turn if
still no contact. - Don't re-enter. Mark the escaped pocket no-go so the sweep / gap-fill doesn't
route straight back in (OOMWOO's coverage planner already does a version of this).
The simulated bumpers now publish (/bumper_left|right/contact), so this is
buildable and testable headless today โ see
oomwoo-one sim-bumpers.
The same bumper-contact mechanism drives edge cleaning in floor-care,
and stack-liveness safety lives in health-monitor.
Important References
- clean-and-map RFC and urdf-gazebo-sim RFC โ the bumper (left / right / front) and any cliff / wheel-drop sensors this package reacts to.
- nav-localize RFC โ pickup / kidnap detection ties into relocalization.
- ROS2 software interfaces โ shared topic/action/service contract for simulation-first modules.
- OOMWOO ROS2 development โ build OOMWOO ROS2 Docker image(s) with your packages.
- Nav2's behavior/recovery server can compose recoveries, but note its
spin/backupare collision-averse (see Design direction above) โ for wedges, prefer contact-aware escapes. - Prior art โ the reactive layer everyone uses: iRobot behavior-based vacuum control โ multi-mode coverage (7173391) and learned escape behaviors; Brooks, A Robust Layered Control System for a Mobile Robot (subsumption, 1986).
- Coverage-planning prior art: opennav_coverage (Nav2 / Fields2Cover, open-field focused), Fraunhofer ipa_room_exploration, and online sensor-based coverage (BA*, Morse decomposition). VFH+ is a contact-tolerant reactive alternative to costmap avoidance.
- Project discussions
- Discord server
Request for Contribution - Instructions
- implement a recovery ladder
- a configurable, ordered set of behaviors, e.g. back up, wiggle / shake free, rotate in place, clear the costmap, nudge, try an alternate path
- pick the right recovery for the situation (wedged, bumper-jammed, no valid path, localization lost)
- for wedges, prefer contact-aware, open-loop escapes (see Design direction above) over Nav2
spin/backup, which are collision-averse and stall in the wedge; start from the bumper-pattern escape heuristics and tune them in sim - post in Project Discussions to let everyone know you're working on it, and post your progress
- escalation
- if behavior N fails, try N+1; track attempts per situation so the robot doesn't repeat a recovery forever
- pause-and-alert
- when the whole ladder is exhausted, stop safely, publish a clear error / status, and wait for a human or a resume command โ never thrash
- safety sensors
- detect cliffs, wheel drop, pickup / kidnap (hand pickup detection to nav-localize), and bumper jams; respond by stopping motors / entering a safe state
- e-stop
- a software emergency stop that brings the robot to a safe state immediately
- status & error reporting
- a structured robot-state / error topic, human-readable, suitable for Home Assistant, so a person knows why the robot paused
- test it well
- induce wedged / stuck situations in sim: trap the robot, drop a dynamic obstacle onto it, place it at a cliff edge, lift it
- verify the ladder runs, escalates, then pauses-and-reports; verify it never thrashes indefinitely
- regression tests (headless, CI-friendly)
- recovery success rate across induced stuck scenarios
- guaranteed termination โ the robot always reaches recovered or paused-and-reported, never an infinite loop
- safety responses fire on cliff / wheel-drop / pickup / e-stop
- submit a PR (pull request) to
contributions/recovery-safety/<your-github-username>/- link to ROS2 package(s)
- instructions, documentation - how to install, run, configure, troubleshoot, test results
- videos of recovery, escalation, and pause-and-alert
- announce your submission in Project Discussions
- iterate with review
- TBD, expect the RFC to evolve
Acceptance criteria
Objective, measurable. Examples:
- A configurable recovery ladder runs the right behaviors for the situation and frees the robot in the large majority of induced stuck scenarios
- Recoveries escalate and are bounded โ the robot never repeats a failed recovery forever
- When recovery is impossible, the robot pauses safely and reports a clear error, then resumes on command
- Safety: cliff, wheel-drop, pickup, and e-stop all bring the robot to a safe state
- Status / error reporting is structured and Home-Assistant-friendly
- Regression tests pass, including a guaranteed-termination check, runnable headless in CI
- Documented and reliably reproducible by someone else
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple
attempts are welcome and useful even if not selected โ modules are swappable, and
a non-selected design is still a valid learning exercise and a fallback.
File: contributions/part-specs/OsakaTX/README.md
Part Specs โ Compiled Datasheets & Specifications
Contributor: OsakaTX
Status: Updated July 17, 2026 โ consolidated batch covering the I/O board wheel connector, caster wheel, side brush motor and brushes, charging contacts, and wall/carpet sensors (new BOM items Jul 12-16). Encoder, gearbox, caster, and connector findings drawn from merged PRs, codetiger/VacuumTiger firmware analysis, and verified calibrations
Methodology: Web research from manufacturer datasheets, public SDKs, open-source reverse-engineering projects (codetiger/VacuumTiger, codetiger/VacuumRobot), physical inspection data from merged contributor PRs (Scowt PR #13), Aliexpress listings, and VacuumTiger firmware empirical calibration๐ See the companion file for detailed methodology, derivation, and cross-referencing:
vacuumtiger-verified-specs.md
This document compiles the electrical and mechanical specifications found for key BOM
parts. Each section covers what was found and what is still missing.
1. Drive Wheel Assembly (Roborock S-family)
Part Identification
The Roborock S4/S5/S5-Max/S6/S7-family drive wheel module is a complete unit:
gearmotor + incremental encoder + rubber tire + suspension + wheel-drop switch.
See BOM.md for the full Aliexpress search links.
Motor Specs (Nidec 20N704RC70 โ "Motor for Wheel")
Sourced from the Nidec Robot Cleaner Motor catalog PDF:
| Parameter | Value |
|---|---|
| Rated voltage | 14.4 V |
| No-load speed | 16,800 rpm |
| No-load current | 0.4 A |
| Rated speed | 13,200 rpm |
| Rated current | 1.4 A |
| Maximum power | 13.8 W |
| Noise (SPL) | 45 dB(A) |
| Status | โ ๏ธ "In development" per Nidec catalog โ model may have changed in production |
Note: The actual motor used in production Roborock wheels may differ from the
catalog entry above. The wheel module includes a gearbox (see estimated ratio below)
that reduces this to the final wheel RPM. The encoder is mounted after the gearbox.
Wheel Dimensions (from PR #10 โ alvarosamudio's URDF, merged)
| Dimension | Value |
|---|---|
| Wheel diameter | 0.065 m (65 mm) |
| Robot body diameter | 0.33 m (330 mm) |
Encoder
- Type: Single-channel Hall-effect sensor (pulse output) โ confirmed via physical inspection by Scowt PR #13 (merged). The wheel-side 7-pin JST connector has exactly one encoder signal wire (blue), plus 5V (orange) and GND (brown). This is NOT a quadrature A/B encoder.
- GD32 decoding: The GD32F103VCT6 hardware timer performs 4ร edge counting on the single pulse train (rising + falling edges ร 2 timer channels), producing effective 4ร resolution.
- Effective ticks/rev (wheel shaft): ~911 ticks/rev โ derived from the calibrated
ticks_per_meter = 4464.0(VacuumTiger firmware, confirmed inencoder_sim.rsunit test) and wheel circumference = ฯ ร 0.065 m โ 0.2042 m. Calculation: 4464 ticks/m ร 0.2042 m/rev โ 911 ticks/rev. - PPR: ~228 PPR (raw encoder pulses per wheel revolution) โ 911 / 4 = ~228. Typical multi-pole magnetic ring encoders range from 8-32 poles, making a multi-pole ring a plausible mechanism but this pole count is speculative without physical inspection.
- Directional ambiguity: The single-channel encoder alone cannot determine rotation direction. Direction is resolved by the IMU gyro in the navigation pipeline (VacuumTiger dhruva-slam).
- Data format: u16 LE wrapping counter at offsets 0x10 (left wheel) / 0x18 (right wheel) in the 96-byte GD32 status packet, streamed at 110 Hz. Confirmed from codetiger/VacuumTiger
sangam-io/src/devices/crl200s/gd32/reader.rsandSENSORSTATUS.md. - Calibrated odometry:
ticks_per_meter = 4464.0,wheel_base = 0.233 mโ empirically calibrated on real hardware and confirmed in multiple VacuumTiger source files:sangam-io/src/devices/mock/config.rs,dhruva-nav/dhruva.toml,dhruva-slam/src/sensors/odometry/wheel_odometry.rs, anddhruva-nav/src/odometry.rs.
Gearbox Ratio
- Estimated ratio: ~190:1 โ derived from
VELOCITY_TO_DEVICE_UNITS = 523.0(empirically calibrated in VacuumTigercommands.rs) and the verified max linear speed of 0.3 m/s. At 16,800 rpm no-load motor speed with 0.065 m wheels, a ~190:1 reduction produces a max wheel speed consistent with 0.3 m/s. Confirmed consistent with the calibrated ticks/m and 911 ticks/rev at the wheel shaft. - Physical verification: โ Not yet confirmed via tooth counting โ requires disassembly.
Connectors
Wheel Module Connector (7-pin JST, cable side)
Confirmed by Scowt PR #13 physical inspection (merged):
| Pin | Wire Color | Function |
|---|---|---|
| 1 | Grey | Limit switch (wheel-drop, NC) |
| 2 | Grey | Limit switch (wheel-drop, common) |
| 3 | Orange | Encoder VCC (+5V) |
| 4 | Blue | Encoder signal (single-channel pulse) |
| 5 | Brown | Encoder GND |
| 6 | Black | Motor power (-) |
| 7 | Red | Motor power (+) |
Cable length: ~250 mm (per Scowt observation).
Mainboard Connectors (J25/J26 โ 16-pin SHD 1.0mm)
Motor power is on separate connectors (J24 left / J27 right, 2-pin PH 2.0mm) โ NOT carried by J25/J26.
J25 (bottom, left wheel): Left wheel encoder (3 wires) + Dustbox power + Left cliff sensor + Left bumper
J26 (top, right wheel): Right wheel encoder (3 wires) + Sweeper motor power + Right cliff sensor + Right bumper
Per codetiger/VacuumRobot reverse-engineering. Full per-pin map requires PCB continuity tracing (multimeter). The signal groups above are established; the exact pin-to-signal assignment within each group is hypothesis.
Motor Driver IC
- IC: TMI8870 (TOLL Microelectronic) โ top mark "T8870", ESOP8 package
- Specs: Single H-bridge, 3.6A peak, 6.8-45V, PWM with integrated current regulation
- Pin-compatible: With TI DRV8870
- Confirmed via: TMI8870 datasheet (taoic.oss-cn-hangzhou.aliyuncs.com) matching the "8870" marking on U25 on the motherboard (photographed in codetiger/VacuumRobot Component_Diagram.md)
- Dual ICs: Since TMI8870 is a single-channel H-bridge and the robot has two wheels, a second matching IC should exist on the motherboard (near J27 for the right wheel)
Wheel Module Weight
- Pair: ~463g (0.463 kg shipped pair โ AliExpress listing for original Roborock S6 wheel module)
- Single: ~230g (estimated from pair weight)
What We Still Need
| Item | Status |
|---|---|
| Exact gearbox ratio via tooth counting | โ Needs disassembly |
| Full J25/J26 per-pin map | โ Needs PCB continuity tracing |
| Wheel-drop sensor exact model | โ Needs physical inspection |
| Cable length (exact) | โ Needs physical measurement |
| Motor driver IC location for right wheel | โ Needs PCB inspection |
References
- Nidec Robot Cleaner Motor Product Introduction PDF
- codetiger/VacuumRobot โ Mainboard Component Diagram
- codetiger/VacuumRobot โ Connection Evidence
- codetiger/VacuumTiger โ Custom firmware with verified calibration
- Scowt PR #13 โ Wheel module 7-pin connector physical inspection
- TMI8870 Motor Driver Datasheet
- Companion file:
io-board-wheel-connector-and-caster.mdโ OOMWOO I/O board 5-pin ZH wheel connector (J12/J13) and on-board DRV8870 analysis
2. Suction Fan / Blower
Nidec 20N-series Blower Units (full assemblies)
From the Nidec catalog PDF:
Standard Blower Units
| Parameter | 20N183L010 A | 20N704R310 / R500 | 20N704S310 | 22N709Q140 |
|---|---|---|---|---|
| Rated voltage | 12 V | 14.4 V | 14.4 V | 14.4 V |
| Rated speed | 15,000 rpm | 17,200 rpm | 15,100 rpm | 22,500 rpm |
| Rated current | 1.7 A | 2.2 A | 1.6 A | 4.5 A |
| Input power | 20 W | 31.7 W | 23 W | 64.8 W |
| Max static pressure | 1.8 kPa | 2.6 kPa | 3.0 kPa | 4.0 kPa |
| Max air volume | 0.63 mยณ/min | 0.78 mยณ/min | 0.63 mยณ/min | 0.99 mยณ/min |
| Noise | 67 dB(A) | 70 dB(A) | 68 dB(A) | 75 dB(A) |
| Fixing device | With | With | Without | Without |
Nidec BLDC Bare Motors (for Blower โ without impeller housing)
| Parameter | 20N704K500 B | 20N704P110 A | 22N709P230 D | 35N048P010 |
|---|---|---|---|---|
| Rated voltage | 12 V | 13 V | 14.4 V | 18 V |
| No-load speed | 16,500 rpm | 23,000 rpm | 29,000 rpm | 28,800 rpm |
| No-load current | 0.4 A | 0.6 A | 0.6 A | 0.8 A |
| Rated speed | 13,500 rpm | 16,700 rpm | 24,800 rpm | 25,900 rpm |
| Rated current | 1.4 A | 1.75 A | 2.8 A | 7.1 A |
| Max power | 15.9 W | 21.2 W | 58.4 W | 74.6 W |
| Noise | 40 dB(A) | 50 dB(A) | 65 dB(A) | 60 dB(A) |
Fan Control Interface (BLDC bare motors)
From the catalog, the Nidec Smart_20N series BLDC motors support:
| Feature | Details |
|---|---|
| Control | PWM input for speed control |
| Feedback | FG (frequency generator / tachometer) output |
| Special | 22N709P230 D additionally has SS (soft-start) |
| Drive | 3-phase BLDC โ requires external driver/controller |
| Voltage range | 5โ24 V (Smart_20N series datasheet) |
| Mass | 25โ30 g (bare motor) |
Driving the Fans
- The open-source ripinteer/fan_protector project is a reference for driving/protecting these BLDC blowers
- The jniebuhr/roborock-pcb project has a custom PCB for driving Roborock fans (Nidec-based), including connector pinout
- Connector on the Roborock CPAP board: JST XH 3-pin 2.54mm for motor, JST XH 2-pin 2.54mm for fan
What We Still Need
| Item | Status |
|---|---|
| Full suction-assembly-level datasheet (including impeller housing) | โ Missing (we have bare motor specs) |
| Specific connector model + pinout for each assembly variant | โ Unknown |
| Cable length(s) | โ Unknown |
| Signal waveforms (PWM, FG) | โ Unknown |
| Weight of full assembly | โ Unknown |
References
- Nidec Robot Cleaner Motor PD
- Nidec Smart_20N series product page
- jniebuhr/roborock-pcb โ custom PCB with pinout
- ripinteer/fan_protector โ BLDC driver reference
3. LiDAR โ 3irobotix CRL-200S / Delta-2D
Basic Specs
| Parameter | Value |
|---|---|
| Model | 3irobotix CRL-200S (same platform as Delta-2D) |
| Type | Laser triangulation (not ToF) |
| Range | 0.13โ8 m @ 100% reflectivity |
| Accuracy | < 1% @ 5m |
| Scan rate | 4โ10 Hz (configurable via motor voltage) |
| Points/sec | 2โ5 KHz |
| Wavelength | 780 nm |
| Laser class | Class 1 |
| Max ambient | 1K lux |
| Weight | ~175 g |
| Retail | ~$28โ40 |
| Life | Estimated 1,500+ hours |
| Power | 0.35A idle, 0.37A ranging @ 5V (~1.75 W) + motor ~0.1A |
Interface
| Parameter | Value |
|---|---|
| Connector | JST PH 2.0mm 5-pin |
| Data | UART 115200 baud, 8N1 |
| Protocol | Proprietary 3irobotix โ 8-byte header + variable payload |
| Commands | 0xAE (health), 0xAD (measurement data) |
| Distance multiplier | 0.25 mm per LSB |
Pinout (J17 on 3irobotix CRL-200S mainboard)
| Pin | Function | Direction | Notes |
|---|---|---|---|
| 1 | Motor+ | Power | 5V for rotation |
| 2 | Motor- | Power | GND |
| 3 | TX | Output | LiDAR โ MCU (UART RX) |
| 4 | RX | Input | MCU โ LiDAR (UART TX) |
| 5 | GND | Power | Ground |
Motor Control
| Parameter | Value |
|---|---|
| Motor voltage range | 2.2โ3.8 V (for valid ranging) |
| RPM range | ~240โ420 RPM |
| Motor drive | Direct voltage control (external) or H-bridge / PWM |
| Ranging fails below | ~2.2 V motor (below 240 RPM) |
| Ranging fails above | ~4.0 V motor (above 460 RPM) |
| Angular resolution | 0.77ยฐ at 240 RPM โ 1.41ยฐ at 420 RPM |
Data Format (from notblackmagic.com reverse engineering)
Start byte 0xAA, followed by:
- 2-byte packet type
- Data length
- Angle + distance pairs (each 2 bytes)
- Checksum byte
References
- kaiaai/awesome-2d-lidars โ comparison table & pinout
- kaiaai/LDS โ Arduino LiDAR library supporting CRL-200S / Delta-2D
- notblackmagic.com โ full reverse engineering of Delta-2G (same protocol)
- codetiger/VacuumRobot โ LiDAR protocol decoding
- 3irobotix Delta-2B SDK
- Delta-1A protocol doc (shared with 2A/2B/2G/2D): see notblackmagic.com above
4. VL53L7CX โ Multizone Time-of-Flight Sensor
Basic Specs
| Parameter | Value |
|---|---|
| Type | Time-of-Flight, 8ร8 multizone (64 zones) |
| Field of View | 90ยฐ diagonal (65ยฐ ร 65ยฐ typical) |
| Range | Up to 350 cm (varies by target reflectivity and ambient) |
| IยฒC address | 0x52 (default) โ configurable |
| IยฒC speed | Up to 1 MHz (fast mode+) |
| Supply | 2.8 V (AVDD), 1.8 V (IOVDD) or 2.8 V (optional) |
| Package | 6.4 ร 3.0 ร 1.6 mm (LGA-16) |
Pinout
Correction: earlier revisions of this section listed an 8-pin LGA-12
(4.4 ร 2.4 ร 1.0 mm) pinout โ those were VL53L5CX figures carried over in error.
The VL53L7CX (and pin-to-pin-compatible VL53L7CH) is a 16-ball LGA,
6.4 ร 3.0 ร 1.6 mm. Key signals below; full per-ball map in ST datasheet
DS13865 ยง2.5.
| Ball | Name | Function |
|---|---|---|
| B1, B7 | AVDD | 2.8 / 3.3 V analog & VCSEL supply (both must be powered) |
| A4 | IOVDD | 1.8 / 2.8 / 3.3 V digital & I/O supply |
| C1, C7 | GND | Ground |
| C3 | SDA | IยฒC data (2.2 kฮฉ pull-up to IOVDD) |
| C4 | SCL | IยฒC clock (2.2 kฮฉ pull-up to IOVDD) |
| A3 | INT | Interrupt output (open-drain; 47 kฮฉ pull-up to IOVDD) |
| A5 | LPn | Comms enable (47 kฮฉ pull-up to IOVDD) |
| A1 | I2C_RST | IยฒC interface reset, active high (tie to GND via 47 kฮฉ) |
| B4 | THERMAL_PAD | Tie to ground plane |
| A2, A6, A7, C2, C5, C6 | Reserved | See DS13865 ยง2.5 for per-ball tie / no-connect |
Interface
- IยฒC up to 1 MHz
- Requires external pull-up resistors on SCL/SDA
- Interrupt pin (GPIO1) for data-ready signaling
- LPn pin for low-power mode control
References
5. IMU โ MPU-6050 (common choice, architecture TBD)
Basic Specs
| Parameter | Value |
|---|---|
| Type | 6-axis (3-axis gyro + 3-axis accelerometer) |
| Gyro range | ยฑ250, ยฑ500, ยฑ1000, ยฑ2000 ยฐ/s (programmable) |
| Accel range | ยฑ2g, ยฑ4g, ยฑ8g, ยฑ16g (programmable) |
| IยฒC address | 0x68 (AD0 low) or 0x69 (AD0 high) |
| IยฒC speed | Up to 400 kHz |
| Supply | 2.375โ3.46 V |
| Package | 4ร4ร0.9 mm QFN-24 |
Pinout (QFN-24)
| Pin | Name | Function |
|---|---|---|
| 8 | SCL | IยฒC clock |
| 9 | SDA | IยฒC data |
| 12 | AD0 | IยฒC address select |
| 20 | INT | Interrupt output |
| 6 | VDD | Power (2.4โ3.5 V) |
| 18 | VLOGIC | Logic reference (1.8Vยฑ5% or VDD) |
| 7, 10, 13, 19, 21 | GND | Ground |
References
6. IR Cliff / Proximity Sensors โ TCRT5000 (typical)
Basic Specs
| Parameter | Value |
|---|---|
| Type | Reflective optical sensor (IR LED + phototransistor) |
| Operating voltage | LED: 1.2โ1.5 V forward (typical), Phototransistor: up to 30 V |
| Detection range | 0.2โ15 mm (for reliable cliff detection) |
| Output | Phototransistor collector (open collector โ needs pull-up resistor) |
| Package | 4-pin DIP (standard leaded package) |
Pinout
| Pin | Name | Function |
|---|---|---|
| 1 | A (Anode) | IR LED anode |
| 2 | C (Cathode) | IR LED cathode |
| 3 | C (Collector) | Phototransistor collector (output) |
| 4 | E (Emitter) | Phototransistor emitter (GND) |
Typical Circuit
- IR LED: driven through a current-limiting resistor (e.g., 100โ220 ฮฉ at 3.3โ5 V)
- Phototransistor: collector pulled up to MCU voltage (3.3 V) via a 10โ47 kฮฉ resistor
- Output read as analog voltage (ADC) or digital threshold (comparator)
References
7. Caster Wheel
โ ๏ธ BOM specifies a Roomba-style caster (iRobot part #4624869, $2.50-$5 push-in ball-type). The Roborock S-family caster (50mm wheel-type, OEM #9.01.1272/1273) is a different part โ verify which is selected before designing the mount.
Note on Roborock caster SKUs: replacement listings cite more than one OEM number for the S-family caster โ
9.01.1272/1273(~50mm wheel, ~45mm base) above, andHA00021(~46 ร 52mm) inio-board-wheel-connector-and-caster.md. These appear to be the same donor part under different reseller SKUs; the BOM's primary remains the Roomba-style iRobot 4624869. Confirm the exact SKU and dimensions against the selected part before designing the mount.
Roomba Caster (BOM Source)
| Spec | Value |
|---|---|
| Part number | iRobot 4624869 / RM500CSA |
| Type | Snap-in ball-type caster |
| Wheel diameter | ~25mm |
| Weight | ~30g (plastic) to ~61g (metal+plastic variant) |
| Mounting | Push-in snap-fit |
| Sensor | None (passive) |
| Compatible with | Roomba i3/4/6/8/J7/e5/6/500-900 series |
| Price | $2.50โ$12.95 |
| Availability | Abundant (iRobot official, Amazon, aftermarket) |
Roborock S-family Caster (Alternative / Other BOM Variant)
| Spec | Value |
|---|---|
| OEM part numbers | 9.01.1272 (white) / 9.01.1273 (black) โ confirmed via TechPunt.nl, Roborock India |
| Type | Wheel-type caster |
| Wheel height | ~50mm |
| Base diameter | ~45mm |
| Weight | ~45โ70g |
| Mounting | Clip-in/pop-in (older models) or bolted-on screw bracket (S5 Max, S6 MaxV, E4+) |
| Sensor | None (passive) |
| Price | $4โ17 |
References
- TechPunt.nl โ OEM part listing
- Roborock India โ OEM parts
- iRobot official store โ part 4624869
- Thingiverse โ Roomba caster 3D printable models
- Printables โ Roborock caster bracket model (Uko, Jan 2021)
8. Side Brush Motor (Roborock S-family)
See detailed spec file:
side-brush-charging-contacts-specs.md
Motor Type โ Verified by Physical Teardown
- Brushed DC motor (confirmed by Reddit teardown โ carbon brushes, coal dust inside)
- Sintered bronze self-lubricating bushings (not ball bearings)
- 2-stage plastic gearbox with grease
- Contact pads TP1/TP2 on motor PCB (simple 2-wire DC connection)
- Weight: ~150g
- Robot detects stalls via current sensing and shuts off motor as safety precaution
Firmware Control (VacuumTiger โ verified from source code)
| Parameter | Value | Source |
|---|---|---|
| Command | CMD_SIDE_BRUSH = 0x69 |
constants.rs line 19 |
| Speed format | u8, 0-100% | packet.rs line 141-149 |
| Component ID | "side_brush" |
commands.rs line 75 |
| Main brush command | CMD_MAIN_BRUSH = 0x6A (u8, 0-100%) |
constants.rs line 20 |
BOM Variants
| Type | Price | Notes |
|---|---|---|
| Fixed | $7-10 | Standard for S5/S6/S7 and many other models |
| Extendable (FlexiArm) | $18-35 | For Qrevo Master/Edge, S8 MaxV Ultra, G20S, V20 |
Side Brushes
| Type | Price | Notes |
|---|---|---|
| 5-arm | $2-8 | S5, S50, S51, S55, S6, S60, S6 Pure |
| 3-arm | $3-9 | S8 and many other models |
| 2-arm curved | $3-7 | Saros |
Attachment: single Phillips #2 captive screw.
9. Charging Contacts
See detailed spec file:
side-brush-charging-contacts-specs.md
Robot Side
| Spec | Value |
|---|---|
| Material | Nickel-plated steel strip |
| Dimensions | ~1mm wide, ~0.1mm thick, ~5cm long |
| Price | $1.50-2.50 (pair) |
Dock Side
| Spec | Value |
|---|---|
| Type | Gold-plated pogo pins |
| Current rating | 4A |
| Price | TODO (BOM not yet priced) |
Charging System
| Parameter | Value | Source |
|---|---|---|
| Dock power supply | 20V DC, 1.2A (24W) | Amazon/AliExpress replacement adapter |
| Dock output at contacts | ~19.8-20V DC | Reddit user measurement |
| Robot battery | 13.5-15.5V (4S Li-ion, 14.4V nominal) | VacuumTiger constants.rs |
| Charging method | Contact-based (not inductive) | Standard Roborock |
Firmware Charging Detection (VacuumTiger โ verified from source code)
| Parameter | Value | Source |
|---|---|---|
| Charging flags offset | 0x07 (byte 7 in status packet) | constants.rs line 62 |
| Dock connected flag | bit 0 (0x01) | constants.rs line 101 |
| Charging flag | bit 1 (0x02) | constants.rs line 100 |
| Battery voltage offset | 0x08 (raw / 10 = volts) | constants.rs line 63 |
| Charger power command | CMD_CHARGER_POWER = 0x9B |
constants.rs line 51 |
10. Wall & Carpet Sensors
See detailed spec file:
wall-carpet-sensor-specs.md
Wall Sensor โ TSOP38238 IR Receiver + 940nm IR LED
Active reflective proximity sensor: a 940nm IR LED emits 38kHz-modulated bursts and the TSOP38238 detects the reflection off a nearby wall.
| Parameter | Value | Source |
|---|---|---|
| IR receiver | Vishay TSOP38238 โ 38kHz carrier, 2.0-5.5V, ~0.25mA typ, ยฑ45ยฐ directivity, active-low output | Vishay datasheet (doc 82491) |
| AGC variant | AGC2 (long-burst; drive LED with โฅ10 cycles/burst) | Vishay datasheet (doc 82491) |
| IR LED (representative) | Vishay TSAL6100 โ 940nm, 170mW/sr, ยฑ10ยฐ beam, 1.35V typ Vf, 100mA DC | Vishay datasheet (doc 81009); exact BOM part not specified |
| Output | Active-low digital pulse when a valid 38kHz reflection is detected | TSOP38238 datasheet |
| Premium alternative | VL53L7CX multizone ToF (true distance vs binary detection) | BOM note |
Carpet Sensor โ Ultrasonic 300kHz
| Parameter | Value | Source |
|---|---|---|
| Transducer | HTW HT-300PLTR1612-1 โ 290ยฑ15kHz center, 16mm diameter, ~30mm target distance, โค2mm precision, IP67 | HTW listing (Made-in-China) |
| OEM alternative | Roborock OEM carpet sensor module (~$6.93) | AliExpress listing |
| Principle | Echo-characteristic analysis to distinguish carpet from hard floor | โ |
Summary of Found vs Missing
| Part | Documentation Found | Critical Gaps |
|---|---|---|
| Drive wheel | Motor electrical specs (Nidec 20N704RC70), wheel diameter (65mm), encoder type (single-channel Hall, ~228 PPR), gearbox ratio (~190:1), ticks/meter (4464), wheel module connector (7-pin JST with wire colors), mainboard connectors (J25/J26 16-pin SHD signal groups, J24/J27 2-pin PH motor power), motor driver IC (TMI8870), module weight (~463g pair) | โ Exact gearbox ratio via tooth count, โ full J25/J26 per-pin map, โ wheel-drop sensor model |
| Suction fan | Complete Nidec catalog specs for many models, PWM/FG control, connector types (JST XH) | โ Impeller housing geometry, โ assembly weight, โ cable lengths |
| LiDAR (CRL-200S) | โ Full specs, pinout, protocol, RPM/voltage relationship, power consumption | Minor: exact motor model inside, formal manufacturer datasheet |
| VL53L7CX ToF | โ Full datasheet, IยฒC interface, pinout, FOV, range | None โ standard ST component |
| IMU (MPU-6050) | โ Full datasheet, IยฒC interface, pinout | None โ standard InvenSense component |
| IR cliff sensor | โ TCRT5000 specs, circuit, pinout | None โ standard sensor, subject to final BOM choice |
| Caster wheel | โ Roomba 4624869 specs (25mm ball-type, push-in); Roborock 9.01.1272/1273 (50mm wheel-type); both passive | โ Exact dimensional drawing for chosen variant; โ which BOM variant is selected |
| Side brush motor | Brushed DC motor (teardown-verified), 2-stage plastic gearbox, TP1/TP2 contacts, ~150g, CMD 0x69 speed 0-100%, fixed ($7-10) and FlexiArm ($18-35) variants | โ Exact voltage, โ RPM, โ exact gearbox ratio, โ connector model |
| Side brushes | 5-arm ($2-8), 3-arm ($3-9), 2-arm curved ($3-7); single Phillips screw attachment | None โ standard consumable part |
| Charging contacts (robot) | Nickel-plated steel strip, ~1mmร0.1mmร5cm, $1.50-2.50/pair | None โ standard material |
| Charging contacts (dock) | Gold-plated pogo pins, 4A rating; dock outputs 20V 1.2A (24W) | โ Exact pogo pin model/part number, โ pricing |
| Charging system | CMD_CHARGER_POWER=0x9B, charging flags at offset 0x07 (dock=0x01, charging=0x02), battery voltage at 0x08 | None โ firmware-level specs complete |
| Wall sensor | TSOP38238 IR receiver (38kHz, AGC2, ยฑ45ยฐ, active-low) + 940nm IR LED (TSAL6100 representative); reflective proximity design | โ Exact IR LED part in BOM, โ detection-range tuning |
| Carpet sensor | HTW HT-300PLTR1612-1 ultrasonic (290ยฑ15kHz, IP67, ~30mm range); Roborock OEM module alternative | โ Manufacturer datasheet for exact BOM part, โ echo-analysis thresholds |
File: contributions/part-specs/README.md
Procure Part Specs & Datasheets for Sourced Components
We've already sourced candidate parts (see BOM.md). To design the I/O
board and firmware, drive the motors and fans, and build accurate mounts, we need each
part's detailed electrical + mechanical specs โ pinouts, voltages, currents, encoder
PPR, torque, waveforms, etc. Vendors rarely publish these for vacuum sub-assemblies, so
contributors will find datasheets, ask vendors, or safely reverse-engineer them.
This is the electrical/mechanical data companion to
source-3d-models (which covers the geometry). No robotics
background needed โ a multimeter, patience, and (for reverse-engineering) an oscilloscope go far.
Please check BOM.md and the sourcing follow-along blog post
for datasheets/specs already found.
What we need, per part
Drive wheel assembly (Roborock-family โ see BOM)
- motor model; motor/assembly datasheet (if any)
- encoder type + PPR (pulses per revolution)
- gearbox ratio; wheel diameter
- rated + max motor voltage, current (no-load & stall), torque
- max / rated wheel speed
- cable length(s); connector models (both ends); full connector + motor pinouts
- wheel-drop sensor model + pinout (these modules include one)
- signal waveforms (encoder channels, motor drive)
- assembly weight
Suction fan / blower (several options sourced โ see BOM)
- fan/motor model; datasheet
- rated voltage, current, RPM; airflow + static pressure (Pa)
- how to drive it โ BLDC driver + control interface (PWM / tach / hall / 3-phase),
soft-start / protection behaviour - connector model(s) + pinout; cable length
- signal waveforms
- weight
Caster / universal wheel assembly (Roomba-family โ see BOM)
- model, dimensions, mounting, any embedded sensor, weight, datasheet
Already found vs still missing
Found
- Fan datasheet (some options): https://file.elecfans.com/web1/M00/CC/89/o4YBAF-ZOBKAQBvyADDMAglsvTw020.pdf
- Nidec BLDC motors (candidate fan motors โ bare motors, not the full suction assemblies):
NCJ-20N Type-3,
NCJ-20N Type-4 - Driving the fans: ripinteer/fan_protector
โ reference for driving / protecting the BLDC blower (from earlier project research)
Still missing (help wanted)
- Connector pinouts + cable lengths for wheels, fans, caster
- Encoder type + PPR, gearbox ratios, torque/current under load
- Wheel-drop sensor model + pinout
- Signal waveforms (encoder, motor/fan drive)
- Suction-assembly-level datasheets (we have some bare motors, not the assemblies)
- Weights; caster specs
Reverse-engineering โ only if specs can't be found, and SAFELY
If a spec isn't published, reverse-engineer it by opening an existing vacuum and probing.
Safety first:
- Don't do it unless you're qualified, experienced.
- Opening a vacuum usually voids the warranty and can damage it โ accept that risk knowingly.
- Secure / prop up the vacuum so it can't scoot off the table or bench when the wheels or
fan spin during testing (clamp it, or raise the wheels off the surface). - Respect the Li-ion battery โ don't short, pierce, or stress the pack; disconnect where sensible.
- Mind pinch points and spinning parts โ keep fingers/hair clear of the impeller and brushes.
- Any mains-connected testing (e.g. a dock) โ extra caution; isolate.
- Use a multimeter + oscilloscope to capture voltages, currents, and waveforms; trace and
label connector pinouts; photograph everything.
Legal:
- By performing any work for this project including reverse engineering you agree to
- wave liability, indemnify this project, the legal entity behind it (Remake AI Statutory Trust) and and its founder
- contribute your work and results thereof, if any, as open-source, to be published under Apache 2.0 license
Submit
A PR to contributions/part-specs/<your-github-username>//:
- a spec sheet (markdown table) with everything you found
- any datasheets (PDF) and source links
- photos of connectors + labelled pinouts
- waveform captures where reverse-engineered
- provenance โ which vendor / model / revision the data is from
- announce it in Project Discussions
Acceptance criteria
- Spec sheet for a part (or a clearly-scoped subset)
- Datasheets / links where found
- pinouts + waveforms where reverse-engineered when appropriate
- Provenance stated (part / vendor / revision)
- Verifiable by someone else with the same part
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple attempts
are welcome and useful even if not selected โ a non-selected spec sheet is still a valid
reference and a fallback.
File: contributions/obstacle-avoidance/README.md
Near-Field Obstacle Avoidance: camera + ToF (ROS2 package)
Stop the robot getting stuck on the things a 2D LiDAR cannot see. The turret
LiDAR is blind below its ~10 cm scan plane โ cables, socks, shoes, pet bowls,
thresholds โ which is the top real-world complaint about robot vacuums. This
package adds near-field forward perception from a front camera and/or a
multizone Time-of-Flight (ToF) sensor, detects obstacles in front of the robot,
and publishes them so navigation and recovery can react. Because the physical
robot isn't built yet, the software is developed in a Gazebo simulation; it is
later re-validated on hardware in the live-robot-bringup RFC.
Status โ ready to start work (forward-looking / experimental). This is the
v2 "never gets stuck" direction, not a v1 promise โ the v1 fallback for low
obstacles is the bumper (recovery-safety). Develop the
software in the Gazebo sim (urdf-gazebo-sim); say so in the
discussions so we can coordinate.
Two tracks in this RFC. (1) A software track โ the sensor-agnostic ROS2
package that detects and publishes obstacles (sim-first). (2) A hardware track โ
building and benchmarking the candidate front-depth sensors to decide which one
the robot ships. They meet at a shared obstacle interface: the software must not
care which sensor produced the depth/obstacle data.
Important References
- recovery-safety RFC โ the v1 bumper-based reaction this augments; a detected obstacle should feed the recovery/avoidance ladder.
- clean-and-map RFC / cleaning-jobs RFC โ coverage/nav that consumes the obstacle signal to slow, steer, or replan.
- floor-care RFC โ reactive wall/edge following: the near-field neighbor to obstacle avoidance (follow a boundary vs. steer around it), same reactive-sensing lineage.
- urdf-gazebo-sim RFC โ robot URDF; this package needs a front camera and a front ToF modeled.
- ROS2 software interfaces โ shared topic/action/service contract for simulation-first modules.
- OOMWOO ROS2 development โ build OOMWOO ROS2 Docker image(s) with your packages.
- Project discussions ยท Discord
Front sensor โ three candidate approaches (under evaluation)
The 2D LiDAR handles 360ยฐ mapping/localization. This module fills the below-LiDAR,
forward gap, which needs a wide horizontal FoV (target โฅ120ยฐ) so obstacles
across the robot's path โ not just dead ahead โ are seen. There are three
candidates; which one (or combination) ships is exactly what the hardware track
below is meant to decide.
A. Stereo depth โ 2ร OV5647 + IR pattern illuminator
- Two rolling-shutter cameras with wide lenses (target 120โ160ยฐ horizontal),
computing dense depth by disparity; doubles as the semantic camera. - Textureless surfaces (blank walls/floors) give stereo no features โ pair it
with an 840 nm random-dot pattern illuminator (eye-safe LED + engineered
diffuser or a printed random-dot mask; not a laser projector โ avoids the
Class-1/DOE-interlock burden). Short range is fine; that's all we need. - Sync is mandatory and not automatic: two independent OV5647 on the two CSI
ports free-run and won't genlock. Drive frame-sync over a shared IยฒC control
line, broadcasting a single write to both sensors (+ FREX/snapshot mode). Naive
"2ร cameras" stereo is a known trap. - Cost: uses both CM4/CM5 CSI lanes and real depth-matching compute (competes
with SLAM/NPU on the Pi). Widest FoV, richest data.
B. Multizone ToF โ 2ร VL53L7CX/CH, angled ยฑ30ยฐ
- Each VL53L7CX/CH is an 8ร8 multizone ToF with ~60ยฐ horizontal FoV (the "90ยฐ"
in the datasheet is diagonal). Place two side-by-side, one aimed 30ยฐ left, one
30ยฐ right โ ~120ยฐ horizontal total. - IยฒC, not CSI โ frees both camera lanes, near-zero compute (128 range zones,
not image frames). Class-1 eye-safe (VCSEL sealed in the module). Works in
total darkness and on textureless/blank surfaces โ no illuminator, no pattern. - Sourcing: bare VL53L7CX/CH ~$5.50 at DigiKey; order unpopulated carrier
PCBs, populate and reflow at home. โ ๏ธ It's an optical LGA โ keep flux
off the aperture and follow ST's reflow profile (this part has a cover-glass;
no-clean, no post-wash near the window). - Trade-off: coarse (8ร8 per sensor) โ great for "something is there, this far,
this tall", poor at shape/contour and no semantics.
C. Both combined
- ToF for reliable, dark/blank-proof geometry; stereo (or a single wide camera)
for wide semantics + dense shape. Fuse them. Most capable, most cost/compute.
Sim modeling. Gazebo has no VL53L7CX model โ approximate a multizone ToF with a
low-resolution depth camera or a small ray grid over the same FoV/zones, and
the camera(s) with standard Gazebo camera sensors. Add sensors inside your
submission and propose folding the stable ones back into
urdf-gazebo-sim later โ please don't rewrite that RFC.
Hardware track โ build & benchmark the candidates
Goal: determine, on real obstacles, which of A / B / C best detects the
near-field, below-LiDAR obstacles โ and whether one suffices alone or they must
be combined. This produces a data-backed sensor decision for the BOM.
Build notes
- B (2ร ToF) is the cheapest, lowest-risk build (IยฒC, no CSI, no illuminator,
eye-safe, dark/blank-proof) โ a natural first thing to characterize. Mount two
carriers at ยฑ30ยฐ, verify the seam/overlap near boresight, and publish combined
zones. - A (stereo) needs the sync harness (shared-IยฒC broadcast + FREX) and the
840 nm illuminator; validate passive stereo first (textured obstacles) then
measure how much the pattern illuminator helps on blank floors/walls. - Whichever is characterized, publish the same obstacle interface (below) so the
software track and Nav2 don't care which sensor won.
Test protocol โ obstacles (primary)
Model the obstacle set on how Vacuum Wars tests obstacle avoidance
so results are comparable to commercial robots:
- ~24 objects across categories, scored 1 point per object avoided (their
scale), run at max sensitivity. Categories include cords/cables, socks, shoes,
simulated pet waste, plus a "torture" pass mixing everything โ deliberately
including objects unlikely to be in any trained image library (this is where
ToF's geometry-only detection can beat a camera that relies on recognition). - Include their rug cases: a solid-color rug with same-color items and a
patterned rug with a contrasting item โ both stress depth/segmentation. - Add OOMWOO-specific cases the reviews under-cover: a cable lying flat, a ~2 cm
threshold, and a cliff/edge in-frame. - Run every case in two lighting conditions โ normal light and full darkness โ
and on โฅ2 floor types. Darkness and blank surfaces are the decisive
differentiators: ToF is lighting-independent; stereo needs the IR illuminator and
texture.
Test protocol โ object recognition (secondary)
Lower priority than raw obstacle avoidance. Where a camera is present, measure
classification accuracy for the categories above (feeds semantic behaviors like
"never smear pet waste โ stop and alert"). A miss here should still avoid the
object as an unknown obstacle; recognition only changes the reaction, not the
detection.
Metrics to report (per approach)
- Detection / avoidance rate per obstacle type (true-positive %), and the
aggregate Vacuum-Wars-style score (/24). - False-positive rate on clear floor (does normal cleaning get disrupted?).
- Min detection distance & reaction distance; blind spots / FoV coverage across
the โฅ120ยฐ target (map the seam between the two ToFs / stereo edges). - Darkness and blank-surface performance deltas vs. normal.
- Depth accuracy vs. ground truth; latency / frame rate.
- Pi compute load (CPU/NPU %) โ a real cost for stereo.
- Integration cost: CSI lanes used, power, BOM $, build/reflow difficulty.
Decision framework
Pick the approach that clears the acceptance criteria at the lowest cost +
compute + integration burden. Expected shape of the answer: B (2ร ToF) as the
robust, cheap, dark/blank-proof geometry baseline; add A (camera/stereo) if
semantic recognition or shape/contour proves necessary โ i.e. C for the premium
tier. Let the data decide; publish it so the choice is reviewable.
ROS2 obstacle interface (shared by both tracks)
Whichever sensor is used, publish obstacles in base_link: distance + bearing /
coordinates, plus object_type (unknown in Phase 1; typed in Phase 2), and/or
a PointCloud2 / Range-grid the nav stack can consume as a costmap layer. Feed
recovery-safety / navigation โ coordinate the interface
rather than driving cmd_vel directly where a nav layer owns it.
Request for Contribution โ Instructions
- add the sensors to the sim robot
- front camera (image topic) and front ToF (zone/range topic), co-located and
calibrated to a shared front frame - post in Project Discussions to let everyone know you're working on it, and post progress
- front camera (image topic) and front ToF (zone/range topic), co-located and
- Phase 1 โ detect, don't classify
- from the ToF (primary) and camera, detect any obstacle in the forward
near-field and publish it: distance + bearing / coordinates inbase_link,
with object type = unknown. Free-space vs blocked is enough to be useful. - the point is coverage of the below-LiDAR zone the 2D scan misses
- from the ToF (primary) and camera, detect any obstacle in the forward
- Phase 2 โ classify (later)
- run object detection on the camera, fuse with the ToF, and publish typed
detections (cable, sock, pet-waste, threshold, furniture โฆ) with confidence.
This is the NPU-relevant workload; keep it optional/pluggable.
- run object detection on the camera, fuse with the ToF, and publish typed
- react
- feed detections to navigation / recovery-safety: slow,
steer around, or stop-and-alert (e.g. never smear pet waste). Coordinate the
interface rather than drivingcmd_veldirectly from here where a nav layer owns it.
- feed detections to navigation / recovery-safety: slow,
- (hardware track) build a candidate front sensor (A/B/C above), run the test
protocol, and publish the metrics table so the sensor choice is data-backed.
Coordinate in Discussions
before ordering parts so effort isn't duplicated. - test it well
- build worlds with low obstacles the LiDAR can't see (cable on the floor,
sock, shoe, a 2 cm threshold) and verify they are detected and avoided - verify the robot still cleans normally when the near-field is clear (low false-positive rate)
- build worlds with low obstacles the LiDAR can't see (cable on the floor,
- regression tests (headless, CI-friendly)
- detection rate on a set of placed low obstacles (true-positive %)
- false-positive rate on clear floor
- "did not run over the flagged obstacle" success rate
- submit a PR (pull request) linking your ROS2 package(s) + sim sensor/world additions
- instructions, documentation โ install, run, configure, troubleshoot, test results
- videos of low-obstacle detection and avoidance
- announce your submission in Project Discussions
- iterate with review
- TBD, expect the RFC to evolve
Acceptance criteria
Objective, measurable. Examples:
- Below-LiDAR obstacles (cable, sock, low threshold) are detected and
published with distance/bearing, and the robot avoids running them over - Low false-positive rate on clear floor โ normal cleaning is not disrupted
- Phase 1 works without classification; Phase 2 classification is optional/pluggable
- Regression tests pass (detection %, false-positive %, avoidance success), runnable headless in CI
- Works in at least one world seeded with LiDAR-invisible obstacles
- (hardware track) a candidate is characterized against the Vacuum-Wars-style
protocol in light and darkness, with the metrics table filled in โ enough to
compare it against the other approaches - Documented and reliably reproducible by someone else
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple
attempts are welcome and useful even if not selected โ modules are swappable, and
a non-selected design is still a valid learning exercise and a fallback.
File: contributions/nav-localize/README.md
Localization & Navigation on a Known Map (ROS2 package)
Once the first clean has produced a map, the robot must be able
to operate on that saved map: localize itself, navigate to any goal with Nav2,
recover its pose when it gets lost or is picked up and moved (the kidnapped
robot problem), and resume an unfinished map. Because the physical robot isn't
built yet, this is a Gazebo simulation; it is later re-validated on hardware in
the live-robot-bringup RFC.
Status โ ready to start work. No need to wait for OOMWOO hardware โ develop it in the
Gazebo sim (urdf-gazebo-sim) or on the real
placeholder Proscenic M6 Pro.
Say so in the discussions so we can coordinate.
Important References
- clean-and-map RFC โ produces the saved/partial map this package consumes.
- urdf-gazebo-sim RFC โ robot URDF, Gazebo world(s), bumper.
- ROS2 software interfaces โ shared topic/action/service contract for simulation-first modules.
- Gazebo + Nav2 simulation tutorial โ baseline diff-drive + LiDAR robot in a Gazebo world.
- OOMWOO ROS2 development โ build OOMWOO ROS2 Docker image(s) with your packages.
- Nav2 (navigation), AMCL (localization), and slam_toolbox (localization mode / serialized session continue) are the expected building blocks.
- Project discussions
- Discord server
Request for Contribution - Instructions
- reproduce the baseline first
- load a map saved by clean-and-map and bring up Nav2 + a localizer (AMCL or slam_toolbox localization mode) on the urdf-gazebo-sim robot
- post in Project Discussions to let everyone know you're working on it, and post your progress
- localization on a known map
- global initial localization at startup without being given a pose (e.g. AMCL global init / scan-matching) โ the robot figures out where it is on the saved map
- track pose reliably during navigation; expose a localization-confidence signal (covariance / scan-match score)
- navigation
- Nav2 navigate-to-pose and navigate-through-poses to arbitrary goals on the saved map
- obey dynamic obstacles via the local costmap
- lost / kidnapped recovery
- detect when localization confidence drops (low score, high covariance, or a detected pickup/kidnap)
- relocalize: rotate in place and/or drive to gather scans until the pose re-converges
- define a clear "relocalized" success condition, and what happens if it fails โ hand off to the dock-cycle find-the-dock-when-lost fallback
- resume an unfinished map
- load a partial / serialized SLAM session (e.g. slam_toolbox serialization) and continue mapping where it left off, merging newly seen areas into the existing map without corrupting it
- test it well
- start from many initial poses, including a wrong or unknown initial pose
- kidnap the robot mid-run (teleport it in sim) and verify it recovers
- resume from several partial maps and verify the merged map is correct
- regression tests (headless, CI-friendly)
- relocalization success rate from random poses
- navigation success rate to random reachable goals
- map-resume correctness (resumed + continued map matches a from-scratch map of the same world)
- submit a PR (pull request) to
contributions/nav-localize/<your-github-username>/- link to ROS2 package(s)
- instructions, documentation - how to install, run, configure, troubleshoot, test results
- videos of relocalization-when-lost and map-resume runs
- announce your submission in Project Discussions
- iterate with review
- TBD, expect the RFC to evolve
Acceptance criteria
Objective, measurable. Examples:
- On a saved map, from an unknown initial pose, the robot performs global localization and converges to the correct pose
- Nav2 navigation reaches arbitrary reachable goals reliably, avoiding dynamic obstacles
- When lost / kidnapped, the robot detects it, relocalizes, and resumes โ or cleanly hands off to the find-the-dock fallback when relocalization fails
- An unfinished map can be loaded and mapping continued, producing a complete, uncorrupted map
- Regression tests pass and verify relocalization, navigation, and map-resume, runnable headless in CI
- Documented and reliably reproducible by someone else
- TBD, expect criteria to evolve
The maintainer selects among compliant candidates using these criteria. Multiple
attempts are welcome and useful even if not selected โ modules are swappable, and
a non-selected design is still a valid learning exercise and a fallback.
2. Official Technical Reference & Guides (makerspet/oomwoo-io-firmware)
MCU firmware for the OOMWOO I/O board,
targeting an STM32G473VCT6. Arduino (STM32duino) API on top, FreeRTOS for task
structure, and a HAL/timer-ISR real-time core underneath.
Status โ RFC / not started. This is a request for contribution: the plan
below is the design intent, and the code doesn't exist yet. Say hi in
Discussions or on
Discord if you want to build it.
OOMWOO splits compute across two processors (ARCHITECTURE.md ยง5.4):
a CPU (CM4/CM5-class module) runs ROS 2, SLAM, Nav2, and behaviour; the MCU
on this I/O board owns motors, encoders, sensors, battery charging, and hard
safety. This repo is that MCU firmware. Its defining constraint: safety must
never depend on Linux/ROS 2 โ and, as you'll see below, it must never depend on
the friendly Arduino layer either.
Why STM32G473VCT6
The board drives ~10 actuators and reads a dozen-plus analog channels, so the MCU
needs headroom the earlier STM32G0 (Cortex-M0+, no FPU) didn't comfortably have:
- Cortex-M4F @ up to 170 MHz with an FPU โ real control math (PID, filters,
odometry) in hardware float, with cycles to spare for FreeRTOS + the Arduino layer. - Many timers incl. HRTIM โ enough PWM channels for every motor, plus the
high-resolution timer for clean BLDC/fan drive. - 5ร 12-bit ADCs โ the board has many simultaneous analog channels (per-motor
current sense,VBat, source current, 4ร cliff IR, 2ร dock IR, 2ร side IR); five
ADCs let safety-critical currents be sampled fast and independently. - CORDIC + FMAC math accelerators, 512 KB flash / 128 KB RAM, LQFP100 (hand-
solderable, JLCPCB-friendly).
STM32duino supports the G4 family (Nucleo-G474 is a good bring-up board), and
FreeRTOS is available via the STM32FreeRTOS library โ so "Arduino API + FreeRTOS"
is a supported, real combination on this part.
Architecture โ three layers (the core design decision)
The usual "friendly Arduino or deterministic real-time safety" trade-off is a
false choice here. We get both by layering, so the layer a contributor touches
is not the layer that keeps the robot safe:
| Layer | What | Owned by | Determinism |
|---|---|---|---|
| 3 โ Arduino (STM32duino) API | New behaviours, features, and peripheral bring-up live here. This is the contributor-friendly surface. | community | best-effort |
| 2 โ FreeRTOS tasks (static allocation) | Task structure: CPU-serial comms, control loop, telemetry, charging supervisor, safety supervisor. Watchdog-fed, bounded reaction times. | maintainer + community | soft real-time |
| 1 โ Real-time core (HAL + timer ISRs) | Motor commutation/PWM, encoder capture, the hard-safety cutoffs, the CPU watchdog. Runs in hardware timers / ISRs. | maintainer, safety-reviewed | hard real-time |
The rule that makes this safe: contributor code lives at the Arduino level;
the motor-control and safety core is HAL/ISR and structurally isolated from it.
A bug or an infinite loop in someone's Arduino feature cannot defeat a cliff
stop, an overcurrent cutoff, or the CPU watchdog โ those live in interrupts and a
hardware watchdog that the upper layers cannot starve. That's how you get the
community-attraction of Arduino and the real-time integrity a robot needs.
Safety (non-negotiable, CE-oriented)
Hard safety runs on the MCU, independent of both Linux/ROS 2 and the Arduino
layer:
- Bumper / cliff / wheel-drop โ immediate motor stop, at ISR level.
- Per-motor overcurrent limiting โ a stuck brush, jammed wheel, or stall is
current-limited or cut before thermal/mechanical damage. - CPU watchdog โ if the CPU's periodic health packets stop, the MCU stops the
motors and can assert the CPU-reset line. - MCU independent watchdog (IWDG), static memory allocation, and measured,
documented worst-case reaction times.
Per the project's safety-review gate, safety-critical changes require maintainer
review before merge and a short hazard note (over-current, thermal, short,
mechanical pinch).
What the firmware owns
Source of truth is the board SPEC.md
(work in progress โ treat it as authoritative over this summary, and note its open
TODOs, e.g. the GPIO 36/46 bumper-label question):
- Actuators: 2ร drive wheels (H-bridge + hall encoders), suction fan (BLDC, PWM
- FG feedback), main brush, side brush(es), 2D-LiDAR spin motor, water pump, mop
motors, and the mop-lift / mop-arm / side-brush-arm servos โ each drive path with
current sense where the board provides it.
- FG feedback), main brush, side brush(es), 2D-LiDAR spin motor, water pump, mop
- Sensors: 4ร cliff IR, 2ร dock IR, 2ร side-proximity IR (+ their IR-LED PWM),
2ร bumper switches, 2ร wheel-drop switches, wheel encoders, IMU (SPI + interrupts- FSYNC), and the current-sense/
VBat/source-current analog channels.
- FSYNC), and the current-sense/
- Power & charging: supervise the power-path charger (0.5C charge cap, input
DPM, USB-C PD and dock input, graceful "insufficient charger" handling), plusmotors power enable,vacuum power,CPU power on/off, andCPU reset. - HMI: power/home buttons and power/home LEDs.
CPU โ MCU link
A custom serial protocol over UART โ deliberately not micro-ROS, so the
safety core carries no heavyweight third-party dependency (and no risk of an
upstream library update slipping a bug into safety-critical firmware). The framing,
command set, telemetry, and health/watchdog handshake are being defined in the
io-board-interface RFC.
The MCU: accepts bounded, expiring commands (drive setpoints, motor/actuator
commands); publishes telemetry (encoders, battery/charge state, bumper/cliff/
wheel-drop, per-motor current); and enforces the health handshake that backs the
CPU watchdog. During development, the CPU side can be stood in for by the simulated
MCU serial tool in oomwoo-install.
Toolchain
- STM32duino (the STM32 Arduino core) via the Arduino IDE or PlatformIO;
G473 through the generic-G4 board definition (bring up on a Nucleo-G474 first). - FreeRTOS via
STM32FreeRTOS. - SWD debug (ST-Link) on the board's
SWDIO/SWCLKheader; test/program pads.
Request for contribution โ bring-up milestones
Phased, each testable on the bench before the board even exists (start on a
Nucleo-G474, move to the real board when it's fabbed):
- Blink + SWD + serial echo on a G473 dev board.
- CPU serial link โ implement the io-board-interface framing + health/watchdog
handshake; loopback and echo tests green. - One drive motor, closed loop โ H-bridge PWM + encoder capture + velocity PID
in the real-time core. This is the pattern every other motor follows. - All actuators โ fan (BLDC + FG), brushes, LiDAR spin, pump, mop motors/servos,
each with current sense. - All sensors โ cliff/dock/side IR (ADC), bumpers, wheel-drop, IMU (SPI),
current channels. - Safety layer โ ISR-level cliff/bumper/wheel-drop stop, overcurrent limiting,
IWDG, CPU watchdog/reset; measure and document each cutoff's worst-case
reaction time; hazard note. - Charging supervisor โ power-path charger control, 0.5C cap, input DPM,
insufficient-charger handling. - Integration โ run end-to-end against the CPU (or the simulated MCU serial
tool) driving the ROS 2 hardware bridge.
Acceptance criteria
- Deterministic real-time core โ measured, documented worst-case reaction time
for each safety cutoff. - Safety is layer-independent โ a deliberately hung Arduino-level task must
not defeat a cliff-stop, overcurrent cutoff, or the CPU watchdog. Demonstrate it. - Implements the io-board-interface serial contract โ loopback + integration
tested. - Every actuator and sensor exercised on the bench, documented, reproducible by
someone else. - Charging behaves per spec โ 0.5C cap held; graceful degradation on a weak
charger. - Safety-critical code passed maintainer safety review with a hazard note.
References
- Board: oomwoo-io-board ยท SPEC.md
- CPUโMCU contract: io-board-interface RFC
- System architecture: ARCHITECTURE.md ยง5.4
- STM32duino ยท STM32FreeRTOS
- Project Discussions ยท Discord
License
Apache License 2.0. Contributions are made on that basis; safety-critical
firmware additionally passes maintainer safety review before merge.