2、ROS驱动框架搭建:LaserScan与PointCloud2消息类型、常用雷达驱动(sick、velodyne、rplidar)的launch文件配置、坐标系变换(tf)基础
好,咱们正式开始搭驱动框架。这一章是后面所有调优工作的地基。
你想想看,雷达数据进不来,或者坐标系乱成一锅粥,后面参数调得再好也没用。我早期有个项目,折腾了两天定位不准,最后发现是雷达的frame_id写错了——这种坑,踩过一次就长记性了。
2.1 两种核心消息类型:LaserScan vs PointCloud2
ROS里激光雷达的数据就两种主流格式。搞清楚它们的区别,你才知道什么时候该用哪个。
| 对比项 | LaserScan | PointCloud2 |
|---|---|---|
| 数据结构 | 一维数组(距离+强度) | 二维点阵(x,y,z + 可选字段) |
| 适用雷达 | 单线、低线数(如RPLIDAR、SICK LMS1xx) | 多线、高线数(如Velodyne VLP-16、Ouster) |
| 角度分辨率 | 固定角度增量 | 由点云密度决定 |
| 内存占用 | 小(适合嵌入式) | 大(适合高性能计算) |
| 常用Topic | /scan |
/velodyne_points |
核心要点:LaserScan是"极坐标"思维,PointCloud2是"笛卡尔坐标"思维。做2D导航、建图时,LaserScan够用;做3D感知、避障时,必须用PointCloud2。
我个人习惯,在launch文件里同时保留两个topic的转换节点。万一后面需要3D信息,不用重新改驱动。
2.2 常用雷达驱动配置实战
三种主流雷达,三种不同的配置套路。我一个个说。
2.2.1 RPLIDAR(思岚)—— 入门首选
RPLIDAR的驱动最简单,适合新手练手。但别小看它,我在几个AGV项目里都用过A2M8,稳定性其实不错。
<launch>
<node name="rplidar_node" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" value="/dev/ttyUSB0"/>
<param name="serial_baudrate" value="115200"/>
<param name="frame_id" value="laser"/>
<param name="angle_compensate" value="true"/>
<param name="scan_mode" value="Standard"/>
</node>
</launch>
避坑指南:serial_port别写死。我曾经在批量部署时,每台机器的USB口编号不一样。后来改用udev规则绑定设备别名,比如/dev/rplidar,一劳永逸。
2.2.2 SICK(西克)—— 工业级稳定
SICK的雷达,尤其是LMS1xx系列,在工业AGV里非常常见。驱动配置稍微复杂一点,但胜在稳定。
<launch>
<node name="sick_lms1xx" pkg="lms1xx" type="lms1xx_node" output="screen">
<param name="host" value="192.168.0.10"/>
<param name="port" value="2111"/>
<param name="frame_id" value="laser"/>
<param name="angle_start" value="-45.0"/>
<param name="angle_end" value="225.0"/>
<param name="time_offset" value="0.0"/>
</node>
</launch>
注意:SICK雷达默认使用以太网通信。确保你的工控机IP和雷达IP在同一个网段。我见过有人配了半小时,最后发现是网线没插紧——嗯,这种低级错误我也犯过。
2.2.3 Velodyne(威力登)—— 多线王者
Velodyne VLP-16是3D激光雷达的标杆。驱动配置参数多,但核心就几个。
<launch>
<node name="velodyne_node" pkg="velodyne_driver" type="velodyne_driver_node">
<param name="device_ip" value="192.168.1.201"/>
<param name="port" value="2368"/>
<param name="frame_id" value="velodyne"/>
<param name="model" value="VLP16"/>
<param name="rpm" value="600"/>
</node>
<node name="velodyne_convert" pkg="velodyne_pointcloud" type="velodyne_convert_node">
<param name="calibration" value="$(find velodyne_pointcloud)/calibrations/VLP16.yaml"/>
</node>
</launch>
这里有个细节:Velodyne驱动会输出原始包(/velodyne_packets),需要经过convert节点才能变成PointCloud2。我建议你在launch里把这两个节点分开,方便调试时单独重启。
2.3 坐标系变换(tf)基础
tf是ROS里最容易出问题、也最容易被忽视的部分。说白了,就是告诉系统"雷达装在车上的哪个位置"。
2.3.1 静态tf发布
最常用的方式。雷达相对于车体的位置是固定的,用static_transform_publisher发布一次就行。
<node pkg="tf2_ros" type="static_transform_publisher" name="laser_broadcaster"
args="0.2 0.0 0.3 0 0 0 base_link laser"/>
参数含义:x偏移0.2米,y偏移0米,z偏移0.3米,无旋转。base_link是车体坐标系,laser是雷达坐标系。
我的经验:tf的精度直接影响建图和定位。我曾经在AGV上把z轴偏移写错了0.05米,结果建出来的地图地面是倾斜的。后来用尺子重新量了安装位置,问题解决。所以,别偷懒,拿尺子量。
2.3.2 常见坐标系约定
| 坐标系名称 | 含义 | 常见父坐标系 |
|---|---|---|
base_link |
机器人本体中心 | 无(根坐标系) |
laser |
激光雷达中心 | base_link |
odom |
里程计坐标系 | base_link |
map |
全局地图坐标系 | odom |
2.3.3 验证tf树
启动所有节点后,用命令行检查tf树是否完整:
rosrun tf view_frames
evince frames.pdf
如果看到断开的链路,说明某个坐标系没发布。最常见的问题是frame_id拼写错误——大小写敏感,别问我怎么知道的。
调试小技巧:用rviz添加LaserScan或PointCloud2显示,同时打开tf显示。如果雷达数据出现在车体之外,说明tf参数错了。我每次调试新车型,第一件事就是看rviz里的数据对不对。