Skip to content

An Odometry Subscriber Node

The Initial Code

Having copied the subscriber.py file from your part1_pubsub package, you'll start out with the code discussed here.

Let's look at what we need to change now.

From Simple Subscriber to Odom Subscriber

Imports

We will generally rely on rclpy and the Node class from the rclpy.node library, for most nodes that we will create, so our first two imports will remain the same.

We won't be working with String type messages any more however, so we need to replace this line in order to import the correct message type. As we know from earlier in Part 2, the /odom topic uses messages of the type nav_msgs/msg/Odometry:

$ ros2 topic info /odom
Type: nav_msgs/msg/Odometry
...

This tells us everything we need to know to construct the Python import statement correctly:

from nav_msgs.msg import Odometry

We'll also need to import a handy function that should already exist as an importable module in your part2_navigation package called tb3_tools:

from part2_navigation_modules.tb3_tools import quaternion_to_euler

As the name suggests, we'll use this to convert the raw orientation values from /odom into their Euler Angle representation.

Info

This module can be found here: part2_navigation/part2_navigation_modules/tb3_tools.py, if you want to have a look.

Change the Class Name

Previously our class was called SimpleSubscriber(), change this to something more appropriate now, e.g.: OdomSubscriber():

class OdomSubscriber(Node):

Initialising the Class

The structure of this remains largely the same, we just need to modify a few things:

  1. Change the name that is used to register the node on the ROS Network:

    super().__init__("odom_subscriber")
    
  2. Change the subscription parameters:

    self.my_subscriber = self.create_subscription(
        msg_type=Odometry, 
        topic="odom", 
        callback=self.msg_callback, 
        qos_profile=10,
    )
    
  3. The final thing we'll do inside our class' __init__ method (after we've set up the subscriber) is initialise a counter:

    self.counter = 0 
    

    The reason for this will be explained shortly...

Modifying the Message Callback

This is where the changes are a bit more significant:

def msg_callback(self, topic_message: Odometry): 

    pose = topic_message.pose.pose 

    
    pos_x = pose.position.x
    pos_y = pose.position.y
    pos_z = pose.position.z

    roll, pitch, yaw = quaternion_to_euler(pose.orientation) 

    if self.counter > 10: 
        self.counter = 0
        self.get_logger().info(
            f"x = {pos_x:.3f} (m), y = ? (m), theta_z = ? (radians)"
        ) 
    else:
        self.counter += 1

Updating "Main"

The only thing left to do now is update any relevant parts of the main function to ensure that you are instantiating, spinning and shutting down your node correctly.

← Back to Part 2