尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

IMU加速度计重力消除完全指南:从原理到工程实践

IMU加速度计重力消除完全指南:从原理到工程实践 做IMU数据处理的人十个里有八个会在“重力消除”这一步栽过跟头。我以为自己对加速度计足够熟悉了直到有一次做位移估计实验把IMU贴在桌面上静止不动一阶低通滤波之后对加速度积分积分结果居然漂出了一条长长的抛物线。查了半天才发现问题根本不在积分而在“减重力”这一步表面上看只是减去一个g实际上坐标系没转对、姿态噪声被放大、数值单位没统一任何一个环节出错后面做的所有积分、位姿解算、VIO初始化全是白干。这篇内容主要围绕“加速度计重力消除”这条主线展开从加速度计的测量模型讲起说清楚为什么不能简单地在原始数据上减一个9.8然后给出一套从校准、滤波、坐标变换到重力补偿的完整流程再聊聊我在实际项目中踩过的坑以及怎么用肉眼可见的方式验证重力到底消干净了没有。无论是做位姿解算、行人导航、小车底盘控制还是视觉惯性SLAM预处理这篇都能帮你少走两三个星期的弯路。1. 加速度计为什么“测不准”先搞清楚它测的到底是什么1.1 加速度计输出的不是你想的那个加速度很多初学者拿到MPU6050或者ICM20602之后第一反应都是我把传感器水平放桌上Z轴读出来大概9.8那我把它竖直往上抛Z轴读数是不是就等于抛射加速度加上重力答案是不对。加速度计本质上是一个弹簧质量块系统它测量的是比力也就是外部非引力作用力施加在单位质量上的力。用公式表达就是a_meas a_body - g注意这里的 a_body 是物体在世界坐标系下的真实运动加速度g 是重力加速度向量。移项一下才是我们常用的a_body a_meas g这个符号关系特别容易搞混。静止放在桌面的时候真实运动加速度 a_body 0但加速度计读到的 a_meas g传感器Z轴朝上时读数为正9.8左右。所以如果直接拿加速度计原始输出去做积分哪怕传感器一动不动积分出来也会得到一个持续增加的“虚拟速度”时间一长就是那个经典的抛物线位移。重力消除做的其实就是把这个已知的、恒定的重力分量从测量值里剥掉把剩下的“纯运动加速度”留给后续算法。1.2 重力消除做不好下游任务全遭殃重力是否消除干净影响的不只是位移积分。我在实际项目里见过好几个关联问题根源都指向重力补偿没做好姿态解算如果先用加速度计求横滚角和俯仰角再把机体加速度转到导航系这时候如果直接用未补偿的加速度参与姿态更新横滚俯仰会被重力偏差“带跑”尤其起步刹车瞬间水平方向加速度大姿态角假晃一圈。VIO/SLAM初始化视觉惯性联合初始化时需要估计重力向量在IMU坐标系中的投影。重力消除不干净初始化的尺度估计会整体偏移后续紧耦合优化怎么调都别扭。静止/运动状态检测很多导航系统用加速度计模长判断是否静止。如果重力没有被正确建模运动检测阈值就很难设置阈值设低了静止时频繁误触发设高了低速运动直接被吞掉。所以重力消除不是一个可选项而是IMU数据处理流水线里的一个必要前置环节。1.3 “减个9.8”为什么不行有人会说我把IMU水平放好直接读Z轴静止值当g然后每个采样减去这个值不就行了。实测下来问题有二第一安装不可能绝对水平Z轴方向跟重力方向会有夹角X、Y轴上也有重力投影只减Z轴根本消不干净。第二IMU随着载体旋转时重力在机体坐标系下的投影是变化的此时需要一个姿态矩阵把重力向量实时地旋转到当前机体坐标系下再减才能做到“随时随地的精确抵消”。这一条是全文的核心认知重力消除的本质是把重力向量在实际坐标系下的当前投影值计算出来然后从原始测量中减掉。2. 动手之前先把坐标系和姿态表示搞对齐2.1 常用的三套坐标系别再混了做IMU数据处理坐标系约定是第一道坎。三套坐标系分别是惯性系/导航系n系一般用ENU东-北-天或者NED北-东-地重力向量在这套坐标系下是恒定的。无人机常用NED机器人/自动驾驶常用ENU。我个人建议在代码里统一用ENU重力向量写作 g_n [0, 0, 9.8]^T简单直观。机体坐标系b系原点在IMU芯片中心X轴朝前、Y轴朝左/朝右、Z轴朝上/朝下的约定不同传感器不一样务必读datasheet确认。很多“重力消不干净”的bug源头就是Z轴方向定义跟代码里写反了。世界坐标系如果你的系统里另外定义了世界系那要先明确导航系跟世界系之间的旋转关系重力消除一般在该系统初始化时一次性解算不用在每一帧动态做。2.2 姿态表示欧拉角能看懂但四元数才是干活用的重力消除需要知道“当前姿态”也就是机体坐标系相对于导航系的旋转关系。理论上用欧拉角里的横滚角和俯仰角就够了因为重力消除不关心偏航角——重力方向跟Z轴对齐绕Z轴旋转不会改变重力向量在机体坐标系下的投影。但实际代码里我强烈建议用四元数原因有三个四元数没有万向锁问题横滚角接近90度时欧拉角直接失效从姿态更新角速度积分出来的本身就是四元数形式省去反复转换四元数旋转在数值上更稳定尤其在嵌入式平台上浮点误差更小。假设我们有一个四元数 q_bn表示“从导航系到机体系的旋转”那么重力向量在当前机体坐标系下的投影就是g_b q_bn ⊗ g_n ⊗ q_bn_conj写成矩阵形式g_b R(q_bn) * g_n其中R(q_bn)是从导航系到机体系的旋转矩阵。减重力那一步就是a_motion_b a_meas_b - g_b得到的 a_motion_b 是机体坐标系下的运动加速度。如果需要导航系下的运动加速度再左乘一个R(q_bn)^(-1) R(q_nb)就好。2.3 统一量纲、符号和重力常量这0.1的误差值钱我见过不少代码里g直接写成9.8然后在一轮一轮的调试中怎么都消不干净。工程上这0.01~0.05的误差看起来小但在积分十几秒之后就会积累成明显的速度偏置。建议重力常量写成 g_mag 9.80665 m/s²至少保留到小数点后四位单位必须全部统一到国际单位制m/s²、rad/s、s如果传感器输出的是mg或者g务必先换算符号约定写进代码注释哪个方向是正哪个方向是负把原始数据的正负号和g向量方向对照一遍。这一步做完后面所有公式才不会出现“差一个符号、差半个圆”的诡异现象。3. 一套能落地的重力消除完整流程3.1 流程总览五个环节缺一不可把我在不同项目里反复验证过的流程整理成五个环节顺序很重要别乱调原始数据准备读取三轴加速度、三轴角速度时间戳对齐零偏校准静止放置若干秒计算加速度计和陀螺仪的偏置预处理滤波低通滤波滤掉高频振动噪声姿态更新用陀螺仪积分或融合后的姿态得到四元数重力补偿计算g_b从滤波后的a_meas中减去输出运动加速度。先校准、再滤波、再算姿态、最后减重力。有人会把滤波放在校准前面这样反而会把静态偏置滤进状态里后续补偿越做越偏。3.2 先说零偏校准为什么加速度计也有“零偏”很多人只听说陀螺仪有零偏忽略了加速度计也有零偏和尺度因子误差。加速度计零偏指的是在零加速度输入下输出值不为0的那部分偏差。静止水平放置时理想情况下Z轴应该输出9.8、X/Y轴输出0但实际往往Z轴是9.82、X轴是0.03、Y轴是-0.02。校准方法很简单传感器静止放置采集1~2秒数据对每个轴取平均得到的三个平均值就作为加速度计偏置 b_a。后续处理时先减去偏置a_calibrated a_raw - b_a注意这里有个隐含假设校准时的姿态已知是水平。如果传感器不是水平放置那三个轴的静止读数其实是重力在该姿态下的投影取平均后减掉就会把重力信息“减没了一半”。所以零偏标定一定要在明确的静止水平状态下做或者用六面法/转台法做完整标定。个人项目里最简单的做法把传感器放桌上用水平尺确认板子水平记录30秒静止数据取均值当偏置。3.3 低通滤波截止频率怎么选实践经验最重要原始加速度计数据里混着机架振动、电机抖动、人手细微抖动这些高频分量如果不滤掉在后续积分里会被积成毫无意义的毛刺。滤波是必要的但也不能滤掉真实运动信息尤其是行人步态、小车启停这种频率在0.5~5Hz范围内的信号。我的经验法则静态/准静态测量截止频率可以设在1~2Hz这时候运动内容本来就少重在使用平滑行人导航/手势识别截止频率设在5~10Hz保留步行和谐波分量无人机/车辆动态控制截止频率15~20Hz滤掉电机高频振动又不损失姿态控制带宽。滤波器可以使用二阶Butterworth低通也可以直接上滑动平均。滑动平均的优点是计算简单、零相位延迟用numpy的filtfilt或者离线处理时很好使缺点是有一定相位滞后。如果是在线实时处理优先用Butterworth的forward-backward滤波不太现实非因果那就接受一点相位延迟或者用单通滤波后做延迟补偿。我在离线数据分析时基本都用scipy.signal.sosfiltfilt零相位、边缘抖动小非常适合用来验证重力消除的效果。在线嵌入式场景下一阶/二阶IIR低通就够用了参数上我常用的是一阶 IIR 系数 alpha T / (T 1/(2pifc))fc是截止频率T是采样周期。这个公式自己推导也简单直接用没问题。3.4 从四元数到重力投影这一行代码就结束了姿态更新不是这篇的重点我只强调跟重力消除有关的那个步骤。假设我们已经从融合算法Mahony、Madgwick或者EKF得到实时四元数 q_nb表示导航系到机体系的旋转你可以用任意你喜欢的顺序但必须保持一致那么重力在机体坐标系下的投影可以直接通过旋转矩阵的第三行如果导航系Z轴朝上来算g_b R(q_nb) * [0, 0, 9.80665]用四元数性质展开也可以写成矩阵乘法代码实现非常简单。减重力那一步a_motion_b a_calibrated_filtered - g_b这就是核心。真正让这一步“生效”的前提是前面四步都做对了尤其是姿态q_nb要跟真实的机体姿态一致。如果姿态有10度的偏差那减掉的重力向量也会偏10度残差里就会残留大概9.8 * sin(10°) ≈ 1.7 m/s²的加速度分量这个量级足以把积分结果完全污染。3.5 验证重力有没有消除三个可视化方法百试百灵花了好几个小时写代码怎么确认自己写的重力消除是真的消干净了我用过三种验证方法都能出图肉眼直接判断静止测试把IMU静止放在桌面采集数据做完全部流程后输出a_motion_b。理想情况三个轴都接近0模长接近0。如果看到某个轴稳定在0.5以上说明姿态矩阵有问题或者偏置没校掉。直线运动测试手持IMU沿桌面水平直线滑过去再滑回来观察a_motion_b在运动方向上有明显正负尖峰垂直方向上基本为0。这能同时验证重力消除和坐标轴方向。圆周/摆动测试让IMU做单摆运动竖直方向的重力被消掉后运动方向的分量应该呈周期正弦曲线而且均值应该接近0。如果均值不是0说明重力分量还残留在数据里。这三个方法做完如果曲线肉眼看起来都符合预期基本可以放心往下做积分和位姿解算了。我第一次做的时候就是靠“静止测试”一下子抓到了坐标系定义反了的问题数据显示Z轴稳定在-9.8明明消了g还是残留一个-g检查代码才发现旋转矩阵转置写错了。4. 高动态场景下的“进阶坑”旋转补偿与滤波策略4.1 剧烈旋转时重力投影会“跟不上”低通滤波会带来相位延迟陀螺仪输出的姿态也会有一定滞后。当我们拿着IMU快速旋转、或者设备安装在剧烈颠簸的载体上时姿态矩阵更新不够快重力投影 g_b 就会跟实际重力方向“错位”。这时候减掉一个错位的重力运动加速度里会混入人为的高频“假加速度”。应对办法是提升姿态更新频率和数据时间戳的精度。IMU采样率至少要200Hz以上姿态解算频率跟数据频率严格一致时间戳要精确到毫秒级。如果还在用50Hz的采样率做重力消除那高频运动下残差几乎是一定的。此外可以在姿态解算里融合磁力计抑制偏航漂移——虽然偏航不影响重力投影Z轴分量不依赖偏航但在整体位姿解算中仍然重要。4.2 滤波别把运动加速度一起滤掉了低通滤波是把双刃剑。如果截止频率设得太低比如1Hz那么快速启动时的运动加速度一个频率大概2~5Hz的突变信号会被滤成平滑斜坡后续积分出来的位移幅值就会被严重压低。所以滤波器参数要结合具体应用标定不要照搬网上教程的“经验值”。一个更稳妥的思路是姿态解算用的加速度数据可以不过度滤波因为姿态解算需要较宽频带而专门用于位移积分的加速度数据单独做低通。两条数据支路用不同的滤波参数相互之间不干扰。我自己的系统里就是这种设计姿态支路只做轻微的去毛刺积分支路做重一点的平滑。4.3 在VIO/多传感器融合里重力消除顺序要慎重如果你是做视觉惯性里程计或激光惯性紧耦合重力消除一般不放在最前端的原始数据预处理里而是交给初始化过程去估计。VIO里通常的做法是在初始化阶段联合估计重力向量、速度、尺度因子然后把重力向量作为优化变量的一部分后续通过重力方向约束来抑制漂移。这时候如果提前在预处理阶段就把重力减掉反而会把初始化需要的信息给“抹掉”了。所以重力消除的“层级”很关键纯惯性导航/惯性测量单元直接做位姿积分在预处理阶段消除重力视觉惯性/VIO系统重力作为系统状态参与初始化估计预处理阶段不应减重力用于运动状态检测/特征提取减重力后的数据更干净但阈值要单独调。5. 常见问题与排查技巧实录5.1 静止时加速度模长不是9.8而是9.82或者9.75原因大概率是加速度计尺度因子误差或者安装面不水平。解决办法是先做一次静态校准把三轴比例因子也标出来。如果用的是现成IMU模组多数出厂前做过标定但最好还是自己跑一遍六位置标定就是让每个轴分别朝上和朝下记录数据拟合出零偏和尺度因子。5.2 重力消除后静止输出有缓慢漂移如果静止时a_motion_b从0慢慢漂到0.3再漂回来先怀疑温度漂移和噪声累积但更大的可能是姿态解算的输出在温度变化下慢慢偏了导致重力分量计算也在漂。可以试试在静止时段内强制姿态角回零零速修正或者采用更高精度的姿态初始化。如果这个漂移出现在二次积分后那你得明白即使重力消了加速度噪声依然会被积分二次放大。这是惯性导航的数学本质不是代码bug。要缓解只能靠零速检测、阈值门控、或者更高精度的传感器。5.3 消除重力后运动方向加速度波形“反向”说明坐标轴方向定义跟旋转矩阵不一致。一个快速排查法把IMU沿X轴正向猛推一下如果输出的X轴加速度出现负脉冲说明X轴方向跟代码里的正方向反了。把传感器坐标系定义和旋转矩阵的符号表统一核对一遍就行。5.4 姿态一抖动消除后的加速度就爆出尖峰姿态抖动意味着q_nb存在高频误差重力投影g_b随之高频抖动减法后就会残留大量“假加速度”。这时候应该先平滑姿态对四元数做低通或滑动平均再计算重力投影而不是去平滑原始加速度。很多人在这一步把平滑做反了。5.5 横滚俯仰变化时重力消除后出现“过冲”这通常是因为姿态解算的带宽比运动加速度的带宽低重力投影滞后于实际姿态。如果你发现过冲幅值在剧烈旋转时更大那就验证了我的判断。解决办法是提高姿态解算更新率、降低姿态滤波器对加速度的信任权重调小加速度计权重更多依赖陀螺仪积分或者采用预测补偿。6. 最后一个提醒重力消除的尽头是验证体系我调过很多套IMU处理代码最后发现最容易出问题的不是公式不是代码而是“没有建立起验证闭环”。你说重力消除了怎么证明光靠打印几个数字没用。一定要把原始数据、姿态、消除后的加速度数据同时录下来离线回放、画图、肉眼比对。每次修改算法之后跑一遍静止测试、直线测试、摆动测试把三个验证图存档这样任何一次改动导致回归都能两分钟定位到是哪一段引入的。另外还有一个实用小技巧在最终输出的运动加速度上加一个模长约束。静止时如果模长大于某个阈值比如0.3m/s²大概率说明前一级处理出问题了可以把它标记为异常帧防止异常数据污染后面的积分链路。这个简单粗暴的规则我几乎每个项目都会加省了不知道多少排查时间。IMU数据处理就是这样看起来公式简单但每一环都在跟噪声、时延、坐标约定较劲。重力消除只是第一步但如果你能把这第一步做扎实后面的姿态解算、位姿积分、多传感器融合都会顺畅很多。希望这篇从理论到实践的经验总结能帮你少踩几个我踩过的坑。
返回列表