oomwoo Documentation

Open-source vacuum robot cleaner

RAW Doc

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:

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.

  1. Pick a contribution from the list below.
  2. Let us know you're working on it and your progress.
  3. 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

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 the lib folder.

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/oomwoo in contributions/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.
  • Get an accurate model โ€” three paths:
    1. 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.
    2. 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.
    3. 3D scan the part, convert the mesh into a STEP file. As an example, I use Creality Raptor.
  • 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:

text
contributions/recovery-safety/xbattlax/oomwoo_recovery_safety

Interfaces

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:

bash
source /opt/ros/jazzy/setup.bash
cd /workspace
colcon build \
  --base-paths contributions/recovery-safety/xbattlax/oomwoo_recovery_safety \
  --packages-select oomwoo_recovery_safety

Test

bash
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 --verbose

The 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_vel publishing so motion recoveries outlive base watchdog timeouts
  • a separate completion timeout for delegated commands such as clear_costmap

Run

bash
source /opt/ros/jazzy/setup.bash
source install/setup.bash
ros2 launch oomwoo_recovery_safety recovery_safety.launch.py

Manual trigger example:

bash
ros2 topic pub --once /oomwoo/recovery/event std_msgs/msg/String "{data: bumper_front}"

Mark the current behavior as successful:

bash
ros2 topic pub --once /oomwoo/recovery/behavior_result std_msgs/msg/String "{data: succeeded}"

Trigger e-stop:

bash
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_costmap is 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 succeeded result 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.

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 / backup are 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 in encoder_sim.rs unit 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.rs and SENSORSTATUS.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, and dhruva-nav/src/odometry.rs.

Gearbox Ratio

  • Estimated ratio: ~190:1 โ€” derived from VELOCITY_TO_DEVICE_UNITS = 523.0 (empirically calibrated in VacuumTiger commands.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


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


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


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, and HA00021 (~46 ร— 52mm) in io-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


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

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

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
  • 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 in base_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
  • 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.
  • 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 driving cmd_vel directly from here where a nav layer owns it.
  • (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)
  • 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

Request for Contribution - Instructions

  • reproduce the baseline first
  • 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.
  • 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.
  • Power & charging: supervise the power-path charger (0.5C charge cap, input
    DPM, USB-C PD and dock input, graceful "insufficient charger" handling), plus
    motors power enable, vacuum power, CPU power on/off, and CPU reset.
  • HMI: power/home buttons and power/home LEDs.

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/SWCLK header; 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):

  1. Blink + SWD + serial echo on a G473 dev board.
  2. CPU serial link โ€” implement the io-board-interface framing + health/watchdog
    handshake; loopback and echo tests green.
  3. 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.
  4. All actuators โ€” fan (BLDC + FG), brushes, LiDAR spin, pump, mop motors/servos,
    each with current sense.
  5. All sensors โ€” cliff/dock/side IR (ADC), bumpers, wheel-drop, IMU (SPI),
    current channels.
  6. 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.
  7. Charging supervisor โ€” power-path charger control, 0.5C cap, input DPM,
    insufficient-charger handling.
  8. 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

License

Apache License 2.0. Contributions are made on that basis; safety-critical
firmware additionally passes maintainer safety review before merge.