激光雷达基础与ROS驱动:从原理到实战
各位同学好,我是老张。今天咱们聊聊激光雷达的基础知识,以及怎么在ROS里把它用起来。说实话,我最早接触激光雷达的时候,也被那些技术术语搞得一头雾水。但别担心,咱们一步步来,把原理搞懂,把驱动调通,后面做导航就顺了。
激光雷达工作原理:TOF vs 三角法
市面上主流的激光雷达,工作原理其实就两大类:TOF(飞行时间法)和三角法。我当年在项目里选型时,就吃过亏——选错了原理,导致在室外强光下数据全飘了。所以这块你得搞清楚。
核心区别一句话:TOF测距离靠光速×时间,三角法靠几何相似三角形。
TOF(飞行时间法)
TOF的原理很简单:发射一束激光脉冲,打到物体上反射回来,接收器记录时间差。距离 = 光速 × 时间差 / 2。嗯,初中物理就够用了。
- 优点:测量距离远(几十米到上百米),精度高,受环境光影响小。
- 缺点:成本高,电路复杂,对时间测量精度要求极高(皮秒级)。
- 典型代表:Velodyne、Hesai、Ouster 等机械式或固态激光雷达。
三角法
三角法呢,是发射器与接收器之间有个固定基线。激光打到物体上,接收器上的成像位置会偏移。通过几何关系,就能算出距离。说白了,就是初中几何里的相似三角形。
- 优点:成本低,近距离精度高(厘米级甚至毫米级)。
- 缺点:测量距离短(通常10米以内),远距离精度下降快,易受环境光干扰。
- 典型代表:RPLIDAR A系列、Sick TiM系列等。
| 对比项 | TOF | 三角法 |
|---|---|---|
| 测距原理 | 光飞行时间 | 几何三角 |
| 测量距离 | 远(>30m) | 近(<10m) |
| 近距离精度 | 厘米级 | 毫米级 |
| 远距离精度 | 稳定 | 下降明显 |
| 环境光影响 | 小 | 大 |
| 成本 | 高 | 低 |
| 典型应用 | 自动驾驶、室外导航 | 室内扫地机、AGV |
我的建议:如果你做室内小场景(比如扫地机器人),三角法性价比很高。但要做室外无人车或园区物流,老老实实上TOF。我曾经在强光下用三角法雷达做室外导航,数据直接崩了,排查了三天才发现是原理问题。
ROS中LaserScan消息结构
不管什么原理的激光雷达,在ROS里最终都统一成 sensor_msgs/LaserScan 消息。这个结构你得背下来,因为后面所有算法都靠它。
# sensor_msgs/LaserScan.msg
std_msgs/Header header # 时间戳和坐标系ID
float32 angle_min # 扫描起始角度(弧度)
float32 angle_max # 扫描结束角度(弧度)
float32 angle_increment # 角度分辨率(弧度)
float32 time_increment # 每帧时间间隔(秒)
float32 scan_time # 扫描周期(秒)
float32 range_min # 最小有效距离(米)
float32 range_max # 最大有效距离(米)
float32[] ranges # 距离数据数组(米)
float32[] intensities # 反射强度数据(可选)
这里有几个坑,我当年踩过:
- 角度范围:angle_min 和 angle_max 通常是 [-π, π] 或 [0, 2π],但不同雷达不一样。比如 RPLIDAR 是 [0, 2π],而 Velodyne 是 [-π, π]。你写代码时千万别写死。
- ranges数组长度:理论上应该是 (angle_max - angle_min) / angle_increment + 1。但有些雷达会多一个或少一个点,你得检查。
- 无效值:ranges 里的 inf 或 NaN 表示没测到。处理时记得过滤,不然算法会炸。
注意:intensities 字段不是所有雷达都发。有些雷达(比如老款 RPLIDAR)就不支持。如果你代码里强依赖 intensities,记得先检查数组长度。
使用sensor_msgs驱动雷达
ROS里驱动激光雷达,说白了就是写一个节点,把雷达的原始数据转成 LaserScan 消息发出去。大部分厂商都提供了现成驱动,但有时候你得自己改改。
我以最常见的 RPLIDAR A2 为例,演示一下怎么用官方驱动:
# 安装驱动
sudo apt install ros-noetic-rplidar-ros
# 启动雷达节点
roslaunch rplidar_ros rplidar.launch
# 查看话题
rostopic list
# 应该能看到 /scan 话题
# 打印数据
rostopic echo /scan
如果你用的是其他雷达,比如思岚 S系列、Velodyne、Hesai,流程类似:
- 找到对应的 ROS 驱动包(通常叫 xxx_ros 或 xxx_driver)。
- 安装依赖(可能包括串口库、网络库等)。
- 修改 launch 文件里的参数(串口号、IP地址、坐标系等)。
- 启动节点,检查 /scan 话题是否有数据。
一个小技巧:我习惯在启动雷达后,先用 rostopic hz /scan 看看频率对不对。如果频率不对,可能是串口波特率设错了,或者 USB 线太长导致丢包。
可视化点云数据
光看数字没意思,咱们得把数据可视化出来。ROS里最常用的工具是 RViz。你想想看,激光雷达扫出来的点云在 RViz 里显示出来,那种感觉还是很爽的。
启动 RViz 并显示激光数据:
# 启动 RViz
rosrun rviz rviz
# 在 RViz 界面中:
# 1. 添加 "LaserScan" 显示类型
# 2. 选择话题为 /scan
# 3. 设置坐标系为 laser_frame(或雷达对应的 frame_id)
如果你想把 LaserScan 转成 PointCloud2(点云),方便做更高级的处理,可以用 laser_geometry 包:
# 安装
sudo apt install ros-noetic-laser-geometry
# 使用 laser_scan_to_point_cloud 节点
rosrun laser_geometry laser_scan_to_point_cloud scan:=/scan cloud:=/cloud
这样你就能在 RViz 里同时看到激光扫描线和点云了。我个人习惯用点云模式,因为可以旋转视角,看得更清楚。
避坑指南:我曾经在 RViz 里看不到点云,排查了半天发现是 frame_id 没对上。雷达发的 frame_id 是 "laser",但 RViz 的 Fixed Frame 设成了 "map"。记住:Fixed Frame 必须和雷达的 frame_id 一致,或者有 TF 变换关系。
本章知识体系
下面这张图总结了本章的核心逻辑,你可以对照着复习: