简介:imu-utils是面向机器人导航、自动驾驶、飞行控制及虚拟现实等场景的IMU标定工具包,针对加速度计、陀螺仪等传感器实现偏差、尺度因子、非正交性误差校正,旨在提升惯性数据的测量精度,是搭建高精度定位与姿态解算系统中的重要一环。资源共235个文件,压缩包仅4.32MB,文件类型涵盖114个txt文本、20个h头文件、13个cpp源码、7个yaml/launch配置、7个m脚本等;txt多为说明与数据文件,h/cpp构成算法主体,yaml/launch便于调整参数与启动节点。工具内置Allan方差分析等标定流程,目录结构细分为code_utils和imu_utils两大模块,并修复了错误引用,稳定性更好;开发者还可按硬件环境自定义标定流程,便于二次开发。已有431人学习下载,适合有一定传感器基础的机器人、SLAM方向开发者对照源码研习标定原理,并快速集成到自己的项目中。 大家跑VINS-Mono或者VINS-Fusion的时候,有没有遇到过这种诡异的情况:代码按教程一步步搭好了,数据集也跑得挺顺,结果换到自己的传感器上,初始化特别慢,或者飞一会儿轨迹就开始飘,甚至直接发散。很多人第一反应是调VINS的参数,把process noise、imu_rate翻来覆去改一遍,发现没啥用。我当初也卡在这个坑里好几天,最后才意识到问题出在IMU本身的噪声参数上——你用的imu.yaml还是人家数据集里默认的那份,跟你的传感器根本不是一回事。
imu-utils就是干这个的。它是港科大秦通开源的一套IMU标定工具,专门用来估计陀螺仪和加速度计的噪声密度(noise density)和随机游走(random walk),输出一份和你硬件匹配的imu.yaml。这套工具配合Allan方差法,能帮你把手里的IMU底摸清楚。这篇文章我会从工具边界、编译坑、数据采集、原理、结果落地这几个角度,把整套流程从头到尾捋一遍,包括我在实际使用中踩过的坑和验证过的经验,希望对正在折腾IMU标定的朋友有帮助。
1. 为什么跑VINS总觉得飘:imu-utils要解决的是哪个环节
在动手装工具之前,先搞清楚imu-utils的定位,这点非常关键。很多人以为用imu-utils标定完,IMU的所有误差都解决了,其实不是。
IMU的误差来源分好几层。第一层是零偏(bias),也就是静止时传感器读数不为零,这个可以用静态平均值粗标,VINS在初始化阶段也会在线估计。第二层是尺度因子和安装误差,这是加速度计三个轴不正交、刻度不准造成的,这类参数imu-utils不处理,通常要用imu_tk或者Kalibr做六面标定。第三层才是噪声特性,包括角度随机游走(对应噪声密度)和速率随机游走(对应随机游走/bias instability),imu-utils干的就是这个,而且它只输出这两个核心参数。
用VINS这类视觉惯性里程计算法时,状态方程里的IMU积分模型会把噪声密度和随机游走作为过程噪声协方差的输入。如果你的IMU标称噪声是0.03 deg/sqrt(hr),但imu.yaml里给的还是别人传感器0.01的值,滤波器就会过于信任IMU积分,当视觉观测不稳定时,位置估计会迅速发散。反过来,噪声给大了,IMU的权重又被压低,初始化需要更长时间,动态响应也变迟钝。所以这一步不是可做可不做的流程性工作,它是影响系统性能的上游环节。
我见过有朋友直接拿官方imu_utils仓库里自带的示例文件,或者从网上下一个别人标定好的配置,套在自己的传感器上跑。如果你的IMU型号恰好一样,问题不大,但绝大多数情况下硬件批次、焊接质量、温度特性都不一样,最稳妥的做法是每块板子单独标定一次。尤其做无人车、无人机这种对定位连续性要求很高的项目,IMU噪声参数错一个数量级,后期排查问题会非常痛苦。
2. 编译安装的隐藏门槛:依赖版本、编译顺序和ROS发行版
imu-utils本身是ROS功能包,编译过程不复杂,但有几个前置条件容易卡人。整个工具包含两个仓库:code_utils和imu_utils。code_utils是基础工具库,imu_utils依赖它,所以必须先编译code_utils,再编译imu_utils,顺序不能反,否则rosdep找不到依赖包。
我第一次装的时候就是先clone了imu_utils,catkin_make直接报错找不到code_utils,后来才注意到README上特别标注了依赖顺序。如果你用wstool一次性拉取两个包,编译时最好分开build,或者干脆先只build code_utils,成功后再一起build。
环境方面,我在Ubuntu 18.04 + ROS Melodic和Ubuntu 20.04 + ROS Noetic上都编译过。Melodic没问题,Noetic下需要确认ceres-solver版本。imu-utils的CMakeLists里用的ceres版本比较老,如果你系统装的是ceres 2.x,编译会报API不匹配的错误。两个解决办法:装ceres 1.14.0版本,或者修改CMakeLists把ceres相关依赖降到最低。ceres 1.14在Ubuntu 20.04上可以用源码编译,几分钟就够,不用纠结版本问题。
另外还需要eigen、libdw-dev这些基础库,记得提前装好:
sudo apt-get install libdw-dev libeigen3-dev编译命令有一套统一的流程:
cd your_ws/src git clone https://github.com/gaowenliang/code_utils.git git clone https://github.com/gaowenliang/imu_utils.git cd .. && catkin_make这里有个细节:如果你之前建过多个工作空间,source顺序会影响ROS包发现。建议一个人单独为imu-utils建workspace,避免和别人已有的功能包冲突。还有,如果你的主工作空间用的是catkin build(比如你同时编译PX4固件),那这个工具用catkin_make编译就行,生成的devel目录source一下,功能包依然能被主空间发现,不必强行统一构建工具。
编译完成后,用rospack find imu_utils确认一下能不能找到,能找出来就说明环境没问题。接下来才进入数据采集环节,这也是整个标定流程中我觉得最考验耐心的一步。
3. 数据采集决定成败:静止两小时背后的物理逻辑
imu-utils的标定原理是Allan方差分析,它要求输入一段足够长的静止IMU数据。注意关键词是"足够长"——官方建议至少两个小时,这个时间不是拍脑袋定的,后面解释原理的时候你会明白为什么短数据标出来根本没法用。
数据采集姿势很简单:把设备放在一个稳定、无振动、温度相对恒定的台面上,保持静止,录制IMU的topic,录够一到两个小时。我用的是自己组的一块带BMI088的开发板,放在泡沫垫上,周围不要放风扇、不要有人走动。理论上越静越好,但也不用做到减震台那么夸张,正常的桌面环境足够。
录制命令和普通rosbag一致:
rosbag record /imu/data -O imu_static.bag这里有个经验点:在启动录制之前,先把传感器通电预热几分钟,等温度稳定再开始录。IMU的噪声特性和温度强相关,冷启动那几分钟的数据和后面稳定状态的数据混在一起,会让Allan方差曲线在长相关时间区域出现异常拐点。我对比过冷启动直接录和预热五分钟后录的两份数据,前者的bias instability估计值明显偏大,而且曲线在100秒以后的区域抖动得很厉害。
录制的时长直接决定可用性。如果只录二十分钟,Allan方差曲线在长相关时间区域没有足够的数据支撑,随机游走那一项根本拟合不出来。官方建议两小时,实际操作中一小时起步、两小时最稳。如果时间紧张,至少要保证一小时以上,而且采样频率要尽量高,我习惯设置成200Hz,这样时间序列的点数足够多,方差计算的结果也平滑。
还有一个坑容易被忽略:录制时不要只录IMU数据,建议把相机曝光时间、系统时间戳一起记录下来。因为后续你还需要把IMU时间戳和视觉时间戳对齐,时间戳跳变、回跳会导致Allan方差里出现虚假的周期误差。我遇到过一块GPS授时模块偶尔会给系统时间做微调,导致rosbag里出现两次时间跳跃,标定出来的噪声密度偏大,检查了半天才发现是时间戳问题。所以录制前最好用chrony或者ntp把系统时间同步好,录制过程中不要手动调整时间。
4. Allan方差的直观理解与标定结果解读
Allan方差这个名词听起来很数学,但它的思想其实很直观。假设你有一段很长的静止IMU数据,按不同的积分时间T把整段数据切片,每个切片算一个平均值,然后比较相邻两个切片的平均值差异。当T很小时,差异主要由高频噪声决定;当T很大时,差异主要反映传感器的低频漂移特性。把T从小到大变化,画出横轴是T、纵轴是方差的对数曲线,这条曲线就能把不同时间尺度上的噪声来源分离出来。
为什么需要两小时的数据?因为在Allan方差曲线上,如果要看到长相关时间区域(比如100秒到1000秒)的斜率特征,数据长度至少要达到积分时间的几十倍。你想看1000秒处的方差,数据至少得有个几小时才够统计意义。这也是很多人拿十分钟数据标出来的结果没法用的原因——短数据给不出长相关时间的方差估计,拟合出的随机游走纯属硬凑。
imu-utils跑完后,在输出目录里会生成几个文件,核心的是imu.yaml。里面的结构大概是:
# 陀螺仪 gyro: noise_density: 0.00012345 # rad/s/sqrt(Hz) random_walk: 0.00000321 # rad/s^2/sqrt(Hz) # 加速度计 accel: noise_density: 0.00123456 # m/s^2/sqrt(Hz) random_walk: 0.00001567 # m/s^3/sqrt(Hz)注意单位。陀螺仪的noise_density单位是rad/s/sqrt(Hz),random_walk单位是rad/s^2/sqrt(Hz)。加速度计对应的是m/s^2/sqrt(Hz)和m/s^3/sqrt(Hz)。VINS的配置模板里通常是deg/sqrt(hr)和deg/hr/sqrt(hr)这种单位,直接拷贝数值会错一个量级,后面第5章细说。
除了yaml,工具还会画Allan方差曲线图,PDF和PNG格式都有。你会看到一条拟合曲线和几个关键点的标注,比如bias instability最优点。看曲线的时候有个实操技巧:正常结果的对数曲线应该是平滑的"对勾"形状,左边斜率为-0.5(角度随机游走主导),右边斜率为+0.5(速率随机游走主导),中间凹底大约落在几十秒到几百秒之间。如果你的曲线在中间出现了明显的"台阶"或者突变,说明数据里有周期性干扰,比如电机振动、空调气流或者周围有人走动。重新采集往往比硬调数据更省时间。
5. 从imu.yaml到VINS:参数落地与三个常见误区
拿到imu.yaml不代表标定完成,把它正确用进SLAM系统才是最后一步。这里面最容易出问题的三个地方,我一个个说。
误区一:单位换算。刚才提到imu-utils输出的噪声密度是rad/s/sqrt(Hz)这个国际标准单位。VINS-Mono的配置模板里,imu noise参数通常写成0.01,0.02这种数值,看起来像个经验值。实际上VINS内部对单位有注释说明,但代码版本不同,注释写的单位也可能有出入。我建议你把imu-utils输出的值按国际单位直接用,然后去vins_estimator的nodelet或者estimator节点里核对一遍单位注释。比如IMU噪声的实际物理意义是角度随机游走,典型手持模块在0.01到0.05 deg/sqrt(hr)之间,换算成rad/s/sqrt(Hz)大概是0.00015到0.0007这个范围。如果你算出来是0.000001这种数量级,那基本是数据采集时传感器并没有完全静止,或者时间戳有问题。
误区二:只改噪声,不改随机游走。很多人的做法是把noise_density填进VINS配置,然后random_walk保留原值。实际上这两个参数在IMU积分协方差里各管一段:噪声密度影响短时间积分的不确定性增长速度,随机游走影响长时间积分时候的漂移。VINS初始化阶段对陀螺仪bias估计用的主要是随机游走,这个值给得不准,bias估计会偏慢甚至不收敛。正确做法是两个都填上,而且填之前确认单位。
误区三:标定一次用一辈子。IMU的噪声特性会随温度、供电电压、机械结构变化而变化。如果你的设备经常在户外日晒环境下工作,最好做一次高温和常温和低温的对比标定,至少心里有数。之前做一款户外巡检小车,冬天和夏天标定结果差了一倍多,后来在程序里加了两套参数的温度切换,才把定位稳定性补回来。如果你不改程序,那至少每隔几个月或者传感器经历剧烈温度变化后重新标一次。
还有个小建议:标定结果不要做完就扔。把imu.yaml、Allan曲线图、录制时间、温度环境、传感器型号批次这些信息一起归档。以后换一批板子,或者怀疑参数有问题要复标的时候,有基线数据对比会舒服很多。
我现在的标准流程是:新板子到手,先预热、录两小时静止数据、跑一次imu-utils、看一眼Allan曲线是否正常,然后才写进VINS配置跑数据集验证初始化时间和轨迹精度。这个过程看上去耗时,但真正值钱的是省掉了后面排查问题的大把时间。IMU标定这件事,确实是磨刀不误砍柴工。
本文还有配套的精品资源,点击获取