在自动驾驶、移动机器人和工业检测等场景中,多传感器融合系统的可靠性高度依赖外参标定质量。相机与激光雷达之间的外参只要偏差零点几度,70米外的目标就会产生数十厘米的投影偏移;相机与惯性测量单元之间的时间延迟若未被准确估计,快速转弯时轨迹会出现明显撕裂。独立标定每个传感器虽然可以得到局部最优结果,但很难保证全局一致。联合校准的核心思路是打破传感器之间的独立求解边界,把所有关键参数纳入同一个非线性优化框架,让不同传感器产生的约束互相校正。

为什么独立标定会留下系统级误差
常见的多传感器标定流程通常是串行执行的:先标定相机内参,再标定相机与激光雷达的外参,接着标定相机与惯性测量单元的外参,最后再做时间同步。这个过程中,前一个环节的估计误差会作为已知量传递给后一个环节。例如相机内参中焦距或主点存在微小偏差时,标定板角点的三维坐标恢复就会产生系统性偏移,这些偏移随后被带入激光雷达与相机的外参求解中,导致旋转和平移出现偏置。该偏置并不会在后续环节中被识别出来,反而会继续污染相机与惯性测量单元之间的标定结果。
时间同步误差是另一个容易被独立标定忽略的问题。很多独立标定方法使用准静态数据,只要求传感器在短时间窗口内保持相对静止。在这种条件下,相机曝光时刻与激光雷达扫描时刻即使存在几十毫秒的偏移,也不会在标定目标上形成明显差异。然而车辆一旦进入高速旋转或急加减速状态,同样的时间偏移会表现为一个随运动变化的伪外参误差。融合系统会误以为传感器之间的相对位姿发生了改变,从而产生点云错位或目标重影。
更深层的问题在于坐标基准不统一。独立标定常常以不同传感器作为参考坐标系:相机与激光雷达的标定以激光雷达为基准,相机与惯性测量单元的标定以相机为基准。由于没有统一的基准定义,不同标定结果之间的微小姿态差会在多级坐标变换中被放大。联合校准则直接建立一个统一基准,让所有外参围绕同一个坐标系求解,从结构上避免基准割裂带来的不一致。
联合校准的目标函数与优化结构
联合校准通常被建模为一个非线性最小二乘问题。状态变量包括相机与激光雷达外参、激光雷达与惯性测量单元外参、传感器时间延迟,必要时还可以加入相机内参和激光雷达内参。目标函数由多个残差项组成:视觉重投影误差衡量标定板角点在图像中的预测位置与实际检测位置之间的差异;激光雷达点面误差衡量激光点云中的点与标定板平面法向距离;惯性预积分误差衡量两帧之间由惯性测量单元积分得到的位姿变化与视觉或激光雷达估计值之间的差异。优化器在每次迭代中同时调整所有参数,使这些残差整体下降。
从图优化的角度看,联合校准可以用因子图表示。变量节点对应外参、时延等状态量,残差边对应每一组传感器观测。一个视觉角点观测会连接相机位姿和外参变量,一个激光平面观测会连接激光雷达位姿和外参变量,而惯性预积分边则连接不同时刻的载体状态。这种连接关系生成了稀疏的雅可比矩阵,可以利用列文伯格-马夸尔特方法或高斯牛顿法高效求解。工程上常使用GTSAM、Ceres、g2o等优化库,也可以基于SciPy快速搭建原型验证。
联合优化对初值比较敏感。由于旋转与平移高度耦合,直接使用零初值或粗略初值很容易陷入局部极小。一种可靠的做法是先用独立标定结果作为初值,再分阶段进行联合精化:先固定平移优化旋转,再固定旋转优化平移,最后联合优化所有外参和时间延迟。为了抑制误检测或运动模糊带来的离群点,目标函数中通常会加入Huber核或Cauchy核等鲁棒核函数。
下面是一段简化的联合校准残差构建代码,展示了如何同时纳入相机重投影误差、激光雷达点面误差和时延正则项。
import numpy as np
from scipy.optimize import least_squares
def exp_so3(omega):
theta = np.linalg.norm(omega)
if theta < 1e-12:
return np.eye(3)
k = omega / theta
K = np.array([[0, -k[2], k[1]],
[k[2], 0, -k[0]],
[-k[1], k[0], 0]])
return np.eye(3) + np.sin(theta) * K + (1 - np.cos(theta)) * (K @ K)
def theta_to_se3(theta):
R = exp_so3(theta[3:6])
t = theta[0:3]
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = t
return T
def joint_residual(x, K, corners_3d, pixels, lidar_points, planes, weight_dt):
T_cl = theta_to_se3(x[0:6])
T_il = theta_to_se3(x[6:12])
dt = x[12]
res = []
for p3d, pix in zip(corners_3d, pixels):
p_cam = T_cl[:3, :3] @ p3d + T_cl[:3, 3]
if p_cam[2] <= 0:
res.extend([1e3, 1e3])
continue
u = K[0,0] * p_cam[0] / p_cam[2] + K[0,2]
v = K[1,1] * p_cam[1] / p_cam[2] + K[1,2]
res.extend([u - pix[0], v - pix[1]])
for p_lidar, plane in zip(lidar_points, planes):
normal = plane[0:3]
d = plane[3]
p_imu = T_il[:3, :3] @ p_lidar + T_il[:3, 3]
res.append(normal @ p_imu + d)
res.append(weight_dt * dt)
return np.array(res)
x0 = np.zeros(13)
result = least_squares(joint_residual, x0, loss='huber',
args=(K, corners_3d, pixels, lidar_points, planes, 0.01))
print(result.x)
实现联合校准需要关注的工程细节
标定目标的设计直接影响联合校准精度。相机需要足够多的角点来提供强约束,激光雷达则需要足够大的平面来提取可靠的平面法向量。使用多块标定板组成非对称结构,可以避免单一平面对旋转约束不足的问题。标定板的尺寸应当适中:太小的标定板会降低远距离下的角点检测精度,太大的标定板又可能超出激光雷达的近距离盲区。数据采集时,需要让传感器经历充分的旋转、平移和加减速,以激励所有待估参数,尤其是时间延迟。
退化运动是联合校准中最隐蔽的问题之一。如果载体只进行静止或纯平移运动,某些外参旋转分量会无法观测;如果只绕单一轴旋转,另两个轴的平移分量也可能不可观。实践中可以通过分析雅可比矩阵的条件数或可观测性矩阵来检测退化片段,并将其从数据集中剔除。对于车载系统,常见的有效采集路线包括八字形、环形和包含上下坡的路线,这些路线能够激发多自由度的旋转和平移变化。
完成联合校准后必须进行定量验证。对于相机与激光雷达外参,可以把激光点云投影到图像平面,观察边缘是否对齐;定量指标包括标定板角点重投影误差均值和点面距离均方根误差。对于惯性测量单元相关参数,可以比较联合校准前后的预积分轨迹与视觉里程计轨迹的漂移率。只有测试序列上的误差指标保持稳定,才能说明联合校准参数具备良好的泛化能力,而不是仅仅在标定数据上过拟合。