3、数据采集基础:传感器数据采集原理与格式

好,咱们进入实战环节的第一个硬核模块——数据采集。

说实话,很多做算法的朋友容易忽略这一步。他们觉得数据嘛,拿来用就行了。但我得说句实在话:数据采集的质量,直接决定了你后面所有工作的天花板。你模型再牛,输入的是垃圾,输出也只会是垃圾。

这一章,咱们就聊聊三种最常用的传感器:相机、激光雷达、IMU。我会结合我踩过的坑,把它们的原理、数据格式、以及怎么存怎么传,一次性讲清楚。

3.1 相机:最直观的“眼睛”

相机采集的是图像数据。说白了,就是把三维世界投影到二维平面上。

这里有个关键点:相机采集的不是“照片”,而是“光强分布”。每个像素点记录的是该位置接收到的光子数量。

3.1.1 相机的工作原理

我简单说一下流程:

  • 镜头:把光线聚焦到传感器上
  • 传感器(CMOS/CCD):把光信号转成电信号
  • ADC(模数转换器):把模拟电信号转成数字值
  • ISP(图像信号处理器):做白平衡、去噪、色彩校正等处理

嗯,这里要注意:ISP处理后的图像,其实已经“失真”了。如果你做的是高精度视觉测量,我建议你尽量拿原始RAW数据。我在做自动驾驶项目时就吃过这个亏——用了ISP处理后的图像做标定,结果精度一直上不去,后来换成RAW数据才搞定。

3.1.2 相机数据格式

常见的格式有这些:

格式 说明 典型场景
RAW 传感器原始数据,未处理 高精度标定、专业摄影
YUV 亮度+色度分离存储 视频编码、嵌入式设备
RGB/BGR 最常见的彩色图像格式 通用视觉算法
JPEG/PNG 压缩格式,有损/无损 存储、传输
我的建议:做数据采集时,尽量存RAW或无损格式。压缩格式虽然省空间,但会丢失细节。你想想看,如果采集的数据本身就有损,那标注出来的结果能准吗?

3.2 激光雷达:精准的“尺子”

激光雷达,简称LiDAR。它不像相机那样“看”颜色,而是直接测量距离。

原理其实很简单:发射激光束,测量反射回来的时间。光速是已知的,时间差一算,距离就出来了。

3.2.1 激光雷达的类型

  • 机械式:旋转扫描,360度视野。Velodyne是代表。缺点是贵、有机械磨损
  • 固态式:没有旋转部件,靠相控阵或MEMS镜片扫描。成本低,但视场角小
  • 混合固态:介于两者之间,目前主流方案

我个人习惯用机械式做高精度地图采集,固态式做量产车。为什么?机械式精度高,但寿命短;固态式寿命长,但视野受限。没有完美的方案,只有适合的方案。

3.2.2 点云数据格式

激光雷达采集的数据叫“点云”。每个点包含:

  • xyz坐标:三维空间位置
  • intensity(强度):反射回来的光强,可以区分不同材质
  • ring(环号):属于哪条扫描线
  • timestamp(时间戳):每个点的精确时间

避坑指南:我曾经遇到过一个问题——激光雷达的点云时间戳不准确。后来发现是驱动里用了系统时间,而系统时间被NTP同步时跳变了。解决方案是:用激光雷达硬件提供的PPS信号做时间同步,或者用GPS的PTP协议。

3.3 IMU:感知“姿态”的陀螺仪

IMU(惯性测量单元)包含加速度计陀螺仪。加速度计测线加速度,陀螺仪测角速度。

说白了,IMU就是告诉你“我现在在怎么动”。但它有个致命问题:漂移

3.3.1 IMU的误差来源

  • 零偏:静止时输出不为0
  • 噪声:随机波动
  • 温漂:温度变化导致参数变化
  • 尺度因子误差:输出值与真实值的比例偏差

你想想看,加速度计测的是加速度,你要得到位置,得积分两次。积分一次,误差累积一次。所以纯IMU定位,几秒钟就飘得没边了。

重要提醒:IMU数据不能单独用!必须和相机或激光雷达做融合。我见过有人想用IMU做纯惯性导航,结果10秒后位置误差就超过10米了。IMU的作用是短时间内的相对运动估计,不是绝对定位。

3.4 数据格式与协议

数据采回来了,怎么存?怎么传?这里介绍两种最主流的格式。

3.4.1 ROS Bag

ROS(机器人操作系统)的Bag文件,是机器人领域的事实标准。

它的核心思想是:把不同话题(topic)的数据按时间戳存到一起

# 录制bag
rosbag record /camera/image_raw /lidar/points /imu/data

# 回放bag
rosbag play 2024-01-15-10-30-00.bag

# 查看bag信息
rosbag info 2024-01-15-10-30-00.bag

Bag的好处是:

  • 时间同步:所有数据按时间戳对齐
  • 多传感器:一个文件包含所有数据
  • 可回放:像放录像一样回放数据

但Bag也有缺点:文件体积大,不支持随机访问。你想查第1000帧的数据,得从头读到第1000帧。

3.4.2 HDF5

HDF5是科学计算领域常用的格式。它比Bag更灵活,支持:

  • 分层结构:像文件夹一样组织数据
  • 随机访问:直接读取任意位置的数据
  • 压缩:内置压缩算法,节省空间
  • 并行I/O:多线程同时读写
import h5py
import numpy as np

# 写入HDF5
with h5py.File('sensor_data.h5', 'w') as f:
    # 创建组
    camera_group = f.create_group('camera')
    lidar_group = f.create_group('lidar')
    
    # 写入数据
    camera_group.create_dataset('image_0001', data=image_data)
    camera_group.create_dataset('timestamp', data=timestamps)
    
    lidar_group.create_dataset('point_cloud_0001', data=point_cloud)
    lidar_group.create_dataset('intensity', data=intensity_data)

# 读取HDF5
with h5py.File('sensor_data.h5', 'r') as f:
    image = f['camera/image_0001'][:]
    points = f['lidar/point_cloud_0001'][:]
我的选择:做原型验证时用ROS Bag,方便调试。做大规模数据采集时用HDF5,性能更好。如果你要处理TB级的数据,HDF5几乎是唯一选择。

3.5 时间同步:被忽视的关键

最后,我必须强调一个容易被忽视的问题——时间同步

相机、激光雷达、IMU各自有自己的时钟。如果不做同步,你拿到的数据就是“错位的”。比如相机拍到一辆车在位置A,激光雷达却认为它在位置B。

解决方案:

  • 硬件同步:用GPS的PPS信号给所有传感器提供统一时钟
  • 软件同步:用NTP或PTP协议做网络时间同步
  • 后处理同步:采集时记录每个数据的时间戳,事后做插值对齐
血的教训:我曾经在一个项目中,因为时间同步没做好,导致标定结果一直不对。折腾了两周才发现是相机和激光雷达的时间差了200毫秒。200毫秒,对于高速运动的车辆来说,就是几米的误差。从那以后,我每次做数据采集,第一件事就是检查时间同步。

好了,这一章的内容就到这里。数据采集是基础中的基础,别嫌烦,把这一步做扎实了,后面的路会顺很多。