feat: adaptive camera power modes (Issue #375) #376
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "sl-perception/issue-375-camera-power-modes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
5-mode FSM for dynamic sensor activation. Avoids running all 4 CSI cameras when unnecessary, saving ~1 GB RAM and significant Orin compute.
Modes
New message type
CameraPowerMode.msg: mode (0-4), mode_name, 8 sensor flags, trigger_speed_mps, trigger_scenario, scenario_overrideCore library: _camera_power_manager.py (pure Python)
CameraPowerFSM.update(speed_mps, scenario, battery_pct)returnsModeDecisiondowngrade_hold_s(default 5 s) to prevent flappingbattery_pct < thresholdidle_to_social_s(30 s) when near-stoppedROS2 node: camera_power_node.py
/saltybot/speed,/saltybot/scenario,/saltybot/battery_pct/saltybot/camera_mode(TRANSIENT_LOCAL, 2 Hz)/saltybot/camera_cmd/{front,rear,left,right,realsense,lidar,uwb,webcam}(Bool)Tests: 64/64 passing
Covers: sensor configs, speed upgrades, hysteresis, scenario overrides, battery cap, idle timer, reset, full ride scenario.
Safety invariants
Test plan
ros2 run saltybot_bringup camera_power/saltybot/camera_cmd/rearTrue in ACTIVE/FULLCloses #375
Generated with Claude Code
Implements a 5-mode FSM for dynamic sensor activation based on speed, scenario, and battery level — avoids running all 4 CSI cameras + full sensor suite when unnecessary, saving ~1 GB RAM and significant compute. Five modes (sensor sets): SLEEP — no sensors (~150 MB RAM) SOCIAL — webcam only (~400 MB RAM, parked/socialising) AWARE — front CSI + RealSense + LIDAR (~850 MB RAM, indoor/<5km/h) ACTIVE — front+rear CSI + RealSense + LIDAR + UWB (~1.15 GB, 5-15km/h) FULL — all 4 CSI + RealSense + LIDAR + UWB (~1.55 GB, >15km/h) Core library — _camera_power_manager.py (pure Python, no ROS2 deps) - CameraPowerFSM.update(speed_mps, scenario, battery_pct) → ModeDecision - Speed-driven upgrades: instant (safety-first) - Speed-driven downgrades: held for downgrade_hold_s (default 5s, anti-flap) - Scenario overrides (instant, bypass hysteresis): · CROSSING / EMERGENCY → FULL always · PARKED → SOCIAL immediately · INDOOR → cap at AWARE (never ACTIVE/FULL indoors) - Battery low cap: battery_pct < threshold → cap at AWARE - Idle timer: near-zero speed holds at AWARE for idle_to_social_s (30s) before dropping to SOCIAL (avoids cycling at traffic lights) ROS2 node — camera_power_node.py - Subscribes: /saltybot/speed, /saltybot/scenario, /saltybot/battery_pct - Publishes: /saltybot/camera_mode (CameraPowerMode, latched, 2 Hz) - Publishes: /saltybot/camera_cmd/{front,rear,left,right,realsense,lidar,uwb,webcam} (std_msgs/Bool, TRANSIENT_LOCAL so late subscribers get last state) - Logs mode transitions with speed/scenario/battery context Tests — test/test_camera_power_manager.py: 64/64 passing - Sensor configs: counts, correct flags per mode, safety invariants - Speed upgrades: instantaneous at all thresholds, no hold required - Downgrade hysteresis: hold timer, cancellation on speed spike, hold=0 instant - Scenario overrides: CROSSING/EMERGENCY/PARKED/INDOOR, all CSIs on crossing - Battery low: cap at AWARE, threshold boundary - Idle timer: delay AWARE→SOCIAL, motion resets timer - Reset, labels, ModeDecision fields - Integration: full ride scenario (walk→jog→sprint→crossing→indoor→park→low bat) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>