激光雷达原理与数据解析

各位同学,欢迎来到第二章。上一章我们聊了传感器融合的整体框架,这一章咱们把目光聚焦到最核心的传感器之一——激光雷达上。

说实话,我刚开始接触机器人时,觉得激光雷达就是个“高级转盘”,转一圈就能知道周围有啥。后来踩了不少坑才明白,这里面的门道可不少。今天我就把这些年积累的经验,从原理到实战,一步步拆给你看。

激光雷达工作原理

激光雷达,英文叫 LiDAR(Light Detection And Ranging)。说白了,就是通过发射激光束,测量激光从发射到反射回来的时间差,从而计算出目标物体的距离。

你想想看,这就像你对着山谷喊一声,听回声判断山有多远。只不过激光雷达用的是光速,精度能达到厘米级甚至毫米级。

核心公式:距离 = (光速 × 飞行时间) / 2

除以2是因为激光走了个来回,我们只想要单程距离。

根据扫描方式,常见的激光雷达分这么几类:

  • 机械旋转式:通过电机带动激光收发模块旋转,实现360°扫描。Velodyne、禾赛的早期产品都是这种。优点是视野广,缺点是机械结构容易磨损。
  • 固态式:没有旋转部件,靠光学相控阵或微振镜来改变激光方向。体积小、寿命长,但视场角通常有限。
  • 混合固态式:比如 Livox 的棱镜扫描方案,介于两者之间,算是折中方案。

我个人习惯在室内导航场景用机械旋转式,便宜且成熟。但如果你做的是无人机或者车载,固态式会更合适——毕竟旋转部件在震动环境下容易出问题。

一个小经验:选型时别只看线数(16线、32线、64线),还要关注角分辨率和帧率。角分辨率决定了你能看清多小的物体,帧率决定了动态场景下的数据密度。

点云数据格式

激光雷达采集到的原始数据,经过处理后就是点云(Point Cloud)。每个点包含三维坐标 (x, y, z) 和反射强度 (intensity)。

ROS2 中最常用的点云消息类型是 sensor_msgs/msg/PointCloud2。这个格式比旧版的 PointCloud 更灵活,支持自定义字段。

来看一个典型的点云消息结构:

# sensor_msgs/msg/PointCloud2
std_msgs/Header header          # 时间戳和坐标系
uint32 height                   # 如果是无序点云,height=1
uint32 width                    # 点的数量
PointField[] fields             # 字段定义(x, y, z, intensity等)
bool is_bigendian               # 字节序
uint32 point_step               # 每个点的字节数
uint32 row_step                 # 每行的字节数
uint8[] data                    # 原始二进制数据
bool is_dense                   # 是否包含无效点(NaN)

这里有个坑,我刚开始用的时候经常搞混:height 和 width 的含义。对于无序点云(大多数单线或机械式雷达),height=1,width 就是点的总数。但对于某些固态雷达,数据可能是按行排列的,这时候 height 就代表行数。

我曾经在解析某款国产雷达的数据时,默认把 height 当成了1,结果点云显示出来全是乱的。后来查文档才发现,这款雷达的数据是按16行排列的。所以,拿到新雷达第一步,先看 height 和 width 的值。

点云数据量通常很大。举个例子,一个32线、10Hz的雷达,每秒产生的点数大约是:

参数 数值
线数 32
每线点数 ~2000
帧率 10 Hz
每秒点数 32 × 2000 × 10 = 640,000
每秒数据量 ~12 MB(每个点16字节)

嗯,这里要注意,如果你的机器人主控性能一般,处理这么大数据量可能会卡顿。我建议在发布端就做降采样,或者用 VoxelGrid 滤波器减少点数。

ROS2驱动配置

ROS2 的驱动配置,说白了就是让激光雷达的数据能正确发布到 ROS2 的 topic 上。不同品牌的雷达驱动略有不同,但核心步骤是相通的。

以我常用的思岚 A1 为例,驱动包是 sllidar_ros2。安装和配置步骤如下:

  1. 安装驱动:
cd ~/ros2_ws/src
git clone https://github.com/Slamtec/sllidar_ros2.git
cd ..
colcon build --packages-select sllidar_ros2
source install/setup.bash
  1. 配置串口权限:
sudo chmod 666 /dev/ttyUSB0

这一步我经常忘。每次插上雷达发现没数据,第一反应就是检查串口权限。你可以把用户加到 dialout 组,一劳永逸:

sudo usermod -a -G dialout $USER
  1. 启动驱动节点:
ros2 launch sllidar_ros2 sllidar_a1_launch.py

启动后,你可以用 ros2 topic list 查看是否出现了 /scan 话题。再用 ros2 topic echo /scan 看看有没有数据流。

一个小技巧:如果雷达数据断断续续,多半是 USB 供电不足。我遇到过好几次,换个 USB 口或者用带外接电源的 USB HUB 就能解决。

对于其他品牌的雷达,比如 Velodyne、Ouster,驱动配置思路类似,只是参数文件里需要设置 IP 地址、端口号等网络参数。这里就不一一展开了。

使用rviz2可视化点云

数据有了,怎么看?rviz2 就是我们的眼睛。

启动 rviz2 很简单:

ros2 run rviz2 rviz2

然后在界面里:

  1. 点击左下角的 "Add" 按钮
  2. 选择 "By topic" 标签
  3. 找到 /scan 话题,选择 "LaserScan" 显示类型

如果你用的是 3D 激光雷达,话题通常是 /points 或 /velodyne_points,显示类型选择 "PointCloud2"。

这里有个关键设置:Fixed Frame。默认是 map,但如果你没有启动 map 坐标系,需要改成 laser_frame 或 base_link。否则你会看到点云在屏幕上乱飞,或者根本显示不出来。

我曾经在调试时花了半小时找问题,点云就是不出来。后来发现 Fixed Frame 设成了 map,而我的雷达数据是在 laser_frame 坐标系下发布的。坐标系不匹配,rviz2 就没法正确显示。

为了让可视化更清晰,我习惯调整这几个参数:

  • Size (m):点的大小,默认 0.01,室内场景可以调到 0.02 或 0.03
  • Style:选择 "Points" 或 "Boxes",别选 "Flat Squares",太吃性能
  • Decay Time:设为 0.5 秒,可以看到历史轨迹,方便判断动态物体

下面这张图展示了激光雷达数据从采集到可视化的完整流程:

激光雷达硬件 ROS2驱动节点 /scan 话题 rviz2可视化 串口/网络 发布 订阅 激光雷达数据流:硬件 → 驱动 → 话题 → 可视化 关键:确保 Fixed Frame 与雷达坐标系一致

看到这个流程,你应该明白了:激光雷达的数据从硬件出来,经过驱动节点转换成 ROS2 消息,发布到话题上,最后 rviz2 订阅并显示出来。每一步都可能出问题,但只要你按照这个链路去排查,总能找到原因。

好了,这一章的内容就到这里。激光雷达的原理和配置是后续所有传感器融合工作的基础,建议你亲手操作一遍,把雷达跑起来,在 rviz2 里看到点云的那一刻,你会觉得一切都值得。