chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:31:04 +08:00
commit 43552b5423
52 changed files with 4226 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
# OOMWOO Architecture Brief
> *Status: DRAFT / skeleton.* This document defines the system so that modules
> can be built in parallel without colliding. Sections marked *TBD* are the
> gating decisions; until they are filled in, hardware modules that must fit
> together cannot be finalized. Treat the interface specs as the contract every
> module agrees to.
## 1. Purpose/Goal and scope
OOMWOO is an open-source, 3D-printed, ROS2-based home robot vacuum with 2D LiDAR
and Home Assistant support. It is designed to be *built from scratch by
the community*, module by module, clean well and to double as an affordable ROS2
development and learning platform.
*North star (not MVP):* OOMWOO is also the reference hardware for a broader
robot application platform. Architectural boundaries (especially the app layer in
§6) are drawn with that future in mind, but the MVP below deliberately excludes it.
## 2. Design principles
- *Open and swappable.* Every module has a defined interface. Any compliant
implementation can replace another. No module depends on the internals of
another, only on its published interface.
- *Simulation-first.* Software must run in Gazebo before it runs on hardware,
so contributors with no robot can still build and test.
- *Affordable and printable.* Target off-the-shelf parts (a CM4/CM5-class compute
module, common vacuum LiDARs, sourced Roborock/Dreame/Xiaomi motors and wear
parts) and FDM-printable chassis parts.
- *Safety is reviewed, not crowd-trusted.* Battery, charging, and motor-driver
modules pass a maintainer safety review before merge (see §8).
- *Reference-design backed.* A known-working vacuum (see the references in the
[README](../README.md)) anchors the geometry and proves feasibility.
## 3. System overview
```
LiDAR (UART, ~5 Hz) · MIPI camera(s) · IMU · serial audio
|
+-------------v-------------------------------+
| CPU - CM4 / CM5 (or pin-compatible module) |
| ROS2 · SLAM (slam_toolbox) · Nav2 · behavior |
| educational variant: ESP32-S3 + micro-ROS |
| (SLAM offboard on a dev PC over Wi-Fi) |
+-------------^----------------+---------------+
serial (cmds/telemetry) + | custom serial protocol
CPU-reset / health GPIO | (NOT micro-ROS)
+-------------+----------------v---------------+
| MCU - STM32G070 (FreeRTOS, static alloc) |
| motors · encoders · sensors · charging ctrl |
| SAFETY (no Linux/ROS2): bumper/cliff/wheel- |
| drop stop · current limit · CPU watchdog |
+-------------+--------------------+-----------+
| |
+----------+----+ +--------+---------+
| L/R drive | | suction fan, |
| wheels, brush | | bumper, cliff, |
| | | IR, wheel-drop |
+---------------+ +------------------+
Power: off-the-shelf 4S2P Li-ion pack (built-in BMS).
The CPU module + MCU sit on one carrier I/O board.
```
> The CPU/MCU split keeps *all hard safety on the MCU*, independent of Linux/ROS2.
> Interfaces are largely decided (see §5); refine as the io-pcb spec settles.
## 4. Coordinate frames and conventions
- *TBD:* Define `base_link` origin and orientation (REP-103: x-forward,
y-left, z-up). All mechanical mounting points and URDF frames reference this.
- *TBD:* Define the reference plane (floor contact), robot diameter, and height
envelope. *These two numbers gate every hardware module.* Source these from the *sourced
parts* + a 3D-scanned donor (see [source-3d-models](../contributions/source-3d-models));
the current baseline is a ~349 mm round body ([oomwoo-one URDF](https://github.com/makerspet/oomwoo-one)).
- Units: millimeters, kilograms, SI. Right-handed frames. Angles in radians.
## 5. Hardware architecture
### 5.1 Chassis and reference frame
The chassis is the *integration backbone*. It publishes the mounting interface
every other hardware module targets. Reference geometry (dimensions, wheelbase,
motor specs, mass) comes from the *sourced parts* ([BOM](../BOM.md)) + 3D scans of
a donor vacuum (see [source-3d-models](../contributions/source-3d-models)); the
[oomwoo-one URDF](https://github.com/makerspet/oomwoo-one) carries the current
~349 mm round-body baseline.
- *TBD:* Overall diameter and height budget.
- *TBD:* Mounting grid / bolt pattern standard (e.g., M3 on a defined pitch).
- *TBD:* Mass budget per module and total target mass.
### 5.2 Mechanical interface standard (the contract)
Every hardware module's RFC must specify, against this standard:
- Mounting points (bolt pattern, location relative to `base_link`).
- Bounding envelope (max size the module may occupy).
- Mass budget.
- Mating tolerances and print orientation.
- *TBD:* Define the standard connector/fastener set (screw sizes, heat-set
inserts, etc.) so parts from different authors actually mate.
### 5.3 Electrical interface standard (the contract)
- *Battery:* off-the-shelf pack with a *built-in BMS**4S2P Li-ion*, ~14.4 V
nominal, ~5200 mAh / ~75 Wh (OEM BRR-2P4S-5200 class), charged 16.8 V CC/CV with
NTC temperature sense. Chemistry is now decided; see the [BOM](../BOM.md).
- *TBD:* Power rails distributed to modules (VBAT, 5V, 3.3V) and connector types/pinouts.
- *CPU ↔ MCU:* a *custom high-speed serial protocol* (not micro-ROS) carries
commands/telemetry, plus discrete GPIOs (CPU power on/off, and a CPU-reset line
the MCU asserts on missed health packets). The *MCU owns motors and sensors*; the
CPU never drives them directly.
- *Sensors:* bumper/cliff/wheel-drop and analog IR are *MCU-side* (digital in / ADC);
the *LiDAR (UART, ~5 Hz)*, MIPI camera(s), IMU, and serial audio attach to the *CPU*.
### 5.4 Compute (CPU) and real-time controller (MCU)
OOMWOO splits compute across two processors — mirroring how consumer vacuums are
built, and, crucially, so that *safety never depends on Linux/ROS2*.
*CPU (compute module).* The I/O board is a *carrier* that accepts a *Raspberry Pi
Compute Module 4 or 5* and — because the CM4 pinout is a de-facto standard — the
many *pin-compatible alternative modules* (Radxa CM3/CM4, Pine64 SOQuartz, LuckFox
Core3566, …), several with an *NPU* for future on-device vision. The CPU runs
*ROS2, SLAM (slam_toolbox), Nav2, LiDAR processing, and high-level behavior*. CM
modules are low-profile (helps the height budget) and swappable (hackable, cheaper,
NPU options).
- *Minimum target: a 4 GB CM4/CM5 (or Pi 4).* Realistic prior art runs
slam_toolbox + Nav2 onboard a 4 GB Pi 4. Getting the floor to *2 GB* is a goal
(ROS2 composable nodes; selectively rewriting heavy Python nodes in Rust/C++) —
*no guarantee*, to be settled by the compute-benchmark. No 816 GB module needed.
- *Cooling:* no dedicated CPU fan — the suction fan's airflow cools the compute
board, as in consumer vacuums.
- The earlier bespoke *RK3562* reference schematic is *dropped* in favour of the
CM4/CM5 carrier.
*MCU (real-time / safety controller).* A dedicated microcontroller — *tentatively
the STM32G070RBT6* (~56 GPIO incl. 16 ADC channels, ~$1 at JLCPCB, LQFP not BGA) —
owns *motors, encoders, all sensors, battery-charging control, and safety*. Its
role is *fixed*: functionality does not migrate onto the CPU, and CPU work does not
migrate onto the MCU.
- Firmware is *tentatively FreeRTOS* (static allocation, watchdog, guaranteed
reaction times, CE-oriented) speaking a *custom serial protocol — not micro-ROS*
(the tried-and-true consumer-vacuum approach; cf. the reverse-engineered
[3irobotix protocol](https://github.com/codetiger/VacuumRobot)).
- *Hard safety lives here, independent of Linux/ROS2:* the MCU stops all motors on
a *bumper hit, cliff detection, or wheel-drop*, current-limits a *stuck brush*,
and *watchdogs the CPU* — if the CPU's health packets stop, it stops the motors
and can *reset the CPU*.
- Tentative ~60-signal pin budget: see the [io-pcb RFC](../contributions/io-pcb)
appendix (why the MCU needs a high-GPIO part).
*CPU ↔ MCU link.* A *high-speed serial* channel carries commands/telemetry both
ways, plus discrete GPIOs — notably the *CPU-reset* line the MCU asserts on missed
health packets, and CPU power on/off. Any LiDAR supported by `kaiaai/LDS` /
`lds2d` is interface-compatible.
### 5.5 Two build profiles
The same carrier I/O board + MCU supports two swappable compute configurations:
| | *Consumer / regular* | *Educational / lower-cost* |
|---|---|---|
| CPU-slot module | CM4 / CM5 (or pin-compatible alt) | *ESP32-S3* board in the CM4 form factor |
| Where ROS2 / SLAM runs | *onboard* (ROS2 + slam_toolbox + Nav2) | *offboard* on a local dev PC; ESP32-S3 runs *micro-ROS* |
| Link | self-contained robot | robot ↔ dev PC over *Wi-Fi* |
| Trade-off | plug-and-play for non-experts | cheaper, but Wi-Fi congestion / dead-zones — a learning platform, not a polished consumer product |
Onboard SLAM is the default for the consumer version *so non-experts can build and
use it* without setting up a separate ROS2 dev machine. The ESP32-S3 can only be
the *CPU-slot* option — it lacks the ~60 GPIO the MCU role needs, so it never
replaces the STM32.
## 6. Software architecture
### 6.1 ROS2 graph (MVP)
- Core nodes (MVP): LiDAR driver, base controller (diff-drive), odometry,
teleop, SLAM (manual mapping), TF/URDF publisher.
- *Interface contract:* each software module's RFC declares the ROS2 topics,
services, message types, and parameters it publishes/consumes. Modules depend
on these interfaces, not on each other's code. See
[SOFTWARE_INTERFACES.md](SOFTWARE_INTERFACES.md) for the current draft ROS2
graph contract.
### 6.2 Simulation
- Gazebo + URDF, with a set of residential-layout worlds for navigation and
coverage testing. Sim parity is a first-class requirement, not an afterthought.
### 6.3 Application layer (Phase 2 — north star, NOT in MVP)
A ROS2-agnostic layer that runs third-party apps locally in isolated *Podman*
containers, so app developers need no ROS2 expertise. Documented here only to
keep its boundary clean; *explicitly out of scope for the Aug 31 MVP.*
## 7. MVP definition (target: 2026-08-31)
*In scope:* ROS2 on a CM4/CM5-class compute module · LiDAR · manual SLAM/mapping · teleop drive ·
3D-printed chassis · Gazebo sim with URDF · evaluation + demo video. No dock,
no autonomous exploration, no Home Assistant, no app layer.
*Explicit non-goals for MVP:* autonomous coverage, docking, auto-empty, mopping,
Home Assistant, the app platform, accessories. These are later phases.
*Critical-path ownership:* the maintainer (+ small core) own the chassis,
interface specs, and integration so the MVP does not depend on volunteer delivery
timing. Community modules accelerate and improve the MVP; they do not block it.
## 8. Safety review gate
Battery, charging, motor-driver, and mains-adjacent modules require maintainer
safety review before merge. RFCs for these modules must include a hazard note
(over-current, thermal, short, mechanical pinch).
The battery risk is *reduced* by using an *off-the-shelf 4S2P Li-ion pack with a
built-in BMS* (over-charge / over-discharge / short protection); the review then
focuses on the *16.8 V CC/CV charging path + NTC temperature sense*. *Hard safety
lives on the MCU, never on Linux/ROS2* — it independently stops motors on
bumper/cliff/wheel-drop, current-limits a stuck brush, and watchdog-resets the CPU.
## 9. Roadmap (phases after MVP)
1. Rechargeable battery + basic dock + autonomous floor mapping.
2. Home Assistant integration.
3. Application layer (Podman app runtime) + first delightful apps.
4. Accessories and novel apps; integrations (e.g., LeRobot arm).
## 10. Open questions
- *Resolved:* the MCU runs a *custom serial protocol (not micro-ROS)*; the CPU runs
*onboard ROS2/SLAM/Nav2*. micro-ROS is used only in the *educational* ESP32-S3
profile (SLAM offboard on a dev PC). See §5.45.5.
- *Resolved:* battery is an off-the-shelf *4S2P Li-ion pack with a built-in BMS*,
charged 16.8 V CC/CV. See §5.3, §8.
- Can OOMWOO's onboard ROS2 stack fit in *2 GB* (composable nodes, selective Rust)
rather than 4 GB? To be answered by the compute-benchmark.
- MCU family: *STM32G070RBT6* is the tentative pick (GPIO/ADC count, ~$1 at JLCPCB,
LQFP) — open to alternatives.
- One hardware-agnostic HAL covering reference vacuum + DIY builds (community idea)?
- Module selection process: who decides which competing implementation wins, and
on what criteria? (See each module's acceptance criteria.)
+103
View File
@@ -0,0 +1,103 @@
# Contributing to OOMWOO
Thanks for your interest. OOMWOO is an open-source robot vacuum you build
yourself, and it's at a very early stage. That's the best time to get involved,
the foundations are still being laid and your input can shape the direction.
The project is built *module by module* so many people can work in parallel.
Browse the [module list in the README](../README.md#requests-for-contributions),
and see [ARCHITECTURE.md](ARCHITECTURE.md) for how the pieces fit together.
## Ways to help right now
You don't need to be a roboticist to contribute:
- *Ideas and feedback* — open a [Discussion](https://github.com/makerspet/oomwoo/discussions)
about features, design choices, or what would make you build one.
- *Code* — firmware, ROS2 packages, Home Assistant integration.
- *Hardware* — 3D-printable chassis design, mechanical parts, PCB.
- *Documentation* — build guides, wiring diagrams, troubleshooting notes.
- *Testing* — once there's something to build, real-world build reports are gold.
- *Spread the word* — star the repo, share your build, post a demo.
## Getting started
1. *Pick a module.* Browse the
[module list in the README](../README.md#requests-for-contributions) and choose a
hardware or software module. Software and simulation modules can start
immediately; hardware modules wait on the interface specs in
[ARCHITECTURE.md](ARCHITECTURE.md). Read the module's `README.md` so you know
the contract.
2. *Start a conversation first.* Claim or ask about the module in its
[Issue](https://github.com/makerspet/oomwoo/issues) or
[Discussion](https://github.com/makerspet/oomwoo/discussions) before writing
code, so we align on the approach and avoid wasted effort.
3. *Build it in your own repo.* For code and simulation modules, develop your
package in your **own public repository** — you own it, version it, and keep the
credit. Build against the ROS2 interface contract in
[SOFTWARE_INTERFACES.md](SOFTWARE_INTERFACES.md) so your work stays interoperable
with other modules. (Docs and small reference material are handled differently —
see below.)
4. *Submit a pointer PR.* Add a link to your repo in the module's entry with a
one-line description. It's small, easy to review, and lets several
implementations of the same module sit side by side. Keep the PR focused.
5. *Iterate in the open.* Modules are swappable — the best implementation surfaces
over time, with the maintainer having the last call. A design that isn't
selected is still a useful fallback.
## How contributions are structured
OOMWOO keeps the core small and lets the community grow around it:
- *Canonical / reference code stays first-party.* [oomwoo-one](https://github.com/makerspet/oomwoo-one)
(robot description + sim), [oomwoo-install](https://github.com/makerspet/oomwoo-install)
(dev environment), and the `kaiaai_*` packages are maintained by the project so the
out-of-the-box build always works.
- *Module implementations (code) live in your repo.* You build a competing
implementation of a module — a sim, a navigation stack, a behavior — in your own
repository and submit a *link*. The project features accepted work from the
module's page, credited to you. When a contribution is *featured*, we pin a
specific commit or tag (and may fork it into the makerspet org) so the reference
build stays reproducible even if the upstream repo moves.
- *Docs, specs and small reference material stay in-tree.* Part specifications,
datasheets, STEP-model sourcing notes, PCB notes, and benchmarks are lightweight
and best kept alongside the project — contribute those under
`contributions/<module>/<your-username>/` as files in a PR.
Why links for code? You keep ownership, credit, and freedom to iterate; the project
stays lean and avoids absorbing third-party code and its licensing; and multiple
implementations of a module can coexist and be compared. The shared
[SOFTWARE_INTERFACES.md](SOFTWARE_INTERFACES.md) contract is what keeps
independently-built modules compatible.
## Hardware contributions
For CAD and mechanical work, please include source files (not just exported STLs)
where possible, so others can modify your design. Note the tool and version you
used. If your change affects the bill of materials, mention it in the PR. Each
hardware module must stay within the mechanical/electrical interfaces in
[ARCHITECTURE.md](ARCHITECTURE.md).
*Safety:* battery, charging, motor-driver, and mains-adjacent modules require a
maintainer safety review before merge. Include a hazard note in your submission.
## Code style
Conventions are still being established. For now: keep it simple, readable, and
consistent with the surrounding code. ROS2 packages should follow standard ROS2
layout and naming. We'll formalize linting and style as the codebase grows.
## Licensing
By contributing, you agree that your contributions are licensed under the
project's [Apache License 2.0](../LICENSE). Hardware design files will be released
under an open hardware license (to be finalized); contributions of hardware
files are made on that same open basis.
## Community and conduct
Be respectful, helpful, and welcoming. We want OOMWOO to be an easy, friendly
place for makers of every skill level. Harassment or hostility isn't tolerated.
Questions? Open a [Discussion](https://github.com/makerspet/oomwoo/discussions?discussions_q=)
or join us on [Discord](https://discord.gg/3y2JKz5T25).
+64
View File
@@ -0,0 +1,64 @@
# RFC Backlog (planned / not-yet-active)
Planned modules that are *not yet active RFCs*. The RFCs ready to work on *now* live in the
[README status table](../README.md#requests-for-contributions), and each active RFC's full
spec is under [contributions/](../contributions). An item here graduates into an active RFC
(its own `contributions/<module>/` folder) once it is unblocked and ready.
*Phase legend:* `MVP` = targeted for the bare-bones build · `P2` = next phase ·
`P3+` = later. *Safety* = requires a maintainer safety review.
## On hold (have an RFC, paused pending sourced parts + a 3D reference design)
| Module | RFC | Notes |
|---|---|---|
| Dust bin 3D design | [dust-bin](../contributions/dust-bin) | Design / print / test the dust bin — waits on sourced parts + a 3D design |
| Blower fan assembly | [vacuum-fan](../contributions/vacuum-fan) | Fans already sourced (see BOM); the volute / gasket housing waits on the 3D design |
## Planned hardware (mechanical design)
Waits on sourced parts + a 3D reference-design sketch, then becomes an active
`contributions/` RFC. Part *specs* and *STEP models* are already active — see
[part-specs](../contributions/part-specs) and [source-3d-models](../contributions/source-3d-models).
The motor-driver / power PCB and battery charging are now the active
[io-pcb](../contributions/io-pcb) RFC.
| Module | ID | Phase | Notes |
|---|---|---|---|
| Chassis / base frame (reference) | `hw-chassis` | MVP | Integration backbone; defines the mechanical interface. Maintainer-owned. |
| Drive-wheel mounts (L/R) | `hw-wheel-mount` | MVP | Mount + suspension around the sourced wheel modules. |
| Compute mount (RPi 5) | `hw-compute-mount` | MVP | Mount + airflow for the Pi 5. |
| LiDAR mount | `hw-lidar-mount` | MVP | Centered turret; parametric for other models. |
| Main brush assembly | `hw-main-brush` | MVP | *Tapered rubber anti-tangle roller* + drive. |
| Bumper (mechanical + switches) | `hw-bumper` | MVP | Contact detection. |
| Cliff-sensor mounts | `hw-cliff` | MVP | IR drop detection at edges / stairs. |
| Top cover / shell | `hw-shell` | MVP | Cosmetic + protective; LiDAR clearance. |
| Wiring harness | `hw-harness` | MVP | Connector pinouts per [io-pcb](../contributions/io-pcb) + [part-specs](../contributions/part-specs). |
| Side brush | `hw-side-brush` | P2 | Edge cleaning. |
| Mop module (dual-spinning) | `hw-mop` | P2 | 3D-printed *dual-spinning* pads; skip the self-washing roller. |
| Charging dock (basic) | `hw-dock` | MVP | *Safety.* Contacts + alignment. |
| Charging dock (auto-empty) | `hw-dock` | P2 | |
| Charging dock (mop wash/dry) | `hw-dock` | P2 | |
## Planned software (later phase)
Foundational software (URDF, sim, SLAM, Nav2, coverage, teleop, sensors) is already covered by
the active RFCs. Remaining, later-phase work:
| Module | ID | Phase | Notes |
|---|---|---|---|
| Diagnostics / telemetry | `sw-diagnostics` | P2 | Health, logs. |
| Regression / CI tests | `sw-regression-tests` | P2 | Sim-based tests gating PRs. |
| Home Assistant integration | `sw-homeassistant` | P2 | MQTT / HA entity, map, control. |
| App runtime layer | `sw-app-runtime` | P3+ | ROS2-agnostic app sandbox. North star. |
| Web UI / dashboard | `sw-webui` | P3+ | Local control + map view. |
## Non-engineering contributions (also wanted)
| Track | Phase | Notes |
|---|---|---|
| 3D-print validation | MVP | Confirm parts print cleanly on common FDM printers. |
| Real-home testing | MVP/P2 | Build and report on real floors. |
| Docs / build guides | MVP | Turn working modules into step-by-step instructions. |
| Posts / videos / demos | ongoing | Content that grows the project (highly valued). |
| SOTA research | ongoing | Best-in-class prior art per module (part of each RFC). |
+159
View File
@@ -0,0 +1,159 @@
# OOMWOO ROS2 Software Interfaces
> Status: DRAFT. This is the shared software contract for simulation-first
> contributions. It reflects the current `urdf-gazebo-sim` package and should be
> updated whenever a module needs a new public topic, service, action, frame, or
> parameter.
## Purpose
OOMWOO software modules are meant to be swappable. A contributor should be able
to build `clean-and-map`, `nav-localize`, `recovery-safety`, `dock-cycle`, or
`cleaning-jobs` without depending on another module's private implementation.
This document defines the public ROS2 surface area those modules can share while
the hardware is still evolving. It is not a final hardware API.
## Naming rules
- Public names below are shown as root topics, for example `/scan`. Launch files
and node configs may use relative names such as `scan` when they resolve to
the same root topic in the default launch.
- Use REP-103 frames and SI units.
- Prefer standard ROS2/Nav2 message types before adding custom OOMWOO messages.
- If a module introduces a new public interface, document the producer, consumer,
message type, QoS expectation, and failure behavior in its README and update
this file.
- Simulation-only details, such as Gazebo collision entity names, must not leak
into cross-module contracts unless they are explicitly marked as simulation
diagnostics.
## Frames
| Frame | Owner | Meaning |
|---|---|---|
| `map` | SLAM/localization | Global map frame used by SLAM, AMCL, Nav2, and saved maps. |
| `odom` | Base odometry | Locally continuous odometry frame. |
| `base_footprint` | Robot description / odometry | Planar base frame for navigation. |
| `base_link` | Robot description | Main robot body frame. Hardware modules should reference this once geometry is frozen. |
| `base_scan` | Robot description | 2D LiDAR frame. |
Open decision: `base_link` origin, reference plane, robot diameter, and height
envelope are still defined in `ARCHITECTURE.md`.
## Baseline Topics
These topics are provided by the current Gazebo simulation or standard Nav2/SLAM
bringup and should be treated as the MVP baseline.
| Topic | Type | Direction | Producer | Consumers |
|---|---|---|---|---|
| `/cmd_vel` | `geometry_msgs/msg/Twist` | Command | Teleop, Nav2 velocity smoother, recovery nodes | Gazebo diff-drive / base controller |
| `/odom` | `nav_msgs/msg/Odometry` | State | Gazebo odometry / base controller | SLAM, AMCL, Nav2, recovery and job logic |
| `/tf` | `tf2_msgs/msg/TFMessage` | State | Robot state publisher, odometry, SLAM/localization | All pose-aware modules |
| `/joint_states` | `sensor_msgs/msg/JointState` | State | Gazebo joint state publisher / hardware base | Robot state publisher, diagnostics |
| `/scan` | `sensor_msgs/msg/LaserScan` | Sensor | 2D LiDAR / Gazebo LiDAR | SLAM, AMCL, Nav2 costmaps, wall following |
| `/map` | `nav_msgs/msg/OccupancyGrid` | State | SLAM or map server | Nav2, cleaning, zones, visualization |
| `/bumper_left` | `ros_gz_interfaces/msg/Contacts` in Gazebo | Sensor | Gazebo left contact sensor | Recovery, safety, clean-and-map obstacle handling |
| `/bumper_right` | `ros_gz_interfaces/msg/Contacts` in Gazebo | Sensor | Gazebo right contact sensor | Recovery, safety, clean-and-map obstacle handling |
### Bumper events
The current simulation publishes raw Gazebo contact messages:
- Message type: `ros_gz_interfaces/msg/Contacts`
- Contact list field: `contacts`
- Per-contact fields: `collision1`, `collision2`, `positions`, `normals`,
`depths`, `wrenches`
Consumers should treat `len(msg.contacts) > 0` as a bumper event after filtering
out ground-plane contacts. Do not read a `collisions` field; that belongs to the
single-contact message type and is not what the bridge publishes.
Hardware may eventually replace raw Gazebo contacts with a normalized bumper
message. Until that decision is made, module submissions should isolate the
Gazebo-specific parsing behind a small adapter.
## Nav2 Interfaces
Modules should reuse Nav2 actions and servers where possible.
| Interface | Type | Typical consumer |
|---|---|---|
| `/navigate_to_pose` | `nav2_msgs/action/NavigateToPose` | `nav-localize`, `cleaning-jobs`, `dock-cycle` |
| `/navigate_through_poses` | `nav2_msgs/action/NavigateThroughPoses` | Coverage, room jobs, dock approach |
| Nav2 behavior server | `spin`, `backup`, `drive_on_heading`, `wait` behaviors | Recovery and local fallback logic |
| Costmaps | Nav2 local/global costmap topics | Obstacle handling, zones, diagnostics |
| Map saver | Nav2 map saver service/CLI | `clean-and-map`, `nav-localize` |
If a module needs to command motion directly, it must define how it arbitrates
with Nav2 and recovery nodes so two nodes do not fight over `/cmd_vel`.
## Module Contracts
| Module | Inputs | Outputs / public behavior |
|---|---|---|
| `urdf-gazebo-sim` | `/cmd_vel` | Publishes `/scan`, `/odom`, `/tf`, `/joint_states`, `/bumper_left`, `/bumper_right`; provides worlds and robot description. |
| `clean-and-map` | `/scan`, `/odom`, `/tf`, bumper events, optional Nav2 actions | Drives first-pass coverage, produces a complete map, defines a done condition, saves map artifacts. |
| `nav-localize` | Saved map, `/scan`, `/odom`, `/tf`, Nav2 bringup | Provides known-map navigation, relocalization, and map-resume behavior. |
| `recovery-safety` | Bumper events, future cliff/wheel-drop/pickup/e-stop signals, Nav2 failures | Stops or gates motion, runs bounded recoveries, publishes clear pause/error status. |
| `floor-care` | `/scan`, map/coverage context, future surface sensor | Provides wall/edge following, surface classification, and mop actuator decisions. |
| `cleaning-jobs` | Saved map, zones, coverage progress, battery/bin/mop status, Nav2 actions | Provides start/pause/resume/cancel/status job behavior suitable for a future Home Assistant layer. |
| `dock-cycle` | Nav2/localization, dock marker, battery/service state | Provides undock, return-to-dock, precise docking, recharge/service completion, and find-dock fallback. |
| `live-robot-bringup` | Hardware drivers, same logical topics | Validates that hardware exposes the same public interfaces as the simulation. |
## Status and Errors
The final robot status API is still open. Until it is selected, modules that
need status reporting should document:
- `state`: short machine-readable state, for example `cleaning`, `recovering`,
`paused`, `docked`, or `error`
- `reason_code`: stable machine-readable reason, for example `BUMPER_STUCK`,
`LOCALIZATION_LOST`, or `LOW_BATTERY`
- `message`: human-readable explanation
- `recoverable`: whether a resume command is expected to work
- `source`: module name that produced the status
Open decision: choose the transport and type for cross-module status, likely a
standard diagnostic message or a small OOMWOO-specific message package.
## QoS and Parameters
- `use_sim_time` should be true in simulation launch files.
- Sensor streams such as `/scan` should use sensor-data QoS where configurable.
- `/map` and saved-map metadata should be available to late joiners where the
producer supports transient-local durability.
- Command topics should use small queues and should fail safe: stale commands
must not keep the robot moving.
## Validation Checklist
A module submission that depends on the MVP simulation should document how to
check the interfaces it uses. At minimum:
```bash
ros2 topic list
ros2 topic echo /scan --once
ros2 topic echo /odom --once
ros2 topic echo /bumper_left
ros2 topic echo /bumper_right
ros2 run tf2_tools view_frames
```
For Nav2-based modules, also document how to send a `NavigateToPose` goal and
how to confirm `/cmd_vel` arbitration is safe.
## Miscellaneous
- PR your packages into the official distribution [makerspet/oomwoo-install](https://github.com/makerspet/oomwoo-install)
- put your ROS2 packages under `/ros_ws/src` (don't create another colcon workspace under `~/`)
- follow conventions of being able to select a robot package using `kaia config robot.model oomwoo_one`, see [tutorial](https://makerspet.com/blog/simulate-oomwoo-one-robot-vacuum-in-gazebo-with-ros-2/)
## Open Decisions
- Final hardware bumper/cliff/wheel-drop message shape.
- Robot-wide status/error message type and topic.
- Battery, dust-bin, mop, and dock service state interfaces.
- Localization-confidence interface for relocalization and kidnap detection.
- Job action/service API for start, pause, resume, cancel, and status.
+169
View File
@@ -0,0 +1,169 @@
# Write Your First OOMWOO ROS 2 Package: Cover the Floor While Mapping
> *Draft for makerspet.com (WordPress / Gutenberg).* Post 2 of 2. Builds on Post 1
> (*Simulate the oomwoo-one Robot Vacuum in Gazebo with ROS 2*). Here you'll write a small
> *pure-ROS 2* package that drives `oomwoo-one` on a coverage path *while* SLAM maps the
> room, and launch it all with one `ros2 launch`.
This is the "hello world" of developing for OOMWOO. It's deliberately simple — a reactive
"drive forward, turn when blocked" coverage that, combined with SLAM, maps and roughly covers
a room. Proper boustrophedon coverage is the [clean-and-map
RFC](https://github.com/makerspet/oomwoo/tree/main/contributions/clean-and-map); this teaches
you the mechanics of writing and launching an OOMWOO node.
## Prerequisites
The dev environment from *Post 1* (the `makerspet/oomwoo:jazzy-dev` container running, with
`kaia config robot.model oomwoo_one` set). Everything below runs *inside the container*.
## 1. Create a ROS 2 package
```
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python oomwoo_coverage --dependencies rclpy sensor_msgs geometry_msgs
```
## 2. Write the coverage node
Create `~/ros2_ws/src/oomwoo_coverage/oomwoo_coverage/coverage_node.py`:
```python
import math
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
class Coverage(Node):
"""Drive forward; when the path ahead is blocked, turn until it clears.
Combined with SLAM, this bounces around a room and maps it."""
def __init__(self):
super().__init__('coverage')
self.pub = self.create_publisher(Twist, 'cmd_vel', 10)
self.create_subscription(LaserScan, 'scan', self.on_scan, 10)
self.clear = True
self.turn_dir = 1.0
self.create_timer(0.1, self.tick) # 10 Hz control loop
def on_scan(self, msg):
n = len(msg.ranges)
if n == 0:
return
# Check the forward +/- 25 deg sector (forward = scan index 0 for this LiDAR;
# adjust 'center' if your scan's zero points elsewhere).
sector = int(math.radians(25) / msg.angle_increment)
idxs = [(i) % n for i in range(-sector, sector + 1)]
fwd = [msg.ranges[i] for i in idxs
if msg.range_min < msg.ranges[i] < msg.range_max]
was_clear = self.clear
self.clear = (min(fwd) > 0.35) if fwd else True
if was_clear and not self.clear:
self.turn_dir *= -1.0 # alternate turn direction each time we hit something
def tick(self):
cmd = Twist()
if self.clear:
cmd.linear.x = 0.20 # m/s forward
else:
cmd.angular.z = 0.8 * self.turn_dir # rad/s turn until clear
self.pub.publish(cmd)
def main():
rclpy.init()
node = Coverage()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
```
## 3. Register the node
In `~/ros2_ws/src/oomwoo_coverage/setup.py`, add the console script:
```python
entry_points={
'console_scripts': [
'coverage = oomwoo_coverage.coverage_node:main',
],
},
```
## 4. Add a launch file (sim + SLAM + your node, in one command)
Create `~/ros2_ws/src/oomwoo_coverage/launch/coverage.launch.py`:
```python
import os
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
gazebo = IncludeLaunchDescription(PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('kaiaai_gazebo'),
'launch', 'world.launch.py')))
nav = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('kaiaai_bringup'),
'launch', 'navigation.launch.py')),
launch_arguments={'use_sim_time': 'true', 'slam': 'True'}.items())
coverage = Node(package='oomwoo_coverage', executable='coverage',
name='coverage', parameters=[{'use_sim_time': True}])
# give Gazebo + SLAM ~12 s to come up before the robot starts moving
return LaunchDescription([gazebo, nav, TimerAction(period=12.0, actions=[coverage])])
```
Reference the launch folder in `setup.py` `data_files` so it installs:
```python
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
```
(add `import os` and `from glob import glob` at the top of `setup.py`).
## 5. Build and run
```
cd ~/ros2_ws
colcon build --packages-select oomwoo_coverage
source install/setup.bash
ros2 launch oomwoo_coverage coverage.launch.py
```
Gazebo and RViz open, SLAM starts, and after ~12 s oomwoo-one begins driving itself —
forward until it's blocked, then turning — while the map fills in. Open RViz
(`ros2 launch kaiaai_bringup monitor_robot.launch.py use_sim_time:=true` in another shell) to
watch the map grow.
## 6. Save the map
```
ros2 run nav2_map_server map_saver_cli -f ~/maps/map
```
## What you just learned
- created a ROS 2 package, wrote a node that *subscribes to `/scan` and publishes `/cmd_vel`*,
- combined *your code + SLAM* in a single `ros2 launch`,
- produced a real map from an autonomous run.
That's the whole loop of developing for OOMWOO. From here, the natural next step is *real
coverage path planning* (boustrophedon, wall-following, frontier exploration) — which is
exactly the [clean-and-map RFC](https://github.com/makerspet/oomwoo/tree/main/contributions/clean-and-map).
Pick it up (or another module) from the [Requests for
Contributions](https://github.com/makerspet/oomwoo#requests-for-contributions), and come build
with us on [Discord](https://discord.gg/3y2JKz5T25).
+127
View File
@@ -0,0 +1,127 @@
# Simulate the oomwoo-one Robot Vacuum in Gazebo with ROS 2
> *Draft for makerspet.com (WordPress / Gutenberg).* Post 1 of 2: set up the OOMWOO
> software dev environment and drive `oomwoo-one` in simulation — no robot required.
> (Post 2 teaches you to write your own OOMWOO code.)
[OOMWOO](https://github.com/makerspet/oomwoo) is an open-source robot vacuum you build
yourself. *oomwoo-one* is the first model. This tutorial gets its ROS 2 simulation running
in *Gazebo* so you can develop mapping, navigation, and cleaning behaviours with *no
hardware* — everything runs in Docker on *Ubuntu or Windows*.
You'll get: SLAM mapping, autonomous Nav2 navigation, manual driving, and bumper sensors —
the same interfaces the real robot will expose.
## Prerequisites
- *Docker* — Docker Desktop on Windows/macOS, Docker Engine on Linux.
- *An X server* for the GUI windows (Gazebo, RViz):
- *Windows:* [VcXsrv](https://sourceforge.net/projects/vcxsrv/) (XLaunch).
- *Linux:* native X — nothing to install.
- No physical robot.
## 1. Start the X server (Windows only)
Launch *XLaunch* (from VcXsrv) and accept the defaults *except*:
> On the *"Display settings"* page, set *Display number = `0`* (not `-1`).
> The Docker container connects to `host.docker.internal:0.0`, so the display number *must
> be 0* or no GUI windows will appear.
Also tick *"Disable access control"* on the "Extra settings" page so the container can
connect. Finish the wizard — a tiny X icon appears in your tray.
On *Linux*, instead allow local Docker to reach your X server:
```bash
xhost +local:docker
```
## 2. Pull the OOMWOO Docker image
```
docker pull makerspet/oomwoo:jazzy-dev
```
## 3. Start the container
*Windows (PowerShell):*
```powershell
docker run --name makerspet -it --rm -v c:\maps:/root/maps -p 8888:8888/udp -p 5555:5555/udp -e DISPLAY=host.docker.internal:0.0 -e LIBGL_ALWAYS_INDIRECT=0 --add-host=host.docker.internal:host-gateway makerspet/oomwoo:jazzy-dev
```
(`DISPLAY=...:0.0` matches the XLaunch *display 0* from step 1.)
*Ubuntu / Linux:*
```bash
docker run --name makerspet -it --rm -v ~/maps:/root/maps -p 8888:8888/udp -p 5555:5555/udp -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --network host makerspet/oomwoo:jazzy-dev
```
Need more terminals into the same container? Open another PowerShell/terminal and run:
```
docker exec -it makerspet bash
```
## 4. Select the oomwoo-one model
Inside the container:
```
kaia config robot.model oomwoo_one
```
## 5. Launch the Gazebo world
```
ros2 launch kaiaai_gazebo world.launch.py
```
A Gazebo window opens with oomwoo-one in a living-room world.
## 6. Start SLAM mapping
In a new container shell (`docker exec -it makerspet bash`):
```
ros2 launch kaiaai_bringup navigation.launch.py use_sim_time:=true slam:=True
```
## 7. Open the RViz monitor
```
ros2 launch kaiaai_bringup monitor_robot.launch.py use_sim_time:=true
```
Watch the map build as the robot moves.
## 8. Drive it manually
```
ros2 run kaiaai_teleop teleop_keyboard
```
Use the keyboard to drive oomwoo-one around and fill in the map.
## 9. Autonomous navigation
In RViz, click *"Nav2 Goal"* and click-drag a destination — oomwoo-one plans a path and
drives there on its own.
## 10. Check the bumper sensors
```
ros2 topic echo /bumper_left
ros2 topic echo /bumper_right
```
Drive into a wall and watch the left/right contact events fire.
## 11. Save your map
```
ros2 run nav2_map_server map_saver_cli -f ~/maps/map
```
On Windows the map lands in `c:\maps`; on Linux in `~/maps`.
## What's next
You now have a full oomwoo-one simulation: SLAM, Nav2, teleop, and bumpers, exactly the
interfaces the real robot exposes. In *Post 2* you'll write your *first OOMWOO ROS 2
package* — a node that drives a coverage path *while* mapping — and launch it with
`ros2 launch`.
Want to help build OOMWOO? Grab a module from the [Requests for
Contributions](https://github.com/makerspet/oomwoo#requests-for-contributions) or say hi on
[Discord](https://discord.gg/3y2JKz5T25).
+332
View File
@@ -0,0 +1,332 @@
# OOMWOO Design Document
> *Working design doc.* This accumulates research-backed design decisions before
> they're split into per-module [RFCs](../contributions) and the [RFC backlog](RFC_BACKLOG.md), and/or migrated into
> the [README](../README.md). A condensed version of §1 already lives in the
> README's [Design research](../README.md#design-research) section. Expect this to
> grow as remaining components are researched.
---
## 1. Design research — what makes vacuum users happy
We reviewed the 20252026 consumer robot vacuum landscape (global + China-sourceable
brands, budget → flagship) across RTINGS, VacuumWars, Reddit r/robotvacuums, and
reviewer blogs, then adversarially fact-checked the key claims. The point: copy the
solutions that correlate with happy users, skip the ones that need commercial scale.
### Suction — a sourcing problem, not an engineering one
Real-world cleaning does *not* track advertised suction (Pa). ~$500 mid-tier
models beat flagships in pickup tests. A moderate *sealed* sourced motor + a good
brush + a *tight airflow seal* matches flagship cleaning — *no custom-molded
impeller needed.* Airflow sealing (bin/fan/brush seams) matters more than raw Pa.
[(source)](https://www.thesmarthomehookup.com/the-best-300-600-robot-vacuums-they-beat-the-flagships/)
### Navigation & "never gets stuck" — the #1 user pain, hardest to replicate
Best obstacle avoidance comes from *sensor fusion* (LiDAR + a floor-level 3D-ToF
or RGB camera + AI object recognition), not any single sensor. LiDAR is structurally
*blind below its ~10 cm turret*, which is exactly why robots eat cables and socks.
The Eufy Omni S2 ($1,599) was the only model in one test to pass all 24 obstacles —
and it has the full vision stack. *Never-stuck is commercial-scale.*
- *For OOMWOO:* v1 leans on the *bumper* for low/LiDAR-invisible obstacles (this
is already how the [clean-and-map RFC](../contributions/clean-and-map) handles it).
Camera + AI vision avoidance is a *later / experimental* goal, not an MVP promise.
Don't position OOMWOO as out-navigating commercial flagships; position it as an
open platform to *experiment* with navigation and vision.
[(source)](https://vacuumwars.com/best-robot-vacuums-with-obstacle-avoidance/)
### Brush — anti-tangle is what users notice
Rubber beats bristle, and a *tapered, one-side-mounted roller* resists hair-wrap
best (hair tangling is a top complaint). Easy to 3D-print or source compatible.
### Mop — dual-spinning is the replicable sweet spot
Performance ladder: flat drag pad (worst) → *dual spinning pads* (mid) →
self-washing roller (best). But the roller mop's "better stains / less residual
water" edge was *refuted* under fact-checking — it's overstated. A 3D-printed
*dual-spinning* mop is competitive and DIY-able; *skip the self-washing roller*
(and its multifunction wash/dry dock) for now.
[(source)](https://vacuumwars.com/robot-vacuum-mop-systems/)
### Dock — basic is DIY-able, full-service is not
A *basic charging dock* is well within reach (print the housing; source contacts +
adapter + IR beacon). *Auto-empty / mop-wash / hot-dry all-in-one docks* are
commercial-scale — defer, or use an off-the-shelf corded vac for emptying.
### Cloud-free / local control — the real differentiator
[Valetudo](https://github.com/Hypfer/Valetudo) gives cloud-free MQTT/REST local
control across ~10 brands. *Dreame* is the most rootable (≈16 models) and the
safest donor to study. Cloud-free local operation is OOMWOO's positioning advantage.
### Well-loved models worth studying
Eufy Omni S2 (obstacle avoidance), Narwal Flow (roller mop), Ecovacs Deebot T90 Pro
Omni (~$499 all-rounder), Dreame X40 Ultra (dual-spinning mop; Dreame = best donor).
> *Caveats:* the top-level dimensions (suction-decoupling, sensor-fusion, mop
> ladder) are primary-source and verified. Per-model rankings are *directional*,
> from single-run reviewer tests. Rootability is *per hardware revision* —
> re-verify any specific donor unit before buying to root.
---
## 2. Print vs source strategy
*Rule of thumb: print geometry, source mechanisms and wear items.* Anything with a
gearbox, encoder, rubber compound, spring, pump, or bearing is precision you can buy
for a few dollars; anything custom-shaped that mates with the OOMWOO chassis, print.
| Component | Source or 3D print | Why / how |
|---|---|---|
| *Driving wheel assemblies* | *Source (whole module)* | Complete drive modules (gearmotor + encoder + suspension + rubber tire). 3D print at most an adapter bracket. Why? Requires advanced skill - possibly SLA for gearbox, FDM TPU tire. The #1 "don't print it" part. |
| *Universal / caster wheel* | *Print* or source wheel/ball caster. | Likely a simple passive swivel, possibly TPU. |
| *Side brush assembly* | *Hybrid* | Source brush + small gearmotor; print the mount. Fit a *common replaceable brush*. Fixed (not extendable) for v1. |
| *Main brush* | *Source / hybrid* | Tapered rubber anti-tangle roller in a *common wear-part size*; source compatible, or print core + rubber. |
| *Bumper* | *Hybrid* | Print floating shroud; source lever microswitches + return springs. |
| *Dust bin / water tank* | *Print body + source guts* | Print custom body (mates airflow); source filter (common HEPA size), gasket (or TPU print), latch spring. Water tank adds a sourced *pump + solenoid valve + tubing*. |
| *Mop lift* | *Hybrid (P2)* | Print cam/linkage; source a small *servo or geared motor*. |
| Mop disposable cloths | *Source* | Source (easier) or DIY sew. |
| Mop dryer | *Source* | Source the mop dryer. |
| *Enclosure / top shell* | *Print* | Custom cosmetic/structural; no off-the-shelf equivalent. Design for splitting to fit common print beds. |
| *Dock (basic charge)* | *Print housing + source contacts* | Source *pogo pins / spring contacts / magnets* (magnets can carry [10 A](https://xdaforums.com/t/home-made-pogo-pin-charging-dock.2019847/)) + wall adapter + IR-beacon LEDs. Plenty of [DIY precedent](https://www.instructables.com/Roamer-the-Self-Charging-Companion-Robot/). |
| *Auto-empty dock* | *3D print enclosure + source bin/fan* | Needs its own fan + bin (commercial-scale). Off-the-shelf corded vac bolted to a printed dock is the DIY path. |
| *Mop dock* | *3D print enclosure + source water tanks/hookups* | Needs its own fan + bin (commercial-scale). Off-the-shelf corded vac bolted to a printed dock is the DIY path. |
| Battery, LiDAR, motors, PCB, fasteners, bearings, gaskets | *Source* | Standard sourced parts (custom PCB + LiDAR aside). |
| Single Board Computer | *Source* | Raspberry Pi 5 4GB or better for first model. |
| Input/Output board | *Custom* | No DIY-vacuum I/O PCBs I'm aware of. I'll design a custom PCB for sensors and motor drivers. |
| Cameras, sensors, LiDAR | *Source* | Color + distance cameras for top-tier obstacle avoidance. IR cliff, side proximity sensors. Ultrasonic carpet sensor. |
*Sourcing strategy:* deliberately spec sourced wear parts (brushes, filters, wheel
modules) in *common, abundant sizes* so users buy cheap "universal" / Roomba-style
replacements anywhere. A selling feature *and* less inventory to stock.
---
## 3. Feature decisions
### 3.1 Extendable side brush — *fixed for v1*
The extendable arm (e.g. Roborock FlexiArm) is a *genuinely loved* feature — best
corner-cleaning scores and strong reviews
[(source)](https://vacuumwars.com/vacuum-wars-best-robot-vacuums/). But it's a
mechanically complex actuated mechanism. A well-placed *fixed* side brush captures
most of the corner benefit at a fraction of the complexity. Extendable is a great
*P2+ community mod*, not an MVP requirement.
### 3.2 Body shape — *round*
D-shape cleans corners/edges better, but the real-world advantage is "smaller than
most people expect," and a well-engineered round robot with good side brushes
performs as well or better in most homes
[(source)](https://www.ecovacs.com/us/blog/round-vs-square-robot-vacuum). Round wins
for a DIY/printable platform:
1. Simpler to design, print, and seal.
2. Navigates better — rotates in place, backs out the way it came (D-shape
complicates every nav/recovery RFC).
3. Natural fit for the spinning 2D LiDAR turret.
4. Matches the round teardown reference we're porting.
5. Corners are better solved by the side brush (later extendable) than by body shape.
*Decision: round body + fixed side brush now, extendable side brush later.*
---
## 4. Compute (SBC)
*v1: Raspberry Pi 5 (4 GB).* Chosen to onboard the large Raspberry Pi community —
the biggest contributor wedge. Runs ROS2 + LiDAR SLAM + Nav2 comfortably. No on-board NPU.
- *ML vision option — Hailo AI HAT.* Add the RPi M.2 AI Kit (Hailo-8L, ~13 TOPS) for
real-time camera obstacle detection: keeps the entire RPi ecosystem advantage *and*
gains an NPU. *Check the board-stack height* — a vacuum is only ~10 cm tall and
the M.2 HAT adds Z. Evaluate alternatives (Coral USB/M.2 accelerator, or lighter
CPU-only models) against the height budget.
- *Later: Rockchip RK3588 / RK3576.* Orange Pi 5, Radxa Rock 5B, Banana Pi CM5 —
built-in *6 TOPS NPU*, RKNN toolkit, YOLO ~65 ms/image. Cheaper and integrated, but
driver / ROS2 / kernel maturity *lags RPi*, so it's a *later* move, not the
community-onboarding one.
---
## 5. I/O board (custom, JLCPCB)
No off-the-shelf DIY-vacuum I/O board exists, so we design one. It carries an *MCU
running micro-ROS* that talks to the SBC over a fast serial / USB link: the SBC does
ROS2 / SLAM / nav / vision; the board does real-time motor + sensor I/O.
*MCU:* STM32G070RBT6 (LQFP64, ~$0.93 @ 100 pcs) — cheap, lots of peripherals.
*Pin-budget risk:* the full peripheral set below is a lot for 64 pins. Do a
pin-allocation spreadsheet before committing. Offload the *BLDC fan to an external
ESC* (1 PWM pin instead of in-MCU FOC) to save pins and complexity. If still tight,
consider the STM32G0B1RET6 (same family, more peripherals/RAM) or a 100-pin part.
*LiDAR (3irobotix CRL-200S):* wires to the I/O board. The board *drives the LiDAR
motor* (MOSFET + closed-loop speed control using the LiDAR's RPM feedback) and *passes
raw LiDAR data through the MCU to the SBC* over the fast serial link. *Confirm the MCU
UART bandwidth handles the CRL-200S data rate.*
Cross-checked peripheral list (your running list + `[+]` = additions to consider):
*Sensors*
- 2D LiDAR (CRL-200S) — motor-driven + data passthrough to SBC
- IR cliff / proximity / docking
- Bumper micro-switches (+ optional optical/IR bumper)
- Wheel encoders
- Carpet ultrasonic sensor
- Color camera → *connects to the SBC's CSI/USB, not this board*
- VL53L7CX distance sensor (I²C)
- Water tank level (full/empty)
- Dust bin present / lid open-closed
- Battery level / fuel gauge
- Dock-connected / charge sense
- IMU
- `[+]` Wheel-drop / lift sensor (robot picked up) — distinct from cliff
*Motor drivers*
- Main wheels ×2
- Main brush
- Side brush(es)
- `[+]` *Mop pad spin motor(s)* — for dual-spinning pads (you listed mop *lift* but not *spin*)
- Mop lift servo
- Water pump (low-side MOSFET)
- Vacuum fan (BLDC) — via *external ESC* (recommended)
- LiDAR motor (MOSFET, closed-loop)
*Power*
- Battery connector
- Charging circuit (charge-controller IC)
- Dock contacts
- BMS interface
- Current sense (per-rail and/or per-motor for stall / tangle detection)
- DC-DC converters (5 V for SBC, 3.3 V logic, motor rails)
- Power on/off button + soft-latch power circuit
- `[+]` Protection: reverse-polarity, over-current fuse / eFuse, inrush limiting
*Audio / UI*
- Speaker amp + connector (audio in from the SBC)
- Mic placeholder
- Power / status LEDs
- Buttons (power, dock, clean)
- `[+]` Buzzer (cheap fallback if the speaker amp is deferred)
*Host link:* USB or high-speed UART between MCU and SBC, carrying micro-ROS *and*
the LiDAR passthrough — confirm bandwidth covers both.
> *Scope note:* the *wash/dry dock has its own controller* (ESP32 + WiFi) for its
> pumps / heater / fan / water-level. Those are *not* on the robot I/O board.
---
## 6. Electrical / sensor BoM sketch
Rough *robot* BoM at prototype / low-qty China-sourcing prices (compresses at volume).
Excludes the dock.
| Item | Qty | ~USD | Notes |
|---|---|---|---|
| Drive wheel modules | 2 | 1227 | sourced complete module |
| Caster wheel | 1 | 03 | print or ball caster |
| Suction blower (BLDC) | 1 | 820 | sealed sourced motor |
| Main brush + motor | 1 | 512 | tapered rubber roller |
| Side brush + motor | 12 | 38 | |
| Mop spin motor(s) + pads | 12 | 615 | mopping models |
| Water pump + valve + tubing | 1 | 410 | mopping models |
| Mop lift servo | 1 | 26 | mopping models |
| Battery pack (~14.8 V Li-ion) + BMS | 1 | 1530 | safety review |
| LiDAR (CRL-200S / LDS) | 1 | 3040 | your cost |
| VL53L7CX ToF | 1 | 815 | obstacle detection |
| Color camera | 1 | 515 | to SBC |
| IMU | 1 | 25 | |
| IR cliff / proximity | 34 | 38 | |
| Bumper micro-switches | 23 | 13 | |
| Ultrasonic carpet sensor | 1 | 25 | |
| Speaker + amp, mic, LEDs, buttons | — | 38 | |
| Custom I/O PCB (JLCPCB assembled, low qty) | 1 | 1540 | |
| Wiring, connectors, fasteners, magnets, gaskets, filter | — | 1225 | |
| Printed parts (filament) | — | 515 | |
| *Robot subtotal (sourced parts)* | | *~$130270* | excludes SBC |
| Raspberry Pi 5 4 GB | 1 | ~60 | |
| Hailo AI HAT (optional, premium vision) | 1 | ~70 | |
---
## 7. Water system
*Robot:* an onboard *clean-water tank* (printed) → *solenoid diaphragm pump* (what
commercial units use) → mop head. For spinning pads, dirty water stays in the pads until
the dock washes them.
*Dock tiers (where the water complexity lives):*
- *Auto-empty:* dock fan + bin/bag suck the robot's dustbin out through a sealed port.
The off-the-shelf-corded-vac approach works here.
- *Wash + dry:* *clean tank + dirty tank* (printed) + *two pumps* + a wash
tray/roller + a *hot-air blower (heater + fan)*. Wash *must* include hot-air dry —
wash-without-dry breeds mildew/odor. Needs its *own ESP32 + WiFi controller*.
- *Plumbing hookup:* offer as an *option* on the premium dock (pump + supply/drain
lines + valve); default to tank-based (direct plumbing needs pro install). Skip exotic
water-recycling (e.g. silver-ion distillation).
- DIY parts are cheap/common: 12 V diaphragm or peristaltic pumps, solenoid valves,
silicone tubing, float / capacitive level sensors.
---
## 8. Budget target
*Target: ~$100200 sourced parts + Raspberry Pi 5 4 GB*, aiming at the capability of a
mid-range ($500600) commercial vacuum.
- *Verdict: realistic for the mechanicals + core sensors* at the lowmid end, and it
compresses at volume. But *mopping + premium obstacle detection* (ToF + color camera
+ an NPU accelerator) are exactly the line items that push toward / past $200 — the
Hailo HAT alone is ~$70. So $100200 holds for a capable vacuum; "premium vision now"
wants a +$70-ish allowance (or defer the NPU to the Rockchip generation).
- *Sanity check vs commercial:* a $500600 LiDAR vacuum has roughly a *$120180 FOB
BoM at 5,000 MOQ*. Our low-qty numbers are coherent — we trade *no tooling/molds*
(3D print) for *higher per-part cost* (no volume).
- *Set builder expectations honestly:* total DIY spend (kit + RPi 5 + LiDAR + margin)
lands *above* a commercial unit's BoM. The value proposition is *openness, local
control, and hackability — not beating Roborock on price.*
---
## 9. Product lineup — shared base, three dock tiers
One robot base, three dock tiers, released in order:
1. *Basic charging dock* (first release — simplest, MVP-aligned).
2. *Auto-empty dock* (dust).
3. *Auto-empty + mop-wash + hot-dry dock* (the full-service tier).
Notes:
- Mirrors how commercial brands segment (same robot, dock tiers) and fits the
swappable-module philosophy.
- The *mop hardware (spinning pads + onboard water tank) is an add-on module* on the
shared base — only the mopping models carry it; the base is otherwise constant.
- The *wash+dry dock is almost its own mini-product* (pumps, heater, tanks, ESP32).
Correctly the last and hardest deliverable after the robot itself.
- Skip a wash-*only* dock — drying is mandatory (odor).
---
## 10. Obstacle detection strategy (premium hardware + community ML)
Targets the #1 user pain (getting stuck / eating cables). Strategy: *premium hardware
now, ML maturity via community contribution over time.*
- *Sensors:* *VL53L7CX* multizone ToF (8×8, *90° FoV*, ~350 cm — wider FoV than the
L5CX's 63°, better coverage) *+ color camera.* The ToF alone detects the low / small /
cliff objects the *LiDAR is blind to*, so v1 gets real "doesn't eat cables" value
*before* any ML matures — de-risks the feature.
- *ML:* the *camera + model* is where the NPU matters (Hailo HAT now, Rockchip NPU
later); real-time RGB detection won't run well on the RPi 5 CPU.
- *Community-labeled household-obstacle dataset* is a legitimately novel contribution
track — every contributor's home is training data. Treat it as a first-class
contribution track alongside the RFCs; it doubles as community-building.
---
## 11. Still to research / open decisions
- *Battery:* chemistry (Li-ion 3S/4S?), specific cells + BMS, charge profile — *safety review*.
- *BLDC fan ESC:* select an off-the-shelf ESC vs in-MCU drive.
- *Filter:* pick a common, abundant filter size as the interface standard.
- *Gasket sourcing* vs TPU printing for airflow seals.
- *Dock docking signal:* IR beacon protocol / fiducial / reflective marker.
- *Fastener / heat-set insert standard* (ties to ARCHITECTURE §5.2).
- *Confirm:* MCU pin budget, host-link bandwidth (micro-ROS + LiDAR passthrough), Hailo stack height.
- Remaining mechanical parts not yet covered above.