From ece056ca1acd32320b149f1f1fee69b9c53d7035 Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Sun, 12 Jul 2026 22:41:47 +0800 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20roadmap=20=E2=80=94=20north=20star?= =?UTF-8?q?=20swervebot=20autonomous=20waypoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The charters-and-gates principle applied at system level: the robot application is the consumer of the family; work queues behind gaps the milestone exposes. Gap walk across all repos: Phase 0 platform decision (PocketBeagle is armv7 — the seqlock primitives require lock-free 64-bit atomics; aarch64 SBC recommended) + app skeleton rework (standalone application, never umbrella-pinned); Phase 1 hardware teleop (steering-servo driver is the likely xmDriver gap; safety envelope first); Phase 2 estimation (odometry model, MEKF L0-L5 ladder on robot data); Phase 3 waypoint autonomy (messaging's first production composition, lineage-gated actuation, sim-first); Phase 4 tuning/soak/the end-to-end observability claim. Plus the 70/20/10 portfolio, the four-question test, the standing debt lane, and the explicitly gate-deferred list (iceoryx2, Zenoh, EventHub, reserved taxonomy rows). --- ROADMAP.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..7010e90 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,60 @@ +# XMotion Roadmap — north star: swervebot autonomous waypoints + +- Status: Active (reviewed when a gap closes, not on a calendar) +- Operating rule: the family's charters-and-gates principle applied at system level — **the robot application is the consumer of the family.** Work queues behind a gap this milestone exposes; nothing system-level is built without one. +- Portfolio: ~70% milestone path · ~20% debt-and-lessons (the standing remediation lists) · ~10% exploration, no justification required. +- The four-question test for any proposed task: which milestone gap does it close? who is the named consumer? what measured claim proves it done? is it the smallest step that retires the largest unknown? + +## The milestone (measured, falsifiable) + +**Swervebot drives autonomous waypoint laps**: xmDriver actuation (DDSM drive + steering servos) + IMU/odometry MEKF state estimation + waypoint mission layer + tracking controller, composed over xmMessaging (in-process), black-box telemetry recording throughout, live diagnostics attached — **sustained 30 minutes**, with the observability chain proving control-loop tails on hardware are unaffected by full-rate observation. + +The application repo is [swervebot_controller](https://github.com/rxdu/swervebot_controller) — a standalone application *on top of* the family (ADR 0005: applications compose; it is deliberately NOT an umbrella component and never gets pinned here). + +## Phase 0 — platform + application skeleton (the two decisions everything waits on) + +- [ ] **Compute platform decision (blocking, hardware)**: the current PocketBeagle is 32-bit ARM (Cortex-A8); `xmbase/concurrency`'s seqlock primitives require lock-free 64-bit atomics (`static_assert`ed) and family CI covers x86_64 + aarch64 only. Options: move to an aarch64 SBC (Pi 4/5, Radxa, Jetson — recommended; zero family work), or fund an armv7 port (mutex-fallback primitives + a new CI leg — real cost, one consumer). Decide before any bring-up work. +- [ ] **Swervebot rework — skeleton**: new composition-based application per the family pattern (`docs/` integration-patterns: construction from config, capability-typed actuator groups, app-owned loops); consumes family releases via find_package/debs (or submodules pinned at tags — app's choice, not the umbrella's). Old `external/libxmotion` retired. Port `sbot.yaml` config + FSM/control-mode structure. Gate for phase exit: **teleop parity on the bench** — joystick → SwerveDriveKinematics → DDSM/steering, using xmDriver only. + +## Phase 1 — hardware-in-the-loop teleop (retire the biggest unknown first) + +- [ ] Driver bring-up on the robot: DDSM_210 (exists, consolidated + checksum fixes), RC/sbus receiver (exists), joystick HID (exists); **WaveShare steering-servo driver — likely gap, audit against xmDriver's device set** (owner: xmDriver). +- [ ] Safety envelope before autonomy: failsafe stop path, command clamps, FSM guard states, RC override — validated on stands before wheels touch ground (owner: app + xmDriver HAL capabilities). +- [ ] Telemetry instrumented from day one: app binds the SDK, black-box recording on, `xm_logging`/spans in the control loop (owner: app; everything needed already shipped). +- Measured exit: teleop drive session recorded end-to-end; control-loop period tails published from the MCAP. + +## Phase 2 — state estimation on the robot + +- [ ] Swerve wheel-odometry model (kinematics exists; odometry integration + covariance is the gap — owner: xmNavigation estimation). +- [ ] IMU on robot: imu_hipnuc driver exists; hardware IMU bench exists (`bench/imu_attitude`) — run the attitude bench on the actual unit (owner: umbrella bench). +- [ ] MEKF fusion (IMU + odom) on-target; **validation ladder L0–L5 executed against recorded robot data** (the ladder was proposed for exactly this; owner: xmNavigation). +- [ ] Localization honesty check: odom+IMU dead-reckoning drifts — decide whether waypoint laps need an absolute reference (UWB/LiDAR/camera) or whether drift-bounded laps satisfy the milestone. **Scoping decision, owner: you.** +- Measured exit: pose estimate vs ground-truth tape-measure course; NEES consistency from the ladder. + +## Phase 3 — waypoint autonomy (the composition payoff) + +- [ ] Waypoint mission layer: sequencing, arrival tolerance, loop — small; lives app-side unless a second app demands it (charters/gates). +- [ ] Tracking controller: pure-pursuit-class follower first (MPPI exists for later; smallest step wins), consuming the MEKF pose (owner: xmNavigation control or app-side initially). +- [ ] **Compose over xmMessaging in-process** — estimator → planner → controller as the M1/M13 coupling on a real robot: the transport's first production consumer; lineage (`origin_age`) gating actuation on stale-information (owner: app wiring; messaging is ready). +- [ ] Sim-first: the headless SimLoop + swerve model validates the mission/controller before hardware (exists in nav). +- Measured exit: autonomous laps in sim, then on robot; waypoint arrival errors published. + +## Phase 4 — tuning, soak, and the observability claim + +- [ ] Live tuning loop: start with what ships today (`xmmsg` CLI + MCAP → Foxglove converters); pull **quickviz `bridges/xmotion` (topic-bound scope + tuner)** into scope here if offline iteration proves too slow — this is also the gated first consumer for quickviz I3 counters and depth-N `MessageBuffer` snapshots. +- [ ] 30-minute soak: continuous laps, black box on, `/dev/shm` and RSS flat, deadline-miss counters zero or explained. +- [ ] **The headline measured claim**: control-loop tails with full observability attached vs detached — the M10-A4 shape, end-to-end, on hardware. This closes the observability-budget arc ([docs/design/observability-budget.md](docs/design/observability-budget.md)). + +## Debt lane (~20%, standing) + +- [ ] quickviz: I3 overflow counters · I7 bench CI gate · I5 hardware-GL observer A/B (one command on a desktop session) · `thread_safe_queue` move-fix audit · `namespace xmotion` residue cleanup +- [ ] xmMessaging: bench `reference.json` pinning (needs a designated stable runner) · ASan CI job (ran manually at W2) +- [ ] xmBase: clang-format pass on W1 files where formatter exists +- [ ] Family: arm64 deb builds if the platform decision lands on aarch64 deploy-by-deb + +## Deferred by the gate (not blocked — ungated) + +- **P1 iceoryx2**: same-host IPC is served by the shm backend; revisit when a measured need (or the dependency-acquisition decision) arrives. +- **P2 Zenoh + M12 + threat model**: no second host in the milestone. +- **EventHub build**: waits for its first consumer (possibly Phase 2/3 multi-threaded processing — the design is ready, `xmBase docs/event_hub.md`). +- Depth-N `MessageBuffer` beyond what Phase 4's scope widget demands; `MpscQueue`; `FixedPool`; `TripleBuffer` — all per the taxonomy's reserved rows. From fbd92261409047d54c2ac1c27576d859062bc81e Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Sun, 12 Jul 2026 23:02:13 +0800 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20roadmap=20rework=20=E2=80=94=20two-?= =?UTF-8?q?tier=20architecture,=20CAN=20boundary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner clarification folded in: swervebot_controller keeps its firmware role on the existing PocketBeagle (motors/servos/kinematics/ RC failsafe, high-level interface over CAN); the autonomy tier (estimation/planning/control/messaging/observability) runs on an aarch64/x86 upper computer that sees the base as a CAN device. armv7 support scoped to the driver tier only (xmDriver + xmBase core); corrects the earlier over-claim — Cortex-A8 is ARMv7-A with ldrexd/strexd, so the seqlock atomics are likely available, status 'unverified' not 'incompatible'. New Phase 0 gap: the base CAN protocol spec (command/state/heartbeat/timeout-failsafe, versioned wire vocabulary, owned by the swervebot repo); new Phase 0.5: the swerve_base CAN device driver in xmDriver (upper side), replacing the steering-servo gap at that tier (steering stays base-internal). --- ROADMAP.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 7010e90..11de004 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,25 +7,37 @@ ## The milestone (measured, falsifiable) -**Swervebot drives autonomous waypoint laps**: xmDriver actuation (DDSM drive + steering servos) + IMU/odometry MEKF state estimation + waypoint mission layer + tracking controller, composed over xmMessaging (in-process), black-box telemetry recording throughout, live diagnostics attached — **sustained 30 minutes**, with the observability chain proving control-loop tails on hardware are unaffected by full-rate observation. +**Swervebot drives autonomous waypoint laps**, on a two-computer architecture with **CAN as the boundary**: -The application repo is [swervebot_controller](https://github.com/rxdu/swervebot_controller) — a standalone application *on top of* the family (ADR 0005: applications compose; it is deliberately NOT an umbrella component and never gets pinned here). +- **Base tier ("firmware role")** — the existing PocketBeagle running the reworked [swervebot_controller](https://github.com/rxdu/swervebot_controller): motor/servo control, swerve kinematics, RC failsafe, exposing a high-level command/state interface **over CAN bus**. To the upper layer, the base is a CAN device — like any commercial chassis. +- **Autonomy tier** — an aarch64/x86 computer running the composition: swerve-base CAN driver (xmDriver) + IMU/odometry MEKF + waypoint mission + tracking controller over xmMessaging (in-process), black-box telemetry, live diagnostics — **sustained 30 minutes**, with the observability chain proving control-loop tails are unaffected by full-rate observation. -## Phase 0 — platform + application skeleton (the two decisions everything waits on) +Both applications compose the family (ADR 0005) and are deliberately NOT umbrella components — never pinned here. -- [ ] **Compute platform decision (blocking, hardware)**: the current PocketBeagle is 32-bit ARM (Cortex-A8); `xmbase/concurrency`'s seqlock primitives require lock-free 64-bit atomics (`static_assert`ed) and family CI covers x86_64 + aarch64 only. Options: move to an aarch64 SBC (Pi 4/5, Radxa, Jetson — recommended; zero family work), or fund an armv7 port (mutex-fallback primitives + a new CI leg — real cost, one consumer). Decide before any bring-up work. -- [ ] **Swervebot rework — skeleton**: new composition-based application per the family pattern (`docs/` integration-patterns: construction from config, capability-typed actuator groups, app-owned loops); consumes family releases via find_package/debs (or submodules pinned at tags — app's choice, not the umbrella's). Old `external/libxmotion` retired. Port `sbot.yaml` config + FSM/control-mode structure. Gate for phase exit: **teleop parity on the bench** — joystick → SwerveDriveKinematics → DDSM/steering, using xmDriver only. +**armv7 support is scoped to the driver tier only** (owner decision): the base runs xmDriver + xmBase core on 32-bit ARM; the seqlock/messaging/nav stack is not required there. (Correction of an earlier claim: Cortex-A8 is ARMv7-A, which has `ldrexd`/`strexd` — 64-bit lock-free atomics likely exist; the accurate status is *unverified*, and the narrow scoping keeps the verification burden proportional.) + +## Phase 0 — the CAN contract + two skeletons + +- [ ] **Base CAN protocol spec (the new wire vocabulary)**: command set (body twist in, mode/enable, e-stop), state set (odometry twist/pose delta, module states, faults, battery), heartbeat + **command-timeout failsafe defined ON the base** (loss of CAN = safe stop, non-negotiable), versioned like the family's wire contracts. Lives in the swervebot repo (it owns the interface); the upper-layer driver consumes it. +- [ ] **Swervebot rework — base firmware skeleton**: composition-based app per the family pattern, scoped to the base role (config from `sbot.yaml`, FSM/control modes, RC override, kinematics → DDSM/steering, CAN server). Consumes xmDriver + xmBase core via the app's own pinning. Old `external/libxmotion` retired. Exit gate: **teleop parity on the bench through the new stack**. +- [ ] **armv7 driver-tier build proof**: cross-compile (or on-target build) of xmDriver + xmBase core for armhf; a cross-compile CI check if it proves cheap (GitHub has no armhf runners — build-only). Owner: xmDriver/xmBase. +- [ ] **Upper-compute choice**: which aarch64/x86 machine rides the robot (and whether Phase 1–2 can run it tethered/desk-side first). Owner: you. + +## Phase 0.5 — the upper layer sees the base + +- [ ] **swerve_base CAN device driver in xmDriver** (upper side): speaks the Phase-0 protocol via socketcan (exists), exposes the base as capability-typed HAL (twist-commandable, odometry-reporting, health) like any other device. This replaces the earlier "steering-servo driver" gap — steering stays base-internal behind CAN. +- Measured exit: upper computer commands laps of the *bench-mounted* base over CAN; command→wheel latency and heartbeat-failsafe behavior measured and recorded. ## Phase 1 — hardware-in-the-loop teleop (retire the biggest unknown first) -- [ ] Driver bring-up on the robot: DDSM_210 (exists, consolidated + checksum fixes), RC/sbus receiver (exists), joystick HID (exists); **WaveShare steering-servo driver — likely gap, audit against xmDriver's device set** (owner: xmDriver). -- [ ] Safety envelope before autonomy: failsafe stop path, command clamps, FSM guard states, RC override — validated on stands before wheels touch ground (owner: app + xmDriver HAL capabilities). -- [ ] Telemetry instrumented from day one: app binds the SDK, black-box recording on, `xm_logging`/spans in the control loop (owner: app; everything needed already shipped). -- Measured exit: teleop drive session recorded end-to-end; control-loop period tails published from the MCAP. +- [ ] Base bring-up on the robot: DDSM_210 (exists), WaveShare steering servos (**likely xmDriver gap — audit the device set**; base-side), RC/sbus (exists) — all on the PocketBeagle build. +- [ ] Safety envelope before autonomy, layered: base-level (CAN-timeout failsafe, command clamps, RC override — validated on stands) and upper-level (FSM guards). +- [ ] Telemetry: the autonomy tier binds the SDK with black-box recording from day one; the base stays lean (console/log tier initially — whether the base ever records MCAP is a later, gated question). +- Measured exit: teleop through the FULL chain (joystick on upper computer → CAN → base → wheels) recorded end-to-end; control-loop period tails published from the MCAP. ## Phase 2 — state estimation on the robot -- [ ] Swerve wheel-odometry model (kinematics exists; odometry integration + covariance is the gap — owner: xmNavigation estimation). +- [ ] Swerve wheel-odometry: decide the split — base computes odom (reports over CAN, part of the protocol) vs raw module states up + upper-side model. Then the model/covariance work lands where decided (owner: protocol decision first). - [ ] IMU on robot: imu_hipnuc driver exists; hardware IMU bench exists (`bench/imu_attitude`) — run the attitude bench on the actual unit (owner: umbrella bench). - [ ] MEKF fusion (IMU + odom) on-target; **validation ladder L0–L5 executed against recorded robot data** (the ladder was proposed for exactly this; owner: xmNavigation). - [ ] Localization honesty check: odom+IMU dead-reckoning drifts — decide whether waypoint laps need an absolute reference (UWB/LiDAR/camera) or whether drift-bounded laps satisfy the milestone. **Scoping decision, owner: you.** @@ -50,7 +62,7 @@ The application repo is [swervebot_controller](https://github.com/rxdu/swervebot - [ ] quickviz: I3 overflow counters · I7 bench CI gate · I5 hardware-GL observer A/B (one command on a desktop session) · `thread_safe_queue` move-fix audit · `namespace xmotion` residue cleanup - [ ] xmMessaging: bench `reference.json` pinning (needs a designated stable runner) · ASan CI job (ran manually at W2) - [ ] xmBase: clang-format pass on W1 files where formatter exists -- [ ] Family: arm64 deb builds if the platform decision lands on aarch64 deploy-by-deb +- [ ] Family: arm64 deb builds for the autonomy tier; armhf cross-compile check for the driver tier ## Deferred by the gate (not blocked — ungated) From 235ff9b42044a113443006f02b838de5067a4870 Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Mon, 13 Jul 2026 22:27:02 +0800 Subject: [PATCH 3/3] docs: xmApp application tier in ADR 0003; roadmap repo-name sweep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The application naming rule made derivable (xmApp + function word; compose released components, never umbrella-pinned; type-and-tier over instance — instances are named by config files): codifies the existing xmAppCamera precedent and the swervebot_controller -> xmAppSwerveBase rename. Roadmap links updated. --- ROADMAP.md | 2 +- docs/adr/0003-naming-and-branding.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 11de004..7fc9d43 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ **Swervebot drives autonomous waypoint laps**, on a two-computer architecture with **CAN as the boundary**: -- **Base tier ("firmware role")** — the existing PocketBeagle running the reworked [swervebot_controller](https://github.com/rxdu/swervebot_controller): motor/servo control, swerve kinematics, RC failsafe, exposing a high-level command/state interface **over CAN bus**. To the upper layer, the base is a CAN device — like any commercial chassis. +- **Base tier ("firmware role")** — the existing PocketBeagle running the reworked [xmAppSwerveBase](https://github.com/rxdu/xmAppSwerveBase): motor/servo control, swerve kinematics, RC failsafe, exposing a high-level command/state interface **over CAN bus**. To the upper layer, the base is a CAN device — like any commercial chassis. - **Autonomy tier** — an aarch64/x86 computer running the composition: swerve-base CAN driver (xmDriver) + IMU/odometry MEKF + waypoint mission + tracking controller over xmMessaging (in-process), black-box telemetry, live diagnostics — **sustained 30 minutes**, with the observability chain proving control-loop tails are unaffected by full-rate observation. Both applications compose the family (ADR 0005) and are deliberately NOT umbrella components — never pinned here. diff --git a/docs/adr/0003-naming-and-branding.md b/docs/adr/0003-naming-and-branding.md index ec820de..e2b85c0 100644 --- a/docs/adr/0003-naming-and-branding.md +++ b/docs/adr/0003-naming-and-branding.md @@ -77,6 +77,8 @@ Non-C++ components: **xmBoard** (KiCAD) has no code namespace; **xmFirmware** (Z Everything else keeps the full word: repository names, umbrella pin paths, C++ namespaces, CMake packages/targets, and package names never abbreviate. +**Applications (the `xmApp` tier).** Applications built on the family are named `xmApp` + function word (`xmAppCamera`, `xmAppSwerveBase`). They compose *released* family components and are never pinned into the umbrella (ADR 0005). The function word names what the application is — preferring the robot *type* and tier over a robot *instance* (instances are named by configuration files, not repositories): `xmAppSwerveBase` drives any swerve base; `sbot.yaml` names the robot. + ### 5. Derivation test The scheme is consistent iff all three artifacts derive mechanically from one function word: