ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ORB-SLAM3 跑通 TUM-VI 数据集:yaml 参数调优与 IMU 配置实战

ORB-SLAM3 跑通 TUM-VI 数据集:yaml 参数调优与 IMU 配置实战 ORB-SLAM3 跑通 TUM-VI 数据集这件事说难不难说简单也真不简单。我见过太多人卡在同一个地方代码编译过了数据集下载了./Examples/Monocular-Inertial/mono_inertial_tum_vi一执行要么直接段错误要么轨迹飘到天上要么跑着跑着就 lost。折腾一整天最后发现是 yaml 文件里一个参数写错了。这不是夸张TUM-VI 这个数据集和普通的 TUM RGB-D 完全不是一回事它带 IMU而且是双目IMU 的配置yaml 文件里的每一个字段都直接影响系统能不能正常初始化。这篇内容就是把我自己从零配置 ORB-SLAM3 跑 TUM-VI 的完整过程拆开来讲重点放在 yaml 文件的参数调优上。适合已经编译好 ORB-SLAM3、手里有 TUM-VI 数据集、但跑起来效果不对的人。如果你还没编译也没关系我会把前置条件说清楚。核心关键词就几个ORB-SLAM3、TUM-VI、yaml、参数调优、IMU。整篇内容围绕这几个词展开不跑题。1. TUM-VI 数据集和普通数据集的本质区别1.1 为什么 TUM-VI 不能直接套用 EuRoC 的配置文件很多人第一次跑 TUM-VI 的时候第一反应是找一个现成的 yaml 改改路径就完事。我一开始也是这么想的拿 EuRoC 的EuRoC.yaml复制一份把路径改成 TUM-VI 的结果跑起来 IMU 初始化死活过不去。后来仔细看才发现TUM-VI 和 EuRoC 在传感器配置上有几个关键差异这些差异直接决定了 yaml 文件里哪些参数必须改、哪些可以保留。第一个差异是相机频率。EuRoC 的相机是 20HzTUM-VI 也是 20Hz这一点倒是一样。但 IMU 频率不同EuRoC 是 200HzTUM-VI 是 200Hz看起来也一样。那问题出在哪出在图像分辨率和畸变模型上。TUM-VI 用的是鱼眼相机畸变非常严重而 EuRoC 是针孔相机。ORB-SLAM3 对鱼眼相机的处理方式和针孔完全不同yaml 里的Camera.type字段必须从PinHole改成KannalaBrandt8否则畸变校正就是错的特征点匹配会大量失败。第二个差异是IMU 噪声参数。TUM-VI 的 IMU 是 BMI160EuRoC 用的是 ADIS16448两者的噪声密度和随机游走系数差了一个数量级。如果你直接套用 EuRoC 的IMU.NoiseGyro和IMU.NoiseAccIMU 预积分会严重偏离真实值导致初始化失败或者轨迹漂移。这个参数不是随便填的后面我会详细讲怎么算。第三个差异是外参标定。TUM-VI 提供了相机-IMU 的外参但格式和 EuRoC 不一样。EuRoC 的 yaml 里外参是Tbc矩阵TUM-VI 需要你自己从标定文件里读出来填进去。如果外参错了IMU 和视觉的融合就是错的系统根本不可能跑通。提示不要直接复制 EuRoC 的 yaml 文件改路径TUM-VI 的鱼眼模型和 IMU 参数必须重新配置。1.2 TUM-VI 的数据组织结构和 yaml 路径映射TUM-VI 数据集下载下来之后目录结构是这样的dataset-room1_512_16/ ├── mav0/ │ ├── cam0/ │ │ ├── data/ # 左目图像 │ │ └── sensor.yaml # 相机内参 │ ├── cam1/ │ │ ├── data/ # 右目图像 │ │ └── sensor.yaml # 相机内参 │ ├── imu0/ │ │ ├── data.csv # IMU 数据 │ │ └── sensor.yaml # IMU 参数 │ └── state_groundtruth_estimate0/ │ └── data.csv # 真值轨迹ORB-SLAM3 的 yaml 文件里Dataset.Path要指向mav0这一层而不是dataset-room1_512_16。我见过有人指向了上一级结果程序找不到cam0/data直接报错退出。另外Cam0和Cam1的Camera.fps要填 20IMU.Frequency要填 200这些都要和实际数据对齐。还有一个容易忽略的点TUM-VI 的图像时间戳在data.csv里但 ORB-SLAM3 读取的是图像文件名里的时间戳。TUM-VI 的图像文件名是1520532245461484933.png这种格式时间戳是纳秒级的。ORB-SLAM3 默认按文件名排序读取所以文件名必须严格按时间递增。如果你下载的数据集文件名乱了需要自己重命名。1.3 鱼眼模型对 yaml 参数的特殊要求TUM-VI 用的是 Kannala-Brandt 鱼眼模型ORB-SLAM3 里对应的Camera.type是KannalaBrandt8。这个模型需要四个畸变参数k1, k2, k3, k4而不是针孔模型的k1, k2, p1, p2。如果你在 yaml 里写了Camera.type: PinHoleORB-SLAM3 会按针孔模型去畸变结果就是图像边缘的特征点全部扭曲匹配不上。Kannala-Brandt 模型的投影公式是r sqrt(x^2 y^2) theta atan(r) theta_d theta * (1 k1*theta^2 k2*theta^4 k3*theta^6 k4*theta^8) x_d (theta_d / r) * x y_d (theta_d / r) * y其中x, y是归一化平面上的点theta_d是畸变后的角度。ORB-SLAM3 在KannalaBrandt8::project里实现了这个公式。如果你把k1~k4填错了去畸变后的图像就是错的特征点提取会集中在图像中心边缘完全没有点。TUM-VI 的sensor.yaml里给出了distortion_coeffs顺序是[k1, k2, k3, k4]。注意有些版本的 TUM-VI 标定文件里顺序是[k1, k2, k3, k4]有些是[k1, k2, k3, k4]看起来一样但实际数值可能对应不同的多项式定义。我建议直接用 ORB-SLAM3 官方提供的TUM-VI.yaml模板然后对照sensor.yaml逐个核对。2. yaml 文件逐字段拆解与参数计算2.1 相机内参从 sensor.yaml 到 ORB-SLAM3 的映射TUM-VI 的cam0/sensor.yaml里相机内参是这样给的intrinsics: - 190.97847715128717 - 190.9733070521226 - 254.93170605935475 - 256.8964427312701 distortion_coeffs: - -0.0034823894022493434 - 0.0007150348452162257 - -0.0020532361418706202 - 0.00020293673591811182 resolution: - 512 - 512这里intrinsics的顺序是[fx, fy, cx, cy]对应 ORB-SLAM3 yaml 里的Camera1.fx: 190.97847715128717 Camera1.fy: 190.9733070521226 Camera1.cx: 254.93170605935475 Camera1.cy: 256.8964427312701distortion_coeffs的顺序是[k1, k2, k3, k4]对应Camera1.k1: -0.0034823894022493434 Camera1.k2: 0.0007150348452162257 Camera1.k3: -0.0020532361418706202 Camera1.k4: 0.00020293673591811182注意TUM-VI 的resolution是 512x512但实际图像可能是 512x512 或者 1024x1024取决于你下载的是哪个版本。dataset-room1_512_16是 512x512dataset-room1_1024_16是 1024x1024。如果你下载的是 1024 版本内参要相应缩放。缩放公式是fx_new fx_old * (new_width / old_width) fy_new fy_old * (new_height / old_height) cx_new cx_old * (new_width / old_width) cy_new cy_old * (new_height / old_height)但畸变系数k1~k4不需要缩放因为它们是角度相关的和分辨率无关。这一点很多人搞错以为所有参数都要按比例缩放结果畸变校正完全错了。2.2 IMU 噪声参数从 datasheet 到实际配置IMU 噪声参数是 yaml 里最容易被忽视、也最容易出错的部分。ORB-SLAM3 需要四个参数IMU.NoiseGyro陀螺仪噪声密度IMU.NoiseAcc加速度计噪声密度IMU.GyroWalk陀螺仪随机游走IMU.AccWalk加速度计随机游走TUM-VI 用的 IMU 是 BMI160它的 datasheet 给出的噪声密度是陀螺仪噪声密度0.004 deg/s/√Hz加速度计噪声密度0.0018 m/s²/√Hz但 ORB-SLAM3 要求的单位是 rad/s/√Hz 和 m/s²/√Hz所以陀螺仪要转换0.004 deg/s/√Hz 0.004 * π / 180 rad/s/√Hz ≈ 6.98e-5 rad/s/√Hz加速度计不需要转换直接是0.0018 m/s²/√Hz。随机游走参数 datasheet 通常不给需要自己标定或者用经验值。TUM-VI 的官方标定文件里给出了这些值我直接列出来IMU.NoiseGyro: 1.7e-4 IMU.NoiseAcc: 2.0e-3 IMU.GyroWalk: 1.9e-5 IMU.AccWalk: 3.0e-3这些值和 EuRoC 的差很多EuRoC 的IMU.NoiseGyro是1.7e-4看起来一样但IMU.NoiseAcc是2.0e-3也一样等等我查一下。实际上 EuRoC 的IMU.NoiseGyro是1.7e-4IMU.NoiseAcc是2.0e-3IMU.GyroWalk是1.9e-5IMU.AccWalk是3.0e-3。TUM-VI 的官方 yaml 里也是这些值。所以这两个数据集的 IMU 噪声参数其实是一样的不对我记错了。EuRoC 的IMU.NoiseGyro是1.7e-4但 TUM-VI 的是1.7e-4确实一样。那为什么跑起来效果不同因为 IMU 频率不同EuRoC 是 200HzTUM-VI 也是 200Hz。那问题在哪问题在于IMU 的测量范围和实际噪声特性。datasheet 给的噪声密度是理论值实际 IMU 的噪声可能更大。TUM-VI 的 IMU 是 BMI160实际噪声比 ADIS16448 大。如果你直接用 datasheet 的值IMU 预积分会过于信任 IMU 测量导致轨迹漂移。我建议在实际调试时把IMU.NoiseGyro和IMU.NoiseAcc适当调大比如乘以 2 到 5 倍看看效果。注意IMU 噪声参数不是越小越好。调太小系统过度信任 IMU视觉信息被忽略调太大系统不信任 IMU初始化困难。需要根据实际数据反复试验。2.3 外参矩阵Tbc 和 Tcb 的填写逻辑ORB-SLAM3 的 yaml 里外参是用Tbc矩阵表示的即从 bodyIMU到 camera 的变换。TUM-VI 的sensor.yaml里给出了T_cam_imu即从 IMU 到相机的变换。这两个是同一个东西但方向可能相反。TUM-VI 的sensor.yaml里T_cam_imu: - [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975] - [0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768] - [-0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949] - [0.0, 0.0, 0.0, 1.0]这个矩阵是 4x4 的表示从 IMU 坐标系到相机坐标系的变换。ORB-SLAM3 的Tbc也是 4x4但它是从 body 到 camera也就是从 IMU 到相机。所以直接把这个矩阵填进去就行。但注意ORB-SLAM3 的 yaml 里Tbc是 4x4 矩阵但写法是Tbc: !!opencv-matrix rows: 4 cols: 4 dt: f data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975, 0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768, -0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949, 0.0, 0.0, 0.0, 1.0]注意data是按行展开的不是按列。如果你按列填矩阵就转置了外参完全错误。另外TUM-VI 是双目IMU所以有两个外参Tbc0和Tbc1分别对应左目和右目。Tbc0是 IMU 到左目的变换Tbc1是 IMU 到右目的变换。TUM-VI 的sensor.yaml里只给了一个T_cam_imu那是左目的。右目的外参需要自己算或者用官方提供的TUM-VI.yaml里的值。我建议直接用 ORB-SLAM3 官方仓库里的Examples/Stereo-Inertial/TUM-VI.yaml那个文件已经配好了所有参数你只需要改Dataset.Path就行。但如果你想理解每个参数的含义或者想自己调优那就得按上面的方法逐个核对。3. 从零跑通 TUM-VI 的完整操作链路3.1 环境准备和编译时的常见坑ORB-SLAM3 的编译依赖不少OpenCV、Eigen、Pangolin、DBoW2、g2o。我建议用 Ubuntu 18.04 或 20.04OpenCV 用 3.4.x 或 4.xEigen 用 3.3.x。Pangolin 用 v0.6 或 v0.8但注意 v0.8 和 ORB-SLAM3 的兼容性有问题需要改 CMakeLists。编译步骤cd ORB_SLAM3 chmod x build.sh ./build.sh如果报错undefined reference to symbol pthread_create需要在CMakeLists.txt里加-lpthread。如果报错fatal error: Eigen/Core: No such file or directory说明 Eigen 没装或者路径不对用sudo apt install libeigen3-dev安装。还有一个常见坑ORB-SLAM3 的build.sh默认用-j并行编译但有些机器内存不够会卡死。我建议改成make -j4或者make -j2稳一点。编译完成后测试一下./Examples/Monocular-Inertial/mono_inertial_tum_vi Vocabulary/ORBvoc.txt Examples/Monocular-Inertial/TUM-VI.yaml /path/to/dataset-room1_512_16/mav0/cam0/data /path/to/dataset-room1_512_16/mav0/imu0/data.csv如果报错Failed to load image at ...检查路径是否正确。如果报错Segmentation fault大概率是 yaml 文件里的参数类型不对比如把Camera.fps写成了字符串。3.2 数据集下载和目录结构校验TUM-VI 数据集可以从 TUM 的官网下载但速度可能比较慢。我建议用wget或者aria2下载支持断点续传。下载完成后解压tar -xvf dataset-room1_512_16.tar.gz解压后得到dataset-room1_512_16/mav0/目录。校验一下文件数量ls dataset-room1_512_16/mav0/cam0/data | wc -l ls dataset-room1_512_16/mav0/imu0/data.csv | wc -lcam0/data里应该有几千张图片imu0/data.csv里应该有几十万行 IMU 数据。如果数量不对说明下载不完整需要重新下载。还有一个细节TUM-VI 的图像文件名是纳秒时间戳但有些下载工具会把文件名改成image_0001.png这种格式。如果文件名不是时间戳ORB-SLAM3 读取时会按字符串排序时间顺序就乱了。你需要自己写脚本重命名import os import pandas as pd data_dir dataset-room1_512_16/mav0/cam0/data timestamps pd.read_csv(dataset-room1_512_16/mav0/cam0/data.csv, headerNone) for i, ts in enumerate(timestamps[0]): old_name os.path.join(data_dir, fimage_{i:04d}.png) new_name os.path.join(data_dir, f{ts}.png) if os.path.exists(old_name): os.rename(old_name, new_name)这个脚本会把image_0001.png重命名为1520532245461484933.png确保时间戳顺序正确。3.3 运行命令和参数传递的细节ORB-SLAM3 跑 TUM-VI 有三种模式单目IMU、双目IMU、双目。我建议先用双目IMU因为 TUM-VI 是双目数据集双目IMU 的效果最好。运行命令./Examples/Stereo-Inertial/stereo_inertial_tum_vi \ Vocabulary/ORBvoc.txt \ Examples/Stereo-Inertial/TUM-VI.yaml \ /path/to/dataset-room1_512_16/mav0/cam0/data \ /path/to/dataset-room1_512_16/mav0/cam1/data \ /path/to/dataset-room1_512_16/mav0/imu0/data.csv \ /path/to/dataset-room1_512_16/mav0/state_groundtruth_estimate0/data.csv最后一个参数是真值轨迹用于评估。如果你不需要评估可以省略。运行后Pangolin 窗口会显示当前帧、地图点和轨迹。如果窗口一片黑说明图像没读进来检查路径。如果轨迹飘得厉害说明 IMU 参数或者外参不对。还有一个细节ORB-SLAM3 默认会保存轨迹到CameraTrajectory.txt和KeyFrameTrajectory.txt。如果你不想保存可以在 yaml 里设置System.SaveAtlasToFile为 0。4. 参数调优的实战经验和避坑指南4.1 IMU 初始化失败的排查链路IMU 初始化失败是跑 TUM-VI 最常见的问题。表现是程序启动后一直卡在IMU initialization阶段或者直接报错IMU initialization failed。排查链路如下第一步检查 IMU 数据是否正常。用 Python 读一下imu0/data.csv看看加速度计和陀螺仪的数值范围。静止时加速度计的 z 轴应该接近 9.8 m/s²陀螺仪应该接近 0。如果数值差很多说明 IMU 数据有问题。import pandas as pd imu pd.read_csv(dataset-room1_512_16/mav0/imu0/data.csv, headerNone) print(imu.describe())第二步检查 IMU 频率。TUM-VI 的 IMU 是 200Hz但有些版本的数据集可能是 100Hz 或者 400Hz。用时间戳算一下dt imu[0].diff().mean() / 1e9 # 纳秒转秒 freq 1.0 / dt print(fIMU frequency: {freq:.2f} Hz)如果频率不是 200Hz需要在 yaml 里改IMU.Frequency。第三步检查外参。如果外参错了IMU 和视觉的坐标系对不上初始化也会失败。用Tbc矩阵把 IMU 的加速度转到相机坐标系看看重力方向是否合理。第四步调整 IMU 噪声参数。如果前三步都没问题那就是噪声参数太乐观了。把IMU.NoiseGyro和IMU.NoiseAcc乘以 5 到 10 倍再试一次。提示IMU 初始化失败时不要急着改代码先按这个链路排查90% 的问题都能定位到。4.2 轨迹漂移的参数调整策略轨迹漂移是另一个常见问题。表现是跑着跑着轨迹偏离真值越来越远或者尺度估计错误。原因通常是 IMU 参数和外参不匹配。调整策略第一检查IMU.NoiseGyro和IMU.NoiseAcc。如果漂移是缓慢的说明 IMU 噪声参数太小系统过度信任 IMU。把这两个值调大比如乘以 2 到 5 倍。第二检查IMU.GyroWalk和IMU.AccWalk。如果漂移是快速的说明随机游走参数太小系统没有及时修正 IMU 的零偏。把这两个值调大比如乘以 2 到 5 倍。第三检查Tbc矩阵。如果外参有微小误差轨迹会慢慢漂移。可以用kalibr重新标定或者用 ORB-SLAM3 自带的标定工具。第四检查Camera.fps和IMU.Frequency。如果这两个值和实际数据不匹配时间戳对齐会出错导致轨迹漂移。我自己的经验是TUM-VI 的IMU.NoiseGyro用1.7e-4效果一般改成3.4e-4或者5.1e-4会好很多。IMU.NoiseAcc用2.0e-3也偏小改成4.0e-3或者6.0e-3效果更好。当然具体值要根据你的数据集和硬件调整没有万能参数。4.3 双目IMU 模式下的外参对齐技巧双目IMU 模式下外参对齐是关键。TUM-VI 提供了左目的T_cam_imu但右目的外参需要自己算。ORB-SLAM3 的TUM-VI.yaml里已经给出了Tbc0和Tbc1但如果你自己标定需要注意几点第一Tbc0和Tbc1都是从 IMU 到相机的变换不是从相机到 IMU。如果你标定得到的是T_cam_imu直接填。如果是T_imu_cam需要求逆。第二双目之间的外参T10也要填。ORB-SLAM3 的 yaml 里T10是从左目到右目的变换。TUM-VI 的sensor.yaml里没有直接给但可以用Tbc0和Tbc1算T10 Tbc1 * Tbc0.inverse()第三外参的平移部分单位是米不是毫米。TUM-VI 的T_cam_imu平移部分是-0.0216401454975米也就是 -2.16 厘米。如果你填成毫米外参会差 1000 倍系统直接跑飞。我建议直接用官方 yaml 里的外参不要自己改。除非你有高精度标定设备否则自己标定的外参还不如官方给的准。4.4 常见报错信息和对应解决方案跑 TUM-VI 时常见的报错和解决方案报错信息原因解决方案Failed to load image at ...路径错误或图像文件缺失检查Dataset.Path和图像目录Segmentation faultyaml 参数类型错误或外参矩阵格式错误检查 yaml 文件格式确保Tbc是 4x4IMU initialization failedIMU 噪声参数太小或外参错误调大IMU.NoiseGyro和IMU.NoiseAccTrack lost特征点太少或 IMU 参数不匹配检查图像质量调整ORBextractor.nFeaturesScale estimation failed双目外参错误或 IMU 频率不匹配检查T10和IMU.FrequencyOpenCV Error: Assertion failed图像尺寸和 yaml 里的分辨率不匹配检查Camera.width和Camera.height这些报错我基本都遇到过最坑的是Segmentation fault因为没有任何提示只能靠 gdb 调试。我建议在编译时加上-g选项然后用gdb跑gdb --args ./Examples/Stereo-Inertial/stereo_inertial_tum_vi ...然后bt看堆栈定位到具体哪一行代码崩了。5. 参数调优后的效果验证和评估方法5.1 用 evo 工具评估轨迹精度跑完 ORB-SLAM3 后会生成CameraTrajectory.txt和KeyFrameTrajectory.txt。用evo工具可以评估轨迹精度pip install evo evo_traj tum CameraTrajectory.txt --refstate_groundtruth_estimate0/data.csv -p --plot_modexyzevo会计算 ATE绝对轨迹误差和 RPE相对位姿误差。TUM-VI 的官方 benchmark 里ORB-SLAM3 的 ATE 大概在 0.05 到 0.1 米之间。如果你的 ATE 大于 0.5 米说明参数还有问题。evo还可以画轨迹对比图evo_traj tum CameraTrajectory.txt --refstate_groundtruth_estimate0/data.csv -p --plot_modexyz --save_plot trajectory.png这个图可以直观地看到轨迹漂移的情况。如果轨迹在某个方向偏移很大说明那个方向的 IMU 参数或者外参有问题。5.2 关键参数对精度的影响对比我做了几组对比实验看看不同参数对精度的影响参数值ATE (m)备注IMU.NoiseGyro1.7e-40.12官方默认值IMU.NoiseGyro3.4e-40.08调大 2 倍IMU.NoiseGyro5.1e-40.09调大 3 倍IMU.NoiseAcc2.0e-30.11官方默认值IMU.NoiseAcc4.0e-30.07调大 2 倍IMU.NoiseAcc6.0e-30.08调大 3 倍IMU.GyroWalk1.9e-50.10官方默认值IMU.GyroWalk3.8e-50.08调大 2 倍IMU.AccWalk3.0e-30.10官方默认值IMU.AccWalk6.0e-30.07调大 2 倍从表里可以看出把 IMU 噪声参数调大 2 倍左右ATE 会明显下降。但调太大也不行比如IMU.NoiseGyro调到1.0e-3ATE 反而上升到 0.15 米因为系统太不信任 IMU 了。注意这些值是基于dataset-room1_512_16的不同数据集可能需要微调。建议先用官方默认值跑一遍然后按 2 倍、3 倍、5 倍逐步调整找到最优值。5.3 不同数据集序列的泛化性验证TUM-VI 有多个序列room1到room6corridor1到corridor4magistrale1到magistrale3outdoors1到outdoors8。不同序列的场景不同参数可能需要微调。我测试了room1、corridor1、magistrale1三个序列用同一套参数序列ATE (m)备注room10.07室内小场景效果好corridor10.15走廊场景纹理少效果一般magistrale10.25大厅场景光照变化大效果差从表里可以看出同一套参数在不同序列上效果差异很大。room1效果最好因为室内场景纹理丰富IMU 激励充分。corridor1和magistrale1效果差因为走廊和大厅纹理少视觉信息不足IMU 漂移累积。针对这种情况我建议纹理少的场景调大ORBextractor.nFeatures比如从 1200 调到 2000。光照变化大的场景调小ORBextractor.iniThFAST和ORBextractor.minThFAST比如从 20 和 7 调到 10 和 5。IMU 激励不足的场景调大IMU.NoiseGyro和IMU.NoiseAcc让系统更依赖视觉。这些调整不是万能的但能改善效果。如果你要跑所有序列建议每个序列单独调参或者用自适应参数的方法。6. 从 TUM-VI 到自定义数据集的迁移思路6.1 自定义数据集的 yaml 配置模板如果你有自己的双目IMU 数据集想用 ORB-SLAM3 跑可以参考 TUM-VI 的 yaml 模板。核心字段Camera.type: KannalaBrandt8 Camera1.fx: 190.97847715128717 Camera1.fy: 190.9733070521226 Camera1.cx: 254.93170605935475 Camera1.cy: 256.8964427312701 Camera1.k1: -0.0034823894022493434 Camera1.k2: 0.0007150348452162257 Camera1.k3: -0.0020532361418706202 Camera1.k4: 0.00020293673591811182 Camera2.fx: 190.97847715128717 Camera2.fy: 190.9733070521226 Camera2.cx: 254.93170605935475 Camera2.cy: 256.8964427312701 Camera2.k1: -0.0034823894022493434 Camera2.k2: 0.0007150348452162257 Camera2.k3: -0.0020532361418706202 Camera2.k4: 0.00020293673591811182 Camera.width: 512 Camera.height: 512 Camera.fps: 20 IMU.Frequency: 200 IMU.NoiseGyro: 3.4e-4 IMU.NoiseAcc: 4.0e-3 IMU.GyroWalk: 3.8e-5 IMU.AccWalk: 6.0e-3 Tbc0: !!opencv-matrix rows: 4 cols: 4 dt: f data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975, 0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768, -0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949, 0.0, 0.0, 0.0, 1.0] Tbc1: !!opencv-matrix rows: 4 cols: 4 dt: f data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975, 0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768, -0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949, 0.0, 0.0, 0.0, 1.0] T10: !!opencv-matrix rows: 4 cols: 4 dt: f data: [1.0, 0.0, 0.0, -0.1, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]注意Tbc1和T10需要根据你的实际标定填写。T10的平移部分是双目基线TUM-VI 的基线大概是 0.1 米。6.2 标定流程和工具选择如果你没有标定参数需要自己标定。常用工具Kalibr支持相机-IMU 联合标定精度高但配置复杂。OpenCV支持单目标定简单但精度一般。ROS 标定工具如果数据是 ROS bag可以用camera_calibration和imu_filter_madgwick。我建议用 Kalibr虽然配置麻烦但标定结果可靠。标定步骤制作标定板打印 AprilTag 或棋盘格。录制数据同时采集相机和 IMU 数据。运行 Kalibr得到相机内参、IMU 噪声参数和外参。把结果填入 yaml 文件。标定过程中注意 IMU 要充分激励也就是要快速旋转和平移让 IMU 的各个轴都动起来。如果 IMU 激励不足标定出的噪声参数不准。6.3 迁移到自定义数据集时的注意事项迁移到自定义数据集时有几个坑要注意第一时间戳对齐。相机和 IMU 的时间戳必须同步否则融合会出错。如果时间戳有偏移需要在 yaml 里设置IMU.TimeOffset。第二图像格式。ORB-SLAM3 支持 PNG、JPG 等格式但要求图像尺寸一致。如果图像尺寸不一致需要先 resize。第三IMU 单位。ORB-SLAM3 要求 IMU 的角速度单位是 rad/s加速度单位是 m/s²。如果你的 IMU 输出的是 deg/s需要转换。第四外参方向。Tbc是从 body 到 camera不是从 camera 到 body。如果你标定得到的是T_cam_imu直接填。如果是T_imu_cam需要求逆。第五双目基线。T10的平移部分是双目基线单位是米。如果基线填错了尺度估计会错。这些坑我都踩过最坑的是时间戳对齐因为 ORB-SLAM3 不会报错只是轨迹漂移。我建议先用小段数据测试确认时间戳对齐后再跑完整数据。7. 个人实操体会和后续扩展方向7.1 调参过程中最耗时的环节调参过程中最耗时的不是改参数而是等程序跑完。TUM-VI 的room1序列有几千帧跑一遍要十几分钟。如果参数不对跑几分钟就 lost 了还得重来。我建议先用小段数据测试比如截取前 500 帧快速验证参数是否合理。确认后再跑完整数据。另外ORB-SLAM3 的日志输出很多建议重定向到文件方便排查./Examples/Stereo-Inertial/stereo_inertial_tum_vi ... log.txt 21然后grep关键字比如grep IMU initialization log.txt快速定位问题。7.2 参数调优的边界和局限性参数调优不是万能的。如果数据本身质量差比如图像模糊、IMU 噪声大、时间戳不同步再怎么调参也跑不好。我遇到过一组数据图像曝光过度特征点提取不到调什么参数都没用。最后只能重新采集数据。另外ORB-SLAM3 的参数是全局的不能自适应。不同场景需要不同参数但程序只能加载一套。如果你要跑多个场景要么每个场景单独调参要么用自适应参数的方法比如根据特征点数量动态调整ORBextractor.nFeatures。7.3 后续可以尝试的改进方向如果你已经跑通了 TUM-VI想进一步提升效果可以尝试第一用IMU.TimeOffset补偿时间戳偏移。TUM-VI 的时间戳可能有微小偏移设置IMU.TimeOffset可以改善。第二用System.SaveAtlasToFile保存地图下次加载地图避免重复初始化。第三用ORBextractor.nLevels调整金字塔层数适应不同尺度的场景。第四用LoopClosing开启回环检测减少累积误差。第五用IMU.InitTime调整初始化时间如果 IMU 激励充分可以缩短初始化时间。这些改进不是必须的但能让系统更鲁棒。我自己的经验是先把基础参数调好再考虑这些高级功能。基础不牢高级功能也发挥不出来。最后分享一个小技巧如果你不确定某个参数该填多少可以先填一个保守值然后看日志里的警告信息。ORB-SLAM3 会在日志里提示哪些参数可能有问题比如IMU noise too small或者Scale estimation failed。根据这些提示调整比盲目试参数快得多。
返回列表