3、坐标系与标定:车辆坐标系、传感器坐标系、世界坐标系,以及传感器联合标定方法

各位同学,咱们今天聊一个绕不开的话题——坐标系与标定。

说实话,我在刚入行那会儿,觉得坐标系这东西不就是个数学概念嘛,有啥好纠结的?直到我第一次在实车上做BEV融合,发现激光雷达点云和摄像头图像怎么都对不上,才意识到:坐标系搞不清楚,后面全是白搭。

你想想看,每个传感器都有自己的“小脾气”,它们各自定义了自己的坐标系。你要让它们协同工作,就得先给它们“统一语言”。这就是我们今天要讲的核心。

3.1 三大坐标系:从哪儿来到哪儿去

在BEV模型中,我们通常要面对三个坐标系。我个人习惯把它们比作三个“世界”:

  • 传感器坐标系:传感器自己的“小世界”。比如激光雷达,原点在它的旋转中心;摄像头,原点在它的光心。
  • 车辆坐标系:整车的“基准世界”。通常原点在后轴中心,或者车辆几何中心。X轴朝前,Y轴朝左,Z轴朝上。
  • 世界坐标系:全局的“大世界”。比如GPS定义的经纬高,或者高精地图里的UTM坐标。

为什么要分这么细?我在项目中遇到过一个问题:一辆车的IMU装在车尾,而激光雷达装在车顶。如果不做坐标系转换,IMU测到的加速度和激光雷达看到的障碍物位置,根本对不上。说白了,你得先知道“我在哪儿”,才能知道“它在那儿”。

核心原则:所有传感器数据,最终都要统一到车辆坐标系下,才能做BEV融合。

3.2 传感器坐标系:每个传感器的“小脾气”

咱们一个一个来看。

3.2.1 激光雷达坐标系

激光雷达的坐标系,通常以它的旋转中心为原点。X轴指向正前方,Y轴指向左侧,Z轴指向上方。嗯,这里要注意:不同厂家的定义可能不一样。比如Velodyne和Hesai,它们的坐标系定义就有细微差别。

我曾经踩过一个坑:用某款国产激光雷达,它的Y轴是朝右的,而我默认是朝左。结果点云投影到图像上,左右完全反了。排查了半天才发现是坐标系定义的问题。所以,拿到一个新传感器,第一件事就是看它的数据手册,确认坐标系定义。

3.2.2 摄像头坐标系

摄像头坐标系,原点在光心。Z轴指向镜头前方(也就是拍摄方向),X轴朝右,Y轴朝下。注意,这个Y轴朝下是跟车辆坐标系相反的。所以做投影时,需要额外处理。

我记得有一次做摄像头和激光雷达的融合,发现投影后的点云总是偏上。后来发现,是摄像头坐标系里的Y轴方向搞反了。你想想看,一个简单的符号错误,就能让整个融合结果崩掉。

3.2.3 IMU坐标系

IMU的坐标系,通常以它的芯片中心为原点。X轴朝前,Y轴朝左,Z轴朝上。但IMU的安装位置往往不在车辆中心,所以需要做平移和旋转。

小技巧:IMU的标定,我建议用“六面法”。把IMU放在六个不同的姿态下,采集数据,然后解算出它的零偏和标度因数。这个方法虽然老,但很可靠。

3.3 车辆坐标系:统一战场

车辆坐标系,是所有传感器数据的“归宿”。通常定义如下:

  • 原点:后轴中心(或者车辆几何中心)
  • X轴:车辆前进方向
  • Y轴:车辆左侧方向
  • Z轴:车辆上方方向

为什么选后轴中心?因为车辆的运动学模型,以后轴中心为原点最方便。你想想看,阿克曼转向模型里,后轴中心是不发生侧偏的。所以用它做基准,计算轨迹和位置最准确。

在实际项目中,我习惯把车辆坐标系的原点放在后轴中心的地面投影点上。这样Z轴零点就是地面,方便做高度相关的计算。

3.4 世界坐标系:全局视野

世界坐标系,通常用于多车协同或者高精地图。常见的有:

  • UTM坐标系:以米为单位,适合局部区域
  • 经纬高坐标系:WGS84,适合全球范围
  • 自定义坐标系:比如以停车场入口为原点

世界坐标系和车辆坐标系之间的转换,通常通过GPS/IMU组合导航来实现。说白了,就是知道车在世界坐标系下的位姿,然后就能把传感器数据投影到世界坐标系里。

警告:世界坐标系的精度,取决于GPS和IMU的精度。如果你用消费级的GPS,误差可能达到几米。这种情况下,做BEV融合时,建议以车辆坐标系为主,世界坐标系只做参考。

3.5 传感器联合标定:让它们“说同一种语言”

好了,坐标系定义清楚了,接下来就是标定。标定的目的,就是求出传感器坐标系到车辆坐标系的变换矩阵(旋转矩阵R和平移向量t)。

联合标定,说白了就是让不同传感器“对齐”。我常用的方法有两种:

3.5.1 目标法标定

用标定板或者标定物,让所有传感器同时观测同一个目标。然后通过匹配特征点,解算出变换矩阵。

举个例子,激光雷达和摄像头的联合标定:

  1. 放置一个棋盘格标定板
  2. 激光雷达扫描到标定板的点云
  3. 摄像头拍到标定板的图像
  4. 提取点云中的角点和图像中的角点
  5. 通过PnP算法解算变换矩阵

我曾经在项目里用这种方法,标定完以后,点云投影到图像上的误差在2个像素以内。效果还不错。

3.5.2 无目标法标定

如果环境不允许放标定板,也可以用无目标法。比如:

  • 利用自然特征点(建筑物角点、道路标线等)
  • 利用运动信息(比如车辆直线行驶时,IMU和激光雷达的轨迹应该一致)

无目标法的精度通常不如目标法,但在某些场景下很实用。我记得有一次在野外做测试,没带标定板,就是用路边的电线杆做特征点,硬是把标定做完了。

3.6 标定流程:一步一步来

下面我给出一个典型的联合标定流程,供大家参考:

  1. 准备阶段:确认所有传感器的坐标系定义,准备标定工具(标定板、测量工具等)
  2. 数据采集:让车辆停在平坦地面,放置标定板,同时采集所有传感器数据
  3. 特征提取:从各传感器数据中提取特征点(角点、边缘等)
  4. 匹配求解:用最小二乘法或优化算法,求解变换矩阵
  5. 验证:用新的数据验证标定结果,检查投影误差

关键点:标定不是一次性的。传感器可能会因为振动、温度变化而发生微小的位移。我建议每隔一段时间重新标定一次,或者在每次车辆启动时做一次快速校验。

3.7 代码示例:激光雷达到车辆坐标系的转换

下面给一个简单的Python代码示例,展示如何把激光雷达的点云转换到车辆坐标系下:

import numpy as np

# 假设激光雷达到车辆坐标系的变换矩阵
# R: 旋转矩阵, t: 平移向量
R = np.array([[0.999, -0.017, 0.017],
              [0.017, 0.999, 0.017],
              [-0.017, -0.017, 0.999]])

t = np.array([1.5, 0.0, 0.5])  # 单位:米

# 激光雷达坐标系下的点云(N x 3)
lidar_points = np.array([[10.0, 2.0, -1.0],
                         [20.0, -3.0, 0.5]])

# 转换到车辆坐标系
vehicle_points = (R @ lidar_points.T).T + t

print("车辆坐标系下的点云:")
print(vehicle_points)

这段代码很简单,但实际项目中,你还需要考虑时间同步、畸变校正等问题。嗯,这些我们后面章节会详细讲。

3.8 避坑指南

最后,分享几个我踩过的坑:

  • 坐标系方向搞反:尤其是Y轴,不同传感器定义可能不同。一定要看数据手册。
  • 平移向量单位搞错:有的传感器用毫米,有的用米。统一成米再计算。
  • 旋转矩阵顺序搞错:欧拉角的旋转顺序(比如XYZ还是ZYX)会影响结果。我建议直接用四元数,避免歧义。
  • 忽略时间同步:标定时的数据必须是在同一时刻采集的。如果时间不同步,标定结果会不准。

我的习惯:每次标定完,我都会做一个“投影验证”。把激光雷达点云投影到图像上,看看是否对齐。如果偏差超过3个像素,我就会重新标定。

好了,坐标系与标定这部分就讲到这里。下一章我们会聊传感器的时间同步问题,这也是个容易踩坑的地方。大家有什么问题,欢迎随时交流。