Decision Priority
Decision Priority is the exact order in which SidewalkPilot resolves competing commands on a single control tick. It is the concrete implementation of the layered-autonomy idea: when the human, the LiDAR safety layer, the navigation manager, and the steering model all want something different, this ordering decides who actually moves the servo and motors.
How It Works
The priority chain is enforced in two functions in
code/controller/current/rc_car_app/runtime.py: apply_autonomous_controls(...)
(which decides the autonomous steering/throttle intent) and update_gpio(...)
(which arbitrates AEB and writes hardware). The chain, highest priority first:
- Human / manual override. In the
pygameevent loop, any steering input withabs(value) > 0.1, any throttle> 0.05, or any brake press callscancel_autonomous_mode(...)and, where wired, route cancellation. The change takes effect when the Raspberry Pi 5 loop processes the event; it depends on a connected controller and responsive process. - Center-corridor emergency stop. With AEB enabled, a valid point at or
inside
LIDAR_OVERRIDE_EMERGENCY_STOP_M = 1.05 mrequests a hard stop before model inference is used for motion. - Model availability gate. If there is no emergency stop, the camera model
gets a vote. The Raspberry Pi 5 rejects a camera frame older than 0.75 seconds; a Jetson Orin Nano result
must be no more than
JETSON_RESULT_MAX_AGE_SEC = 0.25 sold and match the selected model. Confidence must be ≥LOW_CAMERA_CONFIDENCE(0.25). If the model is unavailable, stale, or below the configured confidence threshold, the runtime requests a hard stop with reasonmodel_unavailableormodel_low_confidence. Accepted neural results currently use confidence1.0, so this gate is not a calibrated scene-uncertainty detector. - Model steering command. The model's steering angle becomes the servo target
and is mapped to
target_heading_deg(clamped toMAX_TARGET_HEADING_DEG = 60°). LiDAR never replaces this steering value. - LiDAR throttle cap. With AEB enabled, center clearance governs the forward target: 100% at 1.65 m, linearly down to 60% reference at 1.25 m, held to 1.05 m. The model's throttle output is not used.
- AEB re-check and steering/motor command. Back in
update_gpio, the runtime checks the already-computed AEB state immediately before the hardware write; it does not parse a second scan. If AEB is armed andis_stop_brake_condition(...)is true, it forces brake withAEB_BRAKE_RATEand overrides the throttle to zero. The steering target is clamped and mapped to the calibrated servo range. Motor PWM either moves at the selected ramp rate or snaps to zero for the hard-brake branch before the final hardware write.
The important asymmetry is now between axes: the model owns lateral control and LiDAR owns only its configured longitudinal cap/stop. The same LiDAR policy object is reused through the control tick.
Why This Choice
The human can cancel autonomy, a stale model cannot continue driving, and the center-corridor policy can cap or stop forward motion without creating a second steering controller. Telemetry exposes model state, clearance, AEB state, and the chosen LiDAR action. This ordering is inspectable, but quantitative stopping and detection coverage still require controlled tests.
Priority Table
| Priority | Decision | Trigger | Constant / code |
|---|---|---|---|
| 1 | Manual override | stick/throttle/brake input | cancel_autonomous_mode |
| 2 | Emergency hard stop | enabled AEB and center clearance <= 1.05 m | LIDAR_OVERRIDE_EMERGENCY_STOP_M |
| 3 | Model gate | fresh matching result + conf >= 0.25 | 0.75 s local frame guard; JETSON_RESULT_MAX_AGE_SEC = 0.25 |
| 4 | Model steering | mapped heading | MAX_TARGET_HEADING_DEG 60° |
| 5 | LiDAR throttle cap | enabled AEB and center clearance < 1.65 m | LIDAR_GOV_* |
| 6 | AEB re-check and steering/motor command | armed AEB, then final command | AEB_BRAKE_RATE 10.0 |