ARTICLE DETAIL

资讯详情

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

Realsense D455联合标定保姆级教程:Kalibr内参、外参与时延一次搞定

Realsense D455联合标定保姆级教程:Kalibr内参、外参与时延一次搞定 你们有没有遇到过这种情况拿到Realsense D455之后觉得它自带IMU、出厂又标过参数直接拿来做VINS-Fusion或者ORB-SLAM3应该没什么问题。我第一次跑的时候也是这么想的结果轨迹飞得那叫一个离谱原地转圈的姿态估计能偏出十几度前后一对比才发现问题基本都出在标定上。后来老老实实用Kalibr把相机内参、IMU噪声、相机到IMU外参和时延完整走了一遍整个系统才像换了个设备一样。这篇就是我踩了一圈坑之后整理出来的保姆级流程从环境搭建到数据采集从三步标定到常见报错排查一次讲完D455用户可以直接拿着抄。1. 联合标定到底在标什么外参、时延与IMU模型缺一不可很多人把“相机IMU联合标定”理解成求一个旋转矩阵和平移向量这其实是把问题想小了。一套完整的Kalibr标定流程产出的是三类互相独立又互相牵制的参数少了任何一样后续的视觉惯性里程计都会出幺蛾子。1.1 Kalibr标定流程能给出的三类结果第一类是相机内参。对D455的RGB镜头来说Kalibr最常用的模型是pinhole-radtan也就是针孔模型加径向畸变k1、k2和切向畸变p1、p2也有少数情况用pinhole-equi模型。内参决定了像素坐标到三维光线的映射关系听起来是个基础问题但一个像素的偏差在三米外就可能贡献出十几毫米的空间误差。你在VINS里看到的轨迹漂移很多时候不是IMU不行而是相机内参给的焦距和主点有偏差。第二类是IMU噪声特性具体是指陀螺仪和加速度计的噪声密度noise density与随机游走random walk。这两个参数描述的是IMU读数在静态下抖动的幅度以及误差随时间的累积速度。紧耦合VIO系统会把它们写进信息矩阵决定系统到底更信任视觉还是更信任IMU。参数给错整个权重分配就乱了轻则轨迹毛糙重则优化直接发散。第三类是外参和时延。外参就是IMU坐标系在相机坐标系下的位姿或者反过来时延则是因为硬件采样的时间戳做不到完全对齐图像和IMU之间总是存在一个固定的时间偏移。D455的出厂外参可以作为初值使用但时延这东西每台设备、每套驱动版本都不一样必须实际估计。Kalibr的联合标定之所以叫“联合”核心就是把外参和时延放在同一个优化框架里同时估计。1.2 D455自带出厂参数为什么还不能直接信任D455的官方内参可以通过pyrealsense2直接读出来外参也能在驱动配置里看到看起来确实方便。但实际装机之后问题就来了。第一个变数是模组温度。D455连续工作二十分钟以后壳体温度升高镜头模块的物理尺寸会有微小的变化焦距漂移几个像素是常见情况。第二个变数是安装应力。你把相机固定在机器人云台、结构件或者3D打印支架上时螺丝的锁紧力会让外壳受力变形这会直接影响相机坐标系和IMU坐标系之间的姿态关系。第三个变数是畸变模型。官方内参本质上是简化标定过的边缘区域的拟合精度不一定能到视觉算法需要的水平。我实测过同一台D455官方内参和Kalibr重标内参在画面边缘的重投影误差能差出一倍不止。所以我的建议是把出厂参数当作联合标定的初值没问题但最终使用的参数必须以自己标定的结果为准。做VIO项目尤其不要偷这个懒省掉这一步省的是时间亏的是整条轨迹的质量。1.3 哪些场景必须标哪些可以暂时将就如果你只是把D455当普通RGB-D相机用来做目标检测、点云展示或者纯2D识别那确实不用折腾联合标定出厂参数完全够用。但如果你要做下面这些事建议把标定流程完整走一遍VINS-Fusion、VINS-Mono、ORB-SLAM3这类视觉惯性SLAM系统基于深度图IMU的稠密重建或动态感知相机与机械臂、底盘、云台之间的多传感器融合在这些场景里“感觉差不多”的外参是最大的隐患。我曾经在一个机器人底盘项目里直接用别人给的标定文件看起来参数挺合理一套整体系统测下来就是有固定的姿态偏差查了两天才发现是安装时受力方向不一样外参里的平移分量差了两毫米导致所有地图点都带了个系统性的旋转。2. 环境准备从Ubuntu到Kalibr编译每一道坎都提前拆掉标定前先要把环境搭对。这一节看起来零碎但每一步都是我在重装系统、重编源码、换驱动版本之后才沉淀下来的最优顺序。2.1 系统与ROS版本怎么选Kalibr对不同ROS版本的支持情况不一样。我自己最稳的组合是Ubuntu 20.04配ROS NoeticPython3环境Kalibr源码编译基本没有历史包袱。如果你用Ubuntu 18.04和ROS Melodic也能跑通但Python2/Python3混用带来的依赖问题会多出不少。Ubuntu 22.04配ROS Humble也不是不行但Kalibr在较新系统上更容易遇到OpenCV接口变动反而要额外打补丁。安装ROS Noetic之后先把基础工具补齐sudo apt update sudo apt install python3-catkin-tools python3-rosinstall-generator python3-vcstool sudo apt install ros-noetic-vision-opencv ros-noetic-image-proc2.2 Kalibr源码编译一个坑一个坑过Kalibr不需要用二进制包安装直接从源码编译最省心。把工作空间建好代码拉下来构建mkdir -p ~/kalibr_ws/src cd ~/kalibr_ws catkin init catkin config --extend /opt/ros/noetic catkin config --cmake-args -DCMAKE_BUILD_TYPERelease cd src git clone https://github.com/ethz-asl/kalibr.git cd ~/kalibr_ws catkin build这里有几个很容易卡住的点。首先是pyx依赖如果你在运行Kalibr时报ModuleNotFoundError: No module named pyx直接用pip补上。其次是beautifulsoup4版本过旧导致的ImportError: cannot import name NavigableString升级一下就行。还有一个隐蔽问题如果你之前装过Anaconda或者其他Python环境ROS的Python和系统Python容易打架建议在纯净的系统Python3环境里编译和运行。每次编译完别忘了source一下工作空间echo source ~/kalibr_ws/devel/setup.bash ~/.bashrc source ~/.bashrc2.3 启动D455IMU数据流怎么打开默认的realsense-ros驱动并不会自动发布IMU数据必须显式开启陀螺仪和加速度计。D455的IMU在驱动里发布的话题是/camera/imu但只有设置unite_imu_method之后加速度计和陀螺仪才会合并成一个六轴话题。推荐用一个专门的launch命令roslaunch realsense2_camera rs_camera.launch \ enable_gyro:true \ enable_accel:true \ unite_imu_method:linear_interpolation \ gyro_fps:200 \ accel_fps:200 \ color_width:1280 \ color_height:720 \ color_fps:30 \ initial_reset:trueunite_imu_method:linear_interpolation的意思是驱动会把加速度计和陀螺仪采样插值到同一时间基准再合并发布到/camera/imu。如果只用默认设置你会在话题列表里看到/camera/gyro/sample和/camera/accel/sample两个独立话题Kalibr反而不好处理。启动后先确认话题发布正常rostopic list | grep -E camera/(color|imu) rostopic hz /camera/imu正常情况下IMU频率应该在200Hz附近如果只有几十Hz先检查USB带宽D455最好用USB 3.0接口同时别在同一根hub上挂其他高带宽设备。2.4 标定板的选型与YAML参数编写标定板是整套流程里唯一需要物理准备的东西选得好能省一半的事。我强烈建议用AprilGrid而不是传统棋盘格。原因很直接AprilTag每个二维码自带ID即使画面边缘有个别标签被遮挡Kalibr也能通过可见的标签推断整体位姿传统棋盘格一旦出现一边角点被遮挡就容易匹配出错误的棋盘结构。AprilGrid的YAML文件格式如下target_type: aprilgrid tagCols: 6 tagRows: 6 tagSize: 0.0215 tagSpacing: 0.3tagSize是一个标签的边长单位是米这个值必须和打印出来的实物一致差别过大会导致尺度错误。tagSpacing是标签间距与边长的比值不同模板略有不同打印前先确认你的PDF模板对应的是0.3还是0.5。还有一个实操细节打印出来的AprilGrid一定不要直接挂在墙上用最好贴在平整的硬板上铝塑板、亚克力板都行。软纸板稍微一弯标定得到的畸变参数就会吸收掉这些形变误差结果看起来收敛实际用起来就是不对劲。3. 数据采集bag的质量直接决定标定成败很多人在标定环节死磕命令参数却忽略了数据采集这关。实际上Kalibr标定失败的案例里七成以上都能追溯到bag质量问题。这里讲的静态包和动态包是两个不同用途的数据包不能混着用。3.1 静态数据IMU噪声估计的基础静态数据给IMU噪声标定用。把D455固定在一个绝对静止的平台上不要用手扶着手再稳也有微小的抖动直接录两分钟以上rosbag record -O imu_static.bag /camera/imu录制时确保周围没人走动、没有大型设备震动桌面也不要有风扇之类的干扰源。时长建议至少两分钟如果是200Hz的IMU两分钟能积累两万多个样本足够把噪声密度和随机游走估计得比较稳。3.2 动态数据给足六个自由度的激励动态数据给联合标定用录制的是图像加IMU的同步数据。命令很简单rosbag record -O cam_imu.bag /camera/color/image_raw /camera/imu难的是怎么运动。你得让IMU的六个自由度都被充分激励起来。具体操作上我总结了一套固定的动作序列。先把相机对着AprilGrid让板子在画面里占到大概三分之一到二分之一的位置然后开始做大幅度的姿态变化。第一步让相机绕重力方向转一整圈类似你拿着相机原地旋转360度。第二步做大幅度的俯仰和滚转动作尽量让相机的朝向偏离起始姿态超过60度角。第三步在保持板子在画面内的前提下做“8字形”的空间运动让平移和旋转同时发生。全程持续六十到九十秒就够了不用贪多。这里有个关键分寸动作速度一定要控制在图像不模糊的范围内。Kalibr需要从每一帧里检测AprilGrid角点画面一糊那一帧就废了。我见过有人为了激励IMU疯狂甩相机结果一大半帧都检测不到标定板整个bag基本没法用。3.3 录完后的三分钟检查录完别急着跑标定先花三分钟检查一下数据。rosbag info是最基本的工具rosbag info cam_imu.bag重点看三个指标。第一话题的持续时间是否覆盖了完整的运动过程有没有中途断流。第二/camera/color/image_raw的频率是否稳定在30Hz附近如果掉帧严重说明USB带宽不够或者系统负载过高。第三IMU和图像的时间范围是否基本对齐如果两个话题的时间戳范围差了几秒说明驱动里的时间戳同步出了问题这种情况标定出来大概率是错的。另外可以用rqt_image_view抽几帧看一下画面里标定板是否清晰、光线是否均匀。我遇到过环境光太强导致AprilGrid反光黑白块的对比度严重下降检测率直接掉到百分之五十以下。4. 三步标定全流程内参、噪声、外参依次走通数据准备好之后就进入正题了。整套流程分三步走顺序不能乱先标相机内参再标IMU噪声最后做联合外参标定。每一步都依赖上一步的输出跳过任何一步后面的结果都是空中楼阁。4.1 第一步标定D455的相机内参用之前录好的动态数据包执行相机内参标定命令。Kalibr会从bag中等间隔抽取图像帧检测AprilGrid角点并优化内参和畸变系数kalibr_calibrate_cameras \ --target april_6x6.yaml \ --bag cam_imu.bag \ --topics /camera/color/image_raw \ --models pinhole-radtan \ --bag-freq 10.0--bag-freq告诉Kalibr从bag中抽取帧的频率这里设置成10Hz也就是每秒钟最多抽10帧用来标定。不要设太低否则有效帧数不够也不要设太高临近帧之间视角变化太小优化会退化。运行结束后会输出一个camchain.yaml文件内容结构大概长这样cam0: camera_model: pinhole intrinsics: [387.52, 386.89, 639.72, 361.28] distortion_model: radtan distortion_coeffs: [0.0112, -0.0238, 0.0006, 0.0002] resolution: [1280, 720] rostopic: /camera/color/image_raw标定完先看终端的重投影误差一般小于0.5个像素才算正常。这个值如果超过1先把--bag-freq调低一点重新抽取或者换一个运动更平稳的动态包。另外一个常见问题是D455的RGB相机在弱光环境下自动曝光会拉高ISO导致标定板边缘出现伪影角点检测精度下降这时候要么加光要么在驱动里把曝光固定到合适值。4.2 第二步IMU噪声密度与随机游走的实测估计这一步可选但强烈建议做。IMU的噪声参数有两种来源一是直接用BMI055的官方手册数值精度够用但不是最优二是用imu_utils对静态数据做实测估计把生成的YAML喂给Kalibr。实地方差往往比手册值更符合当下这台设备的真实状态。用imu_utils的操作流程是先把code_utils和imu_utils源码下载到工作空间编译然后播放静态数据包同时运行标定节点rosbag play imu_static.bag rosrun imu_utils do_calib imu_static.bag运行完成后在/tmp/imu_utils/目录下会生成类似imu_static_imu.yaml的标定文件。里面包含三轴加速度计和陀螺仪的噪声密度、随机游走例如陀螺仪噪声密度在1e-3量级加速度计在1e-2量级。这个YAML文件就是下一步联合标定要用到的IMU参数文件。如果你不想折腾imu_utils也可以用官方BMI055的数据粗略替代但要注意Kalibr里IMU参数的单位是rad/s和m/s^2别把手册里的度数单位直接填进去。4.3 第三步联合标定外参与时延拿到camchain.yaml和imu.yaml之后执行联合标定kalibr_calibrate_imu_camera \ --target april_6x6.yaml \ --cam camchain.yaml \ --imu imu.yaml \ --bag cam_imu.bag \ --bag-freq 10.0这个命令会同时优化相机到IMU的旋转、平移和时延。运行时间取决于数据量通常几分钟到十几分钟不等。标定完成后会生成cam-imu.yaml文件里面是外参结果cam0: T_cam_imu: R: [[0.99999, -0.00234, 0.00122], [0.00234, 0.99997, 0.00211], [-0.00128, -0.00211, 0.99999]] t: [0.0011, 0.0018, 0.0152] timeshift_cam_imu: -0.0123这里的R和t就是把IMU坐标变换到相机坐标的位姿timeshift_cam_imu单位是秒负值表示图像时间戳比IMU时间戳晚了12.3毫秒。这个时延数值非常关键VINS-Fusion这类系统基本都会读取它来做时间戳补偿。运行结果里另外还会输出一个重投影误差报告同样要低于0.5像素。如果在终端日志里看到类似large residual或者迭代次数飙到几十次还不收敛基本可以确定动态数据激励不足重新录bag比调参有用得多。5. 常见报错排查实录七成问题出在数据三成出在环境这个项目我前后跑了不下二十次把能踩的坑基本都踩遍了。整理几个最典型的报错场景按照“现象—原因—解决”的方式列出来大家遇到问题可以直接对照排查。5.1 环境类报错cv_bridge与Python依赖问题这类报错通常出现在第一次运行Kalibr时最典型的是ImportError: cannot import name NavigableString from bs4这是因为系统里的beautifulsoup4版本太老。升级一下就能解决pip3 install --upgrade beautifulsoup4还有ModuleNotFoundError: No module named pyx装一下即可pip3 install pyx再一个常见情况是ROS的cv_bridge和系统OpenCV冲突报错往往是一大段libopencv_core.so.xxx相关的链接错误。解决办法是确保整个ROS工作空间都用同一个Python版本编译不要混用系统Python和Anaconda。如果你机器上装了Anaconda建议在编译和运行ROS命令前先把Anaconda的PATH临时去掉。5.2 检测类报错标定板看不见或检测率低运行kalibr_calibrate_cameras时终端里刷出一堆类似[ERROR] No corners found in image xxx的日志说明标定板在相当一部分帧里没被检测到。先查环境光。AprilGrid需要黑白分明光线太暗会导致对比度不足太亮会导致反光。用手遮挡一下镜头上方看看画面的对比度是否明显改善如果是就调整一下相机曝光。其次查运动速度动态录制时动作过猛图像模糊会让角点检测直接失败重新录制时把动作放缓。再次查标定板尺寸如果板子在画面里占比太小比如只有十分之一Kalibr很难稳定识别尽量让板子在大部分帧里占画面三分之一以上。还有一个隐蔽原因打印出来的AprilGrid裁边太紧标签边缘或者黑边被误认为其他标签。YAML里的行列数必须和实际板子完全一致多一行少一行都会检测失败。5.3 估计类报错联合标定不收敛或结果发散执行kalibr_calibrate_imu_camera后优化过程不收敛要嘛迭代次数耗尽要嘛结果文件里的旋转矩阵明显不是正交矩阵。这个问题绝大多数情况是动态数据激励不足。判断方法很简单回放录制的动态bag观察整个过程中是否同时覆盖了大幅度的旋转、长时间的平移以及绕重力方向的完整旋转。如果你的动作只是小幅晃动IMU的角速度积分无法提供足够的约束Kalibr的优化必然发散。出现这种报错没有别的捷径重新录制动态数据。这里有个提高成功率的小技巧把运动分成几个不同的阶段前一分钟做大幅度旋转后一分钟做“8字形”平移别把动作混在一起乱来。分阶段的动作有利于优化算法在不同的约束之间取得平衡。5.4 时间戳错位D455数据里最隐蔽的坑这个坑特别隐蔽现象是标定出来的timeshift_cam_imu数值巨大比如超过几百毫秒而且每次标定结果都不一致。这说明IMU和图像的时间戳本身就有问题。D455的IMU和RGB相机虽然共用同一个硬件时钟域但驱动在把数据传给ROS时如果CPU负载很高或者USB传输被中断时间戳可能会叠加额外的延迟。遇到这种情况先检查电脑的电源管理是否开启了省电模式CPU降频会让时间戳质量严重下降。其次确认realsense驱动版本较新老版本对D455的时间同步支持不够完善。还可以做一个简单验证把D455固定住快速转动一下相机然后观察/camera/imu和/camera/color/image_raw里的时间戳。正常情况下两边的header.stamp会以差不多的节奏递增如果发现图像时间戳经常跳变说明USB传输不稳定换一个USB控制器或者重启相机试试。6. 标定完成后怎么确认它真的可用标定跑完不等于工作结束拿到结果文件后还要做一轮验证确认参数真的达到了可以投入使用的水平而不是优化器自嗨出来的数字。6.1 结果文件的基本检查打开cam-imu.yaml先肉眼检查旋转矩阵。旋转矩阵的每一行、每一列的模都应该非常接近1行与行之间互相正交。如果矩阵里有超过千分之一的奇异值说明优化结果有偏谨慎使用。再看平移向量D455的IMU大致位于相机中心的右下方或者后方数值一般在毫米到厘米级如果平移到几十厘米那肯定是外参标错了不要犹豫重新标。重投影误差的终端日志是另一个硬指标小于0.5像素可以接受小于0.3像素说明数据质量很好。大于1像素的话建议先标定相机内参这一环节重新来一遍。6.2 用VINS-Fusion或者ORB-SLAM3实测一轮文件检查过之后建议直接丢进一个真实SLAM系统里做端到端验证。以VINS-Fusion为例在配置文件里把imu_topic指到/camera/imu把image_topic指到/camera/color/image_raw然后将联合标定得到的T_cam_imu填进外参配置。启动系统后做三个简单测试把相机静止放在桌面上观察系统是否输出一段平稳的轨迹而不是持续漂移或者原地转圈手持相机左右平移观察姿态角是否保持稳定绕房间走一圈回到起点观察轨迹的闭环误差有多大。我在实际项目里的对比非常明显用官方默认外参跑同一段路线闭环误差大概在百分之二到百分之三换上Kalibr标定结果之后同样的路线误差能压到百分之零点五以内。这个对比足以说明标定的价值也足以说明把外参配置填好有多重要。6.3 标定的“保质期”与日常维护建议标定结果不是一劳永逸的。如果你拆装了镜头、更换了IMU模块、或者把相机重新固定到一个受力状态完全不同的支架上建议重新标定。温度环境改变过大比如从室内拿到零下环境做实验也可以重新跑一次数据采集成本并不高。我的习惯是把每次都标定相关的文件归档好AprilGrid的YAML、打印板的实际尺寸测量记录、用的哪个bag文件、跑出的camchain和cam-imu结果、标定当天的环境温度。下次出现问题需要重新标定时这些记录能帮你快速排除变量不用从头猜起。另外如果你以后要标定Lidar和IMU、或者做多目与IMU的联合标定Kalibr这套思路依然是通用的掌握了D455的完整流程之后换个传感器组合只是换个驱动和配置文件的事。最后分享一个小习惯标定前把系统里所有无关进程关掉特别是占用CPU的重负载任务。时间戳质量和系统实时性直接影响标定精度一个干净的环境比反复调命令参数有效得多。祝你们都能一次跑通。
返回列表