This section will focus on integrating a robot odometry system with Nav2. First, we are going to provide a brief introduction to odometry, plus the necessary messages and transforms that need to be published for NAV2 to function correctly.
Odometry is typically generated from a variety of sources and fused together using the robot_localization
package. Some of these sources include wheel encoders, visual odometry (RTABMAP
), and dead reckoning from an IMU. These sources are combined to create an odom
frame. A transform from the odom
frame to the base_footprint
frame is then created using the robot_localization
package.
The odometry system provides a locally accurate estimate of a robot’s pose and velocity based on its motion. The odometry information can be obtained from various sources such as IMU, LIDAR, RADAR, VIO, and wheel encoders. One thing to note is that IMUs drift over time while wheel encoders drift over the distance traveled, thus they are often used together to counter each other’s negative characteristics.
The odom
frame and the transformation associated with its use a robot’s odometry system to publish localization information that is continuous but becomes less accurate over time or distance. In order to gain consistently accurate odometry information, a map
frame provides globally accurate information that corrects the odom
frame.
Odometry is published using the nav_msgs/Odometry
message type. The content of that message is shown below:
# 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
For simulated robots, using Gazebo plugins for robot odometry is the simplest and most easily implemented route.
In order for Gazebo odometry to work, all links defined in your URDF
must have associated inertial
tags. There are Gazebo plugins for both differential drive robots and Ackermann steering robots. For the differential drive robot, the odometry is created using the same plugin that controls the movement of the robot. For the Ackermann robot, certain configurations have to be set such that the plugin will publish the odometry but not the wheel tf
transforms.
First, ensure that the gazebo_ros_pkgs
package is installed.
sudo apt install ros-humble-gazebo-ros-pkgs
This should already be satisfied from robot dependencies but is a good check.
Next, we have to set up the Gazebo plugins that output the wheel odometry.
Adding wheel odometry is robot geometry dependent. Let's look to add the odometry to a differential drive robot. Using the Tracer robot as an example, add the following lines of code to your robot XACRO, here I got tracer_gazebo.xacro
.
cd ~/humble_ws/src/tracer/tracer_description/models/xacro
gedit tracer_gazebo.xacro
<aside> ⚠️ Some of these lines will already exist from calling on the differential drive control plugin, ensure that the plugin tags all match.
</aside>
<gazebo>
<plugin name="gazebo_ros_diff_drive" filename="libgazebo_ros_diff_drive.so">
<ros>
<namespace>${robot_namespace}</namespace>
</ros>
<!-- Update rate in Hz -->
<update_rate>50</update_rate>
<!-- wheels -->
<left_joint>left_wheel_joint</left_joint>
<right_joint>right_wheel_joint</right_joint>
<!-- kinematics -->
<wheel_separation>${wheelbase}</wheel_separation>
<wheel_diameter>${2*wheel_radius}</wheel_diameter>
<!-- limits -->
<max_wheel_torque>20</max_wheel_torque>
<max_wheel_acceleration>1.0</max_wheel_acceleration>
<!-- input -->
<command_topic>cmd_vel</command_topic>
<!-- output -->
<publish_odom>true</publish_odom>
<publish_odom_tf>false</publish_odom_tf>
<publish_wheel_tf>true</publish_wheel_tf>
<odometry_topic>wheel_odom</odometry_topic>
<odometry_frame>odom</odometry_frame>
<robot_base_frame>base_footprint</robot_base_frame>
</plugin>