diff --git a/Lidar.MD b/Lidar.MD new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Lidar.MD @@ -0,0 +1 @@ + diff --git a/Lidar_CN.MD b/Lidar_CN.MD new file mode 100644 index 00000000..792c3509 --- /dev/null +++ b/Lidar_CN.MD @@ -0,0 +1,142 @@ +# OrbbecSDK ROS2 雷达驱动 + +此 ROS2 驱动程序支持您使用Orbbec 单线/多线 LiDAR,本文档提供安装说明、使用指南以及其他重要信息,帮助您快速上手使用该驱动程序。 + +## 1. 安装 + +### 1.1 先决条件 + +在使用 OrbbecSDK ROS2 LiDAR驱动程序之前,请确保您的系统上安装了以下依赖项: + +- **ROS2**: 有效安装 ROS2(Humble、Foxy 或其他受支持的发行版)。 + - 如果您需要帮助,请参阅 [ROS2 安装指南](https://docs.ros.org/en/foxy/Installation.html). + +### 1.2 安装 deb 依赖项 + +```bash +# assume you have sourced ROS environment, same blow +sudo apt install libgflags-dev nlohmann-json3-dev \ +ros-$ROS_DISTRO-image-transport ros-${ROS_DISTRO}-image-transport-plugins ros-${ROS_DISTRO}-compressed-image-transport \ +ros-$ROS_DISTRO-image-publisher ros-$ROS_DISTRO-camera-info-manager \ +ros-$ROS_DISTRO-diagnostic-updater ros-$ROS_DISTRO-diagnostic-msgs ros-$ROS_DISTRO-statistics-msgs \ +ros-$ROS_DISTRO-backward-ros libdw-dev +``` + +### 1.3 安装 udev 规则 + +```bash +cd ~/ros2_ws/src/OrbbecSDK_ROS2/orbbec_camera/scripts +sudo bash install_udev_rules.sh +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +### 2. 入门 + +```bash +cd ~/ros2_ws/ +# build release, Default is Debug +colcon build --event-handlers console_direct+ --cmake-args -DCMAKE_BUILD_TYPE=Release +``` + +启动雷达节点 + +* 第一个终端 + +```bash +. ./install/setup.bash +ros2 launch orbbec_camera lidar.launch.py +``` + +* 第二个终端 + +```bash +. ./install/setup.bash +rviz2 +``` + +1.打开Rviz2。 + +2.添加一个 `PointCloud2`或者 `LaserScan`显示。 + +3.`PointCloud2`选择 `/lidar/cloud/points`话题,`LaserScan`选择 `/lidar/scan/points`话题。 + +4.将 `Fixed Frame`设置为 `lidar_lidar_frame`,以正确对齐数据。 + +* `PointCloud2`示例可视化: + +![module in rviz2](./docs/images/lidar0.jpg) + +* `LaserScan`示例可视化: + +![module in rviz2](./docs/images/lidar1.png) + +## 2. 用法 + +### 2.1 运行驱动程序 + +要启动驱动程序,请启动提供的 ROS2 启动文件: + +```bash +source install/setup.bash +# Launch the driver with point cloud data +ros2 launch orbbec_camera lidar.launch.py lidar_format:=LIDAR_POINT +# Launch the driver with sphere point cloud data +ros2 launch orbbec_camera lidar.launch.py lidar_format:=LIDAR_SPHERE_POINT +# Launch the driver with laser scan data +ros2 launch orbbec_camera lidar.launch.py lidar_format:=LIDAR_SCAN +``` + +此命令将启动与 Orbbec LiDAR 设备接口的节点。运行此命令前,请确保 LiDAR 硬件已正确连接。 + +### 2.2 获取已连接雷达的设备信息 + +```bash +ros2 run orbbec_camera list_devices_node +``` + +此命令将列出已连接的 LiDAR 设备,并显示它们各自的 IP 地址和端口。您可以使用这些信息来配置驱动程序以连接到特定设备。 + +### 2.3 检查雷达支持哪些配置 + +```bash +ros2 run orbbec_camera list_camera_profile_mode_node +``` + +### 2.4 参数和配置 + +`lidar.launch.py`文件包含驱动程序的默认参数。您可以通过修改启动文件或创建自定义配置文件来自定义这些设置。关键参数包括: + +- **device_type**:启动的设备类型。可选的值:`lidar`、`camera`。该参数设置为 `lidar`则启动雷达设备,设置为 `camera`则启动相机设备。 +- **camera_name**:启动节点命名空间。 +- **device_num**:设备数量。如果需要启动多个设备,则必须填写此项。 +- **upgrade_firmware**:固件升级功能。输入参数是固件路径。 +- **connection_delay**:重新打开设备的延迟时间(以毫秒为单位)。并且在热插拔时立即重新打开设备可能会导致固件崩溃。 +- **publish_tf**:启用 TF 发布。 +- **tf_publish_rate**:TF 发布频率。 +- **lidar_format**:雷达的数据格式。可选值:`LIDAR_POINT`、`LIDAR_SPHERE_POINT` 、`LIDAR_SCAN` +- **lidar_rate**:雷达的扫描速率。 +- **min_angle**:雷达扫描范围的最小角度,以度为单位(例如 `-135.0`)。默认值:`-135.0`。 +- **max_angle**:雷达扫描范围的最大角度,以度为单位(例如 `135.0`)。默认值:`135.0`。 +- **min_range**:雷达可测量的最小距离,以米为单位。默认值:`0.05`。 +- **max_range**:雷达可测量的最大距离,以米为单位。默认值:`30.0`。 +- **echo_mode**:雷达的回波模式。可选值:`Last Echo`,`First Echo` +- **point_cloud_qos**:ROS 2 消息服务质量 (QoS) 设置。可能的值包括 `SYSTEM_DEFAULT`、`DEFAULT`、`PARAMETER_EVENTS`、`SERVICES_DEFAULT`、`PARAMETERS` 和 `SENSOR_DATA`,并且不区分大小写。这些值分别对应于 `rmw_qos_profile_system_default`、`rmw_qos_profile_default`、`rmw_qos_profile_parameter_events`、`rmw_qos_profile_services_default`、`rmw_qos_profile_parameters` 和 `SENSOR_DATA`。 +- **enumerate_net_device**:启用自动枚举网络设备。 +- **net_device_ip**:网络设备的IP地址。 +- **net_device_port**:网络这边的端口号。 +- **log_level**:SDK日志级别,默认值为 `none`,可选值为 `debug`、`info`、`warn`、`error`、`fatal` +- **time_domain**:设备的时间戳类型。可选值为 `device`、`global`、`system` +- **config_file_path**:YAML 配置文件的路径。默认值为“”。如果未指定配置文件,则将使用启动文件中的默认参数。 +- **enable_heartbeat**:启用心跳功能,默认为 `false`。如果设置为 `true`,摄像头节点将向固件发送心跳信号;如果需要硬件日志记录,也应设置为 `true`。 + +## pointcloud data 详细说明 + +Livox pointcloud2 (PointXYZRT) 点云格式,如下: + +``` +float32 x # X axis, unit:m +float32 y # Y axis, unit:m +float32 z # Z axis, unit:m +uint8 reflectivity # lidar reflectivity +uint8 tag # lidar tag +``` diff --git a/docs/images/lidar0.jpg b/docs/images/lidar0.jpg new file mode 100644 index 00000000..471b730e Binary files /dev/null and b/docs/images/lidar0.jpg differ diff --git a/docs/images/lidar1.png b/docs/images/lidar1.png new file mode 100644 index 00000000..d1048f6f Binary files /dev/null and b/docs/images/lidar1.png differ diff --git a/orbbec_camera/include/orbbec_camera/ob_lidar_node.h b/orbbec_camera/include/orbbec_camera/ob_lidar_node.h index 746c60fe..55a173b8 100644 --- a/orbbec_camera/include/orbbec_camera/ob_lidar_node.h +++ b/orbbec_camera/include/orbbec_camera/ob_lidar_node.h @@ -236,7 +236,7 @@ class OBLidarNode { // lidar std::string lidar_format_ = "ANY"; int lidar_rate_ = 0; - std::string echo_mode_ = "single channel"; + std::string echo_mode_ = ""; std::map rate_int_; std::map rate_; std::map frame_id_; diff --git a/orbbec_camera/launch/lidar.launch.py b/orbbec_camera/launch/lidar.launch.py index 3d9a894f..af59ed64 100644 --- a/orbbec_camera/launch/lidar.launch.py +++ b/orbbec_camera/launch/lidar.launch.py @@ -8,7 +8,7 @@ from launch_ros.descriptions import ComposableNode def load_yaml(file_path): - with open(file_path, 'r') as f: + with open(file_path, "r") as f: return yaml.safe_load(f) @@ -29,20 +29,22 @@ def convert_value(value): return float(value) except ValueError: pass - if value.lower() == 'true': + if value.lower() == "true": return True - elif value.lower() == 'false': + elif value.lower() == "false": return False return value def load_parameters(context, args): - default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args} - config_file_path = LaunchConfiguration('config_file_path').perform(context) + default_params = { + arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args + } + config_file_path = LaunchConfiguration("config_file_path").perform(context) if config_file_path: yaml_params = load_yaml(config_file_path) default_params = merge_params(default_params, yaml_params) - skip_convert = {'config_file_path', 'usb_port', 'serial_number'} + skip_convert = {"config_file_path", "usb_port", "serial_number"} return { key: (value if key in skip_convert else convert_value(value)) for key, value in default_params.items() @@ -51,32 +53,32 @@ def load_parameters(context, args): def generate_launch_description(): args = [ - DeclareLaunchArgument('device_type', default_value='lidar'), - DeclareLaunchArgument('camera_name', default_value='lidar'), - DeclareLaunchArgument('device_num', default_value='1'), - DeclareLaunchArgument('upgrade_firmware', default_value=''), - DeclareLaunchArgument('connection_delay', default_value='10'), - DeclareLaunchArgument('publish_tf', default_value='true'), - DeclareLaunchArgument('frame_id', default_value='scan'), - DeclareLaunchArgument('tf_publish_rate', default_value='0.0'), - DeclareLaunchArgument('lidar_format', default_value='ANY'),#LIDAR_POINT, LIDAR_SPHERE_POINT, LIDAR_SCAN - DeclareLaunchArgument('lidar_rate', default_value='20'), - DeclareLaunchArgument('min_angle', default_value='-135.0'), - DeclareLaunchArgument('max_angle', default_value='135.0'), - DeclareLaunchArgument('min_range', default_value='0.05'), - DeclareLaunchArgument('max_range', default_value='30.0'), - DeclareLaunchArgument('echo_mode', default_value='single channel'), - DeclareLaunchArgument('point_cloud_qos', default_value='default'), - # Network device settings: default enumerate_net_device is set to true, which will automatically enumerate network devices - # If you do not want to automatically enumerate network devices, - # you can set enumerate_net_device to true, net_device_ip to the device's IP address, and net_device_port to the default value of 8090 - DeclareLaunchArgument('enumerate_net_device', default_value='true'), - DeclareLaunchArgument('net_device_ip', default_value=''), - DeclareLaunchArgument('net_device_port', default_value='0'), - DeclareLaunchArgument('log_level', default_value='none'), - DeclareLaunchArgument('time_domain', default_value='device'),# global, device, system - DeclareLaunchArgument('config_file_path', default_value=''), - DeclareLaunchArgument('enable_heartbeat', default_value='false'), + DeclareLaunchArgument("device_type", default_value="lidar"), + DeclareLaunchArgument("camera_name", default_value="lidar"), + DeclareLaunchArgument("device_num", default_value="1"), + DeclareLaunchArgument("upgrade_firmware", default_value=""), + DeclareLaunchArgument("connection_delay", default_value="10"), + DeclareLaunchArgument("publish_tf", default_value="true"), + DeclareLaunchArgument("tf_publish_rate", default_value="0.0"), + DeclareLaunchArgument( + "lidar_format", default_value="ANY" + ), # LIDAR_POINT, LIDAR_SPHERE_POINT, LIDAR_SCAN + DeclareLaunchArgument("lidar_rate", default_value="20"), + DeclareLaunchArgument("min_angle", default_value="-135.0"), + DeclareLaunchArgument("max_angle", default_value="135.0"), + DeclareLaunchArgument("min_range", default_value="0.05"), + DeclareLaunchArgument("max_range", default_value="30.0"), + DeclareLaunchArgument("echo_mode", default_value="single channel"), + DeclareLaunchArgument("point_cloud_qos", default_value="default"), + DeclareLaunchArgument("enumerate_net_device", default_value="true"), + DeclareLaunchArgument("net_device_ip", default_value=""), + DeclareLaunchArgument("net_device_port", default_value="0"), + DeclareLaunchArgument("log_level", default_value="none"), + DeclareLaunchArgument( + "time_domain", default_value="device" + ), # global, device, system + DeclareLaunchArgument("config_file_path", default_value=""), + DeclareLaunchArgument("enable_heartbeat", default_value="false"), ] def get_params(context, args): @@ -98,29 +100,30 @@ def generate_launch_description(): ] else: return [ - GroupAction([ - PushRosNamespace(LaunchConfiguration("camera_name")), - ComposableNodeContainer( - name="camera_container", - namespace="", - package="rclcpp_components", - executable="component_container", - composable_node_descriptions=[ - ComposableNode( - package="orbbec_camera", - plugin="orbbec_camera::OBCameraNodeDriver", - name=LaunchConfiguration("camera_name"), - parameters=params, - ), - ], - # prefix=["xterm -e gdb -ex run --args"], - output="screen", - ) - ]) + GroupAction( + [ + PushRosNamespace(LaunchConfiguration("camera_name")), + ComposableNodeContainer( + name="camera_container", + namespace="", + package="rclcpp_components", + executable="component_container", + composable_node_descriptions=[ + ComposableNode( + package="orbbec_camera", + plugin="orbbec_camera::OBCameraNodeDriver", + name=LaunchConfiguration("camera_name"), + parameters=params, + ), + ], + # prefix=["xterm -e gdb -ex run --args"], + output="screen", + ), + ] + ) ] return LaunchDescription( - args + [ - OpaqueFunction(function=lambda context: create_node_action(context, args)) - ] + args + + [OpaqueFunction(function=lambda context: create_node_action(context, args))] ) diff --git a/orbbec_camera/src/ob_lidar_node.cpp b/orbbec_camera/src/ob_lidar_node.cpp index 79a8b1f9..6d2026d3 100644 --- a/orbbec_camera/src/ob_lidar_node.cpp +++ b/orbbec_camera/src/ob_lidar_node.cpp @@ -138,7 +138,7 @@ void OBLidarNode::getParameters() { setAndGetNodeParameter(tf_publish_rate_, "tf_publish_rate", 0.0); setAndGetNodeParameter(time_domain_, "time_domain", "global"); setAndGetNodeParameter(enable_heartbeat_, "enable_heartbeat", false); - setAndGetNodeParameter(echo_mode_, "echo_mode", "single channel"); + setAndGetNodeParameter(echo_mode_, "echo_mode", ""); setAndGetNodeParameter(point_cloud_qos_, "point_cloud_qos", "default"); setAndGetNodeParameter(min_angle_, "min_angle", -135.0); setAndGetNodeParameter(max_angle_, "max_angle", 135.0); @@ -164,10 +164,11 @@ void OBLidarNode::setupDevices() { RCLCPP_INFO_STREAM(logger_, "Setting heartbeat to " << (enable_heartbeat_ ? "ON" : "OFF")); TRY_TO_SET_PROPERTY(setBoolProperty, OB_PROP_HEARTBEAT_BOOL, enable_heartbeat_); } - if (device_->isPropertySupported(OB_PROP_LIDAR_ECHO_MODE_INT, OB_PERMISSION_READ_WRITE)) { - if (echo_mode_ == "single channel") { + if (!echo_mode_.empty() && + device_->isPropertySupported(OB_PROP_LIDAR_ECHO_MODE_INT, OB_PERMISSION_READ_WRITE)) { + if (echo_mode_ == "Last Echo") { TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_ECHO_MODE_INT, 0); - } else if (echo_mode_ == "dual channel") { + } else if (echo_mode_ == "First Echo") { TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_ECHO_MODE_INT, 1); } RCLCPP_INFO_STREAM(