Files
yiliao2026/docs/superpowers/specs/2026-07-23-unified-usb-camera-launch-design.md

82 lines
2.7 KiB
Markdown

# Unified USB Camera Launch Design
## Goal
Make the camera behavior of `hobot_usb_cam.launch.py` and
`hobot_usb_cam_websocket.launch.py` identical. The WebSocket variant must add
only the WebSocket service.
## Configuration
Add `config/usb_camera.yaml` as the single source of runtime camera parameters:
- `video_device`: `/dev/video0`
- `image_width`: `1280`
- `image_height`: `720`
- `framerate`: `30`
- `pixel_format`: `mjpeg`
- `io_method`: `mmap`
- `zero_copy`: `false`
- `frame_id`: `default_usb_cam`
The calibration data remains in `usb_camera_calibration.yaml`; it is not mixed
with ROS runtime parameters. The shared base launch resolves its installed path
and applies it to the camera node after loading the runtime YAML. Both launch
variants therefore receive the same calibration path without a source-tree
absolute path.
## Launch Structure
`hobot_usb_cam.launch.py` will:
1. Declare one `camera_config` launch argument whose default is the installed
`config/usb_camera.yaml` path.
2. Start the shared-memory environment once.
3. Resolve the installed `usb_camera_calibration.yaml` path.
4. Start one `hobot_usb_cam` node with the YAML file as its parameter source and
the resolved calibration resource path.
`hobot_usb_cam_websocket.launch.py` will:
1. Include `hobot_usb_cam.launch.py` without overriding camera parameters.
2. Include the WebSocket launch configured for `/image`, MJPEG input, image-only
display, and a 30 FPS output limit.
It will not start `hobot_codec`, duplicate the shared-memory launch, or carry
camera parameter literals.
## Data Flow
Without WebSocket:
`/dev/video0 -> hobot_usb_cam -> /image (CompressedImage)`
With WebSocket:
`/dev/video0 -> hobot_usb_cam -> /image (CompressedImage) -> WebSocket`
No RGB conversion or second JPEG encode is performed.
## Validation
An automated structural check will verify that:
- the YAML contains the required 1280x720, 30 FPS, native MJPEG parameters;
- the base launch loads that YAML;
- the WebSocket launch includes the base launch;
- the WebSocket launch does not define a camera node, codec node, or camera
parameter overrides.
After building, each launch will be started separately. Both must publish one
`sensor_msgs/msg/CompressedImage` topic at approximately 30 FPS with decoded
dimensions of 1280x720. Only the WebSocket launch may create the WebSocket node
and port 8080 service.
## Operational Notes
The two launch files cannot run concurrently because they both own
`/dev/video0`. Runtime validation is sequential and stops the first launch
before starting the second. Any separately started `usb_cam_node_exe` must also
be stopped before validation because V4L2 permits only one active capture owner
for this camera.