Skip to content

Part 2 Odometry Explained

Tom Howard edited this page Jul 7, 2021 · 1 revision

The nav_msgs/Odometry message

We can find out about Odometry messages by running the rosmsg info command:

$ rosmsg info nav_msgs/Odometry

Odometry messages are part of the nav_msgs library, hence the nav_msgs/Odometry syntax in the command above. The output of this command is illustrated in the figure below:

Like all ROS messages, Odometry messages have a nested structure, where in this case we have 4 base elements (each with different content):

  • header
    • seq
    • stamp
    • frame_id
  • child_frame_id
  • pose
    • pose
      • position
        • x
        • y
        • z
      • orientation
        • x
        • y
        • z
        • w
    • covariance
  • twist
    • twist
      • linear
        • x
        • y
        • z
      • angular
        • x
        • y
        • z
    • covariance

As shown in the figure, the rosmsg info command provides the element name after the element type. Elements in red are types of ROS message (which is apparent due to the two-part format separated by a forward slash /). The element name then follows this (as shown in green).

Where the line doesn't start with a ROS message type, then this is an actual variable (i.e. data), and these lines are structured with the data type (as shown in blue) followed by the variable name (in purple).

To access a variable from a message in Python you must correctly define the full path to it within the structure of the whole ROS message. Three examples of this are provided in the figure to illustrate how this applies to the Odometry message type specifically.

Building Python Nodes to Work with Odometry

First, you will need to import the Odometry message type from the nav_msgs package:

from nav_msgs.msg import Odometry

When you set up a rospy.Subscriber you need to tell it the name of the topic that the odometry data is being published to, and you also need to then supply the Odometry message type that you have just imported, so that the rospy.Subscriber knows how to process the topic data.

subscriber_object = rospy.Subscriber("[odometry topic]", Odometry, callback_function)

In addition to this you also need to supply the name of a function that must be defined earlier in the Python code and which does something with the message data. In this case, we point it to a function called callback_function.

The callback_function is the function within which you will process the odometry data:

def callback_function(odom_data):

The function can take only one input parameter, in this case we are calling it odom_data. This is where the rospy.Subscriber instance that we set up earlier will put the data that it obtains from the "[odometry topic]" whenever new topic data is published.

Note: If you are building this within a Python Class (like we did in the subscriber example from Part 1), then don't forget to include a self parameter before the odom_data input. This is an essential part of a class instance method, and the function itself still has only one real input parameter for the rospy.Subscriber instance to use:

class a_python_class:
    def callback_function(self, odom_data):
Obtaining the message data

Within the callback function we then obtain the message data from the odom_data input parameter. As an example, we can obtain the linear position of our robot in the x axis by walking through the nested structure of the message (as shown in the figure), separating the element names with dots. In this example, the odom_data.pose.pose.position.x portion of the message is assigned to the variable linear_x:

linear_x = odom_data.pose.pose.position.x

Note: In your code, you will need to define the callback function before you define the rospy.Subscriber instance, otherwise you will get an error. See the Part 1 Subscriber Example for further guidance.