
做机器人或自动驾驶的朋友多少都遇到过这种诡异的毛病IMU上位机读数一切正常数值范围也对姿态解算的静态横滚俯仰误差不到一度可一旦跑起来航向就是管不住地飘或者把IMU数据和相机、激光拼在一起做融合系统时不时给你来个大的跳变。排查了算法、通讯、电源最后才有人提醒你你的IMU从来没有标定过。这个场景我太熟了早期在做智能小车IMU纠偏的时候我就栽在这里。这篇不是什么高深论文就是一份从零到一的IMU标定实战总结重点讲清楚误差模型到底是什么、六面法和Allan方差法具体怎么做、以及做完之后怎么验证结果真的靠谱。适合谁看呢在做视觉/激光SLAM却被IMU飘得头疼的人、自己在做机器人底盘或无人机飞控的业余选手、以及刚接触惯性导航想搞懂标定原理的学生。别管你是几十块的消费级IMU还是上万块的战术级模块标定的套路是一样的只是精度和数据质量的把控程度不同。1. 先想清楚标定到底在标什么误差从哪来、不标会怎样1.1 三类典型误差源确定性误差、随机误差、温度误差很多人一提标定就以为是把数据调到一个固定值其实IMU标定要处理的是好几种性质完全不同的误差。我习惯把它们分成三类这样后面建模、选方法、看结果的时候才不会乱。第一类是确定性误差包括零偏bias、尺度因子误差scale factor error和安装误差axis misalignment。这类误差的特点是只要工作条件不变它基本上是恒定的所以可以用标定实验去估计出来然后在算法里补偿掉。比如陀螺仪的零偏就是把IMU放在桌面上不动你去看它的角速度输出理论上应该是0但实际可能稳定输出0.05°/s这就叫零偏。尺度因子误差可以理解成放大倍数不准你输入一个真实的100°/s角速度它输出的是98.5°/s差了1.5%。安装误差则是制造和贴片时留下的三个轴不正交、或者IMU坐标系和载体坐标系有旋转导致的轴间串扰。第二类是随机误差包括角度随机游走ARW、零偏不稳定性bias instability、速率随机游走RRW等。这一类没有办法通过标定完全消掉因为它们的来源是电子噪声、量化噪声和低频漂移本质上是随机的。我们能做的是用Allan方差法把它们的大小估计出来然后在卡尔曼滤波器里作为噪声参数建模让滤波算法知道IMU有多信得过。第三类是温度相关误差。MEMS器件的零偏和尺度因子都会随温度明显变化消费级IMU的零偏在-40℃到85℃范围内可能漂移几十倍。有些模块内部有温控或出厂补偿没有的话你在实验室标定出来的参数只能在实验室温度附近有效。表格里我列一下典型量级方便你有直观概念误差类型主要来源典型MEMS量级处理方式零偏制造工艺、温度应力0.01°/s~1°/s陀螺几mg~几十mg加速度计六面法/静止法估计温度补偿尺度因子误差增益不准、温漂0.1%~5%转台角速率法/六面法加速度计安装误差PCB贴装、结构装配0.01°~2°12位置法或多位置最小二乘角度随机游走电子热噪声、量化0.01~0.5°/√h无法消除用Allan方差参数化后进滤波器零偏不稳定性低频电路漂移、温漂0.001~0.05°/s部分温度补偿滤波中建模速率随机游走长时漂移视器件等级而定Allan方差参数化1.2 不标定真的会出问题吗两个典型事故现场先讲一个我早期做智能小车IMU纠偏时踩过的坑。小车装了MEMS陀螺静止时Z轴输出大概0.08°/s我觉得这个数很小没必要管。结果小车在实际场景里跑两分钟就能偏出十几度轮式里程计和IMU融合后总是在转弯之后出现明显的航向残余误差我一度以为是里程计打滑反复调融合参数、调纠偏阈值折腾了一周。后来把陀螺数据用静止平均估了一个零偏在程序里直接减掉航向稳定性立刻上了一个台阶。算笔账就明白了0.08°/s的零偏一分钟累积4.8°三分钟就是14.4°放在任何闭环纠偏系统里都是灾难级误差。很多车规或工业级陀螺零偏在0.005°/s左右一分钟才0.3°所以大家经常误以为模块够好就不需要标定其实是人家出厂前已经把零偏校准过了。另一个典型场景是视觉/激光融合里的加速度计问题。比如跑VINS或者LIO这类系统初始化阶段需要靠加速度计输出来估计重力方向。如果加速度计有明显的零偏或者尺度误差重力方向估计就会带偏导致重力分量泄漏到水平加速度里系统的尺度会不稳定快速加减速时轨迹还会出现拉伸或收缩。再叠加一个2%的尺度因子误差车在0.5g加速时加速度测量误差就有0.01g约0.1m/s²几秒钟就能积出一个明显的速度误差。这就是为什么很多人换了更好的相机、调了更多次的滤波参数系统还是不舒服因为根子在IMU内参上。2. 误差模型的数学形式动手前必须先写下来的那组方程2.1 加速度计和陀螺仪的统一误差模型标定不是凭空想出来的它是把一个测量值如何受真值影响的模型反解出来。工程上最常用的IMU误差模型可以写成a_meas K_a · T_a · (a_true b_a n_a)ω_meas K_g · T_g · (ω_true b_g n_g)这里的含义逐项拆开讲。a_meas 是加速度计输出的比力单位通常是 m/s²a_true 是真实的比力。b_a 是加速度计零偏n_a 是随机噪声。K_a 是尺度因子矩阵理想情况下是单位阵实际对角元素接近1但会有偏差。T_a 是安装误差矩阵描述三轴之间的非正交以及IMU坐标系相对载体坐标系的旋转。陀螺仪一组完全对应只是物理量变成了角速度。如果展开成更具体的形式一个常见的K矩阵是K_a [[s_ax, 0, 0], [0, s_ay, 0], [0, 0, s_az]]也就是说每个轴单独一个尺度系数不跨轴。T矩阵则会含有交叉项比如把T_a写成T_a [[1, -α_az, α_ay], [α_az, 1, -α_ax], [-α_ay, α_ax, 1]]这里的α代表轴失准角单位是弧度数值比较小。把矩阵乘开就会发现某个轴的输出不仅取决于它自己的真值还会串进来另外两个轴的少量分量。安装误差最大的麻烦就在这。2.2 从模型反推标定任务参数分三类有了这个模型标定任务就清晰了零偏b六个参数加速度计3个陀螺仪3个。尺度因子K六个参数。安装误差T如果完整的9参数矩阵就是18个参数加上零偏共24个。但是实际工程里边MEMS IMU很少去解全部24个参数因为交叉耦合项本身很小强行估计反而会被噪声放大。业界习惯分成两个档位六参数模型只估计每轴的零偏和尺度因子共6个参数。这个模型简单、稳定是快速标定的首选。十二参数模型在六参数基础上加上加速度计/陀螺仪各自的交叉耦合项也就是把安装误差也算进去。这需要更复杂的多位置实验或者转台实验来提供充分的激励否则最小二乘问题会病态。新手往往一上来就想做最全的标定我的建议是反过来先用六参数模型跑通全流程数据质量没问题再考虑要不要升级到十二参数。很多消费级IMU本身的噪声和温漂就很大你费老大劲解出来的交叉项在下一块板子上可能又变了。2.3 为什么重力永远是加速度计标定的尺子加速度计标定和陀螺仪标定有一个本质区别加速度计可以在地面上用重力当已知参考输入而陀螺仪的参考输入地球自转角速度15°/h对MEMS来说太弱了一般实验室条件根本测不出来。所以六面法能直接标定加速度计的零偏和尺度但对陀螺仪只能标零偏想要标陀螺仪的尺度因子就需要转台提供已知角速率。这一点必须说在前面否则好多人拿着六面法教程问为什么我的陀螺尺度标不出来那不是方法错了是方法的使用范围本来就有限。顺带说明一下为什么静止时加速度计读到的就是重力加速度计测的是比力静止在桌面上时支撑力抵消了重力比力大小等于1g方向向上。更准确地说如果IMU的Z轴垂直向上静止放置加速度计Z轴输出应该是g也就是9.80665 m/s²如果Z轴垂直向下放置输出是-g。这就是把重力当成一把刻度尺的原理。六面法靠的正是这个。3. 六面法实战一个转台都不用六个姿态标出零偏和尺度3.1 六面法的原理上一下一零偏自动抵消六面法的名字来源于它需要把IMU摆成六个不同的姿态每个轴各朝上和朝下一次。以X轴为例当X轴严格竖直朝上时理想情况下加速度计X轴输出是g当X轴严格竖直朝下时输出是-g。实际输出会受到零偏和尺度因子影响a_x_up s_ax · g b_x a_x_down -s_ax · g b_x两式相加再除以2得到零偏b_x (a_x_up a_x_down)/2。两式相减再除以2g得到尺度因子s_ax (a_x_up - a_x_down)/(2g)。你看一次朝上、一次朝下零偏在相减时被抵消尺度在相加时被保留这是六面法最核心的巧妙之处。对其他两个轴同样处理六个姿态正好解出三个轴的零偏和尺度因子合计六个参数。整个实验不需要转台只需要一个可以稳定摆放的立方体安装块和一个水平台面。3.2 实操流程姿态定义、数据采集、时间选择具体执行时我一般按照下面这个流程做每一步都有值得注意的细节。第一步准备安装夹具。IMU要固定在一个有直角基准面的小铝块或3D打印立方体上保证IMU的坐标系和立方体表面严格对齐否则后面摆出来的竖直向上就带了几度的误差。没有工装的话至少把IMU用双面胶可靠固定在水平台面上每换一个姿态都重新确认粘牢。第二步定义六个姿态。我这里用XX-YY-ZZ-来表示。X就是X轴竖直朝上重力在X轴向为正X-是X轴竖直朝下其他轴同理。摆放的时候另外两个轴尽量水平但不需要非常严格因为六参数模型只关心敏感轴的输出其他轴输出不参与该轴的参数计算。如果后面要解安装误差才需要把姿态定义得精确到0.1°以内这时就要用带定位销的直角工装。第三步每个姿态采集1到2分钟数据。采样率用标称采样率就行200Hz的话一个姿态能采两万多点足够了。采集时不要碰桌面不要在强振动环境中做最好等IMU预热至少15分钟再开始。这里有个常见误区有人为了省时间每个姿态只采10秒。短时间的均值受随机游走影响很大陀螺仪尤其明显标出来的零偏不稳定。按我的经验加速度计每个姿态30秒就够陀螺仪零偏建议60秒以上。第四步取每个姿态各轴输出的均值。姿态序列和对应数据要记录好后面计算要用。整理成类似下面的结构单位m/s²姿态axayazX9.6580.1080.052X--9.7180.1010.063Y0.0879.721-0.041Y-0.096-9.669-0.038Z0.042-0.0179.887Z-0.038-0.014-9.892注意表格里非敏感轴的微小输出比如X姿态下ay有0.108这说明IMU并没有完全水平还带了一点绕X轴的倾斜。放在六参数模型里我们忽略它但如果你看到非敏感轴输出超过0.2g说明姿态摆得明显歪了建议重新固定。3.3 参数计算从六个平均值到零偏和尺度附Python示例在Python里做这个计算非常简单。我用numpy直接处理均值列表。import numpy as np # 按顺序填入六个姿态的三轴均值单位 m/s^2 # 顺序[X, X-, Y, Y-, Z, Z-] data np.array([ [ 9.658, 0.108, 0.052], # X [-9.718, 0.101, 0.063], # X- [ 0.087, 9.721, -0.041], # Y [ 0.096, -9.669, -0.038], # Y- [ 0.042, -0.017, 9.887], # Z [ 0.038, -0.014, -9.892], # Z- ]) g 9.80665 # 标准重力加速度 up data[0::2] # 每轴朝上姿态 down data[1::2] # 每轴朝下姿态 bias (up down) / 2.0 scale (up - down) / (2.0 * g) print(零偏 (m/s^2):) print(np.diag(bias)) print(尺度因子:) print(np.diag(scale))输出结果会是一个3维向量比如加速度计零偏约0.05 m/s²尺度因子约0.99。实际使用时补偿公式就是a_corrected (a_meas - b_a) / s_a注意如果传感器输出单位不是m/s²而是g那g就取1其他逻辑完全一样。3.4 关于陀螺仪六面法能标什么、不能标什么回到开头那个关键问题。六面法对陀螺仪能做的就是标零偏。因为每个姿态下陀螺输出理论上都是0你只要把六个姿态各自静止的角速度均值再平均一次就是三个轴的陀螺零偏。公式极为简单b_g mean(ω_meas_static)这里需要注意的是MEMS陀螺仪零偏中包含着较大的随机游走成分单次采样噪声可能达到0.1°/s量级所以一定要用长时间均值。如果条件允许静止10分钟以上估计出来的零偏才足够稳六个姿态各1分钟已经算是个折中方案。但陀螺仪的尺度因子和安装误差六面法是真的标不出来。原因是它需要一个已知角速率作为真值而六面法全程静止没有给陀螺任何角速率激励。没有激励就没法把尺度误差暴露出来。想标陀螺尺度因子至少要有一个能做到固定角速率转动的转台或者用高精度机械臂带着IMU做已知角速度运动再或者借助视觉/激光里程计提供一个比较可靠的角度参考。很多研究组做的手持旋转标定本质上就是用外部真值代替转台属于另一个话题了。4. Allan方差法实战把静止数据里的随机噪声拆开4.1 为什么要用Allan方差普通方差说不清楚时间尺度随机误差和确定性误差最大的区别是它没法用一个固定的值来描述因为它会随时间尺度变化。同一个陀螺你拿100Hz的数据算标准差和拿10秒滑动平均后的数据算标准差结果差很多。普通方差把所有时间尺度混在一起根本分不清哪些噪声是短时间的、哪些是长时间的。Allan方差的做法不一样它对原始数据做不同长度的分组平均这个长度叫簇时间τ然后看相邻两组平均值的差的方差。当τ很短时白噪声主导Allan方差表现出随机游走特征当τ逐渐变长零偏不稳定性会冒出来曲线出现平台τ更长时速率随机游走主导Allan方差再次上升。每条噪声成分在log-log曲线上都有自己独特的斜率所以我们能通过观察曲线的形状把混在一起的噪声源一个一个剥出来。用生活化的类比来说普通方差是拍一张快照告诉你数据有多散Allan方差是拍一段录像告诉你数据在不同时间尺度下分别怎么动。融合定位里需要的就是后面这种信息因为卡尔曼滤波器的假设里角度随机游走参数和零偏不稳定性参数对应着完全不同的状态模型。4.2 数据采集要求时长、环境、预热缺一不可Allan方差对数据质量的要求比六面法高得多。核心要求是把IMU固定在一个完全静止、无振动的环境中连续采集至少2小时以上采样率保持恒定。为什么要这么久因为要通过统计方法估计随机误差样本量和时间跨度都决定了你能分辨的噪声范围。Allan方差最大能分析的τ大约是总时长的十分之一到二分之一你采集2小时最多只能把τ推到几百秒到几千秒的范围再大就没样本了算出来的点方差极大没有参考价值。如果想把零偏不稳定性看得更清楚我建议采3到4小时工业级器件甚至要8小时以上。环境上的要求关键就俩字静、稳。桌面上的硬盘风扇振动、空调气流、人来回走动都会给加速度计数据注入额外噪声而这些噪声根本不是传感器本身的随机误差会直接污染Allan方差曲线。我做实验时会用一块大理石平台IMU底下垫几层泡棉减振周围用亚克力罩子挡气流。另外一定要预热零偏还随着温度在缓慢爬的时候Allan方差图的长τ段会出现一个很明显的上扬容易被误判成速率随机游走。4.3 Allan方差的计算过程与Python实现Allan方差计算的经典方法是对角速度积分得到角度增量序列θ再对不同簇时间做二阶差分统计。数学定义是σ²(τ) (1/(2(N-2m))) · Σ [θ(i2m) - 2θ(im) θ(i)]²其中τm·dtdt是采样间隔N是总采样点数。这里的θ是累积积分后的角度对陀螺仪加速度计则用速度累积。直接按定义写一个基础版Python函数很容易import numpy as np def allan_deviation(data, dt, max_m): 计算Allan标准差。 data: 陀螺角速度(°/s)或加速度计比力(m/s^2)序列 dt: 采样间隔秒 max_m: 最大簇计数 # 先做累计积分陀螺得到角度加速度计得到速度增量 theta np.cumsum(data) * dt N len(theta) tau [] adev [] for m in range(1, max_m 1): if 2 * m N: break t m * dt tau.append(t) delta theta[2*m:] - 2*theta[m:N-m] theta[:N-2*m] avar np.mean(delta**2) / 2.0 adev.append(np.sqrt(avar)) return np.array(tau), np.array(adev)使用的时候如果数据是200Hz采样、时长2小时N大约144万点max_m取到N/10大概就是7万这个双层循环会非常慢。切分估计更合适也就是先把数据按τ分段每组求平均再在组与组之间做Allan方差。这个群平均版本在工程里更常用效率和稳定性都好很多这里不展开代码但原理和上面这个函数完全一致。画图的时候用双对数坐标横轴是τ秒纵轴是Allan标准差。一个典型的MEMS陀螺仪Allan曲线从短τ到长τ会依次出现斜率-1的量化噪声段、斜率-1/2的角度随机游走段、接近水平的零偏不稳定性平台、斜率1/2的速率随机游走段。如果你的曲线长τ段一直往上翘得很厉害先检查是不是数据里带了趋势项比如温度还在漂。4.4 从曲线到参数各种噪声的斜率与单位换算看Allan曲线时最难的部分不是算曲线而是从曲线里把参数读出来。下面这个表格是必须印在脑子里的参考斜率噪声类型与Allan标准差的数学关系提取方式-1量化噪声 Qσ(τ) √3·Q/τ拟合-1段Q σ·τ/√3-1/2角度随机游走 ARWσ(τ) ARW/√τ_hτ_h为小时ARW σ(τ)·√τ_h0零偏不稳定性 Bσ_min ≈ 0.664·B曲线最低点σ_minB σ_min/0.6641/2速率随机游走 Kσ(τ) K·√(τ/3)拟合1/2段K σ·√3/√τ1速率斜坡 Rσ(τ) R·τ/√2拟合1段实际提取的时候单位换算是最容易出错的。以角度随机游走为例它的单位是°/√h。如果你从曲线上看到τ1秒处的σ值是0.01°/s那ARW就是σ·√τ_h其中√τ_h√(1/3600)1/60所以ARW0.01/60≈0.000167°/s×√h不对这里要特别小心。我换一种更不容易错的方式说明。假设τ是秒Allan标准差是σ(τ)单位是°/s。把τ换算成小时τ_hτ/3600公式σ(τ)ARW/√τ_h成立。那么ARWσ(τ)·√τ_hσ(τ)·√(τ/3600)σ(τ)·√τ/60。所以如果你读的是τ1秒处的σARWσ(1s)/60。如果读的是τ3600秒处的σ那ARW直接等于σ(3600s)×1单位是°/√h。很多标定报告里用τ3600秒处读值就是这个原因。零偏不稳定性提取相对简单找到Allan曲线的最低点读纵坐标值σ_min再除以0.664就是B。但要注意实际MEMS曲线最低点常常是一个宽平台而不是尖点而且如果有速率随机游走成分较强最低点会被抬高。所以更稳妥的做法是用一个二次多项式去拟合并最低点附近的小段曲线再把顶点值当成σ_min而不是直接取单个最小值。我自己经常发现直接取最小值和拟合出来的值能差20%到30%对滤波参数来说这个误差不算小。5. 标定结果验证、常见数据坑与我的经验总结5.1 三条验证手段残差、静态角、实际导航标定做完参数拿到手千万别急着往工程代码里一塞就完事。我至少会做三层验证。第一层是残差验证。把标定参数回带到六面法的六个姿态数据里计算补偿后每个姿态的三轴输出再和理论的重力分量做差。如果标定有效残差应该在几个mg以内也就是小于0.005g。如果残差有非常明显的方向性规律比如X姿态残差为正、X-姿态残差为负说明你的尺度或零偏估计还有残余偏差或者忽略了安装误差。这时候就要考虑上十二参数模型。第二层是静态角验证。把IMU放在水平平台上静止用标定后的加速度计数据计算横滚角和俯仰角理论上在0.01°到0.1°左右取决于器件噪声。如果横滚俯仰稳定后有个0.5°以上的固定偏差多半是安装误差或者加速度计尺度因子没标干净。第三层是实际导航/融合效果验证。这个对做小车、无人机的人最直观。记录一段直线行驶加转弯的IMU原始数据在同一个算法框架下对比标定前后的航向漂移、姿态稳定性和融合轨迹平滑度。我在那个智能小车项目里最直观的感受是标定前静止静止不动时航向在那慢慢飘标定后长时间不动基本能稳住转弯回来误差也小很多。如果你跑VINS/LIO标定IMU内参后初始化速度明显变快、尺度更稳定这都算有效的验收指标。5.2 我在实操中踩过的五个坑第一个坑是没预热就开始采集。有一次我做六面法上班一开机就摆姿态采完算出来的零偏和标定报告差了10倍。后来发现问题出在陀螺仪上电前10分钟的零偏漂移非常快数据里混进了一个缓慢变化的趋势Allan方差长τ段全被污染了。现在我的标准流程是上电后先静止放20分钟等输出稳定再动手。第二个坑是采样率中途变化。有些IMU在Windows下插拔USB或驱动异常时采样率会掉但数据流看起来还是连续的。Allan方差算法默认dt恒定采样率一变τ就全错了。所以采完之后一定要检查时间戳间隔看有没有跳变。我习惯在代码里加一道校验如果相邻时间戳间隔超过1.5倍标称间隔就报警并废弃这一段数据。第三个坑是桌面振动。实验室楼上有重型设备在运行或者桌面下放着NAS硬盘这些微振动在加速度计Allan曲线上会表现为一个高频段异常突起。我之前一度以为加速度计硬件坏了后来搬到楼下的大理石台面上去测曲线立刻恢复正常。对于加速度计的Allan方差减振工装不是可选项是必需品。第四个坑是Allan曲线末端乱飞。τ接近总时长一半的时候样本数量可能只有几个算出来的Allan方差根本没有统计意义。很多新手看到曲线末端突然上翘就以为是速率随机游走很大其实是样本不足。我给自己定的规矩是画图时最多画到总时长的1/10超过的部分不做参数提取。第五个坑是单位记混。从Allan曲线读出来的ARW有的人给的是°/√h有的人给的是°/s/√Hz中间差着√3600倍关系。事很正常但一旦写进滤波器参数设置就全乱了。我给自己的土办法是把所有单位统一成接口文档要求的单位然后拿着原始Allan曲线算一遍数自己验证一次别直接抄别人的标定结论。5.3 标定之后内参标定是所有融合方案前的第一步最后再说说标定在整个系统链路里的位置。很多人一上来就查 lidar-imu标定、camera-imu标定、VINS参数标定忙活半天结果外参标定出来的结果不稳定。我这些年看了太多这样的问题最后发现根子往往在IMU内参没做。想想也合理外参标定的本质是估计传感器坐标系之间的相对位姿如果你的IMU自身测量值还带着没补偿的零偏和尺度误差标定解算器会把内参误差强行折进外参里这个外参换个温度、换个运动状态就不准了。所以我的建议是固定一条流水线先做六面法标定确定性误差再做Allan方差法提取随机噪声参数然后才开始外参标定、融合算法调参。这三个步骤之间最好还有一次数据归档把标定时的环境温度、IMU序列号、固件版本都记下来。我自己就吃过没记温区的亏——同一块IMU在空调房和室外差着好几度的零偏标定数据如果不记录环境条件后面查起来非常被动。做IMU标定最大的体会就是它不是什么高深的学术问题而是一个脏活累活拼的是耐心、记录习惯和对数据质量异常的敏感度。只要把误差模型写清楚、把两类方法练熟、把验证流程走完整大部分融合系统的异常都能在标定环节找到突破口。