From 5a568621ed18f054bc80218574619f4f1db220b6 Mon Sep 17 00:00:00 2001 From: ob-yalian Date: Wed, 10 Jun 2026 09:35:30 +0800 Subject: [PATCH] Refactor benchmark documentation and tools --- .../4_application_guide/launch_parameters.md | 4 +- .../5_advanced_guide/advanced_guide.rst | 1 - .../configuration/net_camera.md | 93 +------- .../camera_devices/6_benchmark/benchmark.rst | 14 +- .../6_benchmark/benchmark_tools.md | 212 ++++++++++++++++++ .../6_benchmark/benchmark_usage.md | 119 ---------- .../6_benchmark/device_query_tools.md | 71 ++++++ .../6_benchmark/diagnostic_tools.md | 118 ++++++++++ .../firmware_update_tool.md | 10 +- .../6_benchmark/introduction.md | 45 ---- .../6_benchmark/multi_camera_tools.md | 68 ++++++ .../6_benchmark/network_config_tools.md | 86 +++++++ .../camera_devices/6_benchmark/othertools.md | 110 --------- .../camera_devices/6_benchmark/tools.md | 35 +++ 14 files changed, 608 insertions(+), 378 deletions(-) create mode 100644 docs/en/source/camera_devices/6_benchmark/benchmark_tools.md delete mode 100644 docs/en/source/camera_devices/6_benchmark/benchmark_usage.md create mode 100644 docs/en/source/camera_devices/6_benchmark/device_query_tools.md create mode 100644 docs/en/source/camera_devices/6_benchmark/diagnostic_tools.md rename docs/en/source/camera_devices/{5_advanced_guide/configuration => 6_benchmark}/firmware_update_tool.md (61%) delete mode 100644 docs/en/source/camera_devices/6_benchmark/introduction.md create mode 100644 docs/en/source/camera_devices/6_benchmark/multi_camera_tools.md create mode 100644 docs/en/source/camera_devices/6_benchmark/network_config_tools.md delete mode 100644 docs/en/source/camera_devices/6_benchmark/othertools.md create mode 100644 docs/en/source/camera_devices/6_benchmark/tools.md diff --git a/docs/en/source/camera_devices/4_application_guide/launch_parameters.md b/docs/en/source/camera_devices/4_application_guide/launch_parameters.md index 3315ffb2..2e489ff0 100644 --- a/docs/en/source/camera_devices/4_application_guide/launch_parameters.md +++ b/docs/en/source/camera_devices/4_application_guide/launch_parameters.md @@ -253,9 +253,9 @@ The following are the launch parameters available: #### Firmware & Backend * **`upgrade_firmware`** - * The input parameter is the firmware path. For new versions, use the standalone `firmware_update_tool` for firmware updates. See [firmware_update_tool](../5_advanced_guide/configuration/firmware_update_tool.md). + * The input parameter is the firmware path. For new versions, use the standalone `firmware_update_tool` for firmware updates. See [firmware_update_tool Tool](../6_benchmark/firmware_update_tool.md). * **`preset_firmware_path`** - * The input parameter is the preset firmware path. If multiple paths are input, each path needs to be separated by `,` and a maximum of 3 firmware paths can be input. For new versions, use the standalone tool to burn presets. See [firmware_update_tool](../5_advanced_guide/configuration/firmware_update_tool.md). + * The input parameter is the preset firmware path. If multiple paths are input, each path needs to be separated by `,` and a maximum of 3 firmware paths can be input. For new versions, use the standalone tool to burn presets. See [firmware_update_tool Tool](../6_benchmark/firmware_update_tool.md). * **`uvc_backend`** * Optional values: `v4l2`, `libuvc`. See [Lower CPU Usage](../5_advanced_guide/performance/lower_cpu_usage.md) for low-CPU scenarios. * **`connection_delay`** 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 2a31b7b8..4f38a379 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 @@ -40,5 +40,4 @@ Configuration & Modes configuration/disparity_search_offset.md configuration/interleave_ae_mode.md configuration/predefined_presets.md - configuration/firmware_update_tool.md configuration/net_camera.md diff --git a/docs/en/source/camera_devices/5_advanced_guide/configuration/net_camera.md b/docs/en/source/camera_devices/5_advanced_guide/configuration/net_camera.md index 082fb922..50654921 100644 --- a/docs/en/source/camera_devices/5_advanced_guide/configuration/net_camera.md +++ b/docs/en/source/camera_devices/5_advanced_guide/configuration/net_camera.md @@ -44,98 +44,9 @@ For [multi_net_camera.launch.py](https://github.com/orbbec/OrbbecSDK_ROS2/blob/v ros2 launch orbbec_camera multi_net_camera.launch.py ``` -Use `list_devices_node` to inspect connected devices. Since v2.8.x, this tool also prints firmware version, preset list, preset version, local network interface name for Ethernet devices, and IP source type (`NONE`, `LLA`, `DHCP`, `PERSISTENT`). If one device fails during enumeration, the tool continues enumerating the remaining devices. +Use `list_devices_node` to inspect connected devices. For its output fields and usage, see [Device Query and Basic Maintenance Tools](../../6_benchmark/device_query_tools.md#list_devices_node). -To enable SDK and firmware logs, add `--sdk_log_level debug`: - -```bash -ros2 run orbbec_camera list_devices_node -- --sdk_log_level debug -``` - -## ip_config_tool Utility - -The **`ip_config_tool`** executable allows you to configure network camera IP settings directly from ROS 2, including DHCP, static IP, Force IP, and DHCP address assignment timeout. This is useful for quickly assigning or updating IP addresses without modifying launch files. - -> **Note:** DHCP / persistent IP configuration applied with `set_ip` is written to the device. `force_ip` is temporary and must be applied again after the device is powered off or restarted. -> **Compatibility**: `set_device_ip` is still kept as a legacy alias and calls `ip_config_tool`. The old `old_ip` argument has been renamed to `current_ip`. - -**Example Usage** - -Show help: - -```bash -ros2 run orbbec_camera ip_config_tool -- --help -``` - -Enable DHCP: - -```bash -ros2 run orbbec_camera ip_config_tool -- \ -set_ip \ ---current_ip 192.168.1.10 \ ---enable_dhcp true \ ---enable_persistent_ip false -``` - -Disable DHCP and set a persistent IP: - -```bash -ros2 run orbbec_camera ip_config_tool -- \ -set_ip \ ---current_ip 192.168.1.10 \ ---enable_dhcp false \ ---enable_persistent_ip true \ ---new_ip 192.168.1.11 \ ---mask 255.255.255.0 \ ---gateway 192.168.1.1 -``` - -Enable both DHCP and persistent IP (requires a device/firmware that supports IP config V2): - -```bash -ros2 run orbbec_camera ip_config_tool -- \ -set_ip \ ---current_ip 192.168.1.10 \ ---enable_dhcp true \ ---enable_persistent_ip true \ ---new_ip 192.168.1.11 \ ---mask 255.255.255.0 \ ---gateway 192.168.1.1 -``` - -Force IP by MAC address: - -```bash -ros2 run orbbec_camera ip_config_tool -- \ -force_ip \ ---force_ip_mac 54:14:FD:06:07:DA \ ---new_ip 192.168.1.50 \ ---mask 255.255.255.0 \ ---gateway 192.168.1.1 -``` - -Set DHCP address assignment timeout: - -```bash -ros2 run orbbec_camera ip_config_tool -- \ -set_dhcp_timeout \ ---current_ip 192.168.1.10 \ ---timeout 10 -``` - -**Parameters** - -- **`current_ip`** – Current IP address of the device. -- **`enable_dhcp`** – Enable or disable DHCP for the `set_ip` or `force_ip` subcommand. -- **`enable_persistent_ip`** – Enable or disable persistent IP for the `set_ip` subcommand. -- **`new_ip`** – Persistent IP or Force IP address to assign. -- **`mask`** – Subnet mask for the new IP. -- **`gateway`** – Gateway address for the new IP. -- **`force_ip_mac`** – Target MAC address for Force IP. -- **`timeout`** / **`dhcp_assign_ip_timeout`** – DHCP address assignment timeout in seconds. -- **`sdk_log_level`** – SDK file log level. Optional values: `debug`, `info`, `warn`, `error`, `fatal`, `off`. Any non-`off` value also attempts to enable firmware logs. - -> **Version notes**: The `LLA` switch was supported only by Gemini 335Le firmware `1.7.05` and above and Gemini 435Le firmware `1.3.17` and above. +To directly modify DHCP, persistent IP, Force IP, or DHCP address assignment timeout for network cameras, use [Network Configuration Tools](../../6_benchmark/network_config_tools.md) in Chapter 6. ## Force IP Function diff --git a/docs/en/source/camera_devices/6_benchmark/benchmark.rst b/docs/en/source/camera_devices/6_benchmark/benchmark.rst index a7a3f2ba..336ae187 100644 --- a/docs/en/source/camera_devices/6_benchmark/benchmark.rst +++ b/docs/en/source/camera_devices/6_benchmark/benchmark.rst @@ -1,11 +1,15 @@ -Benchmark +Tools ====================================================== -This chapter introduces how to use the benchmark tool to test the performance of different cameras. +This chapter summarizes the device query, maintenance, network configuration, performance diagnostics, multi-camera, and debugging helper tools provided by OrbbecSDK_ROS2. .. toctree:: :maxdepth: 2 - introduction.md - benchmark_usage.md - othertools.md \ No newline at end of file + tools.md + device_query_tools.md + network_config_tools.md + firmware_update_tool.md + benchmark_tools.md + diagnostic_tools.md + multi_camera_tools.md diff --git a/docs/en/source/camera_devices/6_benchmark/benchmark_tools.md b/docs/en/source/camera_devices/6_benchmark/benchmark_tools.md new file mode 100644 index 00000000..aa4ae035 --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/benchmark_tools.md @@ -0,0 +1,212 @@ +# Performance Benchmark Tools + +This section introduces the performance benchmark tools, their purpose, and the metrics they help measure. + +## common_benchmark_node.py + +`common_benchmark_node.py` monitors Orbbec camera performance in a ROS environment. It collects and records key camera metrics such as frame rate, latency, system resource usage, and packet/drop rate to help evaluate camera node stability and performance. Statistics are updated once per second. + +Features: + +- Measures published image frame rate and latency (current, minimum, maximum, and average). +- Monitors camera node CPU/ARM usage (current, minimum, maximum, and average). +- Tracks frame drop rate (publisher) and packet loss rate (subscriber). +- Prints real-time statistics at 1 Hz and saves results to a CSV file. +- Supports configurable runtime and CSV output path. + +In ROS 1, both frame drop rate and packet loss rate can be measured. In ROS 2, the header does not contain the `seq` field, so only publisher-side frame drop rate is calculated. + +![common_benchmark_ros1](../image/benchmark_images/common_benchmark_ros1.png "ROS1") + +![common_benchmark_ros2](../image/benchmark_images/common_benchmark_ros2.png "ROS2") + +Run example: + +```bash +ros2 run orbbec_camera common_benchmark_node.py \ + --run_time 2h \ + --csv_file /path/to/log.csv +``` + +Parameters: + +- `--run_time`: Monitoring duration, specified as a time string such as `"10s"`, `"5m"`, `"1h"`, or `"2d"`. The default is 10 seconds. +- `--csv_file`: Output CSV file path. By default, it is saved in the workspace directory as `camera_monitor_log.csv`. + +Multi-camera monitoring example: + +```bash +ros2 run orbbec_camera common_benchmark_node.py \ +--run_time 1h \ +--csv_file /tmp/cam_log.csv \ +--camera_names camera_01,camera_02 +``` + +## service_benchmark_node.py + +`service_benchmark_node` monitors service call performance. It measures service call success rate and execution time. + +Features: + +- Benchmarks a single service call and measures latency and success rate. +- Benchmarks multiple services defined in a YAML configuration file. +- Can save benchmark results to a CSV file. + +![service benchmark](../image/benchmark_images/service_benchmark.png) + +When collecting data for multiple services, using a CSV file is recommended for analysis. + +### ROS2 C++ + +Single service benchmark: + +```bash +ros2 run orbbec_camera service_benchmark_node \ + --ros-args \ + -p service_name:=/camera/get_depth_gain \ + -p service_type:=orbbec_camera_msgs/srv/GetInt32 \ + -p count:=10 +``` + +Multiple service benchmark (YAML configuration): + +```bash +ros2 run orbbec_camera service_benchmark_node \ + --ros-args \ + -p yaml_file:=/path/to/default_service.yaml +``` + +### ROS2 Python + +Single service benchmark: + +```bash +ros2 run orbbec_camera service_benchmark_node.py --service /camera/get_depth_gain --count 10 +``` + +Multiple service benchmark (YAML configuration): + +```bash +ros2 run orbbec_camera service_benchmark_node.py --yaml_file /path/to/default_service.yaml +``` + +Example YAML configuration is available at `orbbec_camera/scripts/default_service.yaml`: + +```yaml +default_count: 10 + +services: +- name: /camera/get_auto_white_balance + type: orbbec_camera_msgs/srv/GetInt32 +- name: /camera/get_color_exposure + type: orbbec_camera_msgs/srv/GetInt32 +- name: /camera/get_color_gain + type: orbbec_camera_msgs/srv/GetInt32 +- name: /camera/get_depth_exposure + type: orbbec_camera_msgs/srv/GetInt32 +- name: /camera/get_depth_gain + type: orbbec_camera_msgs/srv/GetInt32 +- name: /camera/get_device_info + type: orbbec_camera_msgs/srv/GetDeviceInfo +- name: /camera/send_software_trigger + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_auto_white_balance + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_color_ae_roi + type: orbbec_camera_msgs/srv/SetArrays + request: {data_param: [0,1279,0,719]} +- name: /camera/set_color_auto_exposure + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_color_exposure + type: orbbec_camera_msgs/srv/SetInt32 + request: {data: 30} +- name: /camera/set_color_flip + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_color_gain + type: orbbec_camera_msgs/srv/SetInt32 + request: {data: 20} +- name: /camera/set_color_mirror + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_color_rotation + type: orbbec_camera_msgs/srv/SetInt32 + request: {data: 90} +- name: /camera/set_depth_ae_roi + type: orbbec_camera_msgs/srv/SetArrays + request: {data_param: [0,1279,0,719]} +- name: /camera/set_depth_auto_exposure + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_depth_exposure + type: orbbec_camera_msgs/srv/SetInt32 + request: {data: 3000} +- name: /camera/set_depth_flip + type: std_srvs/srv/SetBool + request: {data: false} +- name: /camera/set_depth_gain + type: orbbec_camera_msgs/srv/SetInt32 + request: {data: 200} +``` + +## ob_benchmark_node + +> This tool benchmarks the performance of different OrbbecSDK_ROS2 camera configurations. Benchmark results depend on the camera and settings used. It currently only applies to ROS 2 Humble. + +Example usage code is available in [example](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples). + +### Tool Configuration + +The configuration file is `orbbec_camera/config/tools/startbenchmark/start_benchmark_params.json`. + +```json +{ + "start_benchmark_params": { + "camera_name": [ + "camera_01", + "camera_02", + "camera_03", + "camera_04" + ], + "process_name": "component_conta", + "switch_cycle": 300, + "test_cycle": 1, + "skip_number": 30 + } +} +``` + +- `camera_name`: Camera names to configure, such as `"camera_01"` or `"camera_02"`. +- `process_name`: Process name to monitor. For example, `"component_conta"` monitors the container process data. +- `switch_cycle`: Configuration switch interval in seconds. For example, `300` means the configuration switches every 300 seconds. +- `test_cycle`: Test interval in seconds. For example, `1` means the tool collects monitored process data every second. +- `skip_number`: Number of data points to skip. For example, `30` means the first 30 data points are ignored. + +### Camera Configuration (Launch Files) + +The launch folder contains multiple `.launch.py` files (`ob_benchmark_0.launch.py`, `ob_benchmark_1.launch.py`, ..., `ob_benchmark_19.launch.py`). Each file corresponds to a different camera configuration. + +### Run ob_benchmark + +```bash +source install/setup.bash +ros2 run orbbec_camera ob_benchmark_node +``` + +### Output Data Files + +Output data files are stored in the `ob_benchmark` folder with names such as `0.csv`, `1.csv`, ..., `19.csv`. + +- `0.csv` contains data from the `ob_benchmark_0.launch.py` configuration. +- `1.csv` contains data from the `ob_benchmark_1.launch.py` configuration. + +## start_benchmark_node + +`start_benchmark_node` is the subscriber used in the benchmark workflow. It subscribes to multi-camera color, depth, IR, and point cloud topics according to `camera_name` in `start_benchmark_params.json`. It is usually used together with benchmark launch files. + +```bash +ros2 run orbbec_camera start_benchmark_node +``` diff --git a/docs/en/source/camera_devices/6_benchmark/benchmark_usage.md b/docs/en/source/camera_devices/6_benchmark/benchmark_usage.md deleted file mode 100644 index 3b3e8842..00000000 --- a/docs/en/source/camera_devices/6_benchmark/benchmark_usage.md +++ /dev/null @@ -1,119 +0,0 @@ -# Benchmark Usage - -This section introduces how to use the benchmark tool in C++ and Python, and provides an example YAML configuration file. - -## Using common benchmark node - -``` -ros2 run orbbec_camera common_benchmark_node.py \ -    --run_time 2h \ -    --csv_file /path/to/log.csv -``` - - - -* **Parameters** - * **--run_time**: Duration for monitoring, specified as time strings like `"10s"`, `"5m"`, `"1h"`, `"2d"`. Default is 10 seconds. - *  **--csv_file**: Path to the output CSV file. By default, it is saved in the workspace directory with the name "camera_monitor_log.csv". - -## Using service benchmark node - -### ROS2 C++ - -* **Single service benchmark** - -``` -ros2 run orbbec_camera service_benchmark_node \ -    --ros-args \ -    -p service_name:=/camera/get_depth_gain \ -    -p service_type:=orbbec_camera_msgs/srv/GetInt32 \ -    -p count:=10 -``` - -* ****Multiple services benchmark (YAML config)**** - -``` -ros2 run orbbec_camera service_benchmark_node \ -    --ros-args \ -    -p yaml_file:=/path/to/default_service_cpp.yaml -``` - -### ROS2 Python - -* **Single service benchmark** - -``` -ros2 run orbbec_camera service_benchmark_node.py --service /camera/get_depth_gain --count 10 -``` - -* ****Multiple services benchmark (YAML config)**** - -``` -ros2 run orbbec_camera service_benchmark_node.py --yaml_file /path/to/default_service.yaml -``` - - - -### **Example YAML configuration** - -We provide an example YAML configuration, located in the `scripts` directory as `service_default.yaml`. - -```yaml -default_count: 50 - -services: -- name: /camera/get_auto_white_balance - type: orbbec_camera_msgs/srv/GetInt32 -- name: /camera/get_color_exposure - type: orbbec_camera_msgs/srv/GetInt32 -- name: /camera/get_color_gain - type: orbbec_camera_msgs/srv/GetInt32 -- name: /camera/get_depth_exposure - type: orbbec_camera_msgs/srv/GetInt32 -- name: /camera/get_depth_gain - type: orbbec_camera_msgs/srv/GetInt32 -- name: /camera/get_device_info - type: orbbec_camera_msgs/srv/GetDeviceInfo -- name: /camera/send_software_trigger - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_auto_white_balance - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_color_ae_roi - type: orbbec_camera_msgs/srv/SetArrays - request: {data_param: [0,1279,0,719]} -- name: /camera/set_color_auto_exposure - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_color_exposure - type: orbbec_camera_msgs/srv/SetInt32 - request: {data: 30} -- name: /camera/set_color_flip - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_color_gain - type: orbbec_camera_msgs/srv/SetInt32 - request: {data: 20} -- name: /camera/set_color_mirror - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_color_rotation - type: orbbec_camera_msgs/srv/SetInt32 - request: {data: 90} -- name: /camera/set_depth_ae_roi - type: orbbec_camera_msgs/srv/SetArrays - request: {data_param: [0,1279,0,719]} -- name: /camera/set_depth_auto_exposure - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_depth_exposure - type: orbbec_camera_msgs/srv/SetInt32 - request: {data: 3000} -- name: /camera/set_depth_flip - type: std_srvs/srv/SetBool - request: {data: false} -- name: /camera/set_depth_gain - type: orbbec_camera_msgs/srv/SetInt32 - request: {data: 200} -``` diff --git a/docs/en/source/camera_devices/6_benchmark/device_query_tools.md b/docs/en/source/camera_devices/6_benchmark/device_query_tools.md new file mode 100644 index 00000000..0301f81d --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/device_query_tools.md @@ -0,0 +1,71 @@ +# Device Query and Basic Maintenance Tools + +This section describes device query tools that can be used without starting the camera node, plus the basic USB permission helper script. + +## list_devices_node + +`list_devices_node` enumerates currently connected Orbbec devices. It prints device name, serial number, USB/network information, firmware version, preset list, preset version, and network device IP configuration status. + +This tool does not require the camera node to be running. It is useful for checking device connection status before launching a camera. + +Since v2.8.x, this tool also prints firmware version, preset list, preset version, local network interface name for Ethernet devices, and IP source type (`NONE`, `LLA`, `DHCP`, `PERSISTENT`). If one device fails during enumeration, the tool continues enumerating the remaining devices. + +```bash +ros2 run orbbec_camera list_devices_node +``` + +To enable SDK file logs and attempt to enable firmware logs: + +```bash +ros2 run orbbec_camera list_devices_node -- --sdk_log_level debug +``` + +## list_depth_work_mode_node + +`list_depth_work_mode_node` queries the current depth work mode and the supported depth work mode list for the current device. It does not require the camera node to be running. + +```bash +ros2 run orbbec_camera list_depth_work_mode_node +``` + +## list_camera_profile_mode_node + +`list_camera_profile_mode_node` queries supported color, depth, IR, IMU, and LiDAR stream profiles, and also prints depth work mode and preset information. It does not require the camera node to be running. + +Query the default device: + +```bash +ros2 run orbbec_camera list_camera_profile_mode_node +``` + +Query by serial number: + +```bash +ros2 run orbbec_camera list_camera_profile_mode_node -- --serial_number +``` + +Enable SDK file logs: + +```bash +ros2 run orbbec_camera list_camera_profile_mode_node -- --sdk_log_level debug +``` + +## list_ob_devices.sh + +`list_ob_devices.sh` is a source script that scans Orbbec USB devices from Linux `/sys/bus/usb` and prints USB port, product name, and serial number. It does not depend on the SDK and does not require the camera node. + +```bash +cd orbbec_camera/scripts +./list_ob_devices.sh +``` + +## install_udev_rules.sh + +`install_udev_rules.sh` installs USB device udev rules to solve device access permission issues for normal users. This script requires `sudo`. + +```bash +cd orbbec_camera/scripts +sudo bash install_udev_rules.sh +``` + +The script reloads udev rules after installation. diff --git a/docs/en/source/camera_devices/6_benchmark/diagnostic_tools.md b/docs/en/source/camera_devices/6_benchmark/diagnostic_tools.md new file mode 100644 index 00000000..5b8660b7 --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/diagnostic_tools.md @@ -0,0 +1,118 @@ +# Diagnostic and Latency Analysis Tools + +This section describes frame continuity, timestamp, topic statistics, end-to-end latency, and debugging helper tools. + +## Frame Drop Log and Timestamp CSV Recording + +After `enable_frame_drop_log` is enabled, the camera node prints color and depth frame drop statistics in the log. This helps locate frame drops at the SDK receive stage and ROS publish stage. When `frame_timestamp_csv_file` is set, the camera node also records color and depth frame timestamp data to a CSV file for analyzing frame continuity, publish latency, and timestamp anomalies. + +```bash +ros2 launch orbbec_camera gemini_330_series.launch.py \ +enable_frame_drop_log:=true \ +frame_timestamp_csv_file:=/tmp/frame_timestamp.csv +``` + +The CSV contains SDK frame index, hardware frame number, sensor timestamp, device/global/system timestamp, steady arrival/publish delta, ROS publish duration, and SDK delay fields. + +### Field Description + +The current CSV contains two groups of fields with the same structure, prefixed by `color_` and `depth_`, for example `color_sdk_frame_index` and `depth_sdk_frame_index`. The two groups have identical definitions and differ only in data source. + +| Field suffix | Description | Unit / Notes | +| --- | --- | --- | +| `_sdk_frame_index` | SDK frame index | `frame->index()` | +| `_hardware_frame_number` | Hardware frame number | `frame->getMetadataValue(OB_FRAME_METADATA_TYPE_FRAME_NUMBER)` | +| `_sensor_ts_sec` | Sensor timestamp | Seconds, usually exposure midpoint | +| `_sensor_ts_delta_us` | Delta between adjacent sensor timestamps | us | +| `_device_ts_sec` | Device clock timestamp | Seconds | +| `_device_ts_delta_us` | Delta between adjacent device timestamps | us | +| `_global_ts_sec` | Global timestamp | Seconds | +| `_global_ts_delta_us` | Delta between adjacent global timestamps | us | +| `_system_ts_sec` | SDK system timestamp | Seconds | +| `_system_ts_delta_us` | Delta between adjacent SDK system timestamps | us | +| `_arrival_steady_delta_us` | Delta between adjacent host steady arrival times | us | +| `_publish_steady_delta_us` | Delta between adjacent host steady times before publishing | us | +| `_arrival_to_publish_steady_us` | Time from ROS receiving the frame to publishing it (steady) | `publish_steady - arrival_steady` | +| `_sdk_delay_from_global_us` | SDK publish delay (global reference) | `arrival_system - global_ts` | +| `_sdk_delay_from_system_us` | SDK publish delay (system reference) | `arrival_system - sdk_system_ts` | + +### Analysis Methods + +#### Hardware Frame Drop Detection + +- Check whether `_hardware_frame_number` is continuous. +- Plot `_sensor_ts_delta_us` as a line chart or scatter plot and check for obvious jumps. +- For example, at 30 fps, the adjacent frame interval should usually be close to 33333 us. + +#### SDK / ROS Frame Drop Detection + +- Check whether `_sdk_frame_index` is continuous. +- Plot `_device_ts_delta_us`, `_global_ts_delta_us`, and `_system_ts_delta_us` as line charts or scatter plots and check for jumps. +- After `enable_frame_drop_log` is enabled, `stage=SDK_RECEIVE` in the log indicates frame drops detected at the SDK receive stage, and `stage=ROS_PUBLISH` indicates frame drops detected at the ROS publish stage. + +#### Latency Analysis + +- SDK latency: check `_sdk_delay_from_global_us` and `_sdk_delay_from_system_us` as line charts or scatter plots to observe delay changes from the low-level timestamp to arrival at the ROS node. +- ROS latency: check `_arrival_to_publish_steady_us` as a line chart or scatter plot to measure the time from the SDK callback receiving a frame to publishing the image on the ROS side. +- If you need a value closer to real processing time, prefer fields related to the steady clock. + +#### Synchronization Note + +This CSV is mainly used to analyze continuity and latency of a single color or depth stream. It cannot directly measure synchronization between color and depth. + +## topic_statistics_node + +`topic_statistics_node` uses ROS 2 topic statistics to collect image topic age and period statistics and writes `statistics.csv` in the current directory. The camera node must be running before using it. + +```bash +ros2 run orbbec_camera topic_statistics_node \ +--ros-args \ +-p image_topic:=/camera/color/image_raw \ +-p statistics_topic:=/statistics +``` + +## frame_latency_node + +`frame_latency_node` subscribes to a specified topic and calculates end-to-end latency from the message header stamp, while also printing FPS. It supports `image`, `points`, `imu`, `metadata`, `camera_info`, `rgbd`, `imu_info`, and `tf` topic types. The camera node must be running before using it. + +```bash +ros2 run orbbec_camera frame_latency_node \ +--ros-args \ +-p topic_name:=/camera/color/image_raw \ +-p topic_type:=image +``` + +Point cloud topic example: + +```bash +ros2 run orbbec_camera frame_latency_node \ +--ros-args \ +-p topic_name:=/camera/depth/points \ +-p topic_type:=points +``` + +## monitor_fd.sh + +`monitor_fd.sh` prints the file descriptor count of the `component_container` process once per second. It is useful for checking file descriptor leaks. The target process must be running before using it. + +```bash +cd orbbec_camera/scripts +./monitor_fd.sh +``` + +## plot_stat.py + +`plot_stat.py` reads `statistics.csv` from the current directory and plots age and period curves from topic statistics. It is usually used together with `topic_statistics_node`. + +```bash +cd +python3 /path/to/orbbec_camera/scripts/plot_stat.py +``` + +## receive_pc.py + +`receive_pc.py` subscribes to `/camera/depth/points` and quickly verifies whether a Python node can receive the point cloud topic. Start the camera node and enable point cloud before using it. + +```bash +python3 orbbec_camera/scripts/receive_pc.py +``` diff --git a/docs/en/source/camera_devices/5_advanced_guide/configuration/firmware_update_tool.md b/docs/en/source/camera_devices/6_benchmark/firmware_update_tool.md similarity index 61% rename from docs/en/source/camera_devices/5_advanced_guide/configuration/firmware_update_tool.md rename to docs/en/source/camera_devices/6_benchmark/firmware_update_tool.md index d6c2eca4..51742031 100644 --- a/docs/en/source/camera_devices/5_advanced_guide/configuration/firmware_update_tool.md +++ b/docs/en/source/camera_devices/6_benchmark/firmware_update_tool.md @@ -1,6 +1,6 @@ -# firmware_update_tool +# firmware_update_tool Tool -`firmware_update_tool` upgrades device firmware or writes preset files from the ROS 2 command line. Before upgrading, make sure the device connection is stable. When multiple devices are connected, specify the serial number to avoid updating the wrong device. +`firmware_update_tool` updates device firmware or burns preset files from the ROS 2 command line. Before updating, make sure the device connection is stable. When multiple devices are connected, specify serial numbers to avoid updating the wrong device. Show help: @@ -8,7 +8,7 @@ Show help: ros2 run orbbec_camera firmware_update_tool -- --help ``` -Upgrade firmware for one device: +Update firmware for one device: ```bash ros2 run orbbec_camera firmware_update_tool -- \ @@ -16,7 +16,7 @@ ros2 run orbbec_camera firmware_update_tool -- \ --firmware_path /path/to/firmware.bin ``` -Write a preset file: +Burn a preset file: ```bash ros2 run orbbec_camera firmware_update_tool -- \ @@ -24,7 +24,7 @@ ros2 run orbbec_camera firmware_update_tool -- \ --preset_path /path/to/preset.bin ``` -For batch updates, `--serial_number` accepts comma-separated values. Add `--continue_on_error` if later devices should still be processed after one device fails. +For batch updates, `--serial_number` accepts comma-separated serial numbers. Add `--continue_on_error` if later devices should still be processed after one device fails. ```bash ros2 run orbbec_camera firmware_update_tool -- \ diff --git a/docs/en/source/camera_devices/6_benchmark/introduction.md b/docs/en/source/camera_devices/6_benchmark/introduction.md deleted file mode 100644 index d6e6c821..00000000 --- a/docs/en/source/camera_devices/6_benchmark/introduction.md +++ /dev/null @@ -1,45 +0,0 @@ -# Introduction - -This section introduces the benchmark tool, explaining its purpose, features, and what it can help you measure. - -## common benchmark node - -`common_benchmark_node.py` is a tool for monitoring the performance of Orbbec cameras running in a ROS environment. It collects and records key camera metrics such as frame rate, latency, system resource usage, and packet loss rate in real time, helping users evaluate the stability and performance of camera nodes (updated once per second). - -**Features** - -- Measure published image frame rate and latency (current, min, max, average) - -- Monitor the camera node's CPU/ARM usage (current, min, max, average) - -- Track frame drop rate (publisher) and packet loss rate (subscriber) - -- Print real-time statistics (1 Hz) to the terminal and save results to a CSV file - -- Support configurable runtime duration and CSV output path - -**Example** - -In ROS1, both frame drop rate and packet loss rate can be measured, while in ROS2, the header lacks the `seq` field, so only the publisher-side frame drop rate is calculated. - -![common_benchmark_ros1](../image/benchmark_images/common_benchmark_ros1.png "ROS1") - -![common_benchmark_ros2](../image/benchmark_images/common_benchmark_ros2.png "ROS2") - -## service benchmark node - -The `service_benchmark_node` tool is used to monitor the performance of service calls. It can measure the success rate of service calls and the time required to execute service. - -**Features** - -- Benchmark a single service call, measuring latency and success rate - -- Benchmark multiple services as defined in a YAML configuration file - -- Optionally save benchmark results to a CSV file - -**Example** - -![service benchmark](../image/benchmark_images/service_benchmark.png) - -When you need to collect data for multiple services, it is recommended to use a CSV file for analysis. \ No newline at end of file diff --git a/docs/en/source/camera_devices/6_benchmark/multi_camera_tools.md b/docs/en/source/camera_devices/6_benchmark/multi_camera_tools.md new file mode 100644 index 00000000..496956fb --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/multi_camera_tools.md @@ -0,0 +1,68 @@ +# Multi-Camera Helper Tools + +This section describes multi-camera image saving, synchronization verification, and static TF debugging helper tools. + +## multi_save_rgbir_node + +`multi_save_rgbir_node` subscribes to multi-camera RGB/IR images and metadata according to `multi_save_rgbir_params.json`, and uses the `start_capture` service to trigger saving. Start the corresponding multi-camera nodes before using it. + +```bash +ros2 run orbbec_camera multi_save_rgbir_node +``` + +The configuration file is: + +```text +orbbec_camera/config/tools/multisavergbir/multi_save_rgbir_params.json +``` + +Trigger saving 10 frames: + +```bash +ros2 service call /start_capture orbbec_camera_msgs/srv/SetInt32 "{data: 10}" +``` + +## image_sync_example_node + +`image_sync_example_node` verifies multi-image timestamp synchronization online. It subscribes to 1 to 8 image topics, displays synchronized images, and prints timestamp difference and FPS statistics. Start the camera node before using it. + +If `sync_topics` is not set, the node automatically discovers color/depth image topics: + +```bash +ros2 run orbbec_camera image_sync_example_node +``` + +You can also specify topics manually: + +```bash +ros2 run orbbec_camera image_sync_example_node \ +--ros-args \ +-p sync_topics:="['/camera_01/color/image_raw', '/camera_02/color/image_raw']" +``` + +For detailed multi-camera synchronization verification, see [Multi-Camera Synchronization Verification Tool](../5_advanced_guide/multi_camera/multi_camera_synced_verification_tool.md). + +## SyncFramesMain.py + +`SyncFramesMain.py` is the offline analysis script for multi-camera synchronization verification. It reads frame data from the output directory, selects the corresponding frame matching script based on device PID, and generates matched, unmatched, and abnormal results. + +```bash +cd orbbec_camera/examples/multi_camera_synced_verification_tool/multicamera_sync/Python +python3 SyncFramesMain.py +``` + +## group_image.py + +`group_image.py` groups saved multi-camera images by timestamp and copies grouped results to the `grouped_images` directory. The default image directory in the script is `/home/orbbec/image/`; modify it to match your environment before using it. + +```bash +python3 orbbec_camera/scripts/group_image.py +``` + +## static_transforms_publisher.py + +`static_transforms_publisher.py` publishes hard-coded static TFs for specific multi-camera debugging scenarios. Modify the matrices and frame names according to the actual calibration before using it. + +```bash +python3 orbbec_camera/scripts/static_transforms_publisher.py +``` diff --git a/docs/en/source/camera_devices/6_benchmark/network_config_tools.md b/docs/en/source/camera_devices/6_benchmark/network_config_tools.md new file mode 100644 index 00000000..c2c747ce --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/network_config_tools.md @@ -0,0 +1,86 @@ +# Network Configuration Tools + +This section describes the network camera IP configuration tool. For network camera startup, automatic enumeration, launching with a specified IP address, and camera-node Force IP parameters, see [Network Camera](../5_advanced_guide/configuration/net_camera.md). + +## ip_config_tool + +`ip_config_tool` configures network camera IP settings directly from ROS 2, including DHCP, persistent IP, Force IP, and DHCP address assignment timeout. It does not require the camera node to be running and is useful for quickly assigning or updating IP addresses. + +> **Note:** DHCP / persistent IP configuration applied with `set_ip` is written to the device. `force_ip` is temporary and must be applied again after the device is powered off or restarted. +> **Compatibility:** `set_device_ip` is kept as a legacy alias and calls `ip_config_tool`. The old `old_ip` argument has been renamed to `current_ip`. + +Show help: + +```bash +ros2 run orbbec_camera ip_config_tool -- --help +``` + +Enable DHCP: + +```bash +ros2 run orbbec_camera ip_config_tool -- \ +set_ip \ +--current_ip 192.168.1.10 \ +--enable_dhcp true \ +--enable_persistent_ip false +``` + +Disable DHCP and set a persistent IP: + +```bash +ros2 run orbbec_camera ip_config_tool -- \ +set_ip \ +--current_ip 192.168.1.10 \ +--enable_dhcp false \ +--enable_persistent_ip true \ +--new_ip 192.168.1.11 \ +--mask 255.255.255.0 \ +--gateway 192.168.1.1 +``` + +Enable both DHCP and persistent IP (requires a device/firmware that supports IP config V2): + +```bash +ros2 run orbbec_camera ip_config_tool -- \ +set_ip \ +--current_ip 192.168.1.10 \ +--enable_dhcp true \ +--enable_persistent_ip true \ +--new_ip 192.168.1.11 \ +--mask 255.255.255.0 \ +--gateway 192.168.1.1 +``` + +Force IP by MAC address: + +```bash +ros2 run orbbec_camera ip_config_tool -- \ +force_ip \ +--force_ip_mac 54:14:FD:06:07:DA \ +--new_ip 192.168.1.50 \ +--mask 255.255.255.0 \ +--gateway 192.168.1.1 +``` + +Set DHCP address assignment timeout: + +```bash +ros2 run orbbec_camera ip_config_tool -- \ +set_dhcp_timeout \ +--current_ip 192.168.1.10 \ +--timeout 10 +``` + +## Parameters + +- **`current_ip`**: Current IP address of the device. +- **`enable_dhcp`**: Enable or disable DHCP for the `set_ip` or `force_ip` subcommand. +- **`enable_persistent_ip`**: Enable or disable persistent IP for the `set_ip` subcommand. +- **`new_ip`**: Persistent IP or Force IP address to assign. +- **`mask`**: Subnet mask for the new IP. +- **`gateway`**: Gateway address for the new IP. +- **`force_ip_mac`**: Target MAC address for Force IP. +- **`timeout`** / **`dhcp_assign_ip_timeout`**: DHCP address assignment timeout in seconds. +- **`sdk_log_level`**: SDK file log level. Optional values: `debug`, `info`, `warn`, `error`, `fatal`, `off`. Any non-`off` value also attempts to enable firmware logs. + +> **Version notes:** The `LLA` switch is supported only by Gemini 335Le firmware `1.7.05` and above and Gemini 435Le firmware `1.3.17` and above. diff --git a/docs/en/source/camera_devices/6_benchmark/othertools.md b/docs/en/source/camera_devices/6_benchmark/othertools.md deleted file mode 100644 index fe807663..00000000 --- a/docs/en/source/camera_devices/6_benchmark/othertools.md +++ /dev/null @@ -1,110 +0,0 @@ -# Other Tools - -## Frame Drop Logging and Frame Timestamp CSV Logging - -When `enable_frame_drop_log` is enabled, the camera node prints Color and Depth frame drop statistics to the log. The log helps distinguish drops detected at the SDK receive stage from drops detected at the ROS publish stage. When `frame_timestamp_csv_file` is set, the camera node also records Color and Depth frame timestamp data to a CSV file for frame continuity, publish latency, and timestamp debugging. - -```bash -ros2 launch orbbec_camera gemini_330_series.launch.py \ -enable_frame_drop_log:=true \ -frame_timestamp_csv_file:=/tmp/frame_timestamp.csv -``` - -The CSV includes SDK frame index, hardware frame number, sensor timestamp, device/global/system timestamp, steady arrival/publish delta values, ROS publish latency, and SDK delay fields. - -### Field Description - -The current CSV contains two sets of homogeneous fields with the prefixes `color_` and `depth_`, for example `color_sdk_frame_index` and `depth_sdk_frame_index`. The definitions are identical for both sets; only the data source differs. - -| Field suffix | Description | Unit / Notes | -| --- | --- | --- | -| `_sdk_frame_index` | SDK frame index | `frame->index()` | -| `_hardware_frame_number` | Hardware frame number | `frame->getMetadataValue(OB_FRAME_METADATA_TYPE_FRAME_NUMBER)` | -| `_sensor_ts_sec` | Sensor timestamp | Seconds, usually the midpoint of the exposure time | -| `_sensor_ts_delta_us` | Delta between adjacent sensor timestamps | us | -| `_device_ts_sec` | Device clock timestamp | Seconds | -| `_device_ts_delta_us` | Delta between adjacent device timestamps | us | -| `_global_ts_sec` | Global timestamp | Seconds | -| `_global_ts_delta_us` | Delta between adjacent global timestamps | us | -| `_system_ts_sec` | SDK system timestamp | Seconds | -| `_system_ts_delta_us` | Delta between adjacent SDK system timestamps | us | -| `_arrival_steady_delta_us` | Delta between adjacent arrival steady timestamps | us | -| `_publish_steady_delta_us` | Delta between adjacent publish steady timestamps | us | -| `_arrival_to_publish_steady_us` | Time from frame arrival to publish on the ROS side (steady) | `publish_steady - arrival_steady` | -| `_sdk_delay_from_global_us` | SDK publish delay referenced to global time | `arrival_system - global_ts` | -| `_sdk_delay_from_system_us` | SDK publish delay referenced to system time | `arrival_system - sdk_system_ts` | - -### Analysis Method - -#### Hardware Frame Drop Detection - -- Check whether `_hardware_frame_number` is continuous. -- Plot `_sensor_ts_delta_us` as a line chart or scatter plot and look for obvious jumps. -- For example, at 30 fps, the interval between adjacent frames should usually be close to 33333 us. - -#### SDK / ROS Frame Drop Detection - -- Check whether `_sdk_frame_index` is continuous. -- Plot `_device_ts_delta_us`, `_global_ts_delta_us`, and `_system_ts_delta_us` to see whether any of them show abnormal jumps. -- When `enable_frame_drop_log` is enabled, `stage=SDK_RECEIVE` means drops were detected at the SDK receive stage, and `stage=ROS_PUBLISH` means drops were detected at the ROS publish stage. - -#### Latency Analysis - -- SDK latency: inspect `_sdk_delay_from_global_us` and `_sdk_delay_from_system_us` with line charts or scatter plots to observe the delay from the underlying timestamp to frame arrival at the ROS node. -- ROS latency: inspect `_arrival_to_publish_steady_us` to measure the time from receiving a frame in the SDK callback to publishing the image on the ROS side. -- If you want a metric closer to actual processing time, prefer fields based on the steady clock. - -#### Synchronization Note - -This CSV is mainly intended for analyzing continuity and latency of a single Color or Depth stream. It cannot be used directly to evaluate synchronization between Color and Depth. - -## Ob_benchmark tool - -> The goal of this tool is to benchmark the performance of various OrbbecSDK_ROS2 camera configurations. The benchmark results depend on the camera and settings used.(Currently only works with ROS2 Humble) - -You can find example usage code in the [example](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples). - -### Tool Configuration ([start_benchmark_params.json](https://github.com/orbbec/OrbbecSDK_ROS2/blob/v2-main/orbbec_camera/config/tools/startbenchmark/start_benchmark_params.json)) - -```json -{ - "start_benchmark_params": { - "camera_name": [ - "camera_01", - "camera_02", - "camera_03", - "camera_04" - ], - "process_name": "component_conta", - "switch_cycle": 300, - "test_cycle": 1, - "skip_number": 30 - } -} -``` - -- `camera_name`: Names of the cameras to be configured. Example: `"camera_01"`, `"camera_02"`, etc. -- `process_name`: The name of the process to be monitored. For example, `"component_conta"` will monitor the data of the container process. -- `switch_cycle`: The cycle time for switching configurations, in seconds. For example, setting it to `300` means the configuration will switch every 300 seconds. -- `test_cycle`: The testing cycle, in seconds. For example, setting it to `1` means the tool will collect data for the monitored process every 1 second. -- `skip_number`: The number of data points to skip. For example, setting it to `30` means that the first 30 data points will be ignored. - -### Camera configuration (launch files) - -In the launch folder, there are multiple.launch.py files (`ob_benchmark_0.launch.py`, `ob_benchmark_1.launch.py`, ..., `ob_benchmark_19.launch.py`). Each file corresponds to a different camera configuration. - -### Running the ob_benchmark tool - -To run the tool, use the following commands: - -```bash -source install/setup.bash -ros2 run orbbec_camera ob_benchmark_node -``` - -### Output Data Files - -The output data files will be stored in the ob_benchmark folder with filenames like `0.csv`, `1.csv`, ..., 19.csv. For example: - -- `0.csv` contains data from the `ob_benchmark_0.launch.py` configuration. -- `1.csv` contains data from the `ob_benchmark_1.launch.py` configuration. diff --git a/docs/en/source/camera_devices/6_benchmark/tools.md b/docs/en/source/camera_devices/6_benchmark/tools.md new file mode 100644 index 00000000..3ceefc34 --- /dev/null +++ b/docs/en/source/camera_devices/6_benchmark/tools.md @@ -0,0 +1,35 @@ +# Tool Index + +This page is an index of common OrbbecSDK_ROS2 tools. It only lists each tool's purpose and the page that contains the full usage notes. Before running `ros2 run` commands, source ROS 2 and the workspace: + +```bash +source /opt/ros/$ROS_DISTRO/setup.bash +source install/setup.bash +``` + +## Tool Overview + +| Tool | Scenario / Full Guide | Summary | +| --- | --- | --- | +| `list_devices_node` (Recommended) | Device query and basic maintenance | Enumerates Orbbec devices and prints device, firmware, preset, and IP status. | +| `list_depth_work_mode_node` | Device query and basic maintenance | Lists the depth work modes supported by the current device. | +| `list_camera_profile_mode_node` (Recommended) | Device query and basic maintenance | Lists supported stream profiles, depth work modes, and presets. | +| `list_ob_devices.sh` | Device query and basic maintenance | Scans Orbbec USB devices from Linux USB sysfs. | +| `install_udev_rules.sh` | Device query and basic maintenance | Installs USB device udev rules. | +| `firmware_update_tool` (Recommended) | Device maintenance | Updates device firmware or burns preset files. | +| `ip_config_tool` (Recommended) | Network configuration | Configures DHCP, persistent IP, and Force IP for network cameras. | +| `common_benchmark_node.py` (Recommended) | Performance benchmark | Collects FPS, latency, CPU, memory, and frame drop statistics. | +| `service_benchmark_node.py` | Performance benchmark | Measures service call latency and success rate. | +| `ob_benchmark_node` | Performance benchmark | Runs benchmark configurations periodically and records CPU/memory data. | +| `start_benchmark_node` | Performance benchmark | Multi-topic subscriber used by the benchmark workflow. | +| `enable_frame_drop_log` / `frame_timestamp_csv_file` (Recommended) | Performance diagnostics | Built-in camera node frame drop logging and timestamp CSV recording. | +| `topic_statistics_node` | Performance diagnostics | Collects image topic age and period statistics. | +| `frame_latency_node` | Performance diagnostics | Measures latency and FPS for a specified topic. | +| `monitor_fd.sh` | Performance diagnostics | Monitors the file descriptor count of `component_container`. | +| `plot_stat.py` | Performance diagnostics | Plots topic statistics curves from `statistics.csv`. | +| `receive_pc.py` | Debug helper | Verifies whether a Python node can receive the point cloud topic. | +| `multi_save_rgbir_node` (Recommended) | Multi-camera | Saves RGB/IR images from multiple cameras. | +| `image_sync_example_node` (Recommended) | Multi-camera | Displays synchronized images and reports multi-topic timestamp statistics. | +| `SyncFramesMain.py` | Multi-camera | Offline analysis script for multi-camera synchronization verification. | +| `group_image.py` | Multi-camera | Groups saved multi-camera images by timestamp. | +| `static_transforms_publisher.py` | Multi-camera debugging | Publishes hard-coded static TFs for multi-camera debugging. |