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拼写错误——大小写敏感,别问我怎么知道的。

ROS激光雷达驱动框架与tf关系 雷达驱动节点 rplidar / sick / velodyne 消息类型 LaserScan / PointCloud2 tf广播 static_transform_publisher move_base gmapping / cartographer amcl 核心流程:驱动节点 → 消息发布 → tf坐标变换 → 下游导航/建图节点 确保frame_id一致,tf树完整,否则下游节点无法正确使用雷达数据

调试小技巧:用rviz添加LaserScan或PointCloud2显示,同时打开tf显示。如果雷达数据出现在车体之外,说明tf参数错了。我每次调试新车型,第一件事就是看rviz里的数据对不对。