设置里程计

在本指南中,我们将介绍如何将我们机器人的里程计系统与Nav2集成。首先,我们将简要介绍里程计,以及需要发布的消息和变换,以确保Nav2的正常运行。接下来,我们将展示如何设置两种不同情况下的里程计。在第一种情况下,我们将展示如何为已有轮式编码器的机器人设置里程计系统。在第二种情况下,我们将在Gazebo中构建一个演示,模拟使用``sam_bot``(我们在上一节中构建的机器人)的正常运行的里程计系统。然后,我们将讨论如何将各种里程计来源融合,以提供平滑的里程计,使用``robot_localization``软件包。最后,我们还将展示如何使用``robot_localization``发布``odom`` => ``base_link``的变换。

参见

本教程中的完整源代码可以在 navigation2_tutorials 存储库的 sam_bot_description 包中找到。请注意,该存储库包含完成本指南中所有教程后的完整代码。

里程计简介

里程计系统根据机器人的运动提供局部精确的姿态和速度估计。里程计信息可以从各种来源获取,例如惯性测量单元 (IMU)、激光雷达 (LIDAR)、雷达 (RADAR)、视觉惯性里程计 (VIO) 和轮子编码器。需要注意的是,IMU会随时间漂移,而轮子编码器会随行驶距离漂移,因此通常将它们结合使用以抵消彼此的负面特征。

``odom``坐标系及其相关变换使用机器人的里程计系统发布连续但随时间或距离准确性逐渐降低的定位信息(取决于传感器模态和漂移情况)。尽管如此,机器人仍然可以使用这些信息来导航其周围的环境(例如避免碰撞)。为了获得一致准确的里程计信息,``map``坐标系提供了全局准确的信息,用于校正``odom``坐标系。

如前面的指南和 REP 105 中所讨论的那样,odom 坐标系与系统的其余部分和 Nav2 通过 odom => base_link 变换相连。这个变换由 tf2 发布器或像 robot_localization 这样的框架发布。robot_localization 还提供额外的功能。我们将在后面的章节中详细讨论 robot_localization

除了必需的``odom`` => ``base_link``变换之外,Nav2还需要发布``nav_msgs/Odometry``消息,因为该消息提供了机器人的速度信息。具体而言,``nav_msgs/Odometry``消息包含以下信息:

# This represents estimates of position and velocity in free space.
# The pose in this message should be specified in the coordinate frame given by header.frame_id
# The twist in this message should be specified in the coordinate frame given by the child_frame_id

# Includes the frame id of the pose parent.
std_msgs/Header header

# Frame id the pose is pointing at. The twist is in this coordinate frame.
string child_frame_id

# Estimated pose that is typically relative to a fixed world frame.
geometry_msgs/PoseWithCovariance pose

# Estimated linear and angular velocity relative to child_frame_id.
geometry_msgs/TwistWithCovariance twist

该消息告诉我们机器人的姿态和速度估计值。header 消息在给定坐标系中提供时间戳数据。pose 消息提供机器人相对于 header.frame_id 指定的坐标系的位置和方向。twist 消息提供相对于 child_frame_id 中定义的坐标系的线速度和角速度。

设置机器人的里程计

为 Nav2 设置物理机器人的里程计系统主要取决于机器人可用的里程计传感器。由于您的机器人可能有大量的配置,特定的设置说明不在本教程的范围内。相反,我们将提供一些基本示例和有用的资源,以帮助您为 Nav2 配置机器人。

首先,我们将使用一个带有轮式编码器作为里程计来源的机器人示例。请注意,轮式编码器在Nav2中并不是必需的,但在大多数设置中很常见。设置里程计的目标是计算里程计信息,并通过ROS 2发布``nav_msgs/Odometry``消息和``odom`` => ``base_link``转换。为了计算这些信息,您需要设置一些代码,将轮式编码器信息转换为里程计信息,类似下面的代码片段:

linear = (right_wheel_est_vel + left_wheel_est_vel) / 2
angular = (right_wheel_est_vel - left_wheel_est_vel) / wheel_separation;

right_wheel_est_velleft_wheel_est_vel 分别是右轮和左轮的估计速度,而 wheel separation 是轮子之间的距离。可以通过简单地获取轮子关节随时间的位置变化来获得 right_wheel_est_velleft_wheel_est_vel 的值。然后可以使用这些信息来发布 Nav2 的要求。有关如何执行此操作的基本示例,请参阅里程计导航文档中的 `此处 <http://wiki.ros.org/navigatio

我们建议的一种手动发布此信息的替代方法是通过``ros2_control``框架。``ros2_control``框架包含了用于在ROS 2中实时控制机器人的各种软件包。对于轮式编码器,``ros2_control``在``ros2_controller``软件包中提供了一个``diff_drive_controller``(差动驱动控制器)。``diff_drive_controller``接收在``cmd_vel``话题上发布的``geometry_msgs/Twist``消息,计算里程计信息,并在``odom``话题上发布``nav_msgs/Odometry``消息。``ros2_control``还提供了处理不同类型传感器的其他软件包。

参见

要获取更多信息,请参阅 ros2_control 文档diff_drive_controller 的 Github 存储库

对于其他类型的传感器(如IMU、VIO等),它们各自的ROS驱动程序应该有关于如何发布里程计信息的文档。请记住,Nav2要求发布``nav_msgs/Odometry``消息和``odom`` => ``base_link``转换,这应该是您在设置里程计系统时的目标。

使用 Gazebo 模拟 Odometry 系统

在本节中,我们将使用Gazebo模拟``sam_bot``的里程计系统,这是我们在本教程系列的上一节中构建的机器人。您可以先阅读那个指南或在 此处获取完整源代码

注解

如果您正在使用自己的物理机器人并已经设置好了里程计传感器,您可以选择跳过本节,直接进入下一节,在那里我们将融合 IMU 和里程计消息以提供平滑的 odom => base_link 转换。

作为本节的概述,我们将首先设置Gazebo和必要的软件包,使其与ROS 2配合工作。接下来,我们将添加Gazebo插件,分别模拟IMU传感器和差动驱动里程计系统,以发布``sensor_msgs/Imu``和``nav_msgs/Odometry``消息。最后,我们将在Gazebo环境中生成``sam_bot``并通过ROS 2验证发布的``sensor_msgs/Imu``和``nav_msgs/Odometry``消息。

设置和先决条件

``Gazebo <http://gazebosim.org/>``_是一个3D模拟器,可以让我们观察虚拟机器人在模拟环境中的运行情况。要开始使用Gazebo和ROS 2,请按照`Gazebo安装文档 <http://ga

我们还需要安装 gazebo_ros_pkgs 包,以便在 Gazebo 中模拟里程计并使用 ROS 2 控制机器人:

sudo apt install ros-<ros2-distro>-gazebo-ros-pkgs

您可以按照此处的说明 `(链接:<http://gazebosim.org/tutorials?tut=ros2_installing&cat=connect_ros#TestingGazeboandROS2integration>`_)测试您是否成功设置了ROS 2和Gazebo环境。

请注意,我们使用 URDF 描述了 sam_bot。然而,Gazebo 使用 Simulation Description Format (SDF) 来描述机器人在模拟环境中的情况。幸运的是,Gazebo 可以自动将兼容的 URDF 文件转换为 SDF。使 URDF 与 Gazebo 兼容的主要要求是在每个 <link> 元素中具有一个 <inertia> 元素。sam_bot 的 URDF 文件已经满足了这个要求,因此它可以直接在 Gazebo 中使用。

参见

有关如何在Gazebo中使用URDF的更多信息,请参阅 `(链接:<http://gazebosim.org/tutorials/?tut=ros_urdf>`_)教程。

向 URDF 添加 Gazebo 插件

现在,我们将向URDF添加Gazebo的IMU传感器和差动驱动插件。要了解Gazebo中可用的不同插件的概述,请查看 `(链接:<http://gazebosim.org/tutorials?tut=ros_gzplugins>`_)教程。

对于我们的机器人,我们将使用 GazeboRosImuSensor,它是一个SensorPlugin。SensorPlugin必须附加到一个链接上,因此我们将创建一个``imu_link``,将IMU传感器附加到该链接上。这个链接将在``<gazebo>``元素下引用。接下来,我们将设置``/demo/imu``作为IMU将发布其信息的主题,并且我们将根据 REP145 设置``initalOrientationAsReference``为``false``。我们还将使用Gazebo的 sensor noise model 为传感器配置添加一些噪声。

现在,我们将按照上述说明设置IMU传感器插件,将以下行添加到URDF中的``</robot>``行之前:

132<link name="imu_link">
133  <visual>
134    <geometry>
135      <box size="0.1 0.1 0.1"/>
136    </geometry>
137  </visual>
138
139  <collision>
140    <geometry>
141      <box size="0.1 0.1 0.1"/>
142    </geometry>
143  </collision>
144
145  <xacro:box_inertia m="0.1" w="0.1" d="0.1" h="0.1"/>
146</link>
147
148<joint name="imu_joint" type="fixed">
149  <parent link="base_link"/>
150  <child link="imu_link"/>
151  <origin xyz="0 0 0.01"/>
152</joint>
153
154 <gazebo reference="imu_link">
155  <sensor name="imu_sensor" type="imu">
156   <plugin filename="libgazebo_ros_imu_sensor.so" name="imu_plugin">
157      <ros>
158        <namespace>/demo</namespace>
159        <remapping>~/out:=imu</remapping>
160      </ros>
161      <initial_orientation_as_reference>false</initial_orientation_as_reference>
162    </plugin>
163    <always_on>true</always_on>
164    <update_rate>100</update_rate>
165    <visualize>true</visualize>
166    <imu>
167      <angular_velocity>
168        <x>
169          <noise type="gaussian">
170            <mean>0.0</mean>
171            <stddev>2e-4</stddev>
172            <bias_mean>0.0000075</bias_mean>
173            <bias_stddev>0.0000008</bias_stddev>
174          </noise>
175        </x>
176        <y>
177          <noise type="gaussian">
178            <mean>0.0</mean>
179            <stddev>2e-4</stddev>
180            <bias_mean>0.0000075</bias_mean>
181            <bias_stddev>0.0000008</bias_stddev>
182          </noise>
183        </y>
184        <z>
185          <noise type="gaussian">
186            <mean>0.0</mean>
187            <stddev>2e-4</stddev>
188            <bias_mean>0.0000075</bias_mean>
189            <bias_stddev>0.0000008</bias_stddev>
190          </noise>
191        </z>
192      </angular_velocity>
193      <linear_acceleration>
194        <x>
195          <noise type="gaussian">
196            <mean>0.0</mean>
197            <stddev>1.7e-2</stddev>
198            <bias_mean>0.1</bias_mean>
199            <bias_stddev>0.001</bias_stddev>
200          </noise>
201        </x>
202        <y>
203          <noise type="gaussian">
204            <mean>0.0</mean>
205            <stddev>1.7e-2</stddev>
206            <bias_mean>0.1</bias_mean>
207            <bias_stddev>0.001</bias_stddev>
208          </noise>
209        </y>
210        <z>
211          <noise type="gaussian">
212            <mean>0.0</mean>
213            <stddev>1.7e-2</stddev>
214            <bias_mean>0.1</bias_mean>
215            <bias_stddev>0.001</bias_stddev>
216          </noise>
217        </z>
218      </linear_acceleration>
219    </imu>
220  </sensor>
221</gazebo>

现在,让我们添加差分驱动的ModelPlugin。我们将配置插件,以便在``/demo/odom``主题上发布``nav_msgs/Odometry``消息。左右轮的关节将设置为``sam_bot``的轮关节。轮子之间的距离和轮子的直径分别根据``wheel_ygap``和``wheel_radius``的定义值设置。

要在URDF中包含此插件,请在IMU插件的``</gazebo>``标签后添加以下行:

223<gazebo>
224  <plugin name='diff_drive' filename='libgazebo_ros_diff_drive.so'>
225    <ros>
226      <namespace>/demo</namespace>
227    </ros>
228
229    <!-- wheels -->
230    <left_joint>drivewhl_l_joint</left_joint>
231    <right_joint>drivewhl_r_joint</right_joint>
232
233    <!-- kinematics -->
234    <wheel_separation>0.4</wheel_separation>
235    <wheel_diameter>0.2</wheel_diameter>
236
237    <!-- limits -->
238    <max_wheel_torque>20</max_wheel_torque>
239    <max_wheel_acceleration>1.0</max_wheel_acceleration>
240
241    <!-- output -->
242    <publish_odom>true</publish_odom>
243    <publish_odom_tf>false</publish_odom_tf>
244    <publish_wheel_tf>true</publish_wheel_tf>
245
246    <odometry_frame>odom</odometry_frame>
247    <robot_base_frame>base_link</robot_base_frame>
248  </plugin>
249</gazebo>

启动和构建文件

现在,我们将编辑我们的启动文件 `(链接:<https://github.com/ros-planning/navigation2_tutorials/blob/master/sam_bot_description/launch/display.launch.py>`_)以在Gazebo中生成``sam_bot``。由于我们将模拟我们的机器人,可以通过删除``generate_launch_description()``内部的以下行来移除关节状态发布器的GUI:

joint_state_publisher_gui_node = launch_ros.actions.Node(
  package='joint_state_publisher_gui',
  executable='joint_state_publisher_gui',
  name='joint_state_publisher_gui',
  condition=launch.conditions.IfCondition(LaunchConfiguration('gui'))
)

移除以下的`gui`参数:

DeclareLaunchArgument(name='gui', default_value='True',
                      description='Flag to enable joint_state_publisher_gui')

从`joint_state_publisher_node`中删除条件:

joint_state_publisher_node = launch_ros.actions.Node(
  package='joint_state_publisher',
  executable='joint_state_publisher',
  name='joint_state_publisher',
  condition=launch.conditions.UnlessCondition(LaunchConfiguration('gui')) # Remove this line
)

接下来,打开 package.xml 并删除这行:

<exec_depend>joint_state_publisher_gui</exec_depend>

要启动 Gazebo,请在 joint_state_publisher_node 行之前添加以下内容

launch.actions.ExecuteProcess(cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_init.so', '-s', 'libgazebo_ros_factory.so'], output='screen'),

现在,我们将在Gazebo中添加一个节点,用于生成``sam_bot``。再次打开 launch/display.launch.py ,在``return launch.LaunchDescription([``行之前粘贴以下代码行。

spawn_entity = launch_ros.actions.Node(
  package='gazebo_ros',
  executable='spawn_entity.py',
  arguments=['-entity', 'sam_bot', '-topic', 'robot_description'],
  output='screen'
)

然后在 rviz_node 行之前添加一行 spawn_entity,如下所示

      robot_state_publisher_node,
      spawn_entity,
      rviz_node
])

构建、运行和验证

让我们运行我们的包,检查系统中是否存在活动的``/demo/imu``和``/demo/odom``主题。

导航到项目的根目录并执行以下命令

colcon build
. install/setup.bash
ros2 launch sam_bot_description display.launch.py

Gazebo 应该会启动,您应该会看到一个名为 sam_bot 的三维模型:

../../_images/gazebo_sam_bot.png

要查看系统中的活动话题,请打开一个新的终端并执行

ros2 topic list

您应该在话题列表中看到 /demo/imu/demo/odom

要查看有关话题的更多信息,请执行

ros2 topic info /demo/imu
ros2 topic info /demo/odom

您应该会看到类似下面的输出:

Type: sensor_msgs/msg/Imu
Publisher count: 1
Subscription count: 0
Type: nav_msgs/msg/Odometry
Publisher count: 1
Subscription count: 0

注意,/demo/imu 话题发布的是 sensor_msgs/Imu 类型的消息,而 /demo/odom 话题发布的是 nav_msgs/Odometry 类型的消息。这些话题上发布的信息分别来自 IMU 传感器和差分驱动的 Gazebo 仿真。还请注意,这两个话题目前都没有订阅者。在下一节中,我们将创建一个 robot_localization 节点来订阅这两个话题。然后,它将使用这两个话题上发布的消息为 Nav2 提供融合的、本地准确且平滑的里程计信息。

机器人定位演示

robot_localization 包用于从 N 个里程计传感器输入的数据中提供融合和本地准确的平滑里程计信息。这些信息可以通过 nav_msgs/Odometrysensor_msgs/Imugeometry_msgs/PoseWithCovarianceStampedgeometry_msgs/TwistWithCovarianceStamped 消息提供给该包。

通常的机器人设置至少包括轮编码器和惯性测量单元 (IMU) 作为其里程计传感器来源。当``robot_localization``接收到多个传感器提供的里程计信息时,它可以通过使用状态估计节点来融合传感器提供的里程计信息。这些节点使用扩展卡尔曼滤波器(ekf_node)或无迹卡尔曼滤波器(ukf_node)来实现融合。此外,该软件包还实现了一个``navsat_transform_node``,在使用GPS时将地理坐标转换为机器人的世界坐标系。

如果在配置中启用了``robot_localization``软件包,它将通过``odometry/filtered``和``accel/filtered``主题发布融合的传感器数据。此外,它还可以在``/tf``主题上发布``odom`` => ``base_link``的变换。

参见

有关``robot_localization``的更多详细信息,请参阅官方的 Robot Localization 文档

如果您的机器人只能提供一个里程计源,使用``robot_localization``除了平滑效果外,几乎没有其他影响。在这种情况下,另一种方法是通过单个里程计源节点使用tf2广播器发布变换。然而,您仍然可以选择使用``robot_localization``来发布变换,输出结果可能仍然具有一定的平滑效果。

参见

有关如何编写 tf2 广播器的更多信息,请查阅如下链接: Writing a tf2 broadcaster (C++) (Python)

在本节的其余部分中,我们将展示如何使用``robot_localization``来融合``sam_bot``的传感器。它将使用发布在``/demo/Imu``上的``sensor_msgs/Imu``消息和发布在``/demo/odom``上的``nav_msgs/Odometry``消息,然后在``odometry/filtered``、accel/filtered``和/tf``主题上发布数据。

配置机器人定位

现在让我们配置``robot_localization``软件包,使用扩展卡尔曼滤波器(ekf_node)来融合里程计信息,并发布``odom`` => ``base_link``的变换。

首先,使用您的机器的软件包管理器安装``robot_localization``软件包,或者执行以下命令进行安装:

sudo apt install ros-<ros2-distro>-robot-localization

接下来,我们使用一个YAML文件来指定``ekf_node``的参数。在您的项目根目录下创建一个名为``config``的目录,并创建一个名为``ekf.yaml``的文件。将以下代码复制到``ekf.yaml``文件中。

### ekf config file ###
ekf_filter_node:
    ros__parameters:
# The frequency, in Hz, at which the filter will output a position estimate. Note that the filter will not begin
# computation until it receives at least one message from one of theinputs. It will then run continuously at the
# frequency specified here, regardless of whether it receives more measurements. Defaults to 30 if unspecified.
        frequency: 30.0

# ekf_localization_node and ukf_localization_node both use a 3D omnidirectional motion model. If this parameter is
# set to true, no 3D information will be used in your state estimate. Use this if you are operating in a planar
# environment and want to ignore the effect of small variations in the ground plane that might otherwise be detected
# by, for example, an IMU. Defaults to false if unspecified.
        two_d_mode: false

# Whether to publish the acceleration state. Defaults to false if unspecified.
        publish_acceleration: true

# Whether to broadcast the transformation over the /tf topic. Defaultsto true if unspecified.
        publish_tf: true

# 1. Set the map_frame, odom_frame, and base_link frames to the appropriate frame names for your system.
#     1a. If your system does not have a map_frame, just remove it, and make sure "world_frame" is set to the value of odom_frame.
# 2. If you are fusing continuous position data such as wheel encoder odometry, visual odometry, or IMU data, set "world_frame"
#    to your odom_frame value. This is the default behavior for robot_localization's state estimation nodes.
# 3. If you are fusing global absolute position data that is subject to discrete jumps (e.g., GPS or position updates from landmark
#    observations) then:
#     3a. Set your "world_frame" to your map_frame value
#     3b. MAKE SURE something else is generating the odom->base_link transform. Note that this can even be another state estimation node
#         from robot_localization! However, that instance should *not* fuse the global data.
        map_frame: map              # Defaults to "map" if unspecified
        odom_frame: odom            # Defaults to "odom" if unspecified
        base_link_frame: base_link  # Defaults to "base_link" ifunspecified
        world_frame: odom           # Defaults to the value ofodom_frame if unspecified

        odom0: demo/odom
        odom0_config: [true,  true,  true,
                       false, false, false,
                       false, false, false,
                       false, false, true,
                       false, false, false]

        imu0: demo/imu
        imu0_config: [false, false, false,
                      true,  true,  true,
                      false, false, false,
                      false, false, false,
                      false, false, false]

在这个配置中,我们定义了``frequency``、two_d_modepublish_accelerationpublish_tfmap_frameodom_frame``base_link_frame``和``world_frame``的参数值。有关您可以修改的其他参数的详细信息,请参阅`状态估计节点的参数 <http://docs.ros.org/en/melodic/api/robot_localization/html/state_estimation_nodes.html#parameters>`_,以及示例``efk.yaml``可以在`这里找到 <https://github.com/cra-ros-pkg/robot_localization/blob/foxy-devel/params/ekf.yaml>`_。

要将传感器输入添加到``ekf_filter_node``,请将序列中的下一个数字添加到其基本名称(odom、imu、pose、twist)。在我们的例子中,我们有一个``nav_msgs/Odometry``和一个``sensor_msgs/Imu``作为滤波器的输入,因此我们使用``odom0``和``imu0``。我们将``odom0``的值设置为``demo/odom``,它是发布``nav_msgs/Odometry``的主题。类似地,我们将``imu0``的值设置为发布``sensor_msgs/Imu``的主题,即``demo/imu``。

您可以使用``_config``参数指定要由滤波器使用的传感器的值。该参数的值的顺序是x、y、z、roll、pitch、yaw、vx、vy、vz、vroll、vpitch、vyaw、ax、ay、az。在我们的例子中,我们将``odom0_config``中除了第1、2、3和12个条目以外的所有条目都设置为``false``,这意味着滤波器只会使用``odom0``的x、y、z和vyaw的值。

在``imu0_config``矩阵中,您会注意到只使用了滚转、俯仰和偏航。典型的移动机器人级别的IMU还会提供角速度和线性加速度。为了使``robot_localization``正常工作,您不应该融合多个彼此有导数关系的字段。由于角速度在IMU内部被融合以提供滚转、俯仰和偏航的估计,我们不应该融合用

参见

有关将输入数据配置为``robot_localization``的更多建议,请参阅`准备用于robot_localization的数据 <http://docs.ros.org/en/melodic/api/robot_localization/html/preparing_sensor_data.html#odometry>`_,以及`配置robot_localization <http://docs.ros.org/en/melodic/api/robot_localization/html/configuring_robot_localization.html>`_。

启动和构建文件

现在,让我们将``ekf_node``添加到启动文件中。打开``launch/display.launch.py``,在``return launch.LaunchDescription([``行之前粘贴以下内容。

robot_localization_node = launch_ros.actions.Node(
       package='robot_localization',
       executable='ekf_node',
       name='ekf_filter_node',
       output='screen',
       parameters=[os.path.join(pkg_share, 'config/ekf.yaml'), {'use_sim_time': LaunchConfiguration('use_sim_time')}]
)

接下来,在``return launch.LaunchDescription([``块中添加以下启动参数。

launch.actions.DeclareLaunchArgument(name='use_sim_time', default_value='True',
                                            description='Flag to enable use_sim_time'),

最后,在``rviz_node``行上方添加``robot_localization_node,``以启动机器人定位节点。

      robot_state_publisher_node,
      spawn_entity,
      robot_localization_node,
      rviz_node
])

接下来,我们需要将``robot_localization``依赖项添加到我们的软件包定义中。打开``package.xml``,并在最后一个``<exec_depend>``标签下面添加以下行。

<exec_depend>robot_localization</exec_depend>

最后,打开``CMakeLists.txt``,并将``config``目录追加到``install(DIRECTORY...)``中,如下面的代码片段所示。

install(
  DIRECTORY src launch rviz config
  DESTINATION share/${PROJECT_NAME}
)

构建、运行和验证

现在让我们构建并运行我们的软件包。导航到项目的根目录并执行以下命令:

colcon build
. install/setup.bash
ros2 launch sam_bot_description display.launch.py

Gazebo和RVIZ应该会启动。在RVIZ窗口中,您应该可以看到``sam_bot``的模型和TF坐标系:

../../_images/rviz.png

接下来,让我们验证系统中是否激活了 odometry/filteredaccel/filtered/tf 主题。打开一个新的终端并执行以下命令:

ros2 topic list

您应该在话题列表中看到``odometry/filtered``,accel/filtered``和/tf``。

您还可以通过执行以下命令再次检查这些主题的订阅者计数:

ros2 topic info /demo/imu
ros2 topic info /demo/odom

您应该看到``/demo/imu``和``/demo/odom``现在各自都有1个订阅者。

要验证 ekf_filter_node 是否是这些主题的订阅者,请执行以下命令:

ros2 node info /ekf_filter_node

您应该看到如下所示的输出。

/ekf_filter_node
Subscribers:
  /demo/imu: sensor_msgs/msg/Imu
  /demo/odom: nav_msgs/msg/Odometry
  /parameter_events: rcl_interfaces/msg/ParameterEvent
  /set_pose: geometry_msgs/msg/PoseWithCovarianceStamped
Publishers:
  /accel/filtered: geometry_msgs/msg/AccelWithCovarianceStamped
  /diagnostics: diagnostic_msgs/msg/DiagnosticArray
  /odometry/filtered: nav_msgs/msg/Odometry
  /parameter_events: rcl_interfaces/msg/ParameterEvent
  /rosout: rcl_interfaces/msg/Log
  /tf: tf2_msgs/msg/TFMessage
Service Servers:
   ...

从上面的输出中,我们可以看到 ekf_filter_node 订阅了 /demo/imu/demo/odom。我们还可以看到 ekf_filter_nodeodometry/filteredaccel/filtered/tf 主题上发布。

您还可以通过使用tf2_echo工具验证``robot_localization``是否发布了``odom`` => ``base_link``的变换。在单独的命令行终端中运行以下命令:

ros2 run tf2_ros tf2_echo odom base_link

您应该看到类似下面所示的连续输出。

At time 8.842000000
- Translation: [0.003, -0.000, 0.127]
- Rotation: in Quaternion [-0.000, 0.092, 0.003, 0.996]
At time 9.842000000
- Translation: [0.002, -0.000, 0.127]
- Rotation: in Quaternion [-0.000, 0.092, 0.003, 0.996]

结论

在本指南中,我们讨论了Nav2从里程计系统所期望的消息和变换。我们已经了解了如何设置里程计系统以及如何验证发布的消息。我们还讨论了如何使用``robot_localization``使用多个里程计传感器提供滤波和平滑的里程计。我们还检查了``robot_localization``是否正确发布了``odom`` => ``base_link``的变换。