VINS系列前篇(4)——相机标定

前期内容回顾 

./kalibr_create_target_pdf --type 'apriltag' --nx 6 --ny 6 --tsize 0.022 --tspace 0.3

大家还记得这一行代码吗?会生成一个标定所需的pdf。大家去打印的时候A4缩放40%。文件我已上传,所需的友友们自行下载。

好啦,我们先进入正文。

cd kalibr_ws
gedit april_6x6_A4.yaml

 我们将以下代码放在april_6x6_A4.yaml中,内容展示如下,后续我们标定的时候需要使用

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

关闭相机的结构光

方法一:

首先启动

 roslaunch realsense2_camera rs_camera.launch

新开终端后运行

rosrun rqt_reconfigure rqt_reconfigure

打开后将camera->stereo_module中的emitter_enabled设置为off(0) ,如下图所示:

方法二:

最简单粗暴地方法就是用电工胶布把红外摄像头给遮住,如图所示:

标定步骤

第一步,设置rviz

roslaunch realsense2_camera rs_camera_vins.launch
rviz

         打开rviz之后,注意一定要先在左侧 Fixed Frame 选择camera_link。左下角 add --> By topic --> /camera/color/image_raw/ --> 双击Camera ,找一个适合的能拍到棋盘格的距离。用同样的方式添加双目topic,/camera/infra1/image_rect_raw、/camera/infra2/image_rect_raw。

如果大家打开后没有双目的话题,就把以下代码粘贴到rs_camera_vins.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="fisheye_width"       default="640"/>
  <arg name="fisheye_height"      default="480"/>
  <arg name="enable_fisheye"      default="false"/>

  <arg name="depth_width"         default="640"/>
  <arg name="depth_height"        default="480"/>
  <arg name="enable_depth"        default="false"/>

  <arg name="infra_width"        default="640"/>
  <arg name="infra_height"       default="480"/>
  <arg name="enable_infra1"       default="true"/>
  <arg name="enable_infra2"       default="true"/>

  <arg name="color_width"         default="640"/>
  <arg name="color_height"        default="480"/>
  <arg name="enable_color"        default="true"/>

  <arg name="fisheye_fps"         default="30"/>
  <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="enable_sync"               default="true"/>
  <arg name="align_depth"               default="true"/>

  <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="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="allow_no_texture_points"   default="false"/>
  <arg name="emitter_enable"   		default="false"/>



  <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="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="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_infra1"            value="$(arg enable_infra1)"/>
      <arg name="enable_infra2"            value="$(arg enable_infra2)"/>

      <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="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="allow_no_texture_points"  value="$(arg allow_no_texture_points)"/>
    </include>
  </group>
</launch>

第二步,修改相机帧数

        kalibr在处理标定数据的时候要求频率不能太高,一般为4Hz,我们可以使用如下命令来更改topic的频率,实际上是将原来的topic以新的频率转成新的topic,实际测试infra1对应左目相机,infra2对应右目相机。

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

第三步,录制ROS数据包

cd kablbr_ws
rosbag record -O multicameras_calibration /infra_left /infra_right /color

  录制包的时候有以下注意事项:盯着rviz里面的画面,确保RGB、左目、右目都能看到完整的棋盘格;录制时三个摄像头都要完整的看到标定板,一定要慢,慢慢晃动

步骤如下:
(1)俯仰角摆动3次
(2)偏航角摆动3次
(3)翻滚角摆动3次
(4)上下移动3次
(5)左右移动3次
(6)前后移动3次
(7)自由移动,摆动幅度大一些,但要移动缓慢些,使得标定目标尽可能出现在相机的所有视野范围内。整体标定时间在90s以上

第四步,使用Kalibr标定

rosrun kalibr kalibr_calibrate_cameras --target april_6x6_A4.yaml --bag  multicameras_calibration.bag --models pinhole-equi pinhole-equi pinhole-equi --topics /infra_left /infra_right /color --bag-from-to 10 100 --show-extraction

博主在运行这一步的时候报错了,说缺少"wx"这个库,需要安装 wxPython 库才能解决这个问题,大家可以输入下面的代码安装

sudo apt-get install python3-wxgtk4.0

标定完成会生成三个文件,如图所示:

我们打开其中的multicameras_calibration-report-cam.pdf文件,翻到最后面。查看results-cam-homeubuntumulticameras_calibration_biaoding.txt中的重投影误差reprojection error数值是多少,理想范围是0.1-0.2。

友友们如果标定出来的数据太发散的话就将bag删除附带三个生成的文件,重新录制数据包(参考步骤三),晃动标定板的速度不要太快,慢慢的晃。博主标定出来的数据还是可以的,大家可以参考一下:

<think>嗯,用户询问的是IMU和Kalibr相机能否同时标定。用户可能正在搭建多传感器系统,比如SLAM或机器人导航平台,需要解决传感器之间的时空对齐问题。从"同时标定"这个表述来看,用户可能误以为标定是分步完成的,但实际上联合标定是同步优化的过程。 用户提到的Kalibr是ETH Zurich开发的多传感器标定工具,支持相机-IMU组合。这里需要澄清几个技术细节:首先,Kalibr的联合标定本质上是非线性的优化问题,需要同时求解相机内参、IMU噪声参数、以及两者之间的外参变换矩阵。其次,标定过程对运动激励有严格要求——需要充分激发IMU的所有自由度,特别是角速度变化要剧烈,否则加速度计偏置和陀螺仪偏差会难以分离。 用户可能没意识到的是标定板的作用。AprilGrid标定板不仅提供视觉特征点,其已知的方格尺寸还能约束尺度因子。这个细节很关键,因为纯IMU数据无法提供绝对尺度信息。另外补充一个实践中的坑:IMU的采样频率通常远高于相机(如200Hz vs 20Hz),Kalibr在处理时会自动做时间戳对齐,但要求硬件同步触发,否则会引入时间漂移误差。 关于标定结果验证,可以建议用户关注重投影误差和IMU残差这两个指标。如果IMU的随机游走噪声参数优化后超过数据手册范围,往往说明标定数据质量有问题。这时候可能需要调整相机曝光时间——因为运动模糊会严重影响角点检测精度,而快速运动恰恰又是激发IMU所必需的矛盾点。</think>是的,**IMU(惯性测量单元)和Kalibr相机可以同时进行联合标定**。这正是Kalibr工具的核心功能之一。这种联合标定对于需要精确融合视觉和惯性数据(如SLAM、VIO、机器人导航等)的应用至关重要。 **联合标定的核心目的和过程如下:** 1. **解决时空对齐问题:** * **空间对齐:** 确定相机光学中心与IMU测量中心之间的**刚性变换关系**(外参),通常表示为一个旋转矩阵 $R_{c}^{i}$ 和一个平移向量 $p_{c}^{i}$。即,知道相机坐标系下的一个点如何转换到IMU坐标系下。 * **时间对齐:** 确定相机快门事件(或图像时间戳)与IMU测量数据之间的**时间偏移量** $t_d$。由于硬件触发或时间戳生成可能存在延迟,这个偏移量需要被精确估计。 2. **Kalibr如何实现联合标定:** 1. **数据采集:** 用户需要同时录制包含相机图像和IMU原始数据(角速度、加速度)的**数据集**。在录制过程中,需要**充分激励所有自由度**(特别是旋转运动),使标定板(如AprilTag)在相机视野内清晰可见,同时IMU能感知到足够的加速度和角速度变化。 2. **输入文件准备:** 你需要准备几个配置文件: * `camchain-...yaml`: 包含相机的内参(焦距、主点、畸变系数等)和相机之间的外参(如果是多目系统)。这通常通过**先标定相机**(单目或多目)得到。 * `imu.yaml`: 包含IMU的噪声模型参数(加速度计和陀螺仪的噪声密度、随机游走参数等)。这些参数通常可以在IMU的数据手册中找到近似值,或者通过采集静态IMU数据进行估计。 * `april_...yaml`: 描述使用的标定板(如AprilTag网格)的规格(标签大小、间距、行数、列数等)。 * `stereo_imu_calibra.bag`: 实际采集的ROS bag文件,包含同步的图像数据和IMU数据流。 3. **运行Kalibr:** 使用`kalibr_calibrate_imu_camera`工具,并提供上述配置文件和数据文件作为输入。 4. **优化求解:** Kalibr内部会执行以下步骤: * 检测每帧图像中的标定板角点。 * 根据相机模型和内参,将角点投影到相机坐标系。 * 利用标定板的已知几何结构,优化求解相机在每一时刻相对于标定板的位姿 $T_{cb}^k$。 * 建立**视觉-惯性约束**:IMU在相邻图像帧之间的积分运动(预积分)应该与相机位姿变化一致。即,利用IMU数据积分得到的从 $T_k$ 到 $T_{k+1}$ 的相对位姿变换 $T_{k}^{k+1}$(在IMU坐标系下),应该与通过相机位姿计算出的 $T_{k}^{k+1}$(转换到IMU坐标系下)一致。 * **联合优化**:将所有时刻的视觉约束(标定板位姿)和惯性约束(IMU预积分)组合成一个**非线性最小二乘问题**。优化的变量包括: * 相机-IMU外参 $(R_{c}^{i}, p_{c}^{i})$。 * 时间偏移量 $t_d$。 * (可选)IMU的噪声模型参数(如果允许优化)。 * (可选)相机轨迹(位姿)的微小调整。 5. **输出结果:** Kalibr输出包含优化后的相机-IMU外参 $(R_{c}^{i}, p_{c}^{i})$、时间偏移量 $t_d$,以及标定的精度信息(重投影误差、IMU测量残差等)。 **关键点:** * **“同时标定”的含义:** 这里的“同时”是指在一个**统一的优化框架下**,利用**同一时间段内采集的视觉和惯性数据**,**一次性估计**出所有需要的参数(外参、时延)。它避免了先标定相机、再标定IMU、最后手测外参的分步流程及其带来的累积误差。 * **依赖相机标定结果:** 虽然目标是联合标定相机和IMU,但通常需要**先提供相机自身的标定结果**(内参和相机间外参)作为输入。Kalibr主要优化的是相机与IMU之间的外参和时延。 * **运动要求:** 采集数据时,**充分、激励性的运动**是联合标定成功的关键。运动需要包含足够大的加速度和角速度变化,并覆盖所有旋转轴。 * **时间同步基础:** Kalibr假设图像和IMU数据流之间有一个**固定的时间偏移** $t_d$,并优化这个值。它不解决硬件触发级别的精确同步问题,但能补偿软件时间戳的固定延迟。 **总结:** Kalibr提供了强大的工具,能够精确地同时(在统一优化框架下)标定相机(单目或多目)与IMU之间的**空间关系(外参)** 和 **时间关系(时延)**。这是构建高性能视觉-惯性融合系统(如VINS, OKVIS, ROVIO等)的基础步骤。你提供的引用文件列表正是进行这种联合标定所需要的典型输入文件[^1]。 [^1]: 引用参考:三、双目摄像头-IMU联合标定 一共需要四个文件 camchain-homeqinluzhistereo_calibra.yaml imu.yaml april_6x6_80x80cm.yaml stereo_imu_calibra.bag
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值