2023年 4月 21日 来源: 新华社微博 字号:默认 超大

        标定前需先安装librealsense SDK2.0以及realsense-ros,可参考教程:Intel Realsense D455深度相机的标定及使用(一)——安装librealsense SDK2.0以及realsense-ros

三、IMU标定

1、重力加速度自检

       插入相机并静置, 终端输入realsense-viewer,开启realsense-viewer左侧的Motion Module模块,将鼠标放在加速度计(Accel stream)上,观察g_norm读数是否在9.8附近。

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

2、 利用官方的rs_imu_calibration.py工具进行IMU自校准

       g_norm读数正常的,请跳过此步骤,直接进入步骤3 ;g_norm读数不正常的,利用官方的rs_imu_calibration.py工具进行IMU自校准,详情参考官方网站:

https://dev.intelrealsense.com/docs/imu-calibration-tool-for-intel-realsense-depth-camera

        我将官方文档中Ubuntu系统下的大致步骤列出如下,英文不好的可以做个参照(window请看源文档)。

        (a)下载rs_imu_calibration.py脚本

https://github.com/IntelRealSense/librealsense

        通过上面的链接下载,下载后在tools/rs_imu_calibration文件夹里可以找到脚本文件rs_imu_calibration.py。

        (b)构建Python环境及其他依赖包

        检查Python版本,通过命令:python --version

        这边使用的是Python2,如果2和3都安装的,运行如下命令进行手动切换。

sudo update-alternatives --config python

        显示如下,键入python3的序号(这里是2),回车。

有 2 个候选项可用于替换 python (提供 /usr/bin/python)。

  选择       路径            优先级  状态
------------------------------------------------------------
* 0            /usr/bin/python3   150       自动模式
  1            /usr/bin/python2   100       手动模式
  2            /usr/bin/python3   150       手动模式

要维持当前值[*]请按<回车键>,或者键入选择的编号:

        注意:此方法不会修改Python的优先级,也就是之后还会切换回Python3。如果想更换Python2为默认环境,需要sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 150加上sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100命令来修改优先级。两种方法二选一!!!

        有些依赖或者软件之前安装过,以防万一,建议还是install一下。

sudo apt-get install python-pip

sudo pip install numpy

sudo pip install pyrealsense2

        (c)运行脚本

        插上相机,进入rs_imu_calibration.py文件所在文件夹(我的在~/Packages/librealsense-master/tools/rs-imu-calibration下),运行

python rs-imu-calibration.py

         出现如下界面,并不停地有读数进来。

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

        (d)从6个位置捕获IMU数据

        将相机以下图所示位置摆放(螺纹孔朝下,懒得自己照相了,图用的是官方文件中的D435i)

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置1

         放置正确后终端会出现:Status.collect_data[...................]],期间不要移动相机,直到省略号满格出现Direction data collected。若不小心移动,会出现Status.collect_dataWARNING: MOVING的警告,此时摆正位置不要移动直到出现Direction data collected

        出现Direction data collected后翻转相机到下一个位置。依次在位置2~6重复操作

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置2
Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置3
Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置4
Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置5
Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定
位置6

         (f)更新数据

        6个位置都捕获完成后,会提示

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

        意思是是否保存原数据,按回车不保存原数据。然后会计算出重力加速度值:

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

         计算完后会提示:Would you like to write the results to the camera? (Y/N)。键入Y写入到设备

3、下载编译用于IMU标定的code_utils和imu_utils       

        (1)Ceres安装

依赖安装:

sudo apt-get install cmake
sudo apt-get install libgoogle-glog-dev
sudo apt-get install libatlas-base-dev
sudo apt-get install libeigen3-dev
sudo apt-get install libsuitesparse-dev

Ceres安装:

git clone https://github.com/ceres-solver/ceres-solver.git
cd ceres-solver
mkdir build
cd build
cmake ..
make -j4
sudo make install

        (2)下载编译code_utils

mkdir -p ~/Calibration/IMU_ws/src   ##可自定义
cd ~/Calibration/IMU_ws/src
git clone https://github.com/gaowenliang/code_utils.git
cd ..
catkin_make -j4

         报错解决1:error:libdw.h没有那个文件或目录

解决措施:sudo apt-get install libdw-dev

        报错解决2:error:backward.hpp没有那个文件或目录

解决措施:将sumpixel_test.cpp中# include "backward.hpp"

改为:#include "code_utils/backward.hpp"

        报错解决3:error:‘integer_sequence’ is not a member of ‘std’

解决措施: 将CMakeLists.txt中的 set(CMAKE_CXX_FLAGS "-std=c++11") 改成 set(CMAKE_CXX_STANDARD 14)

        (3)下载编译imu_utils

cd ~/Calibration/IMU_ws/src  ##和code_utils的工作空间保持一致
git clone https://github.com/gaowenliang/imu_utils.git
cd ..
catkin_make -j4

4、IMU标定

        (1)修改launch文件并启动相机

        在~/Packages/RealsenseRos_ws/src/realsense-ros/realsense2_camera/launch文件夹下(路径仅供参考,具体参照之前realsense-ros的工作空间),复制rs_camera.launch到同一个目录下,并重命名为rs_imu_calibration.launch(命名随意)。并将新文件中的<arg name="unite_imu_method"          default=""/>修改为

<arg name="unite_imu_method"          default="linear_interpolation"/>

        这样做的目的是将accel和gyro的数据合并得到imu话题,不这样做发布的topic没有合并的camera/imu话题。

        用新launch文件启动相机

roslaunch realsense2_camera rs_imu_calibration.launch

        使用rostopic list查看是否有/camera/imu话题发布。

        (2)录制imu数据包

        在保存bag包的路径打开终端,静置相机,终端输入:

rosbag record -O imu_calibration /camera/imu

        放置时间建议大于2h(官方建议)。

        (3)编写启动文件

cd ~/Calibration/IMU_ws/src/imu_utils/launch ##路径仅供参考

gedit d455_imu_calibration.launch

        写入

<launch>

    <node pkg="imu_utils" type="imu_an" name="imu_an" output="screen">
        <!--TOPIC名称和上面一致-->
        <param name="imu_topic" type="string" value= "/camera/imu"/>
        <!--imu_name 无所谓-->
        <param name="imu_name" type="string" value= "d455"/>
        <!--标定结果存放路径-->
        <param name="data_save_path" type="string" value= "$(find imu_utils)/data/"/>
        <!--数据录制时间-min-->
        <param name="max_time_min" type="int" value= "120"/>
        <!--采样频率,即是IMU频率,采样频率可以使用rostopic hz /camera/imu查看,设置为200,为后面的rosbag play播放频率-->
        <param name="max_cluster" type="int" value= "200"/>
    </node>
    
</launch>

        (4)imu标定

        在刚才imu_utils的工作空间下打开终端(我的是~/Calibration/IMU_ws),运行

source ./devel/setup.bash

roslaunch imu_utils d455_imu_calibration.launch

           回放数据包,打开新的终端     

cd 存放imu_calibration.bag的路径
rosbag play -r 200 imu_calibration.bag

        标定完成后在~/Calibration/IMU_ws/src/imu_utils/data下查看,主要看d455_imu_param.yaml文件,文件内容如下(结果仅供参考):

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

        可将标定结果移动到自己创建的文件夹里,后续的标定结果也放在这里(我的路径是~/Calibration/D455/imu_calibration)。

四、多相机标定

1、kalibr安装编译

        kalibr的安装编译与版本环境有很大关系,不同版本的安装差异很大,建议参照官网教程:

https://github.com/ethz-asl/kalibr/wiki/installation

2、标定板制作或淘宝购买

        在kalibr的工作空间下打开终端:

source ./devel/setup.bash

#生成标定板PDF文件(这里是以A4纸的规格生成的)

rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 6 --tsize 0.022 --tspace 0.3

         在工作空间下会找到PDF文件,使用A4纸100%缩放打印出来,量一下大格子的尺寸是否是0.022m(2.2cm),贴在墙上。
        参照官方格式编写yaml文件保存到自己放置自己标定结果的文件夹(~/Calibration/D455)

target_type: 'aprilgrid' #gridtype
tagCols: 6 #number of apriltags 列数
tagRows: 6 #number of apriltags 行数
tagSize: 0.022 #size of apriltag, edge to edge [m] 大格子尺寸,单位为米
tagSpacing: 0.3 #ratio of space between tags to tagSize 小格子与大格子尺寸的比值

 #example: tagSize=2m, spacing=0.5m --> tagSpacing=0.25[-]

3、修改相机启动文件

        在~/Packages/RealsenseRos_ws/src/realsense-ros/realsense2_camera/launch文件夹下(路径仅供参考,具体参照之前realsense-ros的工作空间),创建文件rs_imu_stereo_calibration_640.launch(懒得对比原文件了直接写个新的,后面联合标定也用这个,命名随意)。

<launch>
  <arg name="serial_no"           default=""/>
  <arg name="usb_port_id"         default=""/>
  <arg name="device_type"         default=""/>
  <arg name="json_file_path"      default=""/>
  <arg name="camera"              default="camera"/>
  <arg name="tf_prefix"           default="$(arg camera)"/>
  <arg name="external_manager"    default="false"/>
  <arg name="manager"             default="realsense2_camera_manager"/>
  <arg name="output"              default="screen"/>
  <arg name="respawn"              default="false"/>
  <arg name="fisheye_width"       default="-1"/>
  <arg name="fisheye_height"      default="-1"/>
  <arg name="enable_fisheye"      default="false"/>
  <arg name="depth_width"         default="640"/>
  <arg name="depth_height"        default="480"/>
  <arg name="enable_depth"        default="true"/>
  <arg name="confidence_width"    default="-1"/>
  <arg name="confidence_height"   default="-1"/>
  <arg name="enable_confidence"   default="true"/>
  <arg name="confidence_fps"      default="-1"/>
  <arg name="infra_width"         default="640"/>
  <arg name="infra_height"        default="480"/>
  <arg name="enable_infra"        default="false"/>
  <arg name="enable_infra1"       default="true"/>
  <arg name="enable_infra2"       default="true"/>
  <arg name="infra_rgb"           default="false"/>
  <arg name="color_width"         default="640"/>
  <arg name="color_height"        default="480"/>
  <arg name="enable_color"        default="true"/>
  <arg name="fisheye_fps"         default="-1"/>
  <arg name="depth_fps"           default="30"/>
  <arg name="infra_fps"           default="30"/>
  <arg name="color_fps"           default="30"/>
  <arg name="gyro_fps"            default="200"/>
  <arg name="accel_fps"           default="250"/>
  <arg name="enable_gyro"         default="true"/>
  <arg name="enable_accel"        default="true"/>
  <arg name="enable_pointcloud"         default="false"/>
  <arg name="pointcloud_texture_stream" default="RS2_STREAM_COLOR"/>
  <arg name="pointcloud_texture_index"  default="0"/>
  <arg name="allow_no_texture_points"   default="false"/>
  <arg name="ordered_pc"                default="false"/>
  <arg name="enable_sync"               default="true"/>
  <arg name="align_depth"               default="false"/>
  <arg name="publish_tf"                default="true"/>
  <arg name="tf_publish_rate"           default="0"/>
  <arg name="filters"                   default=""/>
  <arg name="clip_distance"             default="-2"/>
  <arg name="linear_accel_cov"          default="0.01"/>
  <arg name="initial_reset"             default="false"/>
  <arg name="reconnect_timeout"         default="6.0"/>
  <arg name="wait_for_device_timeout"   default="-1.0"/>
  <arg name="unite_imu_method"          default="linear_interpolation"/>
  <arg name="topic_odom_in"             default="odom_in"/>
  <arg name="calib_odom_file"           default=""/>
  <arg name="publish_odom_tf"           default="true"/>
  <arg name="stereo_module/exposure/1"  default="7500"/>
  <arg name="stereo_module/gain/1"      default="16"/>
  <arg name="stereo_module/exposure/2"  default="1"/>
  <arg name="stereo_module/gain/2"      default="16"/>
  <group ns="$(arg camera)">
    <include file="$(find realsense2_camera)/launch/includes/nodelet.launch.xml">
      <arg name="tf_prefix"                value="$(arg tf_prefix)"/>
      <arg name="external_manager"         value="$(arg external_manager)"/>
      <arg name="manager"                  value="$(arg manager)"/>
      <arg name="output"                   value="$(arg output)"/>
      <arg name="respawn"                  value="$(arg respawn)"/>
      <arg name="serial_no"                value="$(arg serial_no)"/>
      <arg name="usb_port_id"              value="$(arg usb_port_id)"/>
      <arg name="device_type"              value="$(arg device_type)"/>
      <arg name="json_file_path"           value="$(arg json_file_path)"/>
      <arg name="enable_pointcloud"        value="$(arg enable_pointcloud)"/>
      <arg name="pointcloud_texture_stream" value="$(arg pointcloud_texture_stream)"/>
      <arg name="pointcloud_texture_index"  value="$(arg pointcloud_texture_index)"/>
      <arg name="enable_sync"              value="$(arg enable_sync)"/>
      <arg name="align_depth"              value="$(arg align_depth)"/>
      <arg name="fisheye_width"            value="$(arg fisheye_width)"/>
      <arg name="fisheye_height"           value="$(arg fisheye_height)"/>
      <arg name="enable_fisheye"           value="$(arg enable_fisheye)"/>
      <arg name="depth_width"              value="$(arg depth_width)"/>
      <arg name="depth_height"             value="$(arg depth_height)"/>
      <arg name="enable_depth"             value="$(arg enable_depth)"/>
      <arg name="confidence_width"         value="$(arg confidence_width)"/>
      <arg name="confidence_height"        value="$(arg confidence_height)"/>
      <arg name="enable_confidence"        value="$(arg enable_confidence)"/>
      <arg name="confidence_fps"           value="$(arg confidence_fps)"/>
      <arg name="color_width"              value="$(arg color_width)"/>
      <arg name="color_height"             value="$(arg color_height)"/>
      <arg name="enable_color"             value="$(arg enable_color)"/>
      <arg name="infra_width"              value="$(arg infra_width)"/>
      <arg name="infra_height"             value="$(arg infra_height)"/>
      <arg name="enable_infra"             value="$(arg enable_infra)"/>
      <arg name="enable_infra1"            value="$(arg enable_infra1)"/>
      <arg name="enable_infra2"            value="$(arg enable_infra2)"/>
      <arg name="infra_rgb"                value="$(arg infra_rgb)"/>
      <arg name="fisheye_fps"              value="$(arg fisheye_fps)"/>
      <arg name="depth_fps"                value="$(arg depth_fps)"/>
      <arg name="infra_fps"                value="$(arg infra_fps)"/>
      <arg name="color_fps"                value="$(arg color_fps)"/>
      <arg name="gyro_fps"                 value="$(arg gyro_fps)"/>
      <arg name="accel_fps"                value="$(arg accel_fps)"/>
      <arg name="enable_gyro"              value="$(arg enable_gyro)"/>
      <arg name="enable_accel"             value="$(arg enable_accel)"/>
      <arg name="publish_tf"               value="$(arg publish_tf)"/>
      <arg name="tf_publish_rate"          value="$(arg tf_publish_rate)"/>
      <arg name="filters"                  value="$(arg filters)"/>
      <arg name="clip_distance"            value="$(arg clip_distance)"/>
      <arg name="linear_accel_cov"         value="$(arg linear_accel_cov)"/>
      <arg name="initial_reset"            value="$(arg initial_reset)"/>
      <arg name="reconnect_timeout"        value="$(arg reconnect_timeout)"/>
      <arg name="wait_for_device_timeout"  value="$(arg wait_for_device_timeout)"/>
      <arg name="unite_imu_method"         value="$(arg unite_imu_method)"/>
      <arg name="topic_odom_in"            value="$(arg topic_odom_in)"/>
      <arg name="calib_odom_file"          value="$(arg calib_odom_file)"/>
      <arg name="publish_odom_tf"          value="$(arg publish_odom_tf)"/>
      <arg name="stereo_module/exposure/1" value="$(arg stereo_module/exposure/1)"/>
      <arg name="stereo_module/gain/1"     value="$(arg stereo_module/gain/1)"/>
      <arg name="stereo_module/exposure/2" value="$(arg stereo_module/exposure/2)"/>
      <arg name="stereo_module/gain/2"     value="$(arg stereo_module/gain/2)"/>
      <arg name="allow_no_texture_points"  value="$(arg allow_no_texture_points)"/>
      <arg name="ordered_pc"               value="$(arg ordered_pc)"/>
    </include>
  </group>
</launch>

4、启动相机并关闭结构光

roslaunch realsense2_camera rs_imu_stereo_calibration_640.launch
rosrun rqt_reconfigure rqt_reconfigure

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

         将图中红圈部分改为OFF

5、打开rviz并修改相机帧数

        新终端运行roscore 和 rviz,点击add添加双目对应的topic,/camera/color/image_raw、/camera/infra1/image_rect_raw、/camera/infra2/image_rect_raw

        按照官方建议修改相机帧数为4Hz,并命名为新话题(此方法会使得发布频率略小于4Hz,报告影响不大)。

rosrun topic_tools throttle messages /camera/color/image_raw 4.0 /color
rosrun topic_tools throttle messages /camera/infra1/image_rect_raw 4.0 /infra_left
rosrun topic_tools throttle messages /camera/infra2/image_rect_raw 4.0 /infra_right

        查看实际频率

rostopic hz /color /infra_left /infra_right

 6、录制bag包

        在bag保存路径打开终端

rosbag record -O camera_calibration_4Hz /infra_left /infra_right /color

        录制时的要求:通过rviz界面观察,手持相机对准标定板。偏航角左右摆动3次,俯仰角摆动3次,滚转角摆动3次,上下移动3次,左右移动3次,前后移动3次,然后自由移动一段时间,摆动幅度要大一点,让视角变化大一点,但是移动要缓慢一点,同时要保证标定板在3个相机视野内部,整个标定时间要在90s以上更好。

7、使用kalibr标定

cd ~/Calibration/Kalibr_ws    #路径仅供参考
source ./devel/setup.bash

         关于第三句命令, 需要根据自己的情况修改。修改说明如下

首先是rosrun kalibr kalibr_calibrate_cameras,

第二段--target ~/Calibration/D455/Aprilgrid.yaml(改为自己标定板yaml文件的路径),

第三段--bag  ~/Dataset/Calibration_D455/640_480/camera_calibration_4Hz.bag,

第四五六段--models pinhole-radtan pinhole-radtan pinhole-radtan这句话不用改,表示三个摄像头的相机模型和畸变模型(详细解释参考Supported models · ethz-asl/kalibr Wiki · GitHub)

第七段--topics /infra_left /infra_right /color话题名称,按我之前步骤来的不用改,

第八段----bag-from-to 5 169 表示处理bag中5-169秒的数据,根据自己录制的bag来确定(通过rosbag info+bag名称 来查看),

第九段--show-extraction表示显示检测特征点的过程

第十段----approx-sync 0.04是三个相机时间同步的容许误差(可以不加这段试试,我的会标定失败)

        综合起来,对于我自己的情况,完整命令如下:

rosrun kalibr kalibr_calibrate_cameras --target /home/andyvictory/Calibration/D455/Aprilgrid.yaml --bag  ~/Dataset/Calibration_D455/640_480/camera_calibration_4Hz.bag --models pinhole-radtan pinhole-radtan pinhole-radtan --topics /infra_left /infra_right /color --bag-from-to 5 169 --show-extraction --approx-sync 0.04 

        标定过程可能有点漫长................       

        如果出现报错:cannot import name NavigationToolbar2Wx

将PlotCollection.py中的NavigationToolbar2Wx换成NavigationToolbar2WxAgg

        最终得到的三个结果文件保存在了kalibr的工作空间下,将文件移动到自己保存结果的文件夹里。看一下camera_calibration_4Hz-report-cam.pdf中的三个相机重投影误差reprojection error,至少也得在1px以内吧,下面是我标定的结果。

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

 五、IMU+双目相机联合标定

1、编写chain.yaml文件

        编写chain.yaml并保存(能找到就行,我还是放在了~/Calibration/D455/640_480下),根据自己之前IMU和相机标定的结果,参照下面的格式编写:

cam0:
  camera_model: pinhole
  distortion_coeffs: [0.006252205171105866, -0.0040039163191851815, 0.0028253923865729047, 0.0014894484127909796]
  distortion_model: radtan
  intrinsics: [387.3061040278026, 388.70426392594715, 321.2185553432099, 243.710879951254]
  resolution: [640, 480]
  rostopic: /infra_left
cam1:
  T_cn_cnm1:
  - [0.9999988621914934, -0.0012557567512840304, 0.0008358771987739831, -0.09586169575038382]
  - [0.0012560162153501813, 0.9999991631746745, -0.0003099567850981058, -0.0002414148329795646]
  - [-0.0008354872689652846, 0.000311006307742342, 0.9999996026179666, -0.0001722652642823169]
  - [0.0, 0.0, 0.0, 1.0]
  camera_model: pinhole
  distortion_coeffs: [0.006593825120537277, -0.008671743399946441, 0.0037681282760781776, 0.0014848895024164256]
  distortion_model: radtan
  intrinsics: [388.18404676436523, 389.27254650876796, 321.4035775541331, 243.8629884469389]
  resolution: [640, 480]
  rostopic: /infra_right

        其中,T_cn_cnm1:表示的是左目相机到右目相机的旋转和平移。

2、录制bag包

        参照之前录制相机标定bag的步骤:

roscore
rviz
roslaunch realsense2_camera rs_imu_stereo_calibration_640.launch
rosrun rqt_reconfigure rqt_reconfigure  ##关闭结构光

        修改相机和IMU发布的频率(这里录制的画面包括了/color相机,我这边是为了以后使用,要是不需要,只用于标定的话可以不录制color的话题即把下面第三句删掉):

rosrun topic_tools throttle messages /camera/infra1/image_rect_raw 20.0 /infra_left
rosrun topic_tools throttle messages /camera/infra2/image_rect_raw 20.0 /infra_right
rosrun topic_tools throttle messages /camera/color/image_raw 20.0 /color
rosrun topic_tools throttle messages /camera/imu 200.0 /imu

        在bag的保存路径打开终端并录制(只录制两个相机画面的这里不需要/color):

rosbag record -O imu_stereo_640.bag /infra_left /infra_right /color /imu

3、联合标定

cd ~/Calibration/Kalibr_ws    #路径仅供参考
source ./devel/setup.bash

        运行命令(参照之前相机标定过程修改)

 rosrun kalibr kalibr_calibrate_imu_camera --bag ~/Dataset/Calibration_D455/640_480/imu_stereo_640.bag --cam ~/Calibration/D455/640_480/second/chain.yaml --imu ~/Calibration/D455/IMU/imu.yaml --target ~/Calibration/D455/Aprilgrid.yaml --bag-from-to 5 136 --show-extraction

        标定结果的四个文件还是放在kalibr的工作空间下,打开imu_stereo_640-results-imucam.txt查看,重投影误差Reprojection error,两个相机的mean都起码都得在0.5以下。

Intel Realsense D455深度相机的标定及使用(二)——对内置IMU和双目相机进行标定

        至此,相机和IMU各自的标定和联合标定的工作都已完成,下一步就是根据标定结果跑自己的算法了。下一篇将以VINS-Fusion算法运行自己用Realsense D455相机录制的数据包。