How to Remap Topics in ROS 2

In this tutorial, we will demonstrate how to remap a topic called /chatter from the command line using ROS 2. 

Remapping topics can be useful in several scenarios, such as avoiding naming conflicts when multiple nodes publish or subscribe to topics with the same name, or integrating third-party packages that use different topic names than your existing system.

We will use the built-in demo_nodes_cpp package, which contains a simple publisher (talker) and subscriber (listener) pair.

 The talker node publishes messages on the /chatter topic, and the listener node subscribes to the /chatter topic.

Prerequisites

  • You have ROS 2 installed.

Command Line

First, open a new terminal and source your ROS 2 installation.

Run the talker node without remapping:

ros2 run demo_nodes_cpp talker

Open another terminal, and run the listener node without remapping:

ros2 run demo_nodes_cpp listener

You should see the listener node receiving messages from the talker node on the /chatter topic.

In a new terminal, run ros2 topic list to see the available topics:

ros2 topic list

You should see the /chatter topic in the list.

1-ros2-topic-list

To verify that the talker node is publishing messages on the /chatter topic, run ros2 topic echo:

ros2 topic echo /chatter
2-ros2-topic-echo

You should see the messages being published by the talker node.

Run ros2 topic info to see the total number of publishers and subscribers for the /chatter topic:

ros2 topic info /chatter

You should see that there is one publisher and one subscriber for the /chatter topic.

3-ros2-topic-info

Now, let’s remap the talker node to publish on a new topic called /conversation.

Stop the talker node using CTRL + C, and type this:

ros2 run demo_nodes_cpp talker --ros-args -r /chatter:=/conversation

Check the listener node terminal. You will notice that it is no longer receiving messages because it is still subscribed to the /chatter topic.

Run ros2 topic list again:

ros2 topic list

You will see the new /conversation topic in the list, but the /chatter topic is no longer present.

4-ros2-topic-list-again

If you run ros2 topic echo /conversation, you will see the messages being published by the talker node on the new topic:

ros2 topic echo /conversation

Run ros2 topic info for the /conversation topic:

ros2 topic info /conversation

You should see that there is one publisher and no subscribers for the /conversation topic.

5-ros2-topic-info

To make the listener node receive messages from the talker node again, we need to remap its subscription from /chatter to /conversation. Stop the listener node (Ctrl+C) and run it with the remapping argument:

ros2 run demo_nodes_cpp listener --ros-args -r /chatter:=/conversation

Now, the listener node will receive messages from the talker node on the remapped /conversation topic.

Run ros2 topic info for the /conversation topic again:

ros2 topic info /conversation

You should now see that there is one publisher and one subscriber for the /conversation topic.

In a Launch File

To remap topics using a launch file in ROS 2, you can use the <remap> tag within the <node> tag.

Create a new launch file called remap_demo.launch.py:

#!/usr/bin/env python3
"""
ROS 2 Topic Remapping Launch File.

This launch file demonstrates how to remap topics in ROS 2 by launching a talker and listener
node pair with remapped topic names. It shows how to change the default topic '/chatter'
to '/conversation' for both nodes.

Launch File Nodes:
    * talker_node (demo_nodes_cpp/talker): Publishes messages on remapped topic
    * listener_node (demo_nodes_cpp/listener): Subscribes to messages on remapped topic

Topic Remappings:
    * /chatter -> /conversation: Remaps the default topic to a new name for both nodes

Example Usage:
    $ ros2 launch your_package remap_demo.launch.py

:author: Addison Sears-Collins
:date: November 26, 2024
"""

# Import the necessary ROS 2 launch modules
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    """
    Generate a launch description for topic remapping demonstration.

    This function creates and returns a LaunchDescription object that specifies how
    to launch and configure the talker and listener nodes with topic remapping.

    Returns
    -------
    LaunchDescription
        A launch description object containing the configured nodes
    """
    return LaunchDescription([
        # Create and configure the talker node
        # This node will publish messages on the remapped topic '/conversation'
        Node(
            package='demo_nodes_cpp',      # The package containing the node
            executable='talker',           # The name of the executable
            name='talker_node',           # A unique name for this node instance
            remappings=[
                # Remap the default '/chatter' topic to '/conversation'
                ('/chatter', '/conversation'),
            ],
            output='screen'               # Display node output in the terminal
        ),

        # Create and configure the listener node
        # This node will subscribe to messages on the remapped topic '/conversation'
        Node(
            package='demo_nodes_cpp',      # The package containing the node
            executable='listener',         # The name of the executable
            name='listener_node',         # A unique name for this node instance
            remappings=[
                # Remap the default '/chatter' topic to '/conversation'
                # This must match the talker's remapping to receive messages
                ('/chatter', '/conversation'),
            ],
            output='screen'               # Display node output in the terminal
        ),
    ])

In this launch file, we define two nodes: talker and listener. For each node, we specify the package, executable, and name. We also use the remappings parameter to remap the /chatter topic to /conversation for both nodes.

To run the launch file, open a new terminal, source your ROS 2 installation, and navigate to the package containing the remap_demo.launch.py file. Then, run the following command:

ros2 launch remap_demo.launch.py

You should see both the talker and listener nodes running, with the talker node publishing messages on the /conversation topic and the listener node subscribing to the /conversation topic.

In a new terminal, run ros2 topic list to see the available topics:

ros2 topic list

You should see the /conversation topic in the list.

To verify that the talker node is publishing messages on the /conversation topic, run ros2 topic echo:

ros2 topic echo /conversation

You should see the messages being published by the talker node.

Run ros2 topic info for the /conversation topic:

ros2 topic info /conversation
7-conversation-topic-launch

You should see that there is one publisher and one subscriber for the /conversation topic.

6-one-publisher-one-subcriber

Using a launch file to remap topics has several advantages:

  1. It allows you to centralize the configuration of your nodes and their remappings in a single file.
  2. It makes it easier to manage complex systems with multiple nodes and remappings.
  3. It enables you to create reusable launch files that can be shared across different projects or with other users.

That’s it! Keep building!

How to Run ROS 2 on Multiple Machines

In this tutorial, we will learn how to run ROS 2 on different machines using the ROS_DOMAIN_ID environment variable. 

We will use the built-in demo_nodes_cpp package as an example, running the talker node on one machine to broadcast “Hello World” messages over a topic called /chatter. We will run the listener node on another machine.

Prerequisites

  • You have ROS 2 installed on multiple computers.

Directions

First, ensure both computers are on the same network.

  • Connect both machines to the same WiFi network or connect them using an Ethernet cable.

We will now set the ROS_DOMAIN_ID on the first machine. 

The ROS_DOMAIN_ID is like a unique channel number that allows ROS 2 nodes to communicate with each other when they are set to the same value, preventing interference from other ROS 2 systems on the same network. The default ROS_DOMAIN_ID is 0, and safe values range from 0 to 101, inclusive.

Open a terminal on the first machine.

Set the ROS_DOMAIN_ID to a valid integer value, e.g., 5:

export ROS_DOMAIN_ID=5

Run the talker node:

ros2 run demo_nodes_cpp talker
1-demo-nodes-cpp-talker-ros2

Set the ROS_DOMAIN_ID on the second machine (listener).

Open a terminal on the second machine.

Set the ROS_DOMAIN_ID to the same value as the first machine:

export ROS_DOMAIN_ID=5

Run the listener node:

ros2 run demo_nodes_cpp listener

Observe the communication. The listener node on the second machine should receive messages from the talker node on the first machine.

2-demo-nodes-listener-other-machine

Press CTRL + C on the second machine (the one with the listener node).

Experiment with different ROS_DOMAIN_ID values.

Set a different ROS_DOMAIN_ID on the second machine, e.g., 8:

export ROS_DOMAIN_ID=8

Run the listener node again:

ros2 run demo_nodes_cpp listener

Observe that the listener node no longer receives messages from the talker node because they are on different ROS domains.

3-nothing-received

Make the ROS_DOMAIN_ID change permanent

Open the .bashrc file in a text editor:

gedit ~/.bashrc

Add the following line at the end of the file:

export ROS_DOMAIN_ID=5

Save the file and exit the text editor.

Source the .bashrc file or open a new terminal for the changes to take effect:

source ~/.bashrc

You can now rerun the listener.

ros2 run demo_nodes_cpp listener

Everything is working again.

By following these steps, you can run ROS 2 nodes on different machines using the ROS_DOMAIN_ID environment variable to ensure they communicate on the same ROS domain.

That’s it! Keep building!

Coordinate Frame Basics and the Right-Hand Rule of Robotics

Welcome to this tutorial on three-dimensional coordinate frames for robots. Understanding 3D coordinate frames is essential for robots to determine their position and navigate the world effectively. Whether it’s picking up an item, avoiding obstacles, or moving around a room, robots rely on these frames to plan their movements with precision.

The Coordinate Axes

1-coordinate-frames-axes

A 3D coordinate frame consists of three perpendicular axes that intersect at a common point called the origin. Each axis is typically represented by a different color for easy identification:

  • X-axis (red): Points forward.
  • Y-axis (green): Points to the left.
  • Z-axis (blue): Points upward.

Think of these axes as directions in space that help describe any position or movement. 

The Right-Hand Rule

2-right-hand-rule-of-robotics

To remember the orientation of the coordinate axes, use the right-hand rule:

  1. Hold out your right hand with your thumb, index finger, and middle finger all perpendicular to each other.
  2. Assign your fingers to the axes:
    • Index Finger: Points along the positive x-axis (forward).
    • Middle Finger: Points along the positive y-axis (left).
    • Thumb: Points along the positive z-axis (upward).

Understanding Rotation: Roll, Pitch, and Yaw

The right-hand rule helps us understand the basic orientation of our coordinate frame, but robots need to do more than just move along straight lines. They also need to rotate and change their orientation in space. This brings us to three fundamental types of rotation: roll, pitch, and yaw. Remember those terms…roll, pitch, and yaw.

Let’s relate these terms to head movements:

roll-pitch-yaw
  • Roll (rotation around the x-axis) is like tilting your head from side to side, as if you’re touching your ear to your shoulder.
  • Pitch (rotation around the y-axis) is like nodding your head up and down.
  • Yaw (rotation around the z-axis) is like shaking your head ‘no’.

Now let’s relate these to the right-hand rule:

  • Rotate your hand as if turning a doorknob. That is roll.
  • Rotate your hand up and down, as if nodding your head “yes.” That is pitch
  • Rotate your hand left and right, as if shaking your head “no.”. That is yaw.

Coordinate Frame Hierarchy

Now that we understand how individual coordinate frames work and how objects can rotate within them, let’s explore how robots use multiple coordinate frames together. This system of related frames, known as a coordinate frame hierarchy, is important for robots to understand their place in the world and how their parts relate to each other.

World Coordinate Frame

3-world-coordinate-frame

The world coordinate frame, which can often be referred to as the map frame, serves as the fixed, global reference point for all robots and objects in a given environment. It never moves or changes, providing a stable point of reference. This frame is often placed at a convenient location, such as the center of a room’s floor or the battery charging station.

Think of the world frame as the “ground truth” of the environment. All other coordinate frames are ultimately referenced back to this frame, allowing different robots and sensors to understand each other’s positions and coordinate actions.

Robot-Specific Frames

Base Frame

5-base-frame

The base frame is attached to the robot’s base or body and moves with the robot as it navigates. 

For mobile robots, the base frame changes position relative to the world frame as the robot moves around.

For robotic arms, the base frame is typically fixed at the bottom/mount point of the arm. This fixed base frame serves as the primary reference point for all joint movements and gripper positions.

Sensor Frames 

6-sensor-frame

Think of sensor frames like the eyes and ears of the robot. Each camera, distance sensor, or touch sensor has its own frame (i.e. x, y, and z axis) that tells the robot what that sensor can “see” or “feel” from its specific location on the robot.

Joint Frames 

7-joint-frame

For robots with arms or moving parts, each joint (like your elbow or wrist) has its own frame. These frames help the robot know how each joint is bent or twisted.

End-Effector Frame

8-end-effector-frame

This is like the robot’s “hand” – it’s the frame at the very end of a robotic arm where tools or grippers are attached. When a robot needs to pick something up or use a tool, it uses this frame to know exactly where its “hand” is.

Frame Relationships

Understanding the relationships between different frames is key to controlling a robot’s movements and interpreting its sensor data.

For example, imagine you want a robotic arm to pick up a ball on a table. The arm’s movements are defined in its local frame, but the ball’s position is given in the world (map) frame. By transforming the ball’s world coordinates into the arm’s frame, the robot can accurately reach and grasp it.

Practical Example

Consider a self-driving car:

  • The car’s starting position is the origin of its coordinate frame.
  • Moving forward means it’s traveling in the positive x direction.
  • Turning left or right involves rotation around the z-axis, which is its yaw movement.
  • If the car moves sideways, that’s along the y-axis.
  • If the car could jump (imagine it could), that would be along the z-axis.

Make Sure You Understand Coordinate Frames

Coordinate frames form the foundation of a robot’s spatial understanding. By maintaining clear relationships between different frames—such as the world (map) frame, robot base frame, sensor frames, and manipulator frames—robots can effectively plan and execute complex tasks.

By understanding 3D coordinate frames, you’ll be better equipped to program and control robots, whether you’re working on simple projects or advanced robotic systems. 

To learn more about common coordinate frames specific to ROS 2 mobile robots, check out this tutorial.

That’s it. Keep building!