feat(social): trigger-based ROS2 bag recorder (Issue #332) #335

Merged
sl-jetson merged 1 commits from sl-jetson/issue-332-rosbag-recorder into main 2026-03-03 13:25:56 -05:00
Collaborator

Summary

Closes #332

New ROS2 node rosbag_recorder_node — subscribes to a Bool trigger and records configurable ROS topics to timestamped bag files via a ros2 bag record subprocess.

  • Subscribes /saltybot/record_trigger (Bool): True = start, False = stop
  • Publishes /saltybot/recording_status (String): idle | recording | stopping | error
  • State machine: idlerecordingstoppingidle; error state on unexpected subprocess exit (retries on next True trigger)
  • Auto-stop: configurable auto_stop_s (default 60 s); set to 0 to disable
  • Graceful shutdown: SIGINT sent to process group; SIGKILL after stop_timeout_s (5 s) if process won't stop
  • Topics: comma-separated topics param; empty = record all (--all)
  • Bag path: {bag_dir}/{bag_prefix}_{YYYYMMDD_HHMMSS} — new file per recording
  • Optional: zstd compression, max bag size split
  • BagRecorderProcess injected via node._recorder — fully mockable for offline testing
  • Pure compute_recording_transition() function for all state-machine logic

Test plan

  • 101/101 offline unit tests pass (test_rosbag_recorder.py)
  • make_bag_path: prefix, directory, string type
  • parse_topics: empty, single, multi, whitespace, empty segments
  • compute_recording_transition: all IDLE/RECORDING/STOPPING/ERROR transitions, auto-stop timing, force-kill timeout, disabled auto-stop/timeout
  • Node init: idle state, publishes immediately, pub/sub/timer, topic parsing
  • _on_trigger: stores value, consumed after poll
  • Poll loop: start/stop/force-kill/auto-stop/error/retry full lifecycle
  • _StubbornRecorder subclass to test SIGKILL path
  • Topics list passed correctly to recorder; empty=all
  • Logging on start/stop/error
  • Config YAML, launch file, setup.py entry point

🤖 Generated with Claude Code

## Summary Closes #332 New ROS2 node `rosbag_recorder_node` — subscribes to a Bool trigger and records configurable ROS topics to timestamped bag files via a `ros2 bag record` subprocess. - Subscribes `/saltybot/record_trigger` (`Bool`): `True` = start, `False` = stop - Publishes `/saltybot/recording_status` (`String`): `idle` | `recording` | `stopping` | `error` - **State machine**: `idle` → `recording` → `stopping` → `idle`; `error` state on unexpected subprocess exit (retries on next `True` trigger) - **Auto-stop**: configurable `auto_stop_s` (default 60 s); set to 0 to disable - **Graceful shutdown**: SIGINT sent to process group; SIGKILL after `stop_timeout_s` (5 s) if process won't stop - **Topics**: comma-separated `topics` param; empty = record all (`--all`) - **Bag path**: `{bag_dir}/{bag_prefix}_{YYYYMMDD_HHMMSS}` — new file per recording - **Optional**: zstd compression, max bag size split - `BagRecorderProcess` injected via `node._recorder` — fully mockable for offline testing - Pure `compute_recording_transition()` function for all state-machine logic ## Test plan - [x] 101/101 offline unit tests pass (`test_rosbag_recorder.py`) - [x] `make_bag_path`: prefix, directory, string type - [x] `parse_topics`: empty, single, multi, whitespace, empty segments - [x] `compute_recording_transition`: all IDLE/RECORDING/STOPPING/ERROR transitions, auto-stop timing, force-kill timeout, disabled auto-stop/timeout - [x] Node init: idle state, publishes immediately, pub/sub/timer, topic parsing - [x] `_on_trigger`: stores value, consumed after poll - [x] Poll loop: start/stop/force-kill/auto-stop/error/retry full lifecycle - [x] `_StubbornRecorder` subclass to test SIGKILL path - [x] Topics list passed correctly to recorder; empty=all - [x] Logging on start/stop/error - [x] Config YAML, launch file, setup.py entry point 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sl-webui added 1 commit 2026-03-03 06:52:20 -05:00
feat(social): trigger-based ROS2 bag recorder (Issue #332)
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 9s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 9s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (pull_request) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
social-bot integration tests / Latency profiling (GPU, Orin) (pull_request) Has been cancelled
e1813f734f
BagRecorderNode: subscribes /saltybot/record_trigger (Bool), spawns
ros2 bag record subprocess, drives idle/recording/stopping/error
state machine; auto-stop timeout, SIGINT graceful shutdown with
SIGKILL fallback. Publishes /saltybot/recording_status (String).
Configurable topics (csv), bag_dir, prefix, compression, size limit.
Subprocess injectable for offline testing. 101/101 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sl-webui force-pushed sl-jetson/issue-332-rosbag-recorder from e1813f734f to 813d6f2529 2026-03-03 13:19:57 -05:00 Compare
sl-jetson merged commit 3bee8f3cb4 into main 2026-03-03 13:25:56 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seb/saltylab-firmware#335
No description provided.