2、传感器数据基础:LiDAR点云数据格式解析、相机图像数据格式解析、传感器坐标系与TF变换、数据录制与回放(rosbag)
好,咱们直接进入正题。这一章我把它叫做「传感器的语言课」。你想想看,Autoware 要感知周围环境,它得先听懂传感器在说什么。LiDAR 吐出来的是点云,相机给的是图像,这两种数据格式完全不同。再加上它们各自装在车上的位置不一样,坐标系还得统一。最后,怎么把这些数据录下来、回放调试?嗯,这就是本章要聊的四个核心。
2.1 LiDAR点云数据格式解析
LiDAR 点云,说白了就是一堆三维坐标点的集合。每个点除了 (x, y, z) 位置,通常还带着强度值(intensity)。我最早接触 Velodyne 的雷达时,看到原始数据包直接懵了——全是二进制流。
在 ROS 里,点云数据最常用的格式是 sensor_msgs::PointCloud2。这个消息类型比老版的 PointCloud 更灵活,它用「字段描述」的方式定义每个点的结构。
核心字段:
header:时间戳和坐标系 IDheight:如果是无序点云,height=1;有序点云(比如某些固态雷达)height>1width:点的数量(无序时)或每行点数(有序时)fields:描述每个点的字段,比如 x, y, z, intensity, ring, time 等point_step:单个点占用的字节数row_step:一行占用的字节数data:原始二进制数据
举个例子,一个典型的 32 线雷达点云,每个点通常占 16 字节(4个float:x, y, z, intensity)。你订阅到 /points_raw 话题后,可以用 pcl_ros 库直接转成 PCL 的点云类型来处理。
// 伪代码示意
void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& msg) {
pcl::PointCloud<pcl::PointXYZI> cloud;
pcl::fromROSMsg(*msg, cloud);
// 现在 cloud.points 里就是一个个带强度的点
for (auto& p : cloud.points) {
// 处理每个点
}
}
我的经验:调试时别直接打印所有点,数据量太大。先检查 msg->width 和 msg->height,确认数据是否正常。我曾经遇到过一次雷达配置错误,width 显示为 0,折腾了半天才发现是驱动没启动。
2.2 相机图像数据格式解析
相机数据相对直观一些。ROS 里图像消息是 sensor_msgs::Image。但这里有个坑——原始图像数据可能非常大(比如 1920x1080 的 RGB 图,一帧就 6MB 多)。所以实际传输时,通常会压缩。
常用的图像编码格式:
rgb8/bgr8:未压缩的彩色图,每个像素 3 字节mono8:灰度图,每个像素 1 字节16UC1:深度图,每个像素 2 字节(比如 Intel RealSense)jpeg/png:压缩格式,通过sensor_msgs::CompressedImage传输
我个人习惯在联调时先用 image_view 或 rqt_image_view 看一眼图像是否正常。如果画面是花的或者全黑,先检查 encoding 字段是否匹配。
# 命令行查看图像话题
rosrun image_view image_view image:=/camera/image_raw
注意:相机和 LiDAR 的时间戳同步是个大问题。如果图像时间戳和点云时间戳差了几十毫秒,融合出来的结果就是「鬼影」。我建议用 approximate_time_policy 做消息同步,容忍度设在 10-20ms。
2.3 传感器坐标系与TF变换
好,数据格式搞懂了,接下来是坐标系。Autoware 里传感器各有各的坐标系:LiDAR 的坐标系是 velodyne,相机的坐标系是 camera,车体本身是 base_link。它们之间怎么换算?靠 TF。
TF(Transform)就是描述两个坐标系之间相对位置和姿态的变换关系。说白了,就是告诉你「LiDAR 装在车顶哪个位置,朝哪个方向」。这个关系通常用一个 4x4 的齐次变换矩阵表示。
关键 TF 树:
map→odom:全局定位odom→base_link:里程计base_link→velodyne:LiDAR 外参base_link→camera:相机外参
你可以在终端用 tf_echo 查看任意两个坐标系的关系:
# 查看 base_link 到 velodyne 的变换
rosrun tf tf_echo base_link velodyne
为什么会搞错坐标系?我遇到过最典型的情况:标定完 LiDAR 和相机后,外参文件里的平移单位是毫米,但代码里默认是米。结果点云投影到图像上,全部偏到画面外面去了。嗯,这种低级错误排查起来最费时间。
2.4 数据录制与回放(rosbag)
最后,rosbag。这是 ROS 生态里最实用的工具,没有之一。你想想看,在实车上调试算法,万一出了问题,车都开走了,你拿什么复现?所以我的习惯是:每次路测,必录 bag。
录制的基本命令:
# 录制所有话题
rosbag record -a -o my_bag
# 只录制指定话题(节省空间)
rosbag record /points_raw /camera/image_raw /tf -o sensor_data
回放时要注意:
- 用
--clock参数发布模拟时钟,让订阅者以为时间在正常流逝 - 用
-r 0.5放慢速度,方便观察细节 - 用
-s 10跳过前 10 秒,避开启动时的异常数据
# 回放 bag,半速播放,跳过前5秒
rosbag play sensor_data.bag -r 0.5 -s 5 --clock
避坑指南:我曾经录了一个 2 小时的 bag,结果回放时发现 LiDAR 话题只录了前 10 分钟。后来排查发现是磁盘写满了。所以录制时建议用 rosbag record --split --size=1024 按大小分片,避免单文件过大导致写入失败。
知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以看到,数据从传感器出来,经过格式解析、坐标系变换,最后被 rosbag 记录下来,形成一个完整的闭环。
这张图从左到右展示了数据流动的四个阶段。每个阶段都有对应的 ROS 消息类型和工具。你调试时遇到问题,可以按这个链路逐级排查:传感器有没有数据?格式对不对?坐标系对不对?bag 录没录上?
好,这一章的内容就到这里。记住,传感器数据是感知系统的「原材料」,原材料质量不行,后面算法再牛也白搭。多动手录几段 bag,多看看原始数据长什么样,慢慢就有感觉了。