☰
IMU标定工具选型:kalibr_allan、imu_utils、imu_tk实战指南
2026/9/28 1:27:06 网站建设 项目流程

上周有个项目让我印象很深:对方用 D435i 跑 VINS-Fusion,视觉跟踪看着很稳,但定位轨迹就是慢慢飘。我打开配置一看,IMU 噪声参数是从网上一份教程里复制的默认值,加计和陀螺的随机游走跟实际传感器根本不是一回事。后来用 imu_utils 重标了一遍,把 noise density 和 random walk 换成真实测量值,问题立刻缓解。类似的场面我遇到过不止一次。

所以这篇东西我想聊聊 kalibr_allan、imu_utils、imu_tk 这三个开源 IMU 标定工具包到底怎么选、怎么用。它们解决的都不是"IMU 装没装正"这种外参问题,而是更底层、更隐蔽的噪声特性问题。如果你在做 lidar imu 标定前置准备、RGB-D 相机配合 IMU 的紧耦合、或者手眼标定之后要评估 IMU 数据质量,这篇文章应该能帮你少走不少弯路。

1. 标定到底在"标"什么:五个参数把 IMU 的坏脾气说清楚

1.1 先看一个真实翻车场景

很多人对 IMU 标定的理解停留在"标完就能消除漂移",这是个挺常见的误区。IMU 的漂移来自两个层面:一个是每次开机都不一样的零偏,另一个是运行中随时间缓慢变化的随机游走。前者靠上电后静止初始化能解决一部分,后者只能靠统计建模,让算法知道"这个传感器大约以多大的速率在随机漂移"。

我见过最典型的问题是这样的:VINS-Mono 里默认的加计噪声参数是0.01,陀螺是0.001,很多移植项目直接沿用。但不同型号 MEMS IMU 的噪声水平可能差一个数量级,一个 D435i 的实测加计 noise density 可能在0.005到0.02之间,一颗工业级光纤陀螺可能只有0.0001。拿别人的参数套自己的传感器,滤波器对 IMU 的信任程度就是错的,表现就是"视觉明明没崩,轨迹却在慢慢漂"。

1.2 随机误差、确定性误差、安装误差要分开看

这里把 IMU 标定涉及的东西拆开,避免三种东西混在一起:

  • 随机误差:陀螺的角度随机游走(Angle Random Walk,ARW)、加计的速度随机游走(Velocity Random Walk,VRW),对应的就是 Allan 方差曲线里的白噪声段;还有长期工作的偏置随机游走(Bias Instability / Rate Random Walk)。它们是概率意义上的统计量,没法用一个固定值消掉,只能建模成滤波器过程噪声。
  • 确定性误差:包括常值零偏(bias)、尺度因子误差(scale factor)、轴间非正交误差(misalignment)。这部分是可以用六位置法或连续旋转法标定出来、然后在数据预处理阶段直接减掉的。
  • 安装误差:IMU 和相机/雷达/机械臂末端之间的旋转和平移外参,一般靠手眼标定或联合标定解决,和上面的传感器自身标定不是一回事。

kalibr_allan、imu_utils 主要做随机误差,imu_tk 在随机误差之外还能做一部分确定性误差。这一点决定了你当前项目该先碰哪个工具。

1.3 标定参数在 VIO 里到底被谁消费

以 VINS-Fusion 这类紧耦合方案为例,IMU 的噪声参数用于预积分协方差传播。简单说,后端优化时会用noise density和random walk去构造过程噪声矩阵,决定每一帧 IMU 测量值在状态估计里有多少话语权。参数给小了,滤波器会过分相信 IMU 短时积分结果,视觉观测稍有延迟或遮挡,姿态就被带偏;参数给大了,IMU 提供的信息几乎不被信任,系统在纯视觉退化场景(比如白墙、暗光)里就直接飘了。

所以标定不是"为了好看",而是给滤波器一个诚实的传感器模型。这就像你知道一个人跑步时会喘,不能让算法假设他是机器人、恒定输出配速,否则后面的配速预测全都会错。

2. 三大工具的定位差异:同是 Allan 方差,三种不同姿势

2.1 共同的数学地基

kalibr_allan、imu_utils 的核心算法都建立在 Allan 方差分析上。Allan 方差的思路很朴素:把一段长时间静止的 IMU 数据按不同的时间窗口长度切块,统计相邻窗口均值的差异方差,然后画出"聚类时间-方差"的双对数曲线。曲线不同段的斜率对应不同误差源:

  • 斜率约 -0.5 的段对应白噪声,曲线在纵轴上的截距换算成 noise density;
  • 曲线最低点对应零偏不稳定性;
  • 斜率约 +0.5 的段对应速率随机游走,也就是 random walk。

理解这个原理很重要,因为后面无论哪个工具跑完,你都要能在图形上判断结果可不可信。如果采集数据时长不够,曲线根本不会走到斜率 +0.5 的段,工具拟合出来的 random walk 可能只是外推值,要用时心里得有数。

2.2 三款工具的定位差异

工具主要功能输入形式依赖输出
kalibr_allanAllan 方差分析、随机噪声参数拟合ROS bagROS(通常配合 Kalibr 生态)YAML 格式噪声参数、Allan 曲线
imu_utilsAllan 方差分析、一键化封装ROS bagROS、code_utilsYAML 格式噪声参数、PNG 曲线图
imu_tk确定性误差标定 + Allan 方差分析文本文件(timestamp, acc, gyr)无 ROS 强依赖,C++ 库解析解形式输出偏差、尺度、轴间误差

kalibr_allan 来自 ETHZ Kalibr 生态,风格偏研究向,适合本来就准备用 Kalibr 做相机-IMU 联合标定的团队。它的好处是和后续工具链自洽,坏处是需要自己编译、配置,对只想快速拿到一组参数学会有点重。

imu_utils 是社区里流传最广的轻量方案,日常最常用。它把 Allan 方差分析包成了一个 ROS 节点,播放 bag 就能出结果,我在这篇里会重点写它的实操。

imu_tk 则走的是另一条路:它有个相当实用的多位置静态标定方法,可以估计加计和陀螺的零偏、尺度因子、轴间非正交误差,同时也能做 Allan 方差分析。它对没有 ROS 环境的嵌入式项目特别友好,输入是纯文本,部署在 ARM 板上也能跑。

2.3 选型速判

如果按使用场景推荐,我的习惯是:

  • 正在用或准备用 Kalibr 做联合标定 → 先上 kalibr_allan,保持整条链路的格式一致;
  • 只想要一份可用的随机噪声参数、越快越好 → imu_utils,晚上录两小时数据,第二天早上出结果;
  • 要用在嵌入式 / 无 ROS 环境,或者想顺便修掉确定性偏差 → imu_tk;
  • 追求严谨、用于论文级精度 → kalibr_allan + imu_tk 双跑交叉验证。

3. kalibr_allan 实操记录:从 rosbag 到 imu.yaml

3.1 环境准备与依赖

kalibr_allan 一般以源码形式放进你的 ROS catkin 工作区。我常用的做法是建一个imu_ws,单独容纳标定相关包,不要跟业务工程混在一起。

需要准备的东西包括:一个可用 ROS 环境、编译 Kalibr 生态所需的基础依赖,以及你最终想用的那个 IMU 驱动。这里最容易忽略的是把 IMU 的采样率固定下来。很多传感器驱动默认值比较随意,我建议统一设置成传感器原生最高频率,比如 200 Hz 或 400 Hz,并且在录制期间不要修改参数。

编译顺序也有讲究。如果是从源码拉取 Kalibr 相关包,建议严格按照仓库文档里的依赖顺序来,避免同时拉了很多没用的可视化依赖。遇到 Eigen、Sophus 版本冲突是常见事,建议用一个干净的 Ubuntu + ROS 环境单独编译。

3.2 数据录制:时长、静止、采样率

kalibr_allan 需要的是长时间静止数据。我实际测试下来的经验是:用于工程估计,1 到 2 小时基本够用;要求严谨一点,最好录 2.5 到 3 小时。太短的数据会让 Allan 曲线在长聚类时间区间没有足够的统计样本,random walk 的拟合误差很大。

录制的具体做法:

  • 把 IMU 固定在一个刚性的台面上,不要放桌上,因为桌子本身可能有低频振动;
  • 关掉电机、风扇等明显振源;
  • 传感器电源保持稳定,不要用那种电压波动明显的 USB 口,否则会在陀螺上看到明显的异常峰;
  • 录制前先上电预热几分钟,让偏置从冷启动状态稳定下来。

录制命令很简单:

rosbag record -O imu_static.bag /imu/data

但要注意,/imu/data这个名字只是示例,实际操作前要确认自己驱动发布的话题名称和消息类型。录制期间我一般每隔几分钟看一眼rostopic hz,确保频率没有掉。

3.3 跑标定并获取输出

kalibr_allan 的典型运行方式是通过 ROS 节点,把 bag 路径、IMU 话题作为参数传进去。不同版本入口略有差异,这里的关键是:运行后它会读整个 bag 的 IMU 数据,计算 Allan 方差并做拟合。

rosrun kalibr_allan kalibr_allan --bag imu_static.bag --imu /imu/data

跑完之后工作目录里会出现结果文件。常见命名类似imu.yaml或者带时间戳的 YAML,里面包含了陀螺和加计的 noise density、random walk 以及部分 Allan 曲线数据。

我第一次跑这个工具的时候有个困惑:它输出的是 rad/s 单位下的功率谱密度,还是离散时间下的参数?这需要仔细阅读头注释。现在比较常见的做法是输出连续时间噪声密度,后续在 kalibr 联合标定时直接用;如果你要转成 VINS 里的离散时间噪声,别忘了除以sqrt(采样周期)。这个换算我后面专门讲。

3.4 输出文件长什么样

一份典型输出的 YAML 内容大概是这样的结构:

gyroscope_noise_density: 1.5833e-04 gyroscope_random_walk: 2.4600e-05 accelerometer_noise_density: 3.6087e-03 accelerometer_random_walk: 3.2917e-03

这几个值后续可以直接喂给 Kalibr 的相机-IMU 联合标定。需要强调的是,不同工具的单位约定可能不同,最好以单位注释为准。如果某些输出没有写单位,可以画 Allan 曲线验证:noise density 对应曲线左端平直段的高度,random walk 对应右侧斜率 0.5 段的延伸值。

4. imu_utils 实操记录:5 分钟拿结果的轻量方案

4.1 安装 code_utils 与 imu_utils

imu_utils 是我在实际项目里用得最多的工具,因为它足够轻。安装时有个先后顺序问题:先编译code_utils,再编译imu_utils,因为后者依赖前者。很多人一上来把所有包扔进 catkin_make,结果 code_utils 还没编译完就报找不到头文件。

建议分开编译:

catkin_make -DCMAKE_BUILD_TYPE=Release source devel/setup.sh

如果你在用较新版本的 ROS,可能还需要处理一些 C++ 标准兼容问题。社区里常见的做法是给 CMakeLists 加-std=c++14,这个按报错信息调整即可,不算大坑。

4.2 修改 launch 文件并播放 bag

imu_utils 的 launch 文件核心参数大致是这些:

<launch> <node pkg="imu_utils" type="imu_an" name="imu_an" output="screen"> <param name="imu_topic" type="string" value="/imu/data"/> <param name="imu_name" type="string" value="imu"/> <param name="data_src" type="string" value="bag路径"/> <param name="time_start" type="int" value="0"/> <param name="time_timespan" type="int" value="180"/> </node> </launch>

这里的time_timespan单位是秒,表示从 bag 里取多少秒数据做分析。我有次偷懒只录了 20 分钟,设了 1200 秒,出来的曲线后半段毛刺特别多,那就是数据量不足的信号。后来统一按 90 分钟以上录制,曲线干净很多。

数据播放方式有两种:一种是用rosbag play imu_static.bag在线播放,同时启动 imu_utils 节点;另一种是把 bag 路径直接写进 launch 文件。我更推荐后者,省得两个终端同步。运行结束后,工作目录会出现imu_utils输出目录,里面是 YAML 和 PNG 曲线图。

4.3 结果怎么看

imu_utils 输出的 YAML 通常按陀螺和加计分别列:

%YAML:1.0 --- type: IMU name: imu Gyr: unit: " rad/s" avg-axis: gyr_n: 1.2696e-04 gyr_w: 1.5920e-05 Acc: unit: " m/s^2" avg-axis: acc_n: 5.9863e-03 acc_w: 5.1989e-03

gyr_n对应角度随机游走噪声密度,gyr_w对应陀螺随机游走;acc_n是加计速度随机游走密度,acc_w是加计偏置随机游走。它还会按 x、y、z 单轴分别输出一份,最后给一个 avg-axis 用于平均值。

同时输出的 PNG 曲线是判断数据质量的重要依据。曲线应该呈现典型的"先下后上"形态:左侧白噪声段接近斜率 -0.5,中间最低点平缓,右侧上升。如果你看到的曲线一直在抖或根本没有低谷,说明数据里有振动或传感器在采集期间发生了位移,建议重新录。

5. imu_tk 实操记录:六面位置法标定确定性误差

5.1 数据格式与采集方法

imu_tk 对输入格式有明确要求:通常是一个文本文件,每一行包括时间戳、三轴加计、三轴陀螺,用逗号或空格分隔。它不关心你的 ROS 话题,也不要求你装 ROS,所以特别适合在嵌入式或无 ROS 环境里用。

采集方式上,imu_tk 常用的确定性误差标定法是"多位置静态法",也就是我们常说的六面法。把 IMU 固定在台面上,依次让 x、y、z 轴分别朝上和朝下,每个姿态保持 30 到 60 秒,同时记录数据。这样一共 6 个位置,每个位置的重力矢量在传感器坐标下指向已知方向,算法就能拟合出加计的零偏、尺度因子和非正交误差。

实际执行的时候要注意"朝向"要尽可能准。你可以用水平尺、直角块或者干脆在 3D 打印的定位块上做标记。如果朝向差个几度,标定出来的轴间误差里会掺入人为误差,反而比不标还差。我自己试过把 IMU 用双面胶贴在手机屏上用手机角度计辅助摆正,效果比随手放强很多。

陀螺的确定性误差标定通常还需要配合角速度激励,典型做法是让 IMU 绕某轴做匀速或已知轨迹的旋转。如果没有转台,只做零偏部分也能接受。

5.2 运行标定并查看输出

imu_tk 的可执行程序通常由仓库提供的示例代码编译而来,主程序输入数据文件,输出标定结果。典型的命令类似:

./imu_tk_calibrate imu_data.txt

运行时会输出加计和陀螺的零偏、尺度因子、轴间误差矩阵。这些输出的含义比较直接:加计的 bias 就是三个轴上的常值零偏,scale 是各轴灵敏度偏差,misalignment 是三轴不正交导致的交叉耦合。

我个人的建议是:把这些确定性参数先手动加在数据处理的前端,然后在已经做过失真误差修正的数据上再跑一轮 Allan 方差,这样拿到的随机噪声参数才更干净。否则确定性误差混在 Allan 方差里,零偏不稳定性会被抬高。

5.3 为什么确定性标定和随机噪声标定要分开做

很多人会问:既然 imu_tk 也能算 Allan 方差,为什么还要再单独跑 imu_utils?我的理解是,两个工具的重心不同。Allan 方差分析的前提是消除确定性趋势后的平稳随机过程;如果数据里还有明显的常值零偏和尺度误差,Allan 曲线形态会偏移,拟合得到的随机游走参数会偏大。

所以在我的工作流里,顺序是固定的:先用 imu_tk 粗标确定性误差,把数据里的固定偏差和尺度问题清理掉;再对这些"去偏后的数据"跑 Allan 方差,得到随机噪声参数。如果项目时间紧,确定性误差不严重,也可以直接跑 Allan,但心里要清楚结果里混着一定确定性成分。

6. 90% 的标定误差来自采集环节:时长、静止、温度、数据连续性

6.1 时长不是越长越好,而是越"稳"越好

很多人以为 Allan 方差分析就是数据越多越好,于是录了好几个小时,结果曲线反而乱糟糟。问题通常不是时长,而是长时间录制中环境发生了变化:桌面的空调风直吹、设备发热、人的走动引起地面振动,这些都会变成长聚类时间段的异常方差。

我在实践中对时长的理解是:至少 1 小时,最好 2 小时,但必须在稳定的实验环境下做。如果现场条件嘈杂,宁愿拆成多次短采集,也不要强求一次录够。多次采集后可以把结果对比一下,看各次标定参数的离散程度,如果两次的 gyr_n 差超过 20%,说明采集环境有问题。

6.2 静止姿态和振动控制

对 Allan 方差分析来说,传感器必须绝对静止。这里的静止不是"放桌上不动"这么简单,有些桌面本身会因为楼上走动、空调共振而微振动,高档 MEMS 陀螺完全能感受到。我吃过一次亏:把 IMU 用双面胶粘在金属台面上,台面下方刚好有个排风扇,结果 Allan 曲线在中等聚类时间段上出现了明显峰值,怎么拟合都对不上。后来换到一块厚橡胶垫上,问题就消失了。

对六面法标定确定性误差来说,还要保证每个姿态的静止时间足够长,让传感器内部的零偏稳定下来。我一般每个姿态放 60 秒,前 10 秒数据不用,只用后 50 秒。

6.3 温度影响:数据开始前先预热

MEMS 陀螺的零偏对温度非常敏感,冷启动和热机状态下的 bias 可能差好几倍。如果你一上电就录标定数据,Allan 方差里的零偏不稳定性会偏大,因为温度漂移被当成了偏置随机游走。

我在项目里的习惯是:传感器上电后至少预热 5 到 10 分钟再开始录数据,同时尽量保证录制过程中的环境温度没有剧烈变化。冬天在室外调试尤其要注意,手一靠近传感器,红外辐射都会在温度曲线上留下痕迹。

6.4 检查数据质量的三个命令

录制完成后,先不要急着跑工具,花一分钟做数据质量检查:

rostopic hz /imu/data rostopic echo /imu/data --noarr

第一看频率是不是稳定;第二看是否有 NaN 或者跳变。还可以用rqt_bag拉一段数据看看整体趋势,确认传感器没有在录制中被人挪动。这三个检查做完再跑标定,不然工具再精确也救不了脏数据。

7. 把标定结果喂进 VINS-Fusion 与 Kalibr:参数转换与验证

7.1 从 Allan 输出到 VINS-Fusion 配置

imu_utils 和 kalibr_allan 输出的通常是连续时间噪声参数,但很多 VIO 框架里期望的噪声参数是离散时间步下的协方差值。以 VINS-Mono/VINS-Fusion 常见的配置文件为例,它需要四类参数:加计噪声密度、陀螺噪声密度、加计随机游走、陀螺随机游走。

如果你手头是 imu_utils 的输出,可以直接把它那四个量填进去:

imu_acc_noise: 5.9863e-03 imu_gyr_noise: 1.2696e-04 imu_acc_random_walk: 5.1989e-03 imu_gyr_random_walk: 1.5920e-05

有的版本里还需要除以sqrt(dt),这个要看具体框架内部是连续模型还是离散模型。我的建议不是去背公式,而是从原理上确认:如果框架里的协方差传播是在离散时间步上进行采样,那么噪声密度往往是功率谱密度形式,需要除以sqrt(dt);如果框架里已经给了连续模型接口,就不需要额外处理。出现疑问时,直接标定一次后做仿真对比,看静止时姿态方差是否合理。

7.2 在 Kalibr 联合标定中的二次使用

如果你用的是 Kalibr 做相机-IMU 联合标定,那标定出来的噪声参数要以 yaml 文件形式提供给kalibr_calibrate_imu_camera。格式大致是:

# 该文件用于 kalibr 联合标定 imu: update_rate: 200.0 gyroscope_noise_density: 1.2696e-04 gyroscope_random_walk: 1.5920e-05 accelerometer_noise_density: 5.9863e-03 accelerometer_random_walk: 5.1989e-03

注意update_rate一定要写实际发布频率,不要写标称值。我有一次把 D435i 的 IMU 标注成 400 Hz,实际驱动只发了 200 Hz,联合标定结果里的时间戳对齐就一直有残差。

7.3 标定结果验证方法

标定完不能直接就用,我习惯先做一个快速验证:

  • 静止漂移测试:把 IMU 固定静止,记录 10 分钟姿态解算结果,看积分出来的姿态角漂移速率是否在合理范围;
  • 直线往返测试:把 IMU 装在机器人上,沿直线走一个来回,看回到起点时位置误差是否在预期范围;
  • 与另一款工具交叉对比:同一份数据用 imu_utils 和 kalibr_allan 各跑一遍,结果应该接近。

如果静止漂移测试里角度还是在快速跑,说明噪声模型还是不对,或者零偏没有处理好。别急着继续联调,回去查数据采集环节更有效。

8. 实测对比表与选型建议:我的最终结论

维度kalibr_allanimu_utilsimu_tk
安装难度中高,依赖较多低,依赖 code_utils中,C++ 编译
数据输入ROS bagROS bag文本文件
核心输出YAML 噪声参数YAML 噪声参数 + PNG 曲线零偏/尺度/轴间误差 + Allan 分析
是否需 ROS是是否
适合场景科研、Kalibr 联合标定工程快速标定嵌入式、无 ROS、确定性误差标定
典型耗时准备 1 天,运行 0.5 小时准备 0.5 天,运行 5 分钟准备 1 天(含六面位),运行 0.5 小时

我的实际选择标准很简单:默认先用 imu_utils 拿随机噪声参数,因为它的曲线输出最直观、结果文件最通用;如果项目里 Kalibr 明显要长期用,就改用 kalibr_allan 保持链路一致;一旦发现传感器存在明显的尺度或轴间误差问题,再引入 imu_tk 做确定性标定。

最后分享一个习惯:每次标定完,我会在工程里同时保留三样东西——数据 bag、标定参数 yaml、当时的环境记录(室温、预热时间、安装方式、录制时长)。这样后续如果发现标定结果存疑,能快速回溯是哪一步出了问题。这个习惯让我省了大量重复采集的时间,也建议你试试。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询