feat: ROS2 gimbal control node (Issue #548) #558

Merged
sl-jetson merged 1 commits from sl-jetson/issue-548-gimbal-ros2 into main 2026-03-14 11:39:59 -04:00
Collaborator

Summary

  • saltybot_gimbal ROS2 Python package: pan/tilt camera head control via JLINK serial bridge to STM32
  • Subscribes /saltybot/gimbal/cmd (Vector3: x=pan_deg, y=tilt_deg, z=speed_deg_s); publishes /saltybot/gimbal/state (JSON)
  • Services: /saltybot/gimbal/home (Trigger), /saltybot/gimbal/look_at (Trigger + look_at_target PointStamped)
  • jlink_gimbal.py: codec matching include/jlink.h — CMD_GIMBAL_POS=0x0B, TLM_GIMBAL_STATE=0x84, CRC16-CCITT, deg*10 encoding
  • MotionAxis: trapezoidal velocity profile (180 deg/s^2 accel, 90 deg/s default)
  • Soft limits: pan +-150 deg, tilt +-45 deg; configurable via YAML / launch args
  • 3D look-at: converts camera-frame PointStamped to pan/tilt via atan2
  • 48 unit tests, all passing offline

Test plan

  • colcon build --packages-select saltybot_gimbal succeeds
  • ros2 launch saltybot_gimbal gimbal.launch.py starts node
  • Publish /saltybot/gimbal/cmd Vector3 -> STM32 receives 0x0B frame
  • /saltybot/gimbal/home service returns gimbal to 0,0
  • Soft limits: pan=200 clamped to 150
  • pytest test/test_gimbal.py -> 48/48 passed

Closes #548

## Summary - **saltybot_gimbal** ROS2 Python package: pan/tilt camera head control via JLINK serial bridge to STM32 - Subscribes /saltybot/gimbal/cmd (Vector3: x=pan_deg, y=tilt_deg, z=speed_deg_s); publishes /saltybot/gimbal/state (JSON) - Services: /saltybot/gimbal/home (Trigger), /saltybot/gimbal/look_at (Trigger + look_at_target PointStamped) - jlink_gimbal.py: codec matching include/jlink.h — CMD_GIMBAL_POS=0x0B, TLM_GIMBAL_STATE=0x84, CRC16-CCITT, deg*10 encoding - MotionAxis: trapezoidal velocity profile (180 deg/s^2 accel, 90 deg/s default) - Soft limits: pan +-150 deg, tilt +-45 deg; configurable via YAML / launch args - 3D look-at: converts camera-frame PointStamped to pan/tilt via atan2 - 48 unit tests, all passing offline ## Test plan - [ ] colcon build --packages-select saltybot_gimbal succeeds - [ ] ros2 launch saltybot_gimbal gimbal.launch.py starts node - [ ] Publish /saltybot/gimbal/cmd Vector3 -> STM32 receives 0x0B frame - [ ] /saltybot/gimbal/home service returns gimbal to 0,0 - [ ] Soft limits: pan=200 clamped to 150 - [ ] pytest test/test_gimbal.py -> 48/48 passed Closes #548
sl-jetson added 1 commit 2026-03-14 10:34:30 -04:00
saltybot_gimbal ROS2 Python package for pan/tilt camera head control
via JLINK binary protocol over serial to STM32 (Issue #547 C side).

- gimbal_node.py: subscribes /saltybot/gimbal/cmd (Vector3: pan, tilt,
  speed), publishes /saltybot/gimbal/state (JSON), /saltybot/gimbal/cmd_echo
- Services: /saltybot/gimbal/home (Trigger), /saltybot/gimbal/look_at
  (Trigger + /saltybot/gimbal/look_at_target PointStamped)
- jlink_gimbal.py: JLINK codec matching jlink.h — CMD_GIMBAL_POS=0x0B,
  TLM_GIMBAL_STATE=0x84, CRC16-CCITT, deg*10 encoding, speed register
- MotionAxis: trapezoidal velocity profile (configurable accel + speed)
- Configurable limits: pan ±150°, tilt ±45° (gimbal_params.yaml)
- Serial reconnect with configurable retry delay
- 48 unit tests — all passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sl-jetson merged commit 6c5ecc9e00 into main 2026-03-14 11:39:59 -04: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#558
No description provided.