From 6b0de3f83fb3a9cd06021a150ca97e3d6716a04c Mon Sep 17 00:00:00 2001 From: slz Date: Thu, 3 Sep 2026 17:29:39 +0800 Subject: [PATCH] docs(camera): add GigE Action Command example --- orbbec_camera/examples/README.MD | 1 + .../examples/gige_action_command/README.md | 68 +++++++++++++++++++ .../multi_gige_action_command.launch.py | 53 +++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 orbbec_camera/examples/gige_action_command/README.md create mode 100644 orbbec_camera/examples/gige_action_command/multi_gige_action_command.launch.py diff --git a/orbbec_camera/examples/README.MD b/orbbec_camera/examples/README.MD index f598b6f7..92ea0115 100644 --- a/orbbec_camera/examples/README.MD +++ b/orbbec_camera/examples/README.MD @@ -12,6 +12,7 @@ For command-line maintenance and diagnostic utilities, see the official | Source | Purpose | Experience Level | Official Guide | | :---: | --- | :---: | --- | | [Net camera](./net_camera) | Launch supported Orbbec network cameras. | ⭐️ | [Network camera guide](https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/5_advanced_guide/configuration/net_camera.html) | +| [GigE Action Command](./gige_action_command) | Configure and trigger a Gemini 335Le camera group over GVCP. | ⭐️⭐️ | [README](./gige_action_command/README.md) | | [GMSL camera](./gmsl_camera) | Launch single, multiple, or synchronized GMSL cameras. | ⭐️ | [GMSL camera guide](https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/5_advanced_guide/multi_camera/gmsl_camera.html) | | [AE/AWB lock test](./ae_awb_lock) | Verify AE/AWB convergence, frame-metadata capture, and manual lock-in through ROS 2. | ⭐️⭐️ | [README](./ae_awb_lock/README.md) | | [Benchmark](./benchmark) | Benchmark the performance of different camera configurations. | ⭐️⭐️ | [Performance benchmark tools](https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/6_benchmark/benchmark_tools.html) | diff --git a/orbbec_camera/examples/gige_action_command/README.md b/orbbec_camera/examples/gige_action_command/README.md new file mode 100644 index 00000000..a2663fef --- /dev/null +++ b/orbbec_camera/examples/gige_action_command/README.md @@ -0,0 +1,68 @@ +# GigE Action Command + +This example starts two Gemini 335Le cameras in Group Actions synchronization mode and one +host-side Action Command sender. The sender is intentionally created once at the top level because +a GVCP Action Command can trigger multiple cameras. + +## Requirements + +- Gemini 335Le firmware 1.8.24 or later +- Orbbec SDK 2.10.2 or later +- Both cameras and the host on the same network + +Before running the example, change the two `net_device_ip` values in +`multi_gige_action_command.launch.py` to match the cameras. + +## Start the cameras and sender + +```bash +ros2 launch orbbec_camera multi_gige_action_command.launch.py +``` + +The launch file creates these device-scoped configuration services and one network-scoped sender: + +```text +/camera_01/get_action_config +/camera_01/set_action_config +/camera_02/get_action_config +/camera_02/set_action_config +/gige_action_command_node/send_action_command +``` + +## Configure the cameras + +Configure Action Signal block 0 on both cameras with matching keys and masks: + +```bash +ros2 service call /camera_01/set_action_config \ + orbbec_camera_msgs/srv/SetActionConfig \ + "{device_key: 1, selector: 0, group_key: 1, group_mask: 1}" + +ros2 service call /camera_02/set_action_config \ + orbbec_camera_msgs/srv/SetActionConfig \ + "{device_key: 1, selector: 0, group_key: 1, group_mask: 1}" +``` + +Read the configuration back when needed: + +```bash +ros2 service call /camera_01/get_action_config \ + orbbec_camera_msgs/srv/GetActionConfig \ + "{selector: 0}" +``` + +## Trigger the group + +Send an immediate broadcast command. Every camera whose device key, group key, and group mask +match the request will be triggered: + +```bash +ros2 service call /gige_action_command_node/send_action_command \ + orbbec_camera_msgs/srv/SendActionCommand \ + "{device_key: 1, group_key: 1, group_mask: 1, destination_ip: '255.255.255.255', scheduled_time: 0}" +``` + +`success: true` means the host dispatched the GVCP command; the protocol does not return a device +acknowledgment. A nonzero `scheduled_time` uses a GVCP/PTP timestamp, with seconds in the upper +32 bits and nanoseconds in the lower 32 bits. Scheduled triggering requires the cameras and sender +host to use synchronized time. diff --git a/orbbec_camera/examples/gige_action_command/multi_gige_action_command.launch.py b/orbbec_camera/examples/gige_action_command/multi_gige_action_command.launch.py new file mode 100644 index 00000000..3efeb0bf --- /dev/null +++ b/orbbec_camera/examples/gige_action_command/multi_gige_action_command.launch.py @@ -0,0 +1,53 @@ +import os + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import GroupAction, IncludeLaunchDescription, TimerAction +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch_ros.actions import Node + + +def generate_launch_description(): + package_dir = get_package_share_directory("orbbec_camera") + camera_launch = os.path.join( + package_dir, "launch", "gemini_330_series.launch.py" + ) + + camera_01 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(camera_launch), + launch_arguments={ + "camera_name": "camera_01", + "enumerate_net_device": "false", + "net_device_ip": "192.168.1.10", + "net_device_port": "8090", + "sync_mode": "group_actions", + "log_file_name": "camera_01.log", + }.items(), + ) + + camera_02 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(camera_launch), + launch_arguments={ + "camera_name": "camera_02", + "enumerate_net_device": "false", + "net_device_ip": "192.168.1.11", + "net_device_port": "8090", + "sync_mode": "group_actions", + "log_file_name": "camera_02.log", + }.items(), + ) + + action_command_node = Node( + package="orbbec_camera", + executable="gige_action_command_node", + name="gige_action_command_node", + output="screen", + ) + + return LaunchDescription( + [ + action_command_node, + TimerAction(period=0.0, actions=[GroupAction([camera_01])]), + TimerAction(period=2.0, actions=[GroupAction([camera_02])]), + ] + )