第三章 传感器基础与数据预处理

各位同学,今天我们来聊聊传感器。说实话,做机器人路径规划这么多年,我踩过最大的坑,往往不是算法本身,而是传感器数据没处理好。你想想看,再牛的算法,喂进去的是垃圾数据,吐出来的只能是更垃圾的结果。

这一章,我会把激光雷达、摄像头、IMU、GPS这几个常用传感器的原理讲清楚,然后重点说说数据怎么滤波、怎么对齐时间戳。嗯,这些都是我实际项目中反复折腾过的东西。

3.1 四大传感器,各有什么脾气?

3.1.1 激光雷达(LiDAR)

激光雷达的原理其实很简单——发射激光束,测量反射回来的时间,算出距离。我习惯把它叫做「机器人的眼睛」,但它跟人眼不一样,它更擅长测距,而不是认东西。

  • 工作原理:TOF(飞行时间法)或三角测距法
  • 常见类型:单线(2D)、多线(3D)、固态
  • 输出数据:点云(Point Cloud),每个点包含(x,y,z)坐标和反射强度
  • 典型频率:10Hz~20Hz

重要:激光雷达对反射材质敏感。黑色物体、玻璃、水面,这些都会导致数据异常。我在做园区无人车时,遇到过雨天积水反射导致误检测的情况,折腾了两天才定位到问题。

3.1.2 摄像头

摄像头提供的是最丰富的环境信息——颜色、纹理、语义。但它有个致命弱点:没有深度信息(除非双目或RGB-D)。说白了,单目摄像头就像你闭上一只眼看世界,能认出东西,但不知道多远。

  • 工作原理:CMOS/CCD感光元件,将光信号转为电信号
  • 常见类型:单目、双目、RGB-D(深度相机)
  • 输出数据:图像帧(RGB或灰度),通常为640×480或更高分辨率
  • 典型频率:30Hz~60Hz

我的经验:摄像头最怕光照变化。从室内到室外,自动曝光需要时间适应,这期间的数据最好别用。我一般会在代码里加一个「曝光稳定检测」逻辑,等增益稳定了再开始处理。

3.1.3 IMU(惯性测量单元)

IMU是个「闷头干活」的传感器。它不依赖外部信号,只靠自己测量加速度和角速度。但问题在于——它有漂移。你想想看,加速度积分一次得速度,再积分一次得位置,误差会像滚雪球一样越滚越大。

  • 工作原理:MEMS微机电系统,测量三轴加速度和三轴角速度
  • 输出数据:加速度(ax, ay, az)、角速度(gx, gy, gz)
  • 典型频率:100Hz~400Hz(远高于其他传感器)
  • 常见问题:零偏、温漂、随机游走

注意:IMU数据不能直接积分使用!必须配合其他传感器做融合。我曾经见过一个新手,直接用IMU积分算位置,跑了10秒就偏了十几米。

3.1.4 GPS(全球定位系统)

GPS提供绝对位置信息,但精度有限。民用GPS在开阔环境下精度约2~5米,有遮挡时可能直接跳到几十米。说白了,GPS只能告诉你「大概在哪」,不能告诉你「精确在哪」。

  • 工作原理:卫星三角定位,至少需要4颗卫星
  • 输出数据:经纬度、海拔、速度、航向角
  • 典型频率:5Hz~10Hz
  • 影响因素:多径效应、电离层延迟、卫星几何分布

3.2 数据滤波——卡尔曼滤波入门

为什么要滤波?因为传感器数据都有噪声。你拿激光雷达测同一个点,每次读数都不一样。这时候就需要滤波,把真实信号从噪声中「提纯」出来。

卡尔曼滤波,说白了就是「预测+修正」的循环。我刚开始学的时候觉得公式很复杂,后来发现核心思想就两句话:

  1. 预测:根据上一时刻的状态,猜一下当前时刻的状态
  2. 更新:用当前时刻的观测值,修正这个猜测

嗯,就这么简单。但具体实现时,有几个关键点要注意。

3.2.1 卡尔曼滤波的五步公式

我直接给出最常用的离散卡尔曼滤波公式,你们直接套用就行:

// 预测步骤
x_pred = A * x_prev + B * u      // 状态预测
P_pred = A * P_prev * A^T + Q    // 协方差预测

// 更新步骤
K = P_pred * H^T * (H * P_pred * H^T + R)^(-1)  // 卡尔曼增益
x = x_pred + K * (z - H * x_pred)                // 状态更新
P = (I - K * H) * P_pred                         // 协方差更新

这里面的参数,我一个个解释:

符号 含义 怎么调?
x 状态向量(比如位置、速度) 根据你的系统定义
A 状态转移矩阵 运动模型决定,匀速就填[1 dt; 0 1]
Q 过程噪声协方差 越大表示对模型越不信任
R 观测噪声协方差 越大表示对传感器越不信任
K 卡尔曼增益 自动计算,不用手动调

调参心得:Q和R是卡尔曼滤波里最关键的参数。我一般先固定R(根据传感器手册),然后调Q。Q调大了,滤波结果会更「相信」观测值,响应快但噪声大;Q调小了,结果更平滑但有延迟。具体怎么平衡?看你的应用场景。

3.2.2 一个简单的1D位置滤波例子

假设我们要滤波一个一维位置信号,比如激光雷达测距值。代码长这样:

import numpy as np

class KalmanFilter1D:
    def __init__(self):
        self.x = 0.0      # 初始位置
        self.P = 1.0      # 初始协方差
        self.Q = 0.01     # 过程噪声
        self.R = 0.1      # 观测噪声
        self.A = 1.0      # 状态转移(位置不变)
        self.H = 1.0      # 观测矩阵
        
    def predict(self):
        self.x = self.A * self.x
        self.P = self.A * self.P * self.A + self.Q
        
    def update(self, z):
        K = self.P * self.H / (self.H * self.P * self.H + self.R)
        self.x = self.x + K * (z - self.H * self.x)
        self.P = (1 - K * self.H) * self.P
        return self.x

# 使用示例
kf = KalmanFilter1D()
measurements = [1.1, 1.3, 0.9, 1.2, 1.0]  # 带噪声的测量值
for z in measurements:
    kf.predict()
    filtered = kf.update(z)
    print(f"测量值: {z:.2f}, 滤波后: {filtered:.2f}")

运行一下你会发现,滤波后的值比原始测量值更平滑、更稳定。这就是卡尔曼滤波的威力。

3.3 时间戳同步——一个容易被忽视的大坑

做多传感器融合时,时间戳同步是个大问题。你想想看,激光雷达10Hz,摄像头30Hz,IMU 200Hz,GPS 5Hz——这些数据到达的时间点完全不一样。如果你不做同步,直接拿最近的数据凑合,结果会非常糟糕。

我遇到过最离谱的一次,因为时间戳没对齐,融合出来的位置轨迹像喝醉了酒一样左右摇摆。查了两天才发现,原来是激光雷达和摄像头的时间基准差了50毫秒。

3.3.1 硬件同步 vs 软件同步

同步方式 原理 精度 成本
硬件同步 用PPS信号或触发线,让传感器同时采集 微秒级 高(需要硬件支持)
软件同步 在代码里做时间戳对齐 毫秒级 低(纯软件实现)

我个人建议:如果条件允许,优先用硬件同步。精度高,省心。但很多低成本方案只能用软件同步,那就得好好处理了。

3.3.2 软件同步的常用方法

软件同步的核心思路就一个:找到时间上最接近的数据对。具体做法:

  1. 给每个传感器数据打上统一的时间戳(比如用系统时间)
  2. 以主传感器(通常是频率最低的那个)的时间为基准
  3. 对每个主传感器数据,找到其他传感器中时间戳最接近的那个
  4. 如果时间差超过阈值(比如10ms),就丢弃或插值
def sync_sensors(laser_data, cam_data, max_time_diff=0.01):
    """
    激光雷达和摄像头数据同步
    laser_data: [(timestamp, pointcloud), ...]
    cam_data: [(timestamp, image), ...]
    """
    synced_pairs = []
    cam_idx = 0
    
    for laser_ts, laser_pc in laser_data:
        # 找到时间最接近的摄像头数据
        while cam_idx < len(cam_data) - 1:
            if abs(cam_data[cam_idx+1][0] - laser_ts) < abs(cam_data[cam_idx][0] - laser_ts):
                cam_idx += 1
            else:
                break
        
        cam_ts, cam_img = cam_data[cam_idx]
        time_diff = abs(laser_ts - cam_ts)
        
        if time_diff < max_time_diff:
            synced_pairs.append((laser_pc, cam_img, laser_ts))
    
    return synced_pairs

避坑指南:我曾经犯过一个错误——直接用ROS的message_filter做同步,没检查时间戳的基准。结果发现激光雷达用的是GPS时间,摄像头用的是系统时间,两者差了十几秒。所以,第一步永远是确认所有传感器的时间基准是否一致。

3.4 本章知识体系总览

为了让大家更直观地理解本章的知识结构,我画了一张流程图:

传感器基础与数据预处理 - 知识体系 激光雷达 摄像头 IMU GPS 数据预处理 去噪 | 归一化 | 异常值剔除 | 坐标系转换 数据滤波 卡尔曼滤波 | 均值滤波 | 中值滤波 时间戳同步 硬件同步 | 软件同步 | 插值对齐 高质量融合数据 → 路径规划

这张图把本章的核心脉络串起来了。从四个传感器出发,经过数据预处理,再分别做滤波和时间同步,最终输出高质量数据给路径规划用。每一步都环环相扣,缺一不可。

最后提醒一句:传感器数据处理没有银弹。卡尔曼滤波不是万能的,时间同步也不是一次调好就完事了。不同场景、不同传感器组合,参数都得重新调。我做了这么多年,每次换传感器或者换场景,都得重新走一遍调试流程。别嫌麻烦,这是必经之路。

好了,这一章的内容就到这里。传感器基础打牢了,后面讲路径规划算法时,你们会发现轻松很多。

可可精品资料库