diff --git a/docs/README.md b/docs/README.md index dd93882e..5a901a1e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -60,6 +60,12 @@ docs/ 2. Translate and adapt for the Chinese version (`docs/zh/`) 3. Ensure both versions build successfully +## Example Documentation + +For examples documented on Pages, the current-version guide is the source of truth for complete usage, configuration, and troubleshooting. Keep their READMEs in the code repository to a short purpose, prerequisites or local settings, run command, and links to the English and Chinese guides. Add new guides to both language navigation trees before shortening an existing README. Keep the example index linked to the source directory and guides. + +The Gemini 435Le example is documented in its source-directory README only; keep its full instructions there and link directly to that README from the example index. + ## Dependencies - Sphinx diff --git a/docs/en/source/camera_devices/4_application_guide/application_guide.rst b/docs/en/source/camera_devices/4_application_guide/application_guide.rst index a3bfc385..8ff7c242 100644 --- a/docs/en/source/camera_devices/4_application_guide/application_guide.rst +++ b/docs/en/source/camera_devices/4_application_guide/application_guide.rst @@ -12,3 +12,4 @@ This chapter introduces application development with the SDK, including launch p coordinate_and_tf.md compressed_image.md point_cloud.md + examples/ae_awb_lock.md diff --git a/docs/en/source/camera_devices/4_application_guide/examples/ae_awb_lock.md b/docs/en/source/camera_devices/4_application_guide/examples/ae_awb_lock.md new file mode 100644 index 00000000..58be9487 --- /dev/null +++ b/docs/en/source/camera_devices/4_application_guide/examples/ae_awb_lock.md @@ -0,0 +1,48 @@ +# AE/AWB Lock Test + +The source file is in [ae_awb_lock](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/ae_awb_lock). + +This sample exposes a test-only ROS 2 action that verifies the AE/AWB capture and manual +lock-in flow through the camera driver's services and color-frame metadata. + +Run the camera driver and this sample in the same namespace: + +```bash +ros2 run orbbec_camera ae_awb_lock_test_node --ros-args -r __ns:=/camera +``` + +Send a goal and print feedback: + +```bash +ros2 action send_goal \ + /camera/run_ae_awb_lock_test \ + orbbec_camera_msgs/action/RunAeAwbLockTest \ + "{timeout_ms: 10000}" \ + --feedback +``` + +The sample subscribes to the relative `color/metadata` topic. It enables auto exposure and auto +white balance, waits until the SDK status equals `1`, captures exposure, color gain, and color +temperature from the latest color-frame metadata, and reads AWB R/B/G gains through the structured +property service. It then disables the auto controls and writes the captured values back in this +order: + +1. Color exposure +2. Color gain +3. AWB R/B/G gains +4. Color temperature + +The final AWB gain readback must exactly match the captured value. Other readback differences are +reported as warnings because the device may quantize those controls. On failure or cancellation, +the sample restores auto exposure and auto white balance. + +Every feedback phase contains a fresh status value read from the camera service. The +`waiting_for_services` feedback is published after all required services become available, because +the status cannot be read before its service is ready. + +The color stream must be enabled, and `/camera/color/metadata` must be available when using the +`/camera` namespace. The action fails instead of writing default values if no metadata arrives +before the goal timeout or if `exposure`, `gain`, or `white_balance` is missing. The goal timeout +covers the main workflow, including service discovery, service calls, convergence, capture, +writeback, and verification. Restoring auto exposure and auto white balance after a failure uses a +separate best-effort timeout. diff --git a/docs/en/source/camera_devices/5_advanced_guide/advanced_guide.rst b/docs/en/source/camera_devices/5_advanced_guide/advanced_guide.rst index 662d18a8..a97464e1 100644 --- a/docs/en/source/camera_devices/5_advanced_guide/advanced_guide.rst +++ b/docs/en/source/camera_devices/5_advanced_guide/advanced_guide.rst @@ -26,6 +26,7 @@ Multi-Camera multi_camera/multi_camera_synced.md multi_camera/multi_camera_synced_verification_tool.md multi_camera/gmsl_camera.md + multi_camera/gige_action_command.md Configuration & Modes diff --git a/docs/en/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md b/docs/en/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md new file mode 100644 index 00000000..d2ea7f31 --- /dev/null +++ b/docs/en/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md @@ -0,0 +1,101 @@ +# GigE Action Command + +The source files are in [gige_action_command](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/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 + +The service exposes three trigger modes. Every camera whose device key, group key, and group mask +match the request will be triggered. + +### Immediate trigger + +Set `trigger_mode` to `0`. The delay and scheduled time fields must be zero: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 0, delay_ms: 0, scheduled_time: 0}" +``` + +### Relative-delay trigger + +Set `trigger_mode` to `1` and provide a positive delay in milliseconds. The node reads the host +system clock, adds the delay, and converts the result to the absolute GVCP/PTP timestamp expected by +the SDK. This example schedules the command one second in the future: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 1, delay_ms: 1000, scheduled_time: 0}" +``` + +The host `CLOCK_REALTIME` must be synchronized to the same PTP domain as the cameras, for example +by using `phc2sys`. The launch file enables camera PTP synchronization, but it does not configure +the host PTP services. Choose a delay long enough for the command to reach the cameras before its +target time. + +### Absolute PTP-time trigger + +Set `trigger_mode` to `2`, leave `delay_ms` at zero, and provide a future encoded PTP timestamp. The +upper 32 bits contain seconds and the lower 32 bits contain nanoseconds: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 2, delay_ms: 0, scheduled_time: }" +``` + +The response returns `encoded_scheduled_time`, the exact 64-bit value sent to the SDK. For delayed +triggering this is the timestamp calculated by the node. `success: true` means the host dispatched +the GVCP command; the protocol does not return a device acknowledgment. diff --git a/docs/en/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md b/docs/en/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md index 66c5b353..b4c40b88 100644 --- a/docs/en/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md +++ b/docs/en/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md @@ -30,12 +30,16 @@ Further details on efficient intra-process communication can be found [here](htt The [multi_camera_shared_container](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/multi_camera_shared_container) example creates one multithreaded component container and loads two Gemini 330 Series camera components into it. Update the two `usb_port` values in `multi_camera_shared_container.launch.py`, then run: +The default ports are `2-1` and `2-2`. Use `ros2 run orbbec_camera list_devices_node` to find the ports on your system. Give each camera a unique `camera_name`. + ```bash ros2 launch orbbec_camera multi_camera_shared_container.launch.py ``` The example passes the following arguments to both camera includes: +The top-level launch file starts `shared_orbbec_container` first, then includes the example-specific `gemini_330_series_shared_container.launch.py` for each camera. The second camera starts two seconds after the first. Both includes must use the same container name, and the container must be running before components are loaded. + * `attach_to_shared_component_container=true`: Loads the camera component into an existing container instead of creating another container. * `component_container_name=shared_orbbec_container`: Selects the target container. The value must match the name of the container created by the parent launch file. * `use_intra_process_comms=true`: Enables intra-process communication for the camera component. diff --git a/docs/zh/source/camera_devices/4_application_guide/application_guide.rst b/docs/zh/source/camera_devices/4_application_guide/application_guide.rst index 7c7dc085..9dd86e6b 100644 --- a/docs/zh/source/camera_devices/4_application_guide/application_guide.rst +++ b/docs/zh/source/camera_devices/4_application_guide/application_guide.rst @@ -12,3 +12,4 @@ coordinate_and_tf.md compressed_image.md point_cloud.md + examples/ae_awb_lock.md diff --git a/docs/zh/source/camera_devices/4_application_guide/examples/ae_awb_lock.md b/docs/zh/source/camera_devices/4_application_guide/examples/ae_awb_lock.md new file mode 100644 index 00000000..b066e8b0 --- /dev/null +++ b/docs/zh/source/camera_devices/4_application_guide/examples/ae_awb_lock.md @@ -0,0 +1,36 @@ +# AE/AWB 锁定测试 + +本示例提供一个测试用 ROS 2 action,通过相机驱动服务和彩色帧元数据验证自动曝光与自动白平衡收敛后切换到手动值的流程。[查看示例源码](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/ae_awb_lock)。 + +## 运行 + +先启动相机驱动,再在同一命名空间启动测试节点: + +```bash +ros2 run orbbec_camera ae_awb_lock_test_node --ros-args -r __ns:=/camera +``` + +发送目标并打印反馈: + +```bash +ros2 action send_goal \ + /camera/run_ae_awb_lock_test \ + orbbec_camera_msgs/action/RunAeAwbLockTest \ + "{timeout_ms: 10000}" \ + --feedback +``` + +## 流程与结果 + +测试节点订阅相对话题 `color/metadata`,启用自动曝光和自动白平衡,等待 SDK 状态变为 `1`。随后,它从最新彩色帧元数据中读取曝光、彩色增益和色温,并通过结构化属性服务读取 AWB 的 R/B/G 增益。关闭自动控制后,按以下顺序写回捕获值: + +1. 彩色曝光 +2. 彩色增益 +3. AWB R/B/G 增益 +4. 色温 + +最后读取的 AWB 增益必须与捕获值完全一致。设备可能量化其他控制值,因此其他读回差异只会作为警告报告。失败或取消时,示例会尝试恢复自动曝光和自动白平衡。 + +每个反馈阶段都包含从相机服务新读取的状态值。只有必需服务全部可用后才会发布 `waiting_for_services` 反馈,因为此前无法读取状态。 + +运行时必须开启彩色流;使用 `/camera` 命名空间时,`/camera/color/metadata` 必须可用。如果超时前没有元数据,或元数据缺少 `exposure`、`gain`、`white_balance`,测试会失败,不会写入默认值。目标超时覆盖服务发现、服务调用、收敛、捕获、写回和验证;失败后的自动控制恢复使用独立的尽力而为超时。 diff --git a/docs/zh/source/camera_devices/5_advanced_guide/advanced_guide.rst b/docs/zh/source/camera_devices/5_advanced_guide/advanced_guide.rst index 3524a731..9020fc1f 100644 --- a/docs/zh/source/camera_devices/5_advanced_guide/advanced_guide.rst +++ b/docs/zh/source/camera_devices/5_advanced_guide/advanced_guide.rst @@ -26,6 +26,7 @@ multi_camera/multi_camera_synced.md multi_camera/multi_camera_synced_verification_tool.md multi_camera/gmsl_camera.md + multi_camera/gige_action_command.md 配置与模式 diff --git a/docs/zh/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md b/docs/zh/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md new file mode 100644 index 00000000..ef36aaa5 --- /dev/null +++ b/docs/zh/source/camera_devices/5_advanced_guide/multi_camera/gige_action_command.md @@ -0,0 +1,87 @@ +# GigE Action Command + +本示例通过 Group Actions 同步模式启动两台 Gemini 335Le 相机,并启动一个主机侧 Action Command 发送节点。一个 GVCP Action Command 可以触发多台相机,因此发送节点只在顶层启动一次。[查看示例源码](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/gige_action_command)。 + +## 运行条件 + +- Gemini 335Le 固件 1.8.24 或更高版本 +- Orbbec SDK 2.10.2 或更高版本 +- 两台相机与主机位于同一网络 + +运行前,修改 `multi_gige_action_command.launch.py` 中两处 `net_device_ip`,使其与相机 IP 一致。 + +## 启动相机和发送节点 + +```bash +ros2 launch orbbec_camera multi_gige_action_command.launch.py +``` + +启动文件为每台相机提供配置服务,并启动一个发送服务: + +```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 +``` + +## 配置相机 + +将两台相机的 Action Signal block 0 配置为相同的 key 和 mask: + +```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}" +``` + +需要时可读取配置: + +```bash +ros2 service call /camera_01/get_action_config \ + orbbec_camera_msgs/srv/GetActionConfig \ + "{selector: 0}" +``` + +## 触发相机组 + +请求中的 device key、group key 和 group mask 与相机配置匹配时,相机会收到触发命令。发送服务支持以下三种模式。 + +### 立即触发 + +将 `trigger_mode` 设为 `0`,延迟和指定时间均设为零: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 0, delay_ms: 0, scheduled_time: 0}" +``` + +### 相对延迟触发 + +将 `trigger_mode` 设为 `1`,并提供正数毫秒延迟。节点读取主机系统时钟,加上延迟后转换为 SDK 所需的绝对 GVCP/PTP 时间戳。以下示例延迟一秒: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 1, delay_ms: 1000, scheduled_time: 0}" +``` + +主机的 `CLOCK_REALTIME` 必须与相机处于同一 PTP 时间域,例如使用 `phc2sys` 同步。启动文件会启用相机的 PTP 同步,但不会配置主机 PTP 服务。延迟应足够长,确保命令能在目标时间前到达相机。 + +### 绝对 PTP 时间触发 + +将 `trigger_mode` 设为 `2`,`delay_ms` 设为零,并提供未来的编码 PTP 时间戳。高 32 位为秒,低 32 位为纳秒: + +```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, broadcast_ip: '255.255.255.255', trigger_mode: 2, delay_ms: 0, scheduled_time: }" +``` + +响应中的 `encoded_scheduled_time` 是发送给 SDK 的准确 64 位数值。延迟触发时,该值由节点计算。`success: true` 表示主机已发出 GVCP 命令;协议不会返回设备确认。 diff --git a/docs/zh/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md b/docs/zh/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md index a9d52888..4154eb9a 100644 --- a/docs/zh/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md +++ b/docs/zh/source/camera_devices/5_advanced_guide/performance/efficient_intra_process_communication.md @@ -30,10 +30,14 @@ [multi_camera_shared_container](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples/multi_camera_shared_container) 示例创建一个多线程组件容器,并将两个 Gemini 330 系列相机组件加载到该容器中。修改 `multi_camera_shared_container.launch.py` 中两台相机的 `usb_port` 后,运行: +默认端口为 `2-1` 和 `2-2`。可通过 `ros2 run orbbec_camera list_devices_node` 查询本机端口,并为每台相机设置不同的 `camera_name`。 + ```bash ros2 launch orbbec_camera multi_camera_shared_container.launch.py ``` +顶层启动文件先创建 `shared_orbbec_container`,再为两台相机分别包含示例专用的 `gemini_330_series_shared_container.launch.py`;第二台相机延迟两秒启动。两个相机必须指定相同的容器名称,并在加载组件前确保容器已经运行。 + 该示例向两个相机 include 传递以下参数: * `attach_to_shared_component_container=true`:将相机组件加载到已有容器中,而不是新建容器。