All work

ROS 2 · GO2 + Jetson

HELIX runs inside a live GO2's ROS 2 graph and audits every recovery command

I built a ROS 2 reliability layer that watches topic timing, heartbeats and logs, turns symptoms into structured fault events, diagnoses a likely cause and audits each recovery command. It ran against the live GO2 graph in eight bounded lab sessions, and the full closed loop ran once: in a 439 s run on an idle robot, 30 anomaly alerts, all idle-jitter threshold crossings, led to 14 recovery decisions that stayed within the allowlist and cooldown policy. Physical actuation of those commands is the next hardware gate.

Repository Evidence ledger Demo video

The HELIX console replaying the recorded Session 8 closed-loop run.

At a glance

1.16 ms
mean ROS 2 callback-path latency, 50 synthetic trials in one process
96.5%
TPR at 0% FPR on synthetic near-threshold anomalies (Z = 3.0); 0% on 3-sigma anomalies in Laplace noise
~81K/s
offline detector throughput on a PC (~64K/s on the Jetson Orin NX)
−53.4%
C++ detector RSS vs the 1-h Python plateau (−47.2% vs cold start); RSS gate still missed
Status
Runs in the live GO2 graph; recovery decision path exercised; physical actuation is the next hardware gate
Role
Sole author: architecture, implementation, hardware sessions
Stack
ROS 2 Humble, C++17, Python, Jetson Orin NX, Unitree GO2
Evidence
Hardware evidence ledger: 8 bounded GO2 lab sessions, April 2026

The problem

Learned robot policies fail in ways that look normal from the outside. Sensors go stale while still publishing. Recurrent state freezes. Topic rates degrade without dropping to zero. Policy outputs stay numerically plausible long after they stopped meaning anything.

A deployment stack needs a layer that notices the system is becoming untrustworthy before a user or a robot is exposed to the consequence, and that can prove afterwards what it noticed and when.

Plenty of robotics work ships a trained policy or a navigation stack. Far less ships the operational layer around it: the thing that detects silent failure, separates confirmed behavior from inferred behavior, and records whether a recovery command was physically acted on. Simulation validation does not establish hardware safety. For an edge robot the reliability layer has to run inside ROS 2, fit a companion computer's budget, survive real topic timing, and leave an audit trail. Most monitoring tooling assumes a datacenter, not a Jetson on a robot.

Core insight

Separate sensing from acting, and make the split explicit in the evidence. That decision is what lets HELIX prove what it detected and which recovery commands it published, without claiming the robot physically executed a safe hold. When the actuation path turned out to be unsubscribed, the architecture surfaced it as a finding instead of hiding it behind a green dashboard.

Architecture

Heartbeat monitoring, topic-rate anomaly detection, and log-pattern parsing feed a diagnosis stage that emits structured FaultEvents. Diagnosis produces recovery hints; a cooldown-aware auditor decides whether an action is permitted, records it, and publishes the zero-velocity command on a dedicated topic.

HELIX architecture: sensing feeds diagnosis, which feeds a cooldown-aware recovery auditor
Architecture diagram from the HELIX repository evidence docs.

What I built

Architecture
Designed the reliability-layer split and the verified / inferred / not-validated evidence ledger that governs every claim in the repo.
Detection paths
Anomaly detector, heartbeat monitor, log parser, diagnosis rules, and the recovery-audit path.
Live integration
Found and fixed the R1 schema mismatch that silently blocked live diagnosis across earlier sessions.
C++ port
Ported the anomaly detector to C++ for the Jetson budget, then reported the failed promotion gate rather than shipping it on.

Evidence

How it was validated

Live GO2 graph
Observed from both companion and development machines across eight sessions.
Jetson sessions
Measured persistent runtime, resource use, and thermal behavior on the Orin NX.
Topic adapter
Bridged real robot topics into HELIX metrics rather than replaying synthetic traces.
Separated benchmarks
Pure algorithm speed, ROS 2 callback latency, and hardware-session behavior measured independently, so no single number does double duty.

Results

Live graph attachability
HELIX nodes observed and processed live GO2 topic-rate streams through an adapter.
Recovery control plane (software)
Session 8, 439 s, robot standing idle: 30 ANOMALY alerts, all natural idle-jitter threshold crossings rather than confirmed faults, produced 14 recovery hints and 14 audited actions (7 published, 7 suppressed by cooldown), with no allowlist or cooldown violation, and 3,064 zero-twist /helix/cmd_vel messages. Published, not physically acted on: the stream had no downstream subscriber.
Latency
1.16 ms mean, 1.24 ms p95 through the actual rclpy callback path: 50 synthetic metric messages in a single-process benchmark, excluding inter-process transport.
Detector realism
96.5% TPR at 0.0% FPR on near-threshold synthetic anomalies, at the benchmark threshold (Z = 3.0), and 0% TPR on 3-sigma anomalies in Laplace noise. Heavy-tailed noise and slow drift remain known weak cases.
C++ port
30-minute hardware parity run: mean RSS 42.51 MB (Python, 1-h plateau) to 19.81 MB, −53.4% (−47.2% against Python at cold start); mean CPU 2.21% to 0.80%. It still missed the 30%-of-Python RSS target I set, so the port stays launch-gated.

Verified on hardware

  • GO2 and Jetson sessions captured live ROS 2 topic landscapes, latency, resource, and HELIX runtime behavior.
  • HELIX emitted structured FaultEvents from bridged GO2 rate metrics (unlabeled fluctuations, not confirmed faults) and from an injected log pattern, detected end to end in about 1.8 s.
  • Diagnosis and recovery-audit messages flowed after the R1 schema fix.
  • The C++ anomaly detector produced a lower-resource live fault stream.

Afterwards: BlackBoxRS

When a robot misbehaves, the useful evidence is seconds old and usually gone. BlackBoxRS is the flight recorder beside HELIX: it builds a reproducible evidence bundle and replays recorded robot data through the same detectors offline, against a virtual clock pinned to bag time.

Real data
Offline replay of a real 330 s GO2 recording (about 94k messages) raised zero anomalies.
Injected fault
Finds a topic dropout injected into that recording from bag timing alone, offline.
Open
The real-bag evidence is offline replay; a live onboard capture is the largest remaining gap. A C++20 runtime exists on a branch, with hardware validation pending.

BlackBoxRS on GitHub

Limitations

Actuation
In Session 8 the published /helix/cmd_vel stream had zero downstream subscribers, so the robot was never physically held. A twist_mux fallback and a closed-loop launch path exist in software; a physical stop is the next hardware test.
Threshold
Natural idle jitter crossed the Z = 3.0 threshold and produced that run's STOP_AND_HOLD decisions; the threshold needs tuning for an idle robot.
Physical faults
In Session 5 a LiDAR cover, USB mic disconnect and topic flood produced 0 fault events because those signals sit outside the adapter's configured inputs, and a 44 s sensor dropout in Session 8 produced 0 anomalies. The dropout path is now fixed in software and awaits a hardware re-test.
Detector data
The headline detector numbers come from synthetic anomalies, not a corpus of confirmed real faults.
Duration
All sessions were bounded; the longest ran about one hour. HELIX has not run as a persistent service.

Next step

Wire a real subscriber to /helix/cmd_vel in a controlled lab session and demonstrate that an injected fault physically holds the robot, with the motion path instrumented on both ends. That single session converts the largest pending row in the ledger into a verified one.