Hi everyone,
Following up on my previous posts on deterministic safety reflexes (Demo 6) and Layer 3 ranking rules, I wanted to share the latest simulation milestone from QERRA-v2 Classical: Webots Demo 7 (Supervisory Gate & Authority Separation).
The Motivation
In ROS 2 mobile bases, we typically route planner commands through twist_mux or nav2_collision_monitor, with watchdog timeouts on cmd_vel.
In Demo 7, I wanted to explore a stricter, isolated architectural pattern inspired by classical Simplex and doer-checker designs:
- The high-level planner is treated as an untrusted proposer running as a separate OS process over non-blocking UDP.
- The Supervisory Gate (the Webots controller) is the sole owner of the wheel motor joint handles. The default command is always zero velocity.
- When a hazard occurs or deliberation fails, the gate clamps the motors, latches, and enforces a formal recovery contract before allowing any motion to resume.
The Scenario: Hospital Corridor Transit
I set up an illustrative healthcare logistics corridor in Webots (R2025a) with a PAL Robotics TIAGo base:
- TIAGo cruises down the corridor at a proposed speed of 2.0 rad/s (~0.196 m/s).
- An obstacle (a platform cart) sits in the active swept path at X = 2.8m.
- The gate continuously evaluates forward Hokuyo lidar ranges (240° FOV, 667 samples) filtered across a 0.64m corridor matching the base width plus margin.
What the Gate Implements:
- Process-Level Isolation:
The proposer runs in an external Python process communicating via non-blocking localhost UDP. It holds zero Webots actuator handles and has no direct path to the motors. - Kinematic Stopping Envelope:
The gate computes an envelope each tick:
d_stop = ceil(v² / (2 * a_design)) + margin
At 2.0 rad/s with a_design = 0.5 m/s² and a 300 mm margin, d_stop is 339 mm. If clearance falls below this, the gate overrides the proposer and commands 0.0 rad/s within a single 32 ms simulation tick. - Recovery Contract & Latch:
After a trip, the gate latches in TRIPPED. It requires a continuous 1.0s dwell of clear readings before an operator reset can be accepted. If an operator attempts a reset while the obstacle is still in front of the robot, the reset is rejected and logged (RESET_REJECTED_HAZARD), holding 0.0 rad/s. - Tamper-Evident Flight Recorder:
Every single tick appends a canonical JSON line to gate_audit.jsonl, chained with a SHA-256 hash of the preceding record for offline verification.
What the Run Shows (RUN_1791713619, n=1):
- Startup Latch: The gate boots in TRIPPED, runs the 1.0s clear dwell, and enters AWAITING_RESET.
- Edge-Triggered Reset: An operator reset (Key R) is accepted at t = 4.38s, transitioning to RUN at 2.0 rad/s.
- Gate Intervention: At t = 31.52s, corridor clearance breaches the 339 mm threshold. The gate cuts velocity to 0.0 rad/s in that exact 32 ms tick.
- Trip reading: 337 mm
- Standstill reading: 301 mm (the robot coasted about 36 mm in simulation physics before reaching complete rest).
- Collision: None observed; the cart was not displaced.
- Recovery Guard: While parked in front of the cart at t = 34s, an operator reset was attempted. The gate evaluated the active hazard and rejected the reset (RESET_REJECTED_HAZARD: 1), keeping motors locked.
- Cryptographic Seal: 1,485 discrete control cycles verified with zero discrepancies (verify_log.py, Head seal: ae37ae62227c4fdca51233b7e4189607898ae2c27eca5bf0847414d1f0d4c191).
Observations, Gaps & Non-Claims:
- Unexplained Startup Slip: From t = 5.76s to 14.40s, wheel encoders recorded 2.0 rad/s while lidar distance stayed flat (~3818 mm). The wheels were turning in simulation, but the base did not translate for about 9 seconds before steady translation began. The exact physics cause in Webots is unconfirmed; logging ground-truth poses is my next diagnostic step.
- Smoke-Test Mode: In this baseline run, the obstacle cart was placed via supervisor script at t = 3.5s. Full dynamic obstacle injection via an independent supervisor robot is scheduled next.
- Placeholder Parameters: a_design (0.5 m/s²) and the 300 mm margin are uncalibrated placeholders. At 0.196 m/s, the braking term is only about 39 mm, so the 300 mm margin dominates. Empirical deceleration calibration against ground truth is needed.
- Scope Boundary: This is an open-source research prototype on a non-RTOS host (Windows 11). It does not claim SIL/PL certification under IEC 61508 or ISO 13849-1, and software process isolation does not replace a physical emergency stop relay.
Video & Links
Video (YouTube):
Licensing:
- Layer 1 (QERRA-HSR physical reflex): Permissive Apache-2.0 (standard library only, designed for standalone reuse).
- Core Framework: Dual-licensed under AGPL-3.0 / commercial licensing (COMMERCIAL-LICENSE.md).
I would welcome any genuine feedback! ![]()
- Is this supervisory pattern useful beyond what nav2_collision_monitor + cmd_vel timeouts already provide?
- Does the latch-plus-dwell-plus-operator-reset recovery contract match how you handle physical holds in shared spaces?
Transparency note: Post drafted with AI engineering assistance in line with QERRA open development disclosure. All architecture, code, and simulation runs were executed locally