前言
vio重中之重就是传感器标定,需要标定的参数一般有:相机内参、相机畸变、相机到imu坐标系的外参、imu噪声
主要工具为:
- imu_utils: https://github.com/gaowenliang/imu_utils
- kalibr: https://github.com/ethz-asl/kalibr
建议系统为ubuntu+ros,我这里使用最常用的 ubuntu18.04+ros-melodic组合,我也制作了一个 docker 镜像方便使用:https://hub.docker.com/repository/docker/vell001/ubt18.04_ros_xrdp
docker 相关可以参考:https://www.jianshu.com/p/52d5b35e7b77?v=1739101080481
安装工具
可以参照:https://blog.csdn.net/qq_38429958/article/details/139276206
- 安装 imu_utils
创建 imu_ws 文件夹,将https://github.com/gaowenliang/code_utils 和 https://github.com/gaowenliang/imu_utils两个项目 clone 到 src 目录下,目录结构如下
├── imu_ws
│ └── src
│ ├── code_utils
│ └── imu_utils
在 imu_ws 文件夹内执行 catkin_make,编译好即可,记得先进入 imu_ws,执行 source devel/setup.bash,才能正常执行该项目下的 ros 命令
- 安装kalibr
创建 kalibr_ws 文件夹,将https://github.com/ethz-asl/kalibr clone 到 src 目录下,目录结构如下
├── kalibr_ws
│ └── src
│ └── kalibr
在 kalibr_ws 文件夹内执行 catkin_make,编译好即可
标定 IMU
- 先录制静止状态下的 imu 数据 120 分钟,官方工具默认时间 120 分钟,也可以短一点,需要改下 launch 参数
- 修改 launch 参数,在 imu_utils下随便找到一个 launch 文件,复制一份进行修改,如:launch/A3.launch
<launch>
<node pkg="imu_utils" type="imu_an" name="imu_an" output="screen">
<param name="imu_topic" type="string" value= "/imu"/>
<param name="imu_name" type="string" value= "redmi"/>
<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就是会用来标定的最大时长,程序必须收集到大于这个时长的数据才会进行标定,所以值要设得比你录制的 imu 数据时长小
- 执行 launch
roslaunch imu_utils A3.launch
- 播放 bag 包,注意可以加速一下
rosbag play -r 200 imu.bag
- 查看标定结果
结果在data_save_path设置的目录下,默认是imu_utils/data 下,如:imu_utils/data/A3_imu_param.yaml
%YAML:1.0
---
type: IMU
name: A3
Gyr:
unit: " rad/s"
avg-axis:
gyr_n: 1.0922514245261136e-04
gyr_w: 3.0407639130588035e-05
x-axis:
gyr_n: 1.1712350336249066e-04
gyr_w: 3.6395480767077183e-05
y-axis:
gyr_n: 1.0957986890514727e-04
gyr_w: 3.1881226725483150e-05
z-axis:
gyr_n: 1.0097205509019619e-04
gyr_w: 2.2946209899203768e-05
Acc:
unit: " m/s^2"
avg-axis:
acc_n: 1.4268671413807624e-03
acc_w: 6.3698303145662391e-04
x-axis:
acc_n: 1.2219441138445304e-03
acc_w: 5.3750668357445538e-04
y-axis:
acc_n: 1.2229466839249080e-03
acc_w: 6.0460048331990467e-04
z-axis:
acc_n: 1.8357106263728492e-03
acc_w: 7.6884192747551168e-04
注意:
关于vins的imu噪声参数设置问题,imu标定的结果只是用来参考,在vins中最好不要直接套用标定的原始参数,使用时最好将标定参数扩大到原始的10倍或者100倍(扩大1~2个数量级),vins运行只需要设置imu噪声参数的大概值,一般情况下参数的数量级差不多能对上就行。关于这个问题的解释可以参考 gaowenliang/imu_utils#36 (comment) 里的讨论和 https://github.com/ethz-asl/kalibr/wiki/IMU-Noise-Model#kalibr-imu-noise-parameters-in-practice 里关于imu噪声模型的解释。imu的内参是在静止、恒温情况下标定的,而imu在实际运行过程中是运动的,而且温度会改变,所以imu内参标定的结果只是用来参考的,而不是直接用在vins中。
参考:https://github.com/TAIL-Robot/TAIL-dataset/issues/4
个人实测,标定参数放大 10 倍对 vins 效果较好,放大 100 倍快速运动容易跑飞
标定camera
https://github.com/ethz-asl/kalibr/wiki/multiple-camera-calibration
前提是已经编译好了kalibr,并进入了kalibr的 catkins_workspace
- 生成并打印标定纸
rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 4 --tsize 0.045 --tspace 0.3 --eps
--tsize 0.045是适合 A3打印的,可以调整这个大小来生成对应纸张大小的标定纸
打印的 pdf 文件在执行命令的当前文件夹生成
➜ kalibr_ws rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 4 --tsize 0.045 --tspace 0.3 --eps
➜ kalibr_ws ls
build devel src target.eps target.pdf
➜ kalibr_ws
注意打印时一定要选 100% 缩放
- 录制标定 bag,可以和 imu 联合标定一起录制,对着标定纸,分别在三轴上平移和旋转三次,然后在做几次随机的三轴平移加旋转的组合运动,总共约两分钟即可
- 按标定纸配置 target 标定参数, target.yaml,内容如下:
target_type: 'aprilgrid' #gridtype
tagCols: 6 #number of apriltags
tagRows: 4 #number of apriltags
tagSize: 0.045 #size of apriltag, edge to edge [m]
tagSpacing: 0.3 #ratio of space between tags to tagSize
- 执行标定命令
rosrun kalibr kalibr_calibrate_cameras --target src/kalibr/config/target.yaml --models "pinhole-radtan" --bag ../bags/cali_usb_imu_cam.bag --bag-from-to 0 100 --show-extraction --topics "/cam"
可以选择多种不同相机,-bag-from-to单位是秒
相机类型参考:https://github.com/ethz-asl/kalibr/wiki/supported-models
标定结果在 bag 包同级目录下
camera+imu 联合标定
https://github.com/ethz-asl/kalibr/wiki/camera-imu-calibration
前提是已经编译好了kalibr,并进入了kalibr的 catkins_workspace,且已经单独标定好了 camera 和 imu
- 准备好标定配置
共需三个 yaml,imu.yaml、camera.yaml、target.yaml,其中target.yaml 和 camera 标定时保持一致
imu.yaml:
#Accelerometers
accelerometer_noise_density: 4.5912914601953958e-02 #Noise density (continuous-time)
accelerometer_random_walk: 9.8473966757113411e-04 #Bias random walk
#Gyroscopes
gyroscope_noise_density: 6.0751586827011324e-04 #Noise density (continuous-time)
gyroscope_random_walk: 4.1785854365612070e-06 #Bias random walk
rostopic: /imu #the IMU ROS topic
update_rate: 200.0 #Hz (for discretization of the values above)
和imu 标定结果字段对应
avg-axis:gyr_n 对应 gyroscope_noise_density
avg-axis:gyr_w 对应 gyroscope_random_walk
avg-axis:acc_n 对应 accelerometer_noise_density
avg-axis:acc_w 对应 accelerometer_random_walk
cam.yaml:
cam0:
cam_overlaps: []
camera_model: pinhole
distortion_coeffs: [-0.036380710744086116, -0.007882677343413932, 0.0003479752209189496, -0.0015383631203022155]
distortion_model: radtan
intrinsics: [237.3156818081089, 238.2197038077451, 316.0410162049171, 252.38010788205997]
resolution: [640, 512]
rostopic: /cam
将 camera 标定结果中的cali_xxx-camchain.yaml 文件 copy 过来即可
- 执行标定命令
rosrun kalibr kalibr_calibrate_imu_camera --target src/kalibr/config/target.yaml --cam src/kalibr/config/cam.yaml --imu src/kalibr/config/imu.yaml --bag ../bags/cali_usb_imu_cam.bag --show-extraction --bag-from-to 0 100
标定时间可能比较长,而且可能存在失败的情况,特别是在时间同步做的不好的设备上
标定结果也是在 bag 包同级目录下,如:
cam0:
T_cam_imu:
- [-0.03697027093857613, 0.9985445095030082, -0.039269092275266995, -0.007567328099210491]
- [0.9985327866190276, 0.03846859891770388, 0.038110903218720134, 0.0023090905083560957]
- [0.0395660601218531, -0.03780250571991218, -0.9985016261617846, -0.028580542483764203]
- [0.0, 0.0, 0.0, 1.0]
cam_overlaps: []
camera_model: pinhole
distortion_coeffs: [-0.010970399611674727, -0.024434225797313736, -0.0003202003909780894, 0.0005251524383918446]
distortion_model: radtan
intrinsics: [467.56912932614364, 468.9251463870643, 638.2787884016901, 502.0816266969794]
resolution: [1280, 1024]
rostopic: /cam
timeshift_cam_imu: 0.020715376889773315
在 pdf 结果里可以看到投影误差情况,如:
我这个是一个较差的 imu设备,没有做时间同步,有较多帧数据误差大于 5 个像素,不过还好,效果好的帧都集中在 3 个像素以内