第四章 相机-IMU联合标定实战:Kalibr工具链深度解析

说实话,做多传感器融合这几年,我踩过最大的坑就是标定。你想想看,相机和IMU各自的数据都挺准的,但一融合就飘得离谱——十有八九是标定没做好。今天咱们就手把手把Kalibr这套工具链走一遍,从相机内参、IMU噪声,到相机-IMU外参,全给它标明白了。

核心知识点速览

  • 相机内参标定:使用Kalibr的kalibr_calibrate_cameras
  • IMU噪声标定:基于Allan方差分析
  • 相机-IMU外参标定:kalibr_calibrate_imu_camera联合优化
相机-IMU联合标定流程 相机内参标定 IMU噪声标定 外参联合标定 棋盘格/Aprilgrid采集 畸变参数估计 重投影误差优化 静止数据采集(2h+) Allan方差计算 噪声密度/随机游走 时间戳同步 BA联合优化 外参矩阵输出 最终输出:camchain.yaml + imu.yaml

4.1 相机内参标定——Kalibr的第一步

相机内参标定,说白了就是搞清楚镜头到底是怎么把三维世界映射到二维图像上的。我最早用OpenCV的棋盘格标定,后来转到Kalibr,发现它支持多种标定板,尤其是Aprilgrid,鲁棒性好了不止一个档次。

我个人习惯用Aprilgrid,因为它每个格子都有独立ID,即使部分遮挡也能识别。你想想看,在实车上采集数据时,标定板经常被遮挡一部分,这时候Aprilgrid的优势就体现出来了。

我的经验:标定板打印时一定要用哑光纸,反光太强会导致角点检测失败。我曾经用普通打印纸,结果阳光下反光严重,白白浪费了半天时间。

先看看标定板的配置文件,我一般这样写:

# april_6x6.yaml
target_type: 'aprilgrid'
tagCols: 6
tagRows: 6
tagSize: 0.088  # 每个格子边长,单位米
tagSpacing: 0.3  # 格子间距比例,相对于tagSize

然后采集数据。这里有个关键点——要保证标定板在画面各个区域都出现,尤其是边缘和角落。我习惯录一段30秒左右的视频,缓慢移动标定板,覆盖整个视野。

标定命令其实很简单:

kalibr_calibrate_cameras \
  --target april_6x6.yaml \
  --bag cam_data.bag \
  --models pinhole-equi \
  --topics /camera/image_raw \
  --bag-from-to 5 35

这里--bag-from-to 5 35的意思是取bag文件第5秒到第35秒的数据。为什么要跳过前几秒?因为刚开始录制时手抖得厉害,数据质量差。

标定完成后,会生成一个camchain.yaml文件,里面包含了相机内参和畸变系数。我一般会看一眼重投影误差,如果超过0.5个像素,说明数据质量有问题,需要重新采集。

输出示例(camchain.yaml关键字段):

cam0:
  camera_model: pinhole
  distortion_model: equidistant
  intrinsics: [458.2, 457.8, 320.1, 240.5]  # fx, fy, cx, cy
  distortion_coeffs: [-0.283, 0.082, -0.001, 0.0004]
  resolution: [640, 480]
  reprojection_error: 0.32  # 像素,小于0.5就算合格

4.2 IMU噪声标定——Allan方差分析法

IMU的噪声参数,很多人直接抄芯片手册,但实际用起来往往对不上。为什么?因为芯片手册给的是理想环境下的值,你焊在板子上、装在设备里,噪声特性早就变了。

我建议自己标定。方法很简单——让IMU静止不动,采集2小时以上的数据,然后用Allan方差分析。

采集数据的命令:

rosbag record -O imu_static.bag /imu/data_raw

然后让设备静置至少2小时。嗯,这里要注意,一定要放在稳固的平台上,别放桌上,桌子可能被人碰到。我一般放地上,周围用东西围起来防止被踢到。

分析Allan方差的Python脚本,我常用这个:

import numpy as np
import matplotlib.pyplot as plt
from allantools import allan

# 读取IMU数据
data = np.loadtxt('imu_data.txt')
gyro_x = data[:, 0]  # 陀螺仪x轴数据

# 计算Allan方差
(taus, adev, _, _) = allan(gyro_x, rate=200.0)  # 200Hz采样率

# 拟合参数
# 噪声密度 = adev在tau=1处的值
# 随机游走 = adev在tau=3处的斜率

plt.loglog(taus, adev)
plt.xlabel('tau (s)')
plt.ylabel('Allan Deviation')
plt.grid(True)
plt.show()

从Allan方差曲线上,我们可以读出两个关键参数:

参数 含义 典型值(消费级IMU)
噪声密度(noise_density) 白噪声水平,单位:°/s/√Hz 0.01 - 0.05
随机游走(random_walk) 偏置稳定性,单位:°/s/√(Hz^3) 0.0001 - 0.001

避坑指南:我曾经有一次标定结果特别差,查了半天发现是数据采集时空调风吹到了设备。IMU对气流非常敏感,哪怕微小的空气流动都会引入噪声。所以标定时最好关掉空调和风扇。

标定完成后,把参数写入imu.yaml

# imu.yaml
accelerometer:
  noise_density: 0.0015  # m/s^2/√Hz
  random_walk: 0.00002   # m/s^2/√(Hz^3)
gyroscope:
  noise_density: 0.0002  # rad/s/√Hz
  random_walk: 0.000003  # rad/s/√(Hz^3)

4.3 相机-IMU外参标定——联合优化的艺术

外参标定,说白了就是搞清楚相机坐标系和IMU坐标系之间的旋转和平移关系。这一步做不好,后面VIO、SLAM全白搭。

Kalibr的外参标定需要同时输入相机数据和IMU数据。采集时要注意:

  • 标定板要始终在视野内
  • 运动要包含六个自由度(平移+旋转)
  • 避免纯旋转,因为纯旋转对IMU激励不够

我一般这样采集:拿着设备走一个"8"字形,同时上下左右晃动,持续2-3分钟。说白了就是让IMU感受到各个方向的加速度和角速度。

标定命令:

kalibr_calibrate_imu_camera \
  --target april_6x6.yaml \
  --cam camchain.yaml \
  --imu imu.yaml \
  --bag data.bag \
  --bag-from-to 10 130

这里--bag-from-to 10 130同样跳过了前10秒,因为刚开始运动时数据不稳定。

标定完成后,会输出外参矩阵。我一般会检查一下旋转矩阵的模是否接近1,平移向量的量级是否合理(通常几厘米到十几厘米)。

输出示例:

cam0_to_imu:
  rotation:
    - [0.9998, -0.0123, 0.0156]
    - [0.0125, 0.9999, -0.0089]
    - [-0.0155, 0.0091, 0.9998]
  translation:
    - [0.052, -0.018, 0.035]  # 米

看到这个旋转矩阵接近单位阵,平移量5厘米左右,说明标定结果合理。如果旋转矩阵偏离单位阵太多,或者平移量达到几十厘米,那就要怀疑数据质量了。

4.4 结果分析与常见问题

标定完成后,我习惯做三件事来验证结果:

  1. 重投影误差检查:相机内参标定的重投影误差应小于0.5像素
  2. IMU积分验证:用标定后的IMU参数做纯积分,看短时间内位置漂移是否合理
  3. 联合初始化测试:把标定结果放到VIO系统中,看初始化是否稳定

我的小技巧:标定完成后,把设备放在桌上静止10秒,然后快速拿起、晃动、放下。看VIO系统能否准确回到初始位置。如果回环闭合误差小于5%,说明标定质量不错。

常见问题及解决方法:

问题现象 可能原因 解决方法
重投影误差>1像素 标定板不平整或图像模糊 更换标定板,检查相机对焦
IMU积分发散太快 噪声参数不准 重新采集2小时以上静止数据
外参标定失败 运动激励不够 增加六自由度运动,避免纯旋转
时间戳不同步 硬件触发或驱动问题 检查相机和IMU的时间戳对齐

嗯,说到时间戳同步,这是个容易被忽略的坑。Kalibr要求相机和IMU的时间戳在同一个时钟域。如果用的是不同时钟源,一定要做硬件同步或者软件插值对齐。我遇到过最离谱的一次,相机用系统时间,IMU用板载时间,差了整整200毫秒,标定结果自然一塌糊涂。

最后总结一下我的标定流程:

  • 第一步:打印Aprilgrid标定板,用哑光纸
  • 第二步:采集相机标定数据,覆盖全视野
  • 第三步:采集IMU静止数据,至少2小时
  • 第四步:采集联合标定数据,六自由度运动
  • 第五步:依次运行三个标定命令
  • 第六步:验证结果,检查各项指标

整套流程走下来,大概需要半天时间。但磨刀不误砍柴工,标定做好了,后面融合的精度才能有保障。


专注资料整理