当前位置: 首页 > article >正文

ROS合集(三)RTAB-Map + EuRoC 数据格式概述

文章目录

    • 一、加载现有bag文件
    • 二、查看消息格式
      • 1、命令行查看
      • 2、直接去 .msg 文件查看
      • 3、ROS Wiki / GitHub
    • 三、Odometry、IMU、TF
      • 1. 里程计(Odometry)
      • 2. IMU(惯性测量单元)
      • 3. TF(坐标变换)
    • 四、查看.launch文件
    • 五、相关文献

一、加载现有bag文件

cd ~/Desktop/Bag
rosbag info MH_01_easy.bag

image-20250319111343492

path:        MH_01_easy.bag
version:     2.0
duration:    3:06s (186s)
start:       Jun 24 2014 12:02:59.81 (1403636579.81)
end:         Jun 24 2014 12:06:06.70 (1403636766.70)
size:        2.5 GB
messages:    47283
compression: none [2456/2456 chunks]
types:       geometry_msgs/PointStamped [c63aecb41bfdfd6b7e1fac37c7cbe7bf]
             sensor_msgs/Image          [060021388200f6f0f447d0fcd9c64743]
             sensor_msgs/Imu            [6a62c6daae103f4ff57a132d6f95cec2]
topics:      /cam0/image_raw    3682 msgs    : sensor_msgs/Image         
             /cam1/image_raw    3682 msgs    : sensor_msgs/Image         
             /imu0             36820 msgs    : sensor_msgs/Imu           
             /leica/position    3099 msgs    : geometry_msgs/PointStamped

可以从bag文件的info信息看到,包含如下内容

  • 双目(立体)SLAM : /cam0/image_raw 和 /cam1/image_raw
  • IMU数据:/imu0
  • 精确定位信息: /leica/position https://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets

image-20250319121430188

需要注意的是这个/leica/position 的话题并不是RTAB-Map 建图算法本身所必需,它往往是一个高精度测量仪器(Leica)提供的地面真实位置(Ground Truth),用于事后分析误差、对比 SLAM 轨迹和真实轨迹。

image-20250319122637678

根据RTAB-Map的论文中我们可以知道,对于输入来说,需要如下内容

  • 单目或者双目相机
  • TF
  • Odometry
  • Laser Scan 或者 Point Cloud (可选)

相较于rosbag info MH_01_easy.bag的信息,似乎仅仅提供了双目相机和IMU的内容

  • /cam0/image_raw
  • /cam1/image_raw
  • /imu0

缺少关键的TF和Odometry的信息

在ROS合集(二)源码构建 RTAB-Map + EuRoC的基础上使用下述命令,可视化 ROS 节点与话题连接关系的图形工具,直观展示系统拓扑结构。

rqt_graph

可以发现tf话题是存在的

image-20250319143638880

Odometry话题也是存在的

image-20250319143717073

具体原因涉及到详细的代码讲解,请查看后续文章,本文仅仅包含概述部分

二、查看消息格式

1、命令行查看

在有 ROS 环境(且包含对应消息包)的终端下,你可以用以下命令查看任何标准消息的内部字段

# 查看话题类型
rostopic type /imu0
# 显示具体消息结构
rosmsg show sensor_msgs/Imu

image-20250319184357352

zhanyong@ubuntu:~/euroc_rtabmap_ws$ rostopic type /imu0
sensor_msgs/Imu
zhanyong@ubuntu:~/euroc_rtabmap_ws$ rosmsg show sensor_msgs/Imu
std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
geometry_msgs/Quaternion orientation
  float64 x
  float64 y
  float64 z
  float64 w
float64[9] orientation_covariance
geometry_msgs/Vector3 angular_velocity
  float64 x
  float64 y
  float64 z
float64[9] angular_velocity_covariance
geometry_msgs/Vector3 linear_acceleration
  float64 x
  float64 y
  float64 z
float64[9] linear_acceleration_covariance

同理,对 sensor_msgs/Imagegeometry_msgs/PointStamped 也可以做

rostopic type /cam0/image_raw
rosmsg show sensor_msgs/Image

2、直接去 .msg 文件查看

标准消息(sensor_msgs、geometry_msgs、std_msgs)都在官方 ros_common_msgs 仓库里,例如 sensor_msgs/Image 定义在:只要安装了相应包 sudo apt-get install ros-<distro>-sensor-msgs,这个 .msg 就会在本地 /opt/ros/<distro>/share/sensor_msgs/msg 里。

查询命令如下

rospack find sensor_msgs
# /opt/ros/noetic/share/sensor_msgs
zhanyong@ubuntu:~/Desktop$ rospack find sensor_msgs
/opt/ros/noetic/share/sensor_msgs
zhanyong@ubuntu:~/Desktop$ cd /opt/ros/noetic/share/sensor_msgs
zhanyong@ubuntu:/opt/ros/noetic/share/sensor_msgs$ ll
total 36
drwxr-xr-x   6 root root  4096 Mar 13 20:52 ./
drwxr-xr-x 307 root root 12288 Mar 16 06:37 ../
drwxr-xr-x   2 root root  4096 Mar 13 20:52 cmake/
drwxr-xr-x   2 root root  4096 Mar 13 20:52 migration_rules/
drwxr-xr-x   2 root root  4096 Mar 13 20:52 msg/
-rw-r--r--   1 root root  1287 Jan 11  2021 package.xml
drwxr-xr-x   2 root root  4096 Mar 13 20:52 srv/
zhanyong@ubuntu:/opt/ros/noetic/share/sensor_msgs$ 

sensor_msgs/msg/Image.msg

image-20250319172016181

如果仅仅希望了解结构,不希望安装ROS,也可以git ros_common进行查看

git clone https://github.com/ros/common_msgs.git

3、ROS Wiki / GitHub

  • https://github.com/ros/common_msgs
  • http://wiki.ros.org/common_msgs

image-20250319173104766

image-20250319170333561

image-20250319173342315

其中具体的结构内容,会在后续的文章中进行解析

三、Odometry、IMU、TF

在 ROS 及常见机器人/SLAM 应用中,里程计(Odometry)IMU(惯性测量单元)TF(坐标变换) 都扮演不同的角色,彼此各有区别又紧密关联。


1. 里程计(Odometry)

  • 含义
    里程计(Odometry)通常指机器人(或传感器载体)的 运动估计,包括位姿(位置+朝向)以及可选的速度、加速度等信息。在 ROS 中,常以 nav_msgs/Odometry 消息或类似格式发布。
  • 来源
    1. 轮式机器人:里程计直接来源于编码器(轮子转过的脉冲、角度)。
    2. 视觉里程计 (VO):利用相机(单目/双目/RGB-D)图像特征跟踪来计算相对运动。
    3. 视觉-惯性里程计 (VIO):结合 IMU 数据和相机数据做更精确或更鲁棒的运动估计。
    4. 其它组合:如激光雷达里程计、UWB、GPS 等。
  • 用途
    1. 给出一个连续的、随时间更新的位姿估计,用于导航、SLAM、运动控制等。
    2. 在 SLAM 里,里程计可用作增量运动,再辅以回环检测/全局优化以减少漂移。

2. IMU(惯性测量单元)

  • 含义
    IMU(Inertial Measurement Unit)包含加速度计和陀螺仪,测量 线加速度角速度。在 ROS 中通常以 sensor_msgs/Imu 消息格式发布。
  • 性质
    1. 原始传感器数据:IMU 提供的原始加速度和角速度往往噪声较大、易漂移,但高频率、动态范围大。
    2. 不能直接提供位置:仅靠原始 IMU 数据无法长时间直接积分得到稳定位置,因为累积误差严重,需要和其它传感器(相机 / 轮式编码器 / GPS / 激光雷达等)联合使用才能得到可靠的位姿估计。
  • 用途
    1. 在 VIO (Visual-Inertial Odometry) 中,与相机数据融合以改进瞬时运动估计的精度鲁棒性
    2. 在飞行器/无人机上,IMU 是姿态控制必备的核心传感器。
    3. 在一些定位/控制算法中,可以用 IMU 的角速度、线加速度做高频补偿或预测。

3. TF(坐标变换)

  • 含义
    在 ROS 里,TF(Transform)并不是一个传感器或估计结果,而是一个坐标系管理与变换广播的工具包(tf/tf2 库)。它在 ROS 系统里用来发布“从某个坐标系到另一个坐标系”的变换关系,包括平移和旋转。
  • 形式
    1. 每个坐标系(frame)用一个字符串命名,如 mapodombase_linkcamera_link 等。
    2. TF 库会记录这些坐标系之间随时间变化的变换(translation + rotation),可以通过 tf_listener 查询指定时间点的变换,用于数据对齐、可视化、传感器融合等。
  • 用途
    1. 如果你有里程计消息,通常会同时发布一条 TF(例如 odom -> base_link),让系统知道:此时刻机器人在 odom 坐标系下位于哪里、朝向如何。
    2. 当系统中有多个传感器(相机、IMU、激光雷达等),通过 TF 可以指定它们各自相对于机器人基座(base_link)的安装位姿(外参)。
    3. RViz、MoveIt 等工具依赖 TF 做数据可视化或运动规划。
对比点里程计(Odometry)IMU(Inertial Measurement Unit)TF(坐标变换)
本质位姿 / 运动估计(nav_msgs/Odometry原始或融合后的加速度、角速度测量(sensor_msgs/Imu坐标系间的变换信息(由 tf2 框架管理和广播)
数据来源轮式编码器 / 视觉VO / IMU融合 / GPS 等加速度计 + 陀螺仪(可能含磁罗盘)通常由节点根据已知外参或在线估计发布变换(如 odom->base_link
功能作用提供当前姿态(位置+朝向)及速度,用于定位/导航提供高频姿态变化信息,用于滤波或里程计融合为多个坐标系间的运算、可视化、数据对齐提供统一接口
发布频率典型 10~30 Hz(或更高)典型 100~200 Hz(甚至可达 1 kHz)根据系统需求和可用数据:可能 10~100+ Hz
是否直接给位置是,里程计本身就是位姿估计否,IMU 原始值不包含绝对位置,需要整合/融合TF 不直接给位置,而是描述坐标系转换关系
在 SLAM 中的作用提供基准运动估计,SLAM 再做全局优化辅助视觉/激光,增强姿态估计的可靠性、高频特性统一发布各传感器、地图、机器人底盘等坐标系的相对姿态
  • Odometry:最终姿态信息,可直接在 RViz 看到机器人移动。
  • IMU:加速度 / 角速度的原始测量,需要与里程计或视觉等融合。
  • TF:提供坐标变换的框架,不是直接传感器数据或姿态估计,而是管理“世界->机器人->传感器”各坐标系随时间的变换,方便系统内各模块对齐数据。

简单来说:

  • IMU 是一个硬件传感器;
  • Odometry 是基于传感器或算法推导出来的运动估计
  • TF 是 ROS 中处理各坐标系的软件工具

四、查看.launch文件

以rtabmap_examples\launch\euroc_datasets.launch为例

git clone https://github.com/introlab/rtabmap_ros.git

具体的参数描述参照注释

<?xml version="1.0"?>
<launch>
<!-- daetz annotation version--> 
<!--
Examples:
   F2M (default VO):
      $ roslaunch rtabmap_examples euroc_datasets.launch
      $ rosbag play -.-clock V1_01_easy.bag

      For MH sequences, we should set MH_seq to true because the ground truth source is different.
      $ roslaunch rtabmap_examples euroc_datasets.launch MH_seq:=true
      $ rosbag play -.-clock MH_01_easy.bag

   MSCKF (VIO):
      $ roslaunch rtabmap_examples euroc_datasets.launch args:="Odom/Strategy 8"
      $ rosbag play -.-clock V1_01_easy.bag

      We need to ignore the first 24 seconds for correct VIO initialization (drone should not move).
      $ roslaunch rtabmap_examples euroc_datasets.launch args:="Odom/Strategy 8" MH_seq:=true
      $ rosbag play -.-clock -s 24 MH_01_easy.bag

   OKVIS (VIO):
      $ roslaunch rtabmap_examples euroc_datasets.launch args:="Odom/Strategy 6 OdomOKVIS/ConfigPath ~/okvis/config/config_fpga_p2_euroc.yaml" MH_seq:=true raw_images_for_odom:=true
      $ rosbag play -.-clock MH_01_easy.bag

   VINS (VIO):
      $ roslaunch rtabmap_examples euroc_datasets.launch args:="Odom/Strategy 9 OdomVINS/ConfigPath ~/catkin_ws/src/VINS-Fusion/config/euroc/euroc_stereo_imu_config.yaml" MH_seq:=true raw_images_for_odom:=true
      $ rosbag play -.-clock MH_01_easy.bag

   VINS (VO):
      $ roslaunch rtabmap_examples euroc_datasets.launch args:="Odom/Strategy 9 OdomVINS/ConfigPath ~/catkin_ws/src/VINS-Fusion/config/euroc/euroc_stereo_config.yaml" MH_seq:=true raw_images_for_odom:=true
      $ rosbag play -.-clock MH_01_easy.bag
-->

<param name="use_sim_time" value="true"/>

<!--
  param 表示参数,name表示参数名,value表示参数值,用于设置全局参数,这里设置为true,表示使用仿真时间
-->

<arg name="feature_type" default="6"/>
<arg name="gravity_opt" default="false"/> <!-- Rtabmap will use IMU data to add gravity constraints to graph -->

<!--
  arg 表示参数,name表示参数名,default表示默认值
  定义或传递可在启动命令行动态指定的参数,可以在 <node>、<include> 或者 Launch 文件中的 if, unless 等地方引用
  也可通过命令行传入参数,如 roslaunch rtabmap_examples euroc_datasets.launch MH_seq:=true
-->
<arg name="args" default=""/>
<arg     if="$(arg gravity_opt)" name="common_args" default="-d --RGBD/CreateOccupancyGrid false --Odom/FeatureType $(arg feature_type) --Kp/DetectorStrategy $(arg feature_type) --Optimizer/GravitySigma 0.3 $(arg args)"/>
<arg unless="$(arg gravity_opt)" name="common_args" default="-d --RGBD/CreateOccupancyGrid false --Odom/FeatureType $(arg feature_type) --Kp/DetectorStrategy $(arg feature_type) $(arg args) "/>

<!-- if 表示仅仅在参数为真时才会执行,unless 表示仅仅在参数为假时才会执行 -->

<arg name="cfg" default=""/>
<arg name="MH_seq" default="false"/> <!-- For MH sequences, the ground truth is coming from a different topic -->
<arg name="raw_images_for_odom" default="false"/>
<arg name="record_ground_truth" default="false"/>
<arg name="rtabmap_viz" default="true"/>
<arg name="rviz" default="false"/>

<!-- Image rectification and publishing synchronized camera_info-->
<group ns="stereo_camera">

<!-- group 表示将若干节点或配置进行分组,并可以指定命名空间 (ns) 等。这样,组内节点的话题等会自动带有 /stereo_camera 前缀,可使相关节点更加有序。 -->
  <node pkg="rtabmap_util" type="yaml_to_camera_info.py" name="yaml_to_camera_info_left">
    <param name="yaml_path" value="$(find rtabmap_examples)/launch/config/euroc_left.yaml"/>
    <remap from="image" to="/cam0/image_raw"/>
    <remap from="camera_info" to="left/camera_info"/>
  </node>

<!-- 
  node 表示启动某个可执行文件(ROS 节点)
  pkg 表示节点所在的包名
  type 表示节点的可执行文件名,指定该包中的哪个可执行文件(或 Python 脚本名)。
  name 表示节点的名称(给该节点起一个唯一的名字)
  param 表示节点的参数,相较于全局参数,这里是该节点的参数
  remap 将某个节点里用到的话题名进行重映射。可以把节点原本订阅或发布的某个话题改名,以适配实际使用环境。
-->

  <node pkg="rtabmap_util" type="yaml_to_camera_info.py" name="yaml_to_camera_info_right">
    <param name="yaml_path" value="$(find rtabmap_examples)/launch/config/euroc_right.yaml"/>
    <param name="frame_id" value="cam1"/>
    <remap from="image" to="/cam1/image_raw"/>
    <remap from="camera_info" to="right/camera_info"/>
  </node>

  <node unless="$(arg raw_images_for_odom)" pkg="stereo_image_proc" type="stereo_image_proc" name="stereo_image_proc">
    <remap from="left/image_raw"    to="/cam0/image_raw"/>
    <remap from="right/image_raw"   to="/cam1/image_raw"/>
  </node>

</group>

<!-- TF frames -->
<node pkg="tf" type="static_transform_publisher" name="imu_base_link" args="0 0 0 3.1415926 -1.570796 0 base_link imu4 100">
  <remap from="tf" to="tf_static"/>
</node>
<!-- TF 一般是通过系统安装,放在全局路径下,所以在自己的工作环境下不会看到tf文件夹-->
<node pkg="tf" type="static_transform_publisher" name="cam0_imu_link" args="-0.021640 -0.064677 0.009811 1.555925 0.025777 0.003757 imu4 cam0 100">
  <remap from="tf" to="tf_static"/>
</node>
<node pkg="tf" type="static_transform_publisher" name="cam1_imu_link" args="-0.019844 0.045369 0.007862 1.558237 0.025393 0.017907 imu4 cam1 100">
  <remap from="tf" to="tf_static"/>
</node>

<!-- For MH sequences, /leica/position doesn't give the orientation, so minimal ground truth error could be as high as 12 cm -->
<node     if="$(arg MH_seq)" pkg="tf" type="static_transform_publisher" name="leica_base_link" args="0.120209 -0.0184772 -0.0748903 0 0 0 leica base_link_gt 100">
  <remap from="tf" to="tf_static"/>
</node>
<node unless="$(arg MH_seq)" pkg="tf" type="static_transform_publisher" name="vicon_base_link" args="0.12395 -0.02781 -0.06901 0 0 0 vicon/firefly_sbx/firefly_sbx base_link_gt 100">
  <remap from="tf" to="tf_static"/>
</node>

<node     if="$(arg MH_seq)" pkg="rtabmap_util" type="point_to_tf.py" name="point_to_tf">
  <remap from="point" to="/leica/position"/>
  <param name="frame_id" value="leica"/>
  <param name="fixed_frame_id" value="world"/>
</node>
<node unless="$(arg MH_seq)" pkg="rtabmap_util" type="transform_to_tf.py" name="transform_to_tf">
  <remap from="transform" to="/vicon/firefly_sbx/firefly_sbx"/>
  <param name="frame_id" value="world"/>
  <param name="child_frame_id" value="vicon/firefly_sbx/firefly_sbx"/>
</node>
<node pkg="tf" type="static_transform_publisher" name="world_to_map" args="0.0 0.0 0.0 0.0 0.0 0.0 /world /map 100">
  <remap from="tf" to="tf_static"/>
</node>

<node pkg="imu_complementary_filter" type="complementary_filter_node" name="imu_filter" output="screen">
   <remap from="imu/data_raw" to="/imu0"/>
   <param name="use_mag" value="false"/>
   <param name="world_frame" value="enu"/>
   <param name="publish_tf" value="false"/>
</node>
<!-- imu_complementary_filter 是一个 imu 数据融合的包,complementary_filter_node 是一个节点,imu_filter 是节点的名字,output="screen" 表示将节点的输出打印到屏幕上 -->

<!-- RTAB-Map -->
<include file="$(find rtabmap_launch)/launch/rtabmap.launch">
<!-- 在一个 Launch 文件中嵌套或导入另一个 Launch 文件,并传递参数给被包含的文件。-->
   <arg     if="$(arg raw_images_for_odom)" name="rtabmap_args" value="$(arg common_args) --Rtabmap/ImagesAlreadyRectified false"/>
   <arg unless="$(arg raw_images_for_odom)" name="rtabmap_args" value="$(arg common_args)"/>
   <arg     if="$(arg raw_images_for_odom)" name="odom_args" value="--Rtabmap/ImagesAlreadyRectified false"/>
   <arg     if="$(arg raw_images_for_odom)" name="left_image_topic" value="/cam0/image_raw"/>
   <arg unless="$(arg raw_images_for_odom)" name="left_image_topic" value="/stereo_camera/left/image_rect"/>
   <arg     if="$(arg raw_images_for_odom)" name="right_image_topic" value="/cam1/image_raw"/>
   <arg name="stereo" value="true"/>
   <arg name="frame_id" value="base_link"/>
   <arg name="wait_for_transform" value="0.1"/>
   <arg if="$(arg record_ground_truth)" name="ground_truth_frame_id" value="world"/>
   <arg if="$(arg record_ground_truth)" name="ground_truth_base_frame_id" value="base_link_gt"/>
   <arg name="cfg" value="$(arg cfg)"/>
   <arg name="imu_topic" value="/imu/data"/>
   <arg name="rtabmap_viz" value="$(arg rtabmap_viz)"/>
   <arg name="rviz" value="$(arg rviz)"/>
   <arg name="wait_imu_to_init" value="true"/>
</include>

</launch>

launch详细介绍会在后续的文章中进行解析

五、相关文献

  • kmavvisualinertialdatasets – ASL Datasets (ethz.ch)

  • GitHub - introlab/rtabmap_ros: RTAB-Map’s ROS package.

  • Index of /en/noetic/api (ros.org)

  • GitHub - ros/common_msgs

  • Common_msgs - ROS Wiki


http://www.kler.cn/a/592668.html

相关文章:

  • 上取整,下取整,四舍五入
  • LS-NET-001-什么是承载网,核心网和接入网
  • 面试总结之 Glide自定义的三级缓存策略
  • 小程序开发与物联网技术的结合:未来趋势
  • 网络编程(客户端间通信)
  • 【2025】基于python+django的小区物业管理系统(源码、万字文档、图文修改、调试答疑)
  • 深入解析 TouchSocket 插件系统架构与实践
  • k8s--集群内的pod调用集群外的服务
  • 穿越是时空之门(java)
  • 《深度学习》—— YOLOv1
  • 突破时空边界:Java实时流处理中窗口操作与时间语义的深度重构
  • 汇编移位指令
  • BERT系列模型
  • 解决下载npm 缓存出现的问题
  • JAVA并发-volatile底层原理
  • opencv初步学习——图像处理2
  • Day67 | 灵神 | 二分查找:统计公平数对的数目
  • SQLMesh系列教程:SQLMesh虚拟数据环境
  • 台式机电脑组装---电源
  • 【C++】STL(1) - 序列容器