感知模块架构:传感器配置方案与数据融合策略

聊到感知模块,我习惯先看传感器配置。说白了,这就是自动驾驶的「眼睛」怎么搭配的问题。你想想看,光靠一种传感器,就像人只用一只眼看世界——总有盲区。

传感器配置方案

先说说主流方案。L4级自动驾驶,传感器配置一般分三档:

  • 视觉主导方案:8-12个摄像头 + 3-5个毫米波雷达 + 12个超声波
  • 激光雷达主导方案:3-5个激光雷达 + 6-8个摄像头 + 5个毫米波雷达
  • 融合均衡方案:1-3个激光雷达 + 8个摄像头 + 5个毫米波雷达 + 12个超声波

我个人更倾向融合均衡方案。为什么?我在项目中遇到过纯视觉方案在隧道出口瞬间「失明」的情况——阳光直射导致摄像头过曝,要不是毫米波雷达及时补位,后果不堪设想。

传感器类型 优势 劣势 典型数量
摄像头 纹理丰富、颜色识别、成本低 光照敏感、深度估计弱 6-12个
激光雷达 3D点云精准、不受光照影响 雨雾衰减、成本高 1-5个
毫米波雷达 全天候、测速准、穿透力强 角度分辨率低、静态目标弱 3-5个
超声波 近距离精准、成本极低 距离短、易受干扰 8-12个

关键原则:传感器配置不是堆数量,而是补短板。每种传感器都有「死穴」,配置方案就是让它们互相兜底。

感知算法流水线

传感器装好了,接下来是算法怎么跑。我习惯把感知流水线分成三个并行的线程:检测、跟踪、分割。

检测(Detection)

检测是感知的入口。摄像头这边,YOLOv8和BEVFormer是目前的主流。激光雷达那边,PointPillars和CenterPoint用得比较多。

嗯,这里要注意:检测不是越快越好。我见过团队为了追求实时性,把模型剪枝到精度崩了——车都开到跟前了还没识别出来。我个人建议,检测帧率稳定在20-30fps就够了,关键是延迟抖动要小。

// 伪代码:检测模块调度
while (sensor_data_ready()) {
    camera_frame = get_camera_frame();
    lidar_pointcloud = get_lidar_pointcloud();
    
    // 并行检测
    det_results_cam = detect_camera(camera_frame);  // YOLOv8
    det_results_lidar = detect_lidar(lidar_pointcloud);  // PointPillars
    
    // 检测结果融合
    fused_detections = fuse_detections(det_results_cam, det_results_lidar);
    
    // 送入跟踪模块
    tracking_module.update(fused_detections);
}

跟踪(Tracking)

检测是「这一刻」的事,跟踪是「连续时刻」的事。我常用的跟踪框架是SORT和DeepSORT的变体。

曾经有个坑:单纯用卡尔曼滤波做跟踪,遇到急刹车时目标ID会频繁切换。后来我加了ReID特征匹配,ID切换率降了60%。说白了,跟踪的核心就是「关联」——把上一帧的目标和当前帧的目标对上号。

避坑指南:我曾经在跟踪模块里用了太复杂的特征提取网络,导致每帧处理时间从15ms飙到45ms。后来换成轻量级特征,效果差不多,速度翻倍。记住:跟踪模块的延迟会直接影响下游规划模块的响应。

分割(Segmentation)

分割是感知的「精细活」。可行驶区域、车道线、路沿、障碍物轮廓,这些都需要分割来做。

摄像头这边,我习惯用基于Transformer的分割头,比如SegFormer。激光雷达那边,RangeNet++和PolarNet效果不错。

你想想看,检测只能告诉你「那里有辆车」,分割能告诉你「这辆车占了哪些像素」。对于泊车场景,分割的精度直接决定了能不能停进去。

数据融合策略

传感器数据都来了,怎么融合?我把它分成三个层次:

  1. 数据级融合:原始数据直接拼接。比如把激光雷达点云投影到图像上,生成RGB+Depth的4通道数据。
  2. 特征级融合:各自提取特征后再融合。比如BEV空间下的特征对齐。
  3. 目标级融合:各自检测出目标后再融合。比如用匈牙利算法做目标匹配。

我个人最常用的是特征级融合。为什么?数据级融合太吃算力,目标级融合又容易丢失细节。特征级融合刚好在中间——既保留了空间信息,又控制了计算量。

注意:融合不是简单的「加和」。不同传感器的坐标系、时间戳、数据频率都不一样。我见过一个项目,摄像头和激光雷达的时间戳差了50ms,结果融合出来的目标位置偏了2米——这要是用在高速上,后果可想而知。

时间同步怎么做?我习惯用硬件触发的方式。每个传感器都接同一个GPS时钟,保证时间戳精度在1ms以内。如果硬件不支持,那就用插值法——把高频传感器的数据对齐到低频传感器的时间戳上。

空间对齐呢?标定是关键。摄像头和激光雷达的外参标定,我推荐用棋盘格法。毫米波雷达的标定比较麻烦,因为它没有视觉特征,需要用角反射器。

// 时间同步伪代码
struct SensorData {
    uint64_t timestamp_us;  // 微秒级时间戳
    void* data;
};

// 使用时间戳对齐
SensorData align_sensors(SensorData cam_data, SensorData lidar_data) {
    // 找到时间戳最接近的帧
    uint64_t time_diff = abs(cam_data.timestamp_us - lidar_data.timestamp_us);
    if (time_diff > 50000) {  // 超过50ms,丢弃
        return invalid_data();
    }
    // 插值对齐
    return interpolate(cam_data, lidar_data, time_diff);
}

最后说一句:数据融合没有银弹。不同场景、不同传感器配置,融合策略都要调整。我建议先跑通目标级融合,再逐步升级到特征级融合。步子迈大了,容易扯着蛋。

总结:感知模块架构的核心就三件事——传感器怎么配、算法怎么跑、数据怎么融。这三件事做好了,感知模块就稳了。剩下的,就是不断迭代优化了。