☰
Realsense D435i标定全流程:IMU与相机联合标定及VINS-Fusion配置
2026/10/7 11:14:58 网站建设 项目流程

1. 为什么D435i的标定值得单独拎出来讲

Realsense D435i这台设备,玩过视觉SLAM或者VIO(视觉惯性里程计)的人应该都不陌生。它本质上是一个RGB-D相机加一颗六轴IMU的组合体,出厂时相机和IMU都各自有标定参数,但问题在于——出厂参数是“通用值”,不是“你这台设备在当前环境下的真实值”。尤其是当你把D435i装到机械臂末端、无人机机架或者移动机器人上之后,相机和IMU之间的外参(相对位姿)以及IMU自身的零偏、噪声密度,都会直接影响后续融合定位的精度。

我最初接触D435i标定是在做一个机械臂视觉抓取项目的时候。当时用VINS-Fusion跑VIO,发现轨迹漂移得厉害,尤其是快速旋转的时候,姿态估计直接崩掉。排查了一圈才发现,问题出在IMU和相机之间的时间戳对齐和外参上。出厂参数虽然能用,但精度不够,尤其是IMU的随机游走噪声,不重新标定的话,VINS的优化过程会一直处于“将就”的状态。

所以这篇文章想做的事情很明确:把D435i的IMU标定和相机标定这两件事,从工具选型、环境搭建、数据采集到参数写入,完整地走一遍。适合谁看?如果你手头有一台D435i,正在做VIO、SLAM或者任何需要相机和IMU融合的项目,并且对出厂参数不太放心,那这篇内容应该能帮你省下不少翻文档和踩坑的时间。

核心关键词就几个:Realsense D435i、IMU标定、相机标定、Kalibr、imu_utils。这几个词基本覆盖了整个流程的工具链和核心概念。

2. 标定前的整体思路与工具选型

2.1 为什么IMU和相机要分开标定再联合标定

很多人一开始会混淆一件事:IMU标定和相机标定是两件独立的事情,但它们最终要服务于同一个目标——让相机和IMU在同一个坐标系下协同工作。

IMU标定解决的是“IMU自身准不准”的问题。它要标定的参数包括:加速度计和陀螺仪的零偏(bias)、噪声密度(noise density)、随机游走(random walk)。这些参数决定了IMU输出的角速度和加速度有多“可信”。

相机标定解决的是“相机看东西准不准”的问题。它要标定的参数包括:内参矩阵(焦距、主点)、畸变系数(径向畸变、切向畸变)。这些参数决定了图像中的像素点如何映射到三维空间。

而联合标定(也叫外参标定)解决的是“IMU和相机之间的相对位置和姿态”的问题。它要标定的是从相机坐标系到IMU坐标系的旋转和平移矩阵。

这三件事的顺序不能乱:先分别标定IMU和相机,拿到各自的内部参数,再做联合标定求外参。如果IMU本身噪声参数不对,联合标定的结果也会受影响。

2.2 工具链选择:Kalibr + imu_utils + Realsense SDK

工具选型这块,我试过几种组合,最终稳定下来的方案是:

  • IMU标定:用imu_utils,配合ROS录制bag包。这个工具是港科大开源的,专门针对IMU的Allan方差分析,能输出零偏、噪声密度和随机游走。相比Kalibr自带的IMU标定,imu_utils对低频IMU的标定更稳,而且输出格式直接能喂给VINS。
  • 相机标定:用Kalibr的kalibr_calibrate_cameras,配合AprilGrid标定板。Kalibr的好处是支持多相机、多IMU的联合标定,而且对畸变模型的支持比较全(radtan、equidistant等)。D435i的RGB相机用radtan模型就够了,双目红外相机如果要用,也可以用radtan。
  • 联合标定:还是用Kalibr的kalibr_calibrate_imu_camera,输入是相机标定结果、IMU标定结果和一个同时包含相机图像和IMU数据的bag包。
  • 数据采集:用Realsense SDK的rs-record或者ROS的rosbag record。我习惯用ROS,因为后续Kalibr和imu_utils都是ROS生态的工具,直接录bag包最省事。

注意:D435i的IMU和相机时间戳默认是不同步的,录制bag包的时候要确保/camera/imu和/camera/color/image_raw两个话题都被录进去,并且时间戳要能对齐。Realsense ROS wrapper有个unite_imu_method参数,可以设置成linear_interpolation,这样IMU的角速度和加速度会合并成一个话题,时间戳也会对齐。

2.3 标定板的选择与制作

相机标定和联合标定都需要标定板。我推荐用AprilGrid,而不是传统的棋盘格。原因很简单:AprilGrid在部分遮挡或者光照不均匀的情况下,角点检测更稳定,而且Kalibr对AprilGrid的支持最好。

AprilGrid的规格我一般用6x6的网格,每个tag大小是0.088m,tag间距是0.0264m。这个尺寸适合D435i的视场角,在1米左右的距离上能完整成像。标定板可以直接打印在A3纸上,然后贴在一块平整的硬板上。注意打印的时候要确保尺寸精确,打印完用尺子量一下实际tag大小,因为打印机可能会有缩放。

实操心得:标定板贴的时候一定要贴平,不能有气泡或者翘边。我一开始用双面胶贴,结果中间鼓起来一块,导致角点检测误差很大。后来改用喷胶,整面均匀喷涂再贴,效果好很多。

3. IMU标定:用imu_utils跑Allan方差

3.1 imu_utils的安装与编译

imu_utils依赖Ceres Solver和ROS,安装之前先确保这两个东西已经装好。Ceres的安装这里不展开,ROS的话建议用Melodic或者Noetic,看你的Ubuntu版本。

编译imu_utils的步骤:

mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/gaowenliang/imu_utils.git git clone https://github.com/gaowenliang/code_utils.git cd .. catkin_make source devel/setup.bash

编译过程中如果报错找不到Ceres,检查一下CMakeLists.txt里的Ceres路径。有时候Ceres装在了/usr/local/lib,但CMake找不到,手动加一下set(Ceres_DIR /usr/local/lib/cmake/Ceres)就行。

3.2 录制IMU数据:静置两小时不是开玩笑

IMU标定的核心是Allan方差分析,而Allan方差需要长时间的静态数据。理论上,数据越长,低频噪声的估计越准。我一般建议至少录2小时,如果时间充裕,录4小时更好。

录制的时候,D435i要放在一个绝对静止的平面上,不能有震动。我试过放在办公桌上,结果楼下有人走动,桌子轻微晃动,标定出来的噪声密度偏大。后来改放在水泥地面上,垫了一层海绵,数据就干净很多。

录制命令:

roslaunch realsense2_camera rs_camera.launch unite_imu_method:=linear_interpolation rosbag record /camera/imu -O imu_static.bag

录完之后,检查一下bag包里IMU数据的频率。D435i的IMU默认是200Hz左右,如果频率波动太大,标定结果会不准。可以用rosbag info看一下。

3.3 配置launch文件并运行标定

imu_utils的launch文件在launch/目录下,我一般复制一份改成自己的:

<launch> <node pkg="imu_utils" type="imu_an" name="imu_an" output="screen"> <param name="imu_topic" type="string" value="/camera/imu"/> <param name="imu_name" type="string" value="d435i"/> <param name="data_save_path" type="string" value="$(find imu_utils)/data/"/> <param name="max_time_min" type="int" value="120"/> <param name="max_cluster" type="int" value="100"/> </node> </launch>

max_time_min设成120,表示用120分钟的数据。max_cluster是聚类数,一般100就够了。

运行:

roslaunch imu_utils d435i_imu.launch rosbag play -r 200 imu_static.bag

-r 200是加速播放,200倍速,这样2小时的bag包大概36秒就能播完。播放过程中,imu_utils会实时计算Allan方差,最后在data/目录下生成一个d435i_imu_param.yaml文件。

3.4 解读标定结果:噪声密度和随机游走

标定完成后,打开yaml文件,你会看到类似这样的内容:

type: IMU name: d435i Gyr: unit: " rad/s" avg-axis: gyr_n: 1.2e-03 gyr_w: 2.3e-05 Acc: unit: " m/s^2" avg-axis: acc_n: 1.5e-02 acc_w: 3.1e-04

这里gyr_n是陀螺仪的噪声密度,gyr_w是陀螺仪的随机游走,acc_n和acc_w对应加速度计。这些值直接决定了VINS-Fusion里IMU的噪声参数。

注意:D435i的IMU是BMI055,属于消费级IMU,噪声密度比工业级IMU大不少。标定出来的gyr_n一般在1e-03到2e-03之间,acc_n在1e-02到2e-02之间。如果你标出来的值比这个范围大一个数量级,检查一下录制时是不是有震动,或者IMU数据频率是不是不稳定。

4. 相机标定:Kalibr跑双目和RGB

4.1 Kalibr的安装与Docker方案

Kalibr的安装是个老大难问题,尤其是依赖的Python版本和ROS版本冲突。我强烈建议用Docker,省去编译的麻烦。Kalibr官方提供了Docker镜像,直接拉下来就能用。

docker pull stereolabs/kalibr:kinetic

或者自己构建:

git clone https://github.com/ethz-asl/kalibr.git cd kalibr docker build -t kalibr .

用Docker的好处是环境隔离,不会污染主机的ROS环境。运行的时候把数据目录挂载进去:

docker run -it -v /home/user/calib_data:/data kalibr

4.2 制作AprilGrid标定板并配置yaml

AprilGrid的yaml配置文件长这样:

target_type: 'aprilgrid' tagCols: 6 tagRows: 6 tagSize: 0.088 tagSpacing: 0.3

tagSpacing是tag间距和tag大小的比值,我用的0.0264/0.088=0.3。这个值要和你实际打印的标定板一致,否则标定出来的内参会偏。

4.3 录制相机数据:覆盖整个视场角

相机标定需要从不同角度拍摄标定板,覆盖整个视场角。我一般录60-80秒的数据,标定板在相机前缓慢移动,确保每个角落都被拍到。

录制命令:

roslaunch realsense2_camera rs_camera.launch rosbag record /camera/color/image_raw /camera/infra1/image_rect_raw /camera/infra2/image_rect_raw -O cam_calib.bag

如果只标RGB相机,只录/camera/color/image_raw就行。如果要标双目红外,把两个红外话题也录上。

实操心得:录制的时候,标定板的移动速度要慢,尤其是旋转的时候。我一开始转太快,导致图像模糊,角点检测失败。后来把移动速度控制在每秒10度左右,标定成功率就上去了。

4.4 运行标定并检查重投影误差

标定命令:

rosrun kalibr kalibr_calibrate_cameras --bag cam_calib.bag --topics /camera/color/image_raw --models radtan --target aprilgrid.yaml

标定完成后,Kalibr会输出一个pdf报告,里面包含重投影误差。重投影误差要小于0.3像素,如果大于0.5像素,说明标定质量不行,需要重新录数据。

我标定D435i的RGB相机,重投影误差一般在0.15-0.25像素之间。双目红外相机的误差会稍微大一点,因为红外图像的分辨率低,角点检测精度不如RGB。

5. 联合标定:Kalibr求IMU和相机外参

5.1 录制联合标定数据:激励所有轴

联合标定需要同时录制相机图像和IMU数据,并且要充分激励IMU的所有轴。具体来说,你要拿着D435i做三组旋转:绕X轴、绕Y轴、绕Z轴,每组旋转都要有正反方向,并且要有平移运动。

我一般录90秒左右,前30秒做旋转,中间30秒做平移,最后30秒做复合运动。旋转的时候要慢,但幅度要大,确保IMU的角速度输出能覆盖整个量程。

录制命令:

roslaunch realsense2_camera rs_camera.launch unite_imu_method:=linear_interpolation rosbag record /camera/color/image_raw /camera/imu -O imu_cam_calib.bag

5.2 配置标定文件并运行

联合标定需要三个输入:相机标定结果、IMU标定结果、联合标定bag包。

rosrun kalibr kalibr_calibrate_imu_camera --bag imu_cam_calib.bag --cam camchain.yaml --imu imu.yaml --target aprilgrid.yaml

camchain.yaml是相机标定输出的文件,imu.yaml是IMU标定输出的文件。Kalibr会自动读取这些文件,然后优化外参。

5.3 外参结果解读与验证

标定完成后,Kalibr会输出一个camchain-imucam.yaml文件,里面包含T_cam_imu矩阵,也就是从IMU坐标系到相机坐标系的变换矩阵。

T_cam_imu: - [0.999, -0.001, 0.002, 0.015] - [0.001, 0.999, -0.003, -0.002] - [-0.002, 0.003, 0.999, 0.001] - [0.0, 0.0, 0.0, 1.0]

这个矩阵的旋转部分应该接近单位矩阵,因为D435i的IMU和相机在出厂时已经做了物理对齐。如果旋转部分偏离单位矩阵太多,说明标定过程中有运动模糊或者时间戳不同步的问题。

注意:D435i的IMU和相机之间的平移量很小,一般在几毫米到一厘米之间。如果标定出来的平移量大于2厘米,检查一下是不是标定板移动太快,或者IMU数据有延迟。

6. 常见问题与排查技巧实录

6.1 IMU标定数据频率不稳定怎么办

D435i的IMU默认输出频率是200Hz,但有时候会因为USB带宽或者驱动问题,频率掉到100Hz甚至更低。频率不稳定会导致Allan方差的计算出现偏差。

排查方法:录一段bag包,用rosbag info看IMU话题的频率。如果频率波动超过10%,检查USB接口是不是USB 3.0,换一个接口试试。另外,unite_imu_method设成linear_interpolation的时候,如果加速度计和陀螺仪的时间戳差异太大,也会导致频率不稳定。

6.2 Kalibr标定相机时角点检测失败

角点检测失败的原因通常有三个:标定板模糊、光照不均匀、标定板超出视场角。

解决方法:录制的时候确保标定板清晰,光照均匀,不要有反光。如果标定板是打印的,确保打印质量够高,tag边缘清晰。另外,Kalibr的--show-extraction参数可以可视化角点检测结果,方便排查。

6.3 联合标定结果不收敛

联合标定不收敛的原因通常是IMU激励不够,或者时间戳不同步。

解决方法:重新录制联合标定数据,确保IMU的三个轴都被充分激励。时间戳方面,检查/camera/imu和/camera/color/image_raw的时间戳是否对齐。可以用rqt_plot画一下两个话题的时间戳差值,如果差值超过5ms,说明时间戳同步有问题。

6.4 标定参数写入VINS-Fusion后轨迹仍然漂移

如果标定参数写入后轨迹仍然漂移,检查一下VINS-Fusion的配置文件里IMU噪声参数和相机外参是否对应。有时候标定出来的参数单位不对,比如gyr_n的单位是rad/s/√Hz,但配置文件里写成了rad/s,这会导致优化过程完全错误。

另外,VINS-Fusion对时间戳的敏感性很高,如果bag包里的时间戳有跳变,也会导致漂移。可以用rosbag filter把时间戳重新对齐一下。

7. 标定参数在VINS-Fusion中的实际配置

标定做完之后,最终要落到VINS-Fusion的配置文件里。我一般把IMU噪声参数和相机外参写在一个yaml文件里,然后通过launch文件加载。

imu_topic: "/camera/imu" image_topic: "/camera/color/image_raw" output_path: "/home/user/vins_output" imu_params: acc_n: 1.5e-02 gyr_n: 1.2e-03 acc_w: 3.1e-04 gyr_w: 2.3e-05 extrinsic_T: [0.015, -0.002, 0.001] extrinsic_R: [0.999, -0.001, 0.002, 0.001, 0.999, -0.003, -0.002, 0.003, 0.999]

extrinsic_T是平移向量,extrinsic_R是旋转矩阵的展平形式。注意VINS-Fusion的旋转矩阵是按行优先展平的,和Kalibr输出的yaml格式不一样,需要手动转换一下。

实操心得:我一开始直接把Kalibr的yaml文件喂给VINS-Fusion,结果发现旋转矩阵的格式不对,导致初始化一直失败。后来写了个Python脚本,自动把Kalibr的yaml转成VINS-Fusion的格式,省了不少事。

8. 标定后的验证:用VINS-Fusion跑一圈

标定参数写入之后,怎么验证标定效果?最直接的方法就是用VINS-Fusion跑一段数据,看轨迹是否闭合。

我一般会录一段包含回环的bag包,比如绕着桌子走一圈,然后看VINS-Fusion输出的轨迹是否回到起点。如果轨迹闭合误差在5厘米以内,说明标定参数基本靠谱。如果误差大于10厘米,说明IMU噪声参数或者外参还有问题。

另外,可以用evo工具评估轨迹的绝对位姿误差(ATE)。如果ATE小于0.1米,说明标定质量不错。

注意:VINS-Fusion的初始化对IMU激励很敏感,如果初始化阶段IMU没有充分激励,即使标定参数正确,轨迹也会漂移。所以跑数据的时候,前几秒要确保有足够的旋转和平移。

9. 一些容易忽略的细节和踩坑记录

第一个坑是IMU和相机的时间戳对齐。D435i的IMU和相机是独立的时间戳源,默认情况下两者有几十毫秒的偏移。如果不做时间戳对齐,联合标定的外参会完全错误。Realsense ROS wrapper的unite_imu_method参数可以解决这个问题,但前提是你要在launch文件里正确设置。

第二个坑是标定板的打印精度。我一开始用普通A4纸打印AprilGrid,结果打印机缩放导致tag尺寸偏小,标定出来的内参焦距偏大。后来改用A3纸,并且在打印设置里关掉“适应页面”选项,确保100%缩放。

第三个坑是IMU标定时的温度漂移。D435i的IMU对温度比较敏感,如果标定过程中设备温度变化太大,零偏会漂移。我一般会先让D435i通电预热10分钟,等温度稳定后再开始录数据。

第四个坑是Kalibr的Docker镜像版本。不同版本的Kalibr对ROS bag包的兼容性不一样,我试过用Kinetic的镜像跑Noetic录的bag包,结果时间戳解析出错。后来统一用Noetic的镜像,问题就没了。

第五个坑是VINS-Fusion的配置文件路径。VINS-Fusion的launch文件里,配置文件的路径是相对路径,如果你把配置文件放在别的目录,需要改成绝对路径。我一开始没注意,结果VINS-Fusion一直加载默认配置,标定参数根本没生效。

10. 标定流程的自动化脚本

标定流程涉及多个步骤,手动操作容易出错。我写了一个简单的bash脚本,把IMU标定、相机标定、联合标定的命令串起来,减少重复劳动。

#!/bin/bash # IMU标定 roslaunch imu_utils d435i_imu.launch & rosbag play -r 200 imu_static.bag wait # 相机标定 rosrun kalibr kalibr_calibrate_cameras --bag cam_calib.bag --topics /camera/color/image_raw --models radtan --target aprilgrid.yaml # 联合标定 rosrun kalibr kalibr_calibrate_imu_camera --bag imu_cam_calib.bag --cam camchain.yaml --imu imu.yaml --target aprilgrid.yaml

这个脚本只是把命令串起来,实际用的时候还需要根据标定结果调整参数。比如IMU标定如果噪声密度偏大,可能需要重新录数据。

实操心得:自动化脚本的好处是减少手动操作,但坏处是如果中间某一步出错,排查起来比较麻烦。我建议第一次标定的时候还是手动一步步来,等流程跑通了再写脚本。

11. 标定结果的长期稳定性与复标定策略

D435i的IMU零偏会随着时间和温度变化,所以标定参数不是一劳永逸的。我一般每隔三个月会重新标定一次IMU,尤其是如果设备经常在不同温度环境下使用。

相机标定相对稳定,只要不摔不碰,内参一般不会变。但如果发现VINS-Fusion的轨迹突然漂移变大,可以先检查相机标定是否还准。用Kalibr重新跑一遍相机标定,对比重投影误差,如果误差明显变大,说明相机内参变了。

联合标定的外参一般比较稳定,因为IMU和相机是刚性连接。但如果设备受到剧烈撞击,外参可能会变。我一般会在设备受到撞击后重新做一次联合标定。

注意:复标定的时候,尽量保持和上次标定相同的环境条件,比如温度、光照、标定板距离。这样标定结果的可比性更强,也更容易发现异常。

12. 从标定到实际部署的最后一公里

标定做完,参数写入VINS-Fusion,跑一圈轨迹也闭合了,是不是就万事大吉了?其实还有最后一公里:实际部署时的实时性。

VINS-Fusion在离线跑bag包的时候,可以慢慢优化,但实际部署时,IMU和相机的数据是实时进来的,如果标定参数不准,优化过程会发散。我一般会在实际部署前,先用离线数据跑一遍,确认轨迹没问题,再上实时。

另外,实际部署时,IMU和相机的时间戳同步更重要。如果时间戳有跳变,VINS-Fusion的初始化会失败。我一般会在ROS节点里加一个时间戳检查,如果发现时间戳跳变超过阈值,就重新初始化。

实操心得:我试过在机械臂上部署VINS-Fusion,结果因为机械臂运动太快,IMU激励过度,导致优化发散。后来把机械臂的运动速度降下来,问题就解决了。所以标定参数虽然重要,但实际部署时的运动模式也要匹配。

13. 一些替代方案和工具对比

除了Kalibr和imu_utils,还有一些其他的标定工具,比如Kalibr的替代品Basalt,或者VINS-Mono自带的标定工具。我试过Basalt,它的优点是标定速度快,但缺点是文档少,遇到问题不好排查。imu_utils的替代品有allan_variance_ros,功能类似,但输出格式和VINS的兼容性不如imu_utils。

相机标定方面,OpenCV的calibrateCamera也能用,但需要自己写代码,而且对AprilGrid的支持不如Kalibr。如果只是标一个RGB相机,OpenCV够用,但如果要标双目或者联合标定,还是Kalibr更省事。

注意:工具选型没有绝对的好坏,关键是看你的项目需求。如果只是做简单的视觉里程计,OpenCV加imu_utils就够了。如果要做VIO或者SLAM,Kalibr的联合标定是绕不开的。

14. 标定数据的备份与管理

标定数据包括bag包、标定结果yaml文件、标定报告pdf。这些数据我一般会按日期归档,比如2025-01-15_d435i_calib/,里面再分imu/、cam/、imu_cam/三个子目录。

bag包比较大,我一般只保留原始bag包和标定结果,中间生成的临时文件会删掉。标定结果yaml文件会同步到Git仓库,方便版本管理。如果标定参数有更新,Git记录能帮你回溯到之前的版本。

实操心得:我一开始没做备份,结果硬盘坏了,标定数据全丢了,只能重新标定。后来养成习惯,标定完立刻备份到NAS和Git仓库,省心很多。

15. 关于D435i标定的一些个人体会

D435i这台设备,出厂参数能用,但不够好用。尤其是做VIO的时候,IMU的噪声参数和外参如果不重新标定,轨迹漂移是必然的。我一开始也觉得标定麻烦,但踩过几次坑之后发现,花两个小时标定,比花两天调参划算得多。

标定流程本身不复杂,关键是细节:时间戳对齐、标定板精度、IMU激励充分、温度稳定。这些细节做好了,标定结果基本靠谱。如果标定结果不理想,不要急着换工具,先检查数据质量,大部分问题都出在数据采集环节。

最后分享一个小技巧:标定的时候,用rqt_plot实时监控IMU的角速度和加速度,确保数据没有跳变或者饱和。如果发现异常,立刻停止录制,重新来。这个习惯帮我省了很多返工的时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询