ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

VINS-Mono轨迹飘飞解决实录:双目+IMU标定与时间戳排查

VINS-Mono轨迹飘飞解决实录:双目+IMU标定与时间戳排查 最近把S系列双目相机接到工控机上跑VINS-Mono原本以为半个小时内就能看到漂亮的轨迹图结果第一版跑起来设备还没走两步轨迹直接往天上一拐接着像喝醉了一样在原地画圈。反复调了一周最后发现问题的根子全在几个不起眼的配置项里。这篇就来记录一下这个“轨迹飘飞解决版”的完整过程包括现象分析、标定细节和可直接复制的配置参数给同样用S系列或者其它双目IMU组合跑VINS-Mono的朋友一个参考。先说结论轨迹飘飞不是某一个参数坏了而是标定外参、时间戳、IMU噪声、图像曝光等多个因素的叠加。单独改任何一个参数都只能压制一部分症状只有把数据链路从头捋一遍让VINS-Mono拿到“干净”的输入轨迹才能稳下来。下面按我实际踩坑的顺序来写没有废话全是操作。1. 先认清轨迹飘飞的现象和根因1.1 飘飞不是一个现象而是好几种症状我一开始以为“轨迹飘飞”就只有一种画面后来反复测试才发现它通常以四种形态出现而且每一种对应的排查方向完全不一样。第一种是竖直方向直接飞走。轨迹原本应该贴着地面走结果跑了没几秒就往Z轴正方向冲像是坐电梯直接上天。这种问题多半出在重力加速度对齐上也就是IMU加速度计数据和相机坐标系之间的旋转关系没对齐。第二种是原地打转轨迹画成一团乱麻。设备明明在往前推轨迹却像在绕圈速度越快圈越小。这一般是IMU角速度和图像运动之间出现了系统性偏差常见原因是外参里的旋转矩阵方向反了或者角速度噪声参数设置得太小让VINS过信IMU的角速度积分。第三种是水平方向上缓慢漂移。设备走完一圈回到起点轨迹却没有闭合误差随时间累积越来越明显。这种通常不是突然爆掉而是慢慢偏常见原因是加速度计噪声偏大、陀螺仪零偏估计不准或者图像帧率太低导致视觉约束不足。第四种是运行几秒后直接跳到另一个位置像瞬移一样。这种往往是图像特征点瞬间丢失回环检测又错误匹配或者是时间戳突然出现跳变导致VINS把两帧图像当成了同一时刻的数据。1.2 我的最终排查结论我刚开始总想找一个“核心参数”觉得改一改就能彻底解决。后来把标定、配置、launch文件全部重新走了一遍才发现是四个问题叠在一起出厂外参和实际安装位置存在毫厘级偏差、图像与IMU时间戳没有严格同步、IMU噪声参数沿用默认值、相机自动曝光导致图像亮度跳变。这四个问题单独拿出来每一个都会引起小幅漂移放在一起就直接“放飞自我”。所以这个“解决版”要做的不是打某个神秘补丁而是把数据链路里最容易出错的环节全部校准到位。2. 硬件与驱动准备先让数据本身是对的2.1 把数据频率和时间戳打到台面上核实跑VINS-Mono之前我建议先用rostopic把相机和IMU的原始数据频率都过一遍。S系列相机驱动起来之后先看图像话题和IMU话题到底叫什么名字、频率是多少、时间戳是不是以秒为单位连续递增。这一步很多人会跳过直接打开launch文件就开跑飘飞之后再来找配置问题其实顺序反了。我自己实际用的命令是这样的rostopic hz /camera/color/image_raw rostopic hz /imu/data_raw rostopic echo /imu/data_raw -n 3rostopic hz能看出频率是否稳定。像IMU话题如果一会儿200Hz一会儿180HzVINS的预积分就会出现额外误差。rostopic echo则重点看header.stamp和header.seq。如果seq连续递增但stamp偶尔回跳或出现零值说明驱动里时间戳处理有问题需要在驱动层修复而不是指望VINS-Mono自己扛过去。这里还要注意一个细节S系列相机的硬件时间戳可能和系统时钟不是同一个源。如果驱动设置不当图像和IMU话题上的时间戳一个是传感器时钟另一个是系统接收时钟两种时间戳混在一起哪怕频率完全正常VINS也会认为数据时序错乱。2.2 时间戳偏差到底要控制在多少才算安全VINS-Mono的视觉惯性对齐对时间戳偏差非常敏感。很多资料会告诉你“毫秒级误差可以接受”我在实际测试里发现这个说法太宽松了。图像时间戳和IMU时间戳之间的偏差如果稳定在3毫秒以内影响还不明显一旦到了10毫秒量级轨迹就会在转弯时出现肉眼可见的横向漂移超过20毫秒旋转过程中直接飘飞。我用S系列相机做的一个简单测试把图像时间戳人为平移30毫秒短距离直线行走的轨迹误差从0.5%涨到了4%以上而且在大幅转动时出现Z轴跳变。这说明时间同步问题优先度极高必须先处理。验证时间偏差的方法很简单在相机前快速晃动设备录制一段bag然后离线对比图像曝光中间时刻和IMU数据的变化趋势。也可以用VINS自带的在线时差估计参数estimate_td来粗评但后面我会说明这个参数不能替代硬件层面的同步修正。如果驱动层面无法直接统一时钟退一步的办法是录bag时用record的--duration配合外部时间服务或者写一个节点把IMU时间戳和图像时间戳按最小二乘拟合对齐。最省事的方式是直接用驱动提供的传感器时间戳前提是驱动文档里明确说明图像和IMU共用一个时钟源。3. 修改VINS-Mono配置文件把每个参数讲明白3.1 内参、畸变、外参不能直接抄出厂标定S系列相机出厂时会提供一份标定文件里面包含左右目的相机内参、畸变系数以及IMU到左目相机的外参。很多人直接把这些数值填进VINS配置里我就是这么做的结果轨迹飘给我看。原因很简单出厂标定是在特定温度、特定应力状态下得到的相机模组在装配和运输过程中可能产生微小位移。特别是外参里的旋转矩阵哪怕只偏了1度跑几十米后横向误差就非常可观。IMU到相机的平移即使偏了1毫米同样会在转动手腕时被放大成明显的漂移。因此强烈建议拿到相机后自己重新标定一次。用棋盘格走一遍Kalibr抑或其它标定工具算出来的内参、畸变、相机与IMU外参比任何出厂值都可靠。如果你完全没标定经验也至少要做一个“外参粗检查”让相机固定记录IMU静止时的重力方向再对比相机观察到的静止环境调整外参旋转部分使两者一致。在VINS配置文件中内参长这样cam0: camera_model: pinholedistortion distortion_coeffs: [0.0, 0.0, 0.0, 0.0] intrinsics: [450, 450, 320, 240]这里intrinsics依次是fx, fy, cx, cydistortion_coeffs顺序是k1, k2, p1, p2。如果用鱼眼镜头要把模型改成equidistant或对应模型否则图像边缘畸变会直接误导特征匹配。外参部分放在VINS配置的body_T_cam0字段。注意这个矩阵表示的是IMU本体坐标系相对于相机坐标系的变换还是相机相对于IMU的变换不同版本VINS的约定略有差异一定要确认清楚。如果方向写反轨迹会立刻以螺旋形式飘走这是我见过最直接的外参错误表现。3.2 IMU噪声参数初始值怎么给VINS配置里的acc_n、gyr_n、acc_w、gyr_w这四个参数决定了VINS对IMU数据有多信任。给太大会让视觉主导轨迹容易抖动给太小则会让IMU积分主导漂移会迅速累积。用S系列这类消费级IMU时我常用的初始经验值如下表参数含义经验值acc_n加速度计噪声密度0.05gyr_n陀螺仪噪声密度0.005acc_w加速度计随机游走0.0005gyr_w陀螺仪随机游走0.000005这四个值的单位是连续时间密度不是离散采样的标准差。如果驱动输出的IMU数据做了滤波平滑噪声密度会比原始指标更小这时可以适当调低gyr_n和acc_n如果数据里明显有振动干扰就要调大一点。VINS在静止时会自己估计零偏所以噪声参数不用特别精确但也不能差一个量级以上。我踩过的一个具体坑是把gyr_n从0.005改成0.0005后轨迹在旋转时表现出“过刚”的倾向明明已经停下来轨迹还会维持一小段惯性漂移。后来恢复默认值并配合准确外参情况立刻好转。3.3 estimate_extrinsic设0还是设1VINS的estimate_extrinsic参数控制是否在线估计相机与IMU外参。设成1表示让VINS在运行过程中自行优化外参设成0则直接读取配置里的body_T_cam0。很多教程为了省事建议直接把estimate_extrinsic设成1。我的实际经验是在标定准确度未知的情况下设为1确实能让轨迹不飘得那么夸张但它收敛到的结果未必是真实外参而且会在某些运动激励不足的场景下收敛到错误局部解。更稳的操作是分两步走先用一段弱光照、多旋转的bag把estimate_extrinsic设为1运行完成后记录它估计出的外参然后把收敛后的外参写回配置并把estimate_extrinsic设回0正式跑。为什么最后要设回0因为在线外参估计需要充分的旋转激励一旦常规使用中运动类型单一VINS就会反向干扰外参导致结果反而变差。固定外参至少让系统少一个自由变量稳定度会高很多。这里还要注意外参通常涵盖旋转和平移两部分。VINS对旋转的敏感性远高于平移所以哪怕平移给得粗略一些旋转部分也必须精确。我拿到的出厂标定文件里旋转矩阵看起来是单位阵附近的值实际标定后发现绕Z轴偏了约1.8度这就是轨迹旋转飘飞的重要原因。3.4 estimate_td到底要不要开estimate_td控制是否在线估计图像和IMU的时间偏差。如果驱动已经做到5毫秒以内的同步我建议设成0避免额外估计造成抖动。如果不太确定时间同步质量先设成1让VINS自己把时间对齐轨迹会有明显改善。我用S系列实际测试时发现estimate_td在视觉初始化成功后大概能修正10毫秒量级的偏差但修正过程会伴随短暂的前几秒轨迹晃动之后趋于稳定。如果你在启动时看到轨迹刚起步有点扭曲过了两三秒又好了这个参数通常在起作用。需要注意estimate_td不能替代驱动层的时间同步修复。如果时间戳本身就有时而连续时而跳变的坏点在线估计反而可能被坏点带偏。所以规范顺序依然是先保证驱动层时间戳干净再决定是否开在线估计。4. 实操流程从头到尾跑通一个解决版4.1 录制数据的三条铁律跑VINS-Mono解决飘飞不要一上来就拿实时数据试后面改参数会很痛苦。我习惯先录一段bag在固定环境里反复测试配置每改一个参数都回放同一段数据对比轨迹。这样能确保看到的变化是命令引起的而不是环境变化造成的。录制bag的时候有三条铁律任何一条不满足都可能为后续排查埋雷。第一启动录制后保持设备完全静止至少2秒再开始移动。VINS初始化阶段需要静止来估计重力方向和陀螺仪零偏如果一上来就动初始零偏就会带偏整条轨迹。哪怕后面算法再有回环修正起始段的误差也会持续影响全局。第二关闭相机的自动曝光和自动白平衡。S系列相机的驱动里如果默认开启自动曝光移动过程中图像亮度会不断变化特征点的像素梯度也跟着变严重影响光流跟踪的稳定性。我处理的方式是在驱动参数里固定曝光时间和增益并确认室内光照恒定。第三录制环境要保证有足够纹理。纯白墙、大面积玻璃、空荡走廊都是VINS的坑。纹理不足时特征点数量掉到几十个光流稍微一断轨迹就开始飘。至少保证画面里有二十个以上稳定角点最好能覆盖图像的四个象限。录制命令可以参考rosbag record /camera/color/image_raw /imu/data_raw -O s_walk.bag4.2 launch文件与topic名替换VINS-Mono自带的示例launch文件默认订阅的是相机的仿真话题直接跑肯定报找不到话题。需要新建一个launch文件把图像话题和IMU话题替换成S系列实际发布的名称。我的做法是复制一份示例launch然后只改配置路径和话题名尽量不动原有结构。launch文件里大致是这样launch arg nameconfig_path default$(find vins_estimator)/../config/s_series/s_robust.yaml / arg namevins_driver default / node namevins_estimator pkgvins_estimator typevins_estimator outputscreen param nameconfig_file typestring value$(arg config_path) / param nameoutput_path typestring value$(find vins_estimator)/output_path / /node /launch注意上面的launch文件里没有直接写图像话题名VINS-Mono的图像和IMU订阅话题是在配置yaml里通过image_topic和imu_topic指定的。所以更关键的修改位置在yamlimage_topic: /camera/color/image_raw imu_topic: /imu/data_raw如果你在S系列驱动里看到的话题名带命名空间或者图像是双目的两个话题请把要用的左目话题名填进去。不要想当然地把两个话题都塞给VINS-Mono它是单目视觉惯性算法只接受一个图像输入。4.3 启动VINS-Mono并保存轨迹改完配置后按这个顺序启动roslaunch vins_estimator s_series.launch roslaunch vins_rviz vins_rviz.launch rosbag play s_walk.bag启动顺序上先把VINS和Rviz起来再播放bag。如果bag播放太快VINS可能出现初始化没完成就开始运动的情况可以用rosbag play --pause控制播放速度等Rviz里出现了稳定的特征点轨迹和重力方向再恢复播放。轨迹最终可以保存下来VINS-Mono提供保存路径的服务rosservice call /vins_estimator/save_path {}调用后会在output_path下生成vins_result_path.txt。这个文件保存的是每个时间戳对应的位置和姿态可以直接用来和真值比较也可以用EVO之类的工具画误差曲线。一个经验是保存轨迹时要注意VINS输出的话题时间戳和bag时间戳是否一致。如果二者有个固定的偏置画图之前先把时间对齐否则会认为轨迹严重漂移其实是时间栅格错位。4.4 怎么判断轨迹算不算正常轨迹飘飞解决没解决不能只看“没飞上天”就说成功。我用三个标准来验收。第一个标准是静止起点。回放bag的前两秒VINS刚完成初始化轨迹应该基本停在一个点上抖动幅度小于1厘米。如果静止时轨迹都在匀速移动说明陀螺仪零偏或者加速度计重力度量有问题。第二个标准是直线段。在桌面上缓慢推动设备走一条直线轨迹应该是一条接近直线的平滑曲线不能出现明显的波浪状摆动。波浪状摆动通常意味着图像特征点选择太分散、外参旋转不准或者图像和IMU时间戳偏差仍然存在。第三个标准是回到原点。走一个四边形回到起点理想情况下轨迹终点和起点应重合实测中漂移在总路程的1%到2%以内就算可以接受。如果超过这个量级先不要改VINS内部参数回去检查标定和时间戳。我实际跑S系列时把这三条标准全部跑通后轨迹已经完全不会“上天”缓慢行走和旋转都能保持稳定放在室内的钢筋桌子上反复平移和转动终点误差控制在0.8%左右。虽然不能和专业惯导比但作为视觉惯性里程计已经进入可用状态。5. 常见问题速查表5.1 症状、原因和对策对照表整理了一张我在实际运行中遇到的问题表遇到同类现象可以直接按行排查。现象最可能原因优先处理方式轨迹往Z轴方向飞升外参旋转矩阵错误或重力对齐异常重新标定外参检查body_T_cam0方向原地打转画圈陀螺仪与外参方向不一致时差偏大检查时间戳偏差修正外参旋转水平方向缓慢漂移IMU噪声过大或相机帧率低调低acc_n/gyr_n提升图像帧率刚起步几秒后轨迹跳变静止初始化不充分或自动曝光开启录bag前静止2秒固定曝光参数转弯后轨迹明显歪时间戳偏差大于10毫秒驱动层同步开estimate_td纹理稀少处轨迹乱飞特征点数量不足换纹理丰富场景或降低特征点阈值回放同一bag轨迹不一样时间戳回跳或多线程调度抖动核对驱动时间戳保证数据源稳定5.2 我的排查顺序如果你不想一张表一张表看我给出一个可以直接照做的排查链条按这个顺序走能省掉至少一半的时间。第一步看时间戳。把rostopic echo打出来确认时长是否连续递增偏差是否在几毫秒内。第二步看外参。用标定工具重新标定或者至少用静止时的重力和视觉方向粗对齐把外参旋转部分修正到1度以内。第三步查噪声参数和estimate_extrinsic。按上一节的经验值填入在线估计外参一次并固化。第四步关自动曝光。录一段固定曝光、纹理正常的数据重复播放观察轨迹。第五步严格静止初始化。每次回放bag的前几秒不要立刻播放用--pause控制节奏。这个顺序的核心逻辑是先确保传感器数据本身无歧义再让VINS去优化。如果一上来就调VINS内部参数很容易陷入“调好A又带歪B”的循环。我亲测过先处理时间戳和外参之后有一半的飘飞现象已经自然消失。6. 个人心得与几个实用习惯这套“解决版”最终落地时我对S系列相机的感受是硬件本身不差但默认数据和VINS所需的输入之间还有一段“调试距离”。厂商给的标定参数只能作为起始参考真正想在具体场景里跑出稳定轨迹标定和时间同步这两个基本功绕不开。我还养成一个习惯每次修改配置前先在文件里加注释记录本次改动和当时的轨迹截图编号。VINS参数联调很容易出现“各参数相互补偿”的假象比如外参调错时把IMU噪声调大视觉主导反而会让轨迹勉强不发散但代价是细微抖动和回环闭合变差。如果没有记录过两天再回看时根本不知道当时为什么这样改。另一件值得做的事是把最终验证通过的一套配置单独存成一个文件夹连同launch文件、bag段和轨迹截图一起归档。以后换一台同样的设备可以把这套配置作为起点再针对新设备的标定差异做增量调整而不是从零开始踩坑。如果你后续想进一步压低漂移还可以考虑给S系列加回环检测的触发条件或者在场景中布设一些标志物辅助视觉特征。不过那已经超出“解决飘飞”的范围了。先把这篇里的数据链路、标定和时间同步处理好至少九成以上的轨迹飘飞问题都能落地稳住。剩下的就是算法参数精细调优的漫长了。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表