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.088mtag间距是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 pkgimu_utils typeimu_an nameimu_an outputscreen param nameimu_topic typestring value/camera/imu/ param nameimu_name typestring valued435i/ param namedata_save_path typestring value$(find imu_utils)/data// param namemax_time_min typeint value120/ param namemax_cluster typeint value100/ /node /launchmax_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跑双目和RGB4.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 kalibr4.2 制作AprilGrid标定板并配置yamlAprilGrid的yaml配置文件长这样target_type: aprilgrid tagCols: 6 tagRows: 6 tagSize: 0.088 tagSpacing: 0.3tagSpacing是tag间距和tag大小的比值我用的0.0264/0.0880.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.bag5.2 配置标定文件并运行联合标定需要三个输入相机标定结果、IMU标定结果、联合标定bag包。rosrun kalibr kalibr_calibrate_imu_camera --bag imu_cam_calib.bag --cam camchain.yaml --imu imu.yaml --target aprilgrid.yamlcamchain.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或者SLAMKalibr的联合标定是绕不开的。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的角速度和加速度确保数据没有跳变或者饱和。如果发现异常立刻停止录制重新来。这个习惯帮我省了很多返工的时间。