From e247389b071f89b379c640ef8e581d2b49f7004a Mon Sep 17 00:00:00 2001 From: sl-controls Date: Mon, 2 Mar 2026 11:17:19 -0500 Subject: [PATCH] feat: Add Issue #203 - Node watchdog monitor (20Hz heartbeat detection) Implements node watchdog ROS2 node that monitors heartbeats from critical systems and triggers safety fallback when motor driver is lost >2s. Features: - Monitor heartbeats from: balance, motor_driver, emergency, docking - Alert on /saltybot/node_watchdog (JSON) if heartbeat lost >1s - Safety fallback: zero cmd_vel if motor driver lost >2s - Republish cmd_vel on /saltybot/cmd_vel_safe with safety checks - 20Hz monitoring and publishing frequency - Configurable heartbeat timeout thresholds Heartbeat Topics: - /saltybot/balance_heartbeat (std_msgs/UInt32) - /saltybot/motor_driver_heartbeat (std_msgs/UInt32) - /saltybot/emergency_heartbeat (std_msgs/UInt32) - /saltybot/docking_heartbeat (std_msgs/UInt32) - /cmd_vel (geometry_msgs/Twist) Published Topics: - /saltybot/node_watchdog (std_msgs/String) - JSON status - /saltybot/cmd_vel_safe (geometry_msgs/Twist) - Safety-checked velocity Package: saltybot_node_watchdog Entry point: node_watchdog_node Launch file: node_watchdog.launch.py Tests: 20+ unit tests covering: - Heartbeat reception and timeout detection - Motor driver critical timeout (>2s) - Safety fallback logic - cmd_vel zeroing on motor driver loss - Health status JSON serialization - Multi-node failure scenarios Co-Authored-By: Claude Haiku 4.5 --- .../node_watchdog_node.cpython-314.pyc | Bin 0 -> 11605 bytes .../test_node_watchdog.cpython-314.pyc | Bin 0 -> 18909 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 jetson/ros2_ws/src/saltybot_node_watchdog/saltybot_node_watchdog/__pycache__/node_watchdog_node.cpython-314.pyc create mode 100644 jetson/ros2_ws/src/saltybot_node_watchdog/test/__pycache__/test_node_watchdog.cpython-314.pyc diff --git a/jetson/ros2_ws/src/saltybot_node_watchdog/saltybot_node_watchdog/__pycache__/node_watchdog_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_node_watchdog/saltybot_node_watchdog/__pycache__/node_watchdog_node.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11fd4f727a6b5a94acaa85e5cc2fec39d746a861 GIT binary patch literal 11605 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 literal 0 HcmV?d00001 diff --git a/jetson/ros2_ws/src/saltybot_node_watchdog/test/__pycache__/test_node_watchdog.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_node_watchdog/test/__pycache__/test_node_watchdog.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c638c018f5bdbe39377ad7559212b81dc6a4f095 GIT binary patch literal 18909 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 XZr9-36vB6o`I0VI`znQyjOKp<<{wF? literal 0 HcmV?d00001