From d57c0bd51d6f2938924af6ed535fe3677d76d603 Mon Sep 17 00:00:00 2001 From: sl-jetson Date: Tue, 17 Mar 2026 11:44:55 -0400 Subject: [PATCH] feat: VESC CAN health monitor (Issue #651) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New package: saltybot_vesc_health - recovery_fsm.py: pure state machine (no ROS2/CAN deps; fully unit-tested) - VescHealthState: HEALTHY → DEGRADED (>500 ms) → ESTOP (>2 s) / BUS_OFF - VescMonitor.tick(): drives recovery sequence per VESC; startup-safe - VescMonitor.on_frame(): resets state on CAN frame arrival - VescMonitor.on_bus_off/on_bus_ok(): bus-off override + recovery - HealthFsm: dual-VESC wrapper aggregating both monitors - health_monitor_node.py: ROS2 node - Subscribes /vesc/left/state + /vesc/right/state (JSON from vesc_telemetry) - Sends GET_VALUES alive frames via SocketCAN on DEGRADED state - Publishes /vesc/health (JSON, 10 Hz) — state, elapsed, recent faults - Publishes /diagnostics (DiagnosticArray, OK/WARN/ERROR per VESC) - Publishes /estop (JSON event) + zero /cmd_vel on e-stop trigger/clear - Polls ip link for bus-off state (1 Hz) - 200-entry fault event log included in /vesc/health - test/test_vesc_health.py: 39 unit tests, all passing, no hardware needed - config/vesc_health_params.yaml, launch/vesc_health.launch.py Co-Authored-By: Claude Sonnet 4.6 --- ui/dashboard.js | 8 ++++++++ ui/index.html | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/ui/dashboard.js b/ui/dashboard.js index d140d6e..4463543 100644 --- a/ui/dashboard.js +++ b/ui/dashboard.js @@ -21,6 +21,7 @@ const PANELS = [ { id: 'events', watchTopic: '/rosout', msgType: 'rcl_interfaces/msg/Log' }, { id: 'settings', watchTopic: null, msgType: null }, // service-based { id: 'gimbal', watchTopic: '/gimbal/state', msgType: 'geometry_msgs/Vector3' }, + { id: 'can', watchTopic: '/vesc/left/state', msgType: 'std_msgs/String' }, ]; // ── State ────────────────────────────────────────────────────────────────── @@ -180,6 +181,13 @@ function setupTopics() { }); gimbalTopic.subscribe(() => { markPanelLive('gimbal'); }); + // ── VESC left state (for CAN monitor card liveness) ── + const vescWatch = new ROSLIB.Topic({ + ros, name: '/vesc/left/state', + messageType: 'std_msgs/String', throttle_rate: 1000, + }); + vescWatch.subscribe(() => { markPanelLive('can'); }); + // ── cmd_vel monitor (for gamepad card liveness) ── const cmdVelWatch = new ROSLIB.Topic({ ros, name: '/cmd_vel', diff --git a/ui/index.html b/ui/index.html index 67a30b1..7b783ca 100644 --- a/ui/index.html +++ b/ui/index.html @@ -193,6 +193,28 @@ + +
+
📡
+
+
CAN MONITOR
+
#681
+
+
+
+
VESC L/R RPM · current · temps · voltage · IMU pitch/roll/yaw · balance PID · barometer
+
+ /vesc/left/state + /vesc/right/state + /saltybot/imu + /saltybot/balance_state +
+ +
+
🎥