27、自动驾驶感知:多传感器融合、点云处理、车道线检测、障碍物识别与跟踪

自动驾驶感知,说白了就是给车装上“眼睛”和“大脑”。

我做了这么多年嵌入式,最深的体会是:单一传感器永远有短板。摄像头怕逆光、怕黑夜;激光雷达怕雨雪、怕灰尘;毫米波雷达分辨率又不够。所以,多传感器融合不是选择题,而是必答题。

这一章,我们就来聊聊在 Jetson 平台上,如何把这几样东西揉到一起,做出靠谱的感知系统。

核心要点:多传感器融合不是简单叠加,而是数据层面的对齐、时间层面的同步、决策层面的互补。

27.1 多传感器融合:为什么必须做?

我见过不少团队,一开始只靠摄像头做感知。结果呢?一到隧道口,车就“瞎”了。为什么?因为摄像头在光照剧烈变化时,动态范围根本跟不上。

激光雷达呢?它不怕暗,但怕大雨。雨滴会反射激光,产生大量噪点。

所以,融合的本质是取长补短

常见的融合策略

  • 前融合(Early Fusion):在原始数据层就合并。比如把激光点云投影到图像上,再一起送进神经网络。好处是信息损失少,坏处是计算量大。
  • 后融合(Late Fusion):每个传感器各自做检测,最后把结果合并。比如摄像头检测到行人,激光雷达也检测到行人,然后做匹配。好处是模块解耦,坏处是可能漏掉单传感器没检测到的目标。
  • 特征融合(Feature Fusion):在神经网络中间层做融合。这是目前工业界的主流做法,兼顾了精度和效率。

我的经验:在 Jetson Orin 上,我建议用特征融合。因为前融合太吃带宽,后融合又容易丢目标。特征融合刚好在中间,性能与精度平衡得最好。

27.2 点云处理:从原始数据到结构化信息

激光雷达出来的数据,是一堆三维坐标点。每个点还有反射强度信息。但原始点云不能直接用——太稀疏、太乱。

我们需要做几件事:

  1. 滤波:去掉离群点、地面点。地面点对障碍物检测是干扰。
  2. 降采样:点云太密了,计算扛不住。用体素滤波器(Voxel Grid Filter)把空间划分成小格子,每个格子只保留一个点。
  3. 分割:把点云分成不同的物体。常用的有欧几里得聚类、区域生长。
  4. 特征提取:对每个物体提取形状、大小、朝向等特征。

我推荐用 PointPillars 这个网络。它把点云投影成伪图像,然后用 2D 卷积处理。在 Jetson 上跑起来非常快,精度也够用。

# 点云体素滤波示例(使用 Open3D)
import open3d as o3d

pcd = o3d.io.read_point_cloud("lidar.pcd")
# 体素下采样,每个体素边长 0.2 米
downsampled = pcd.voxel_down_sample(voxel_size=0.2)
# 去除离群点
cl, ind = downsampled.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)
filtered = downsampled.select_by_index(ind)
o3d.visualization.draw_geometries([filtered])

注意:体素大小不能乱设。设太大,小物体会丢失;设太小,计算量爆炸。我一般从 0.1 米开始试,根据场景调整。

27.3 车道线检测:视觉的看家本领

车道线检测,说白了就是告诉车“你该走哪条道”。

传统方法用霍夫变换、滑动窗口。但现在的自动驾驶,基本都用深度学习。我常用的网络是 LaneNetUltra-Fast-Lane-Detection

LaneNet 的思路很巧妙:它先做语义分割,把每个车道线像素标出来;然后做聚类,把属于同一条线的像素归到一起。这样即使车道线被遮挡,也能推断出完整曲线。

在 Jetson 上部署时,要注意几点:

  • 输入分辨率不要太高。640x360 就够,再高帧率就掉下来了。
  • 用 TensorRT 做 INT8 量化。我试过,精度损失不到 1%,但速度能快 3 倍。
  • 后处理用 CUDA 加速。尤其是曲线拟合,CPU 上跑太慢。

避坑指南:我曾经在一条乡间小路上翻车——因为路沿是黄色的,车道线也是黄色的,模型把路沿当成了车道线。后来我在训练数据里加了大量“非车道线但颜色相似”的负样本,才解决这个问题。

27.4 障碍物识别与跟踪:不只是“看到”

识别出障碍物只是第一步。你还要知道它往哪走、速度多快、会不会撞上。这就是跟踪要做的事。

我常用的跟踪框架是 SORT(Simple Online and Realtime Tracking)和它的升级版 Deep SORT

SORT 的核心是卡尔曼滤波 + 匈牙利匹配。卡尔曼滤波预测目标下一帧的位置,匈牙利匹配把检测结果和已有轨迹配对。简单、快、够用。

Deep SORT 在 SORT 基础上加了外观特征。用一个小网络提取每个目标的特征向量,匹配时不仅看位置,还看长相。这样即使目标短暂被遮挡,重新出现后也能认出它。

# 卡尔曼滤波预测示例(简化版)
import numpy as np

class KalmanFilter:
    def __init__(self):
        self.x = np.zeros(4)  # [x, y, vx, vy]
        self.P = np.eye(4) * 1000  # 初始不确定性很大

    def predict(self, dt=0.1):
        F = np.array([[1, 0, dt, 0],
                      [0, 1, 0, dt],
                      [0, 0, 1, 0],
                      [0, 0, 0, 1]])
        self.x = F @ self.x
        self.P = F @ self.P @ F.T
        return self.x[:2]  # 返回预测位置

关键点:跟踪的难点不在算法本身,而在工程实现。比如:检测帧率不稳定怎么办?目标 ID 频繁跳变怎么办?这些都需要在实际系统中反复调参。

27.5 系统架构:把一切串起来

下面这张图,是我在项目中常用的感知系统架构。它把前面讲的所有模块串在了一起。

多传感器融合感知系统架构 摄像头 激光雷达 毫米波雷达 时间同步 & 空间对齐(坐标变换) 特征融合(BEV 视角 / 特征图拼接) 车道线检测 障碍物检测 目标跟踪 感知结果输出(障碍物列表 + 车道线方程)

你看,整个流程是串行的。传感器数据先做时间同步,然后对齐到统一坐标系,再进入特征融合模块,最后分发给不同的感知任务。

这里有个坑:时间同步。摄像头是 30fps,激光雷达是 10fps,毫米波雷达是 20fps。如果不做同步,你拿到的数据可能是“过去”的。我一般用 PTP(精确时间协议)给所有传感器打时间戳,然后在 Jetson 上做插值对齐。

27.6 在 Jetson 上的部署要点

模块 推荐方案 Jetson 优化技巧
点云处理 PointPillars + TensorRT INT8 量化,CUDA 加速体素化
车道线检测 Ultra-Fast-Lane-Detection 输入 640x360,FP16 推理
障碍物检测 YOLOX + 激光雷达融合 多线程流水线,检测与跟踪分离
目标跟踪 Deep SORT 特征提取网络用轻量级 MobileNet

性能警告:在 Jetson Orin NX 上,如果同时跑点云 + 视觉 + 跟踪,GPU 占用率很容易冲到 90% 以上。我建议用 DLA(深度学习加速器) 分担一部分推理任务,把 GPU 留给后处理和可视化。

嗯,说到可视化,我习惯用 ROS 2 + RViz2 做调试。把点云、检测框、车道线都发布成 topic,在 RViz 里一看就知道哪里有问题。这个习惯帮我省了不少排查时间。

最后说一句:感知系统没有“完美”这一说。你只能在精度、速度、鲁棒性之间做取舍。我的建议是——先让系统跑起来,再一点点优化。别一开始就追求 99% 的精度,那会让你陷入调参的泥潭。

公众号:蓝海资料掘金营,微信deep3321