5.5. Topics#

Topics are a vital element of the ROS graph that act as a bus for nodes to exchange messages.

../_images/Topic-SinglePublisherandSingleSubscriber1.gif

ROS topics use namespaces to distinguish themselves. For example, in a vehicle running ROS, the positions of each wheel may be organized using the following four topics:

/wheels/front/driver/velocity
/wheels/front/passenger/velocity
/wheels/rear/driver/velocity
/wheels/rear/passenger/velocity

Note

Even when creating a small ROS Graph with only a few nodes, the number of topics tends to grow quickly. Using sensible names for topics will help you (and your colleagues!) understand the intended role of a topic, avoid confusing topics.

For example, while the name /wheels/front/driver/velocity might seem quite large and verbose, it is also very explicit which will help you from accidentally confusing it from the topic containing the velocity of the rear driver.

Don’t mind using long topic names, because even on the CLI you can use TAB-completion to quickly autocomplete the name!

A key thing to realize about topics is that the data they contain is dynamic, meaning it changes constantly. In our vehicle example the velocity of each wheel might be measured one thousand times a second or more. Since the data in a ROS topic is constantly changing, an important distinction for a topic is whether the topic is “creating” or as we like to say in ROS publishing, or if it is reading the data, what we call subscribing to the topic.

Typical ROS nodes subscribe to one set of topics, process that input data, and then publish to another set of topics. A node may publish data to any number of topics, and simultaneously have subscriptions to any number of topics. Likewise, a single topic can be published to by multiple nodes and be subscribed to by multiple nodes. We call this a many-to-many communication model.

../_images/Topic-MultiplePublisherandMultipleSubscriber1.gif

Topics are one of the main ways in which data is moved between nodes and therefore between different parts of the system.

5.5.1. Exploring and using topics from the CLI#

The ros2 topic command provides various sub commands to inspect and use topics from your terminal. To see sub commands and syntax for the ros2 topic command, we’ll run: ros2 topic --help. This command outputs the following:

$ ros2 topic --help
usage: ros2 topic [-h] [--include-hidden-topics]
                  Call `ros2 topic <command> -h` for more detailed usage. ...

Various topic related sub-commands

optional arguments:
  -h, --help            show this help message and exit
  --include-hidden-topics
                        Consider hidden topics as well

Commands:
  bw     Display bandwidth used by topic
  delay  Display delay of topic from timestamp in header
  echo   Output messages from a topic
  find   Output a list of available topics of a given type
  hz     Print the average publishing rate to screen
  info   Print information about a topic
  list   Output a list of available topics
  pub    Publish a message to a topic
  type   Print a topic's type

  Call `ros2 topic <command> -h` for more detailed usage.

There are quite a few sub commands; we won’t discuss all of them, but let’s look closely at a few. Sub commands have their own --help option.

5.5.2. Setup a ROS graph#

Let’s return to our turtlesim example and see if we can use the ROS CLI to understand the topics, publishers, and subscribers.

You should by now be able to run two ROS 2 programs running from the turtlesim package. Start running a turtle_node that opens a turtle simulation, and run a turtle_teleop_key program to make the turtle in turtle_node move around. How are these two programs communicating?

5.5.3. Listing all topics in the ROS graph#

Repeating our command pattern let’s try running ros2 topic list --help.

usage: ros2 topic list [-h] [--spin-time SPIN_TIME] [-t] [-c]
                       [--include-hidden-topics]

Output a list of available topics

optional arguments:
  -h, --help            show this help message and exit
  --spin-time SPIN_TIME
                        Spin time in seconds to wait for discovery (only
                        applies when not using an already running daemon)
  -t, --show-types      Additionally show the topic type
  -c, --count-topics    Only display the number of topics discovered
  --include-hidden-topics
                        Consider hidden topics as well

As indicated at the top of this command help file, ros2 topic list will “Output a list of available topics.”

There appears to be a variety of optional arguments that we don’t need to include if we don’t want to. However, the -t, --show-types line looks interesting. It is worth noting that command arguments, sometimes called flags, can have two types. A short form indicated with a single dash (“-“), and a long form indicated by a double dash (”–“). Don’t worry, despite looking different both versions of the argument do the same thing. Let’s try running this command, sub command pair with the --show-types argument.

$ ros2 topic list --show-types
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim/msg/Color]
/turtle1/pose [turtlesim/msg/Pose]

Tip

You can also simply use the shorthand ros2 topic list -t, as the help information indicated.

On the left hand side we see all of the ROS topics running on the system, each starting with /. We can see that most of them are gathered in the /turtle1/ group. This group defines all the inputs and outputs of the little turtle on our screen. The words in square brackets [] to the right of the topic names define the messages used on the topic. Our car wheel example was simple, we were only publishing velocity, but ROS allows you to publish more complex data structures that are defined by a message type. When we added the --show-types flag we told the command to include this information. We’ll dig into messages in detail a bit later.

5.5.4. Getting more info on a single topic#

One of the more commonly used topic sub commands is info. Unsurprisingly, info provides info about a topic. Let’s peek at its help file using ros2 topic info --help

$ ros2 topic info --help
usage: ros2 topic info [-h] topic_name

Print information about a topic

positional arguments:
  topic_name  Name of the ROS topic to get info (e.g. '/chatter')

optional arguments:
  -h, --help  show this help message and exit

That seems pretty straight forward. Let’s give it a go by running it on /turtle1/pose

$ ros2 topic info /turtle1/pose
Type: turtlesim/msg/Pose
Publisher count: 1
Subscriber count: 1

What does this command tell us?

We can also see that this topic has a single publisher, that is to say a single node generating data on the topic. The topic also has a single subscriber, also called a listener, who is processing the incoming pose data.

Notably, it tells us also the message type for the /turtle1/pose topic, which is turtlesim/msg/Pose. From this we can determine that the message type comes from the turtlesim package and its type is Pose.

5.5.5. The message type of a topic#

A single topic can not be used to send and receive messages of multiple message types, since each topic must have only one associated type. This ensures that all nodes that publish and subscribe to the topic will interpret all transmitted bytes of data in the same manner. You can think of a message type as a simple struct or class to describe structured data in most programming languages.

If we only wanted to know the message type of a topic there is a sub command just for that called type:

$ ros2 topic type /turtle1/pose
turtlesim/msg/Pose

While it is not part of the topic command it is worthwhile for us to jump ahead briefly and look at one particular command/sub-command pair, namely the interface command and the show sub command. Note that the interace command will be discussed in more detail in a later section of the manual. For now it suffices to know that its show sub command will print all the information related to a message type so you can better understand the data being moved over a topic.

In the previous example we saw that the topic type sub command told us the /turtle1/pose topic has a type turtlesim/msg/Pose. So what does turtlesim/msg/Pose data look like? We can inspect the data structure transferred by this topic by running the ros2 interface show sub command and giving the message type name as an input:

$ ros2 interface show turtlesim/msg/Pose
float32 x
float32 y
float32 theta

float32 linear_velocity
float32 angular_velocity

From the output we can see each Pose message contains values x and y, which are the position coordinates of our turtle, and that they are of type float32. theta is the direction the head is pointing. The next two values, linear_velocity and angular_velocity, are how fast the turtle is moving and how quickly it is turning, respectively.

To summarize, this message tells us where a turtle is on the screen, where it is headed, and how fast it is moving or rotating.

5.5.6. Inspecting messages on a topic#

Now that we know what ROS topics are on our simple turtlesim and their message types, we can dig in and find out more about how everything works. If we look back at our topic sub commands, we can see a sub command called echo. Echo is computer jargon that means “repeat” something. If you echo a topic it means you want the CLI to repeat what’s on a topic. Let’s look at the echo sub command’s help text:

$ ros2 topic echo --help
usage: ros2 topic echo [-h]
                       [--qos-profile {system_default,sensor_data,services_default,parameters,parameter_events,action_status_default}]
                       [--qos-reliability {system_default,reliable,best_effort}]
                       [--qos-durability {system_default,transient_local,volatile}]
                       [--csv] [--full-length]
                       [--truncate-length TRUNCATE_LENGTH] [--no-arr]
                       [--no-str]
                       topic_name [message_type]

Output messages from a topic

positional arguments:
  topic_name            Name of the ROS topic to listen to (e.g. '/chatter')
  message_type          Type of the ROS message (e.g. 'std_msgs/String')

optional arguments:
  -h, --help            show this help message and exit
  --qos-profile {system_default,sensor_data,services_default,parameters,parameter_events,action_status_default}
                        Quality of service preset profile to subscribe with
                        (default: sensor_data)
  --qos-reliability {system_default,reliable,best_effort}
                        Quality of service reliability setting to subscribe
                        with (overrides reliability value of --qos-profile
                        option, default: best_effort)
  --qos-durability {system_default,transient_local,volatile}
                        Quality of service durability setting to subscribe
                        with (overrides durability value of --qos-profile
                        option, default: volatile)
  --csv                 Output all recursive fields separated by commas (e.g.
                        for plotting)
  --full-length, -f     Output all elements for arrays, bytes, and string with
                        a length > '--truncate-length', by default they are
                        truncated after '--truncate-length' elements with
                        '...''
  --truncate-length TRUNCATE_LENGTH, -l TRUNCATE_LENGTH
                        The length to truncate arrays, bytes, and string to
                        (default: 128)
  --no-arr              Don't print array fields of messages
  --no-str              Don't print string fields of messages

Wow, that’s a lot of features. The top of the help files says that this CLI program “output[s] messages from a topic.” As we scan the positional arguments we see one required argument, a topic name, and an optional message type. We know the message type is optional because it has square brackets [] around it.

Let’s give the simple case a whirl before we address some of the optional elements.

Tip

Topic names are long and easy to mess up, so use the TAB key to let the command line help you complete the name correctly!

Use the ros2 topic echo <topic-name> syntax to display all the messages being transmitted over this topic:

$ ros2 topic echo /turtle1/pose
x: 5.4078755378723145
y: 7.081490516662598
theta: -1.0670461654663086
linear_velocity: 1.0
angular_velocity: 0.0
---
x: 5.4155988693237305
y: 7.067478179931641
theta: -1.0670461654663086
linear_velocity: 1.0
angular_velocity: 0.0
---
x: 5.423322677612305
y: 7.053465843200684
theta: -1.0670461654663086
linear_velocity: 1.0
angular_velocity: 0.0
---
<<GOING ON FOREVER>>

Warning

As you can see, using topic echo will often print a lot of data, fast. You can use CTRL-C to stop the command and stop all the output. Let’s take a look at the /turtle1/pose topic.

Let’s examine what is going on. Between the dashes (---) is a single ROS message on our topic. If you examine the numbers closely you can see that they are changing and doing so in relation to the movement of the turtle. Going back to our car example you can see how this would be useful for understanding the instantaneous velocity of each of our wheels.

Tip

Now that we have the basics down, we can also look into a few of the optional arguments of ros2 topic echo.

From the --help, we see a variety of commands that start with --qos. “QOS” here means “quality of service” and it is a really cool feature that was added in ROS 2. Without getting too technical, QOS is a way of asking for a certain level of networking robustness. A ROS system can operate over a network, and just like streaming video or video games, packets can get dropped or not get to their destination. The OS settings help you control which packets are the most important and should get the highest priority.

Most of the other commands deal with changing the output format of this CLI program, but there is one in particular that is super handy, and it is also new in ROS 2. The --csv flag stands for “comma separated values” and it a very simple way of defining a spreadsheet. What this argument does is make the topic echo command output data in the comma separate value format. Many command lines allow you send data from the screen to a file, saving the data for later review or analysis. To do this file saving in Linux we use the > character followed by a file name. Below are two examples of using the --csv argument:

$ ros2 topic echo /turtle1/pose --csv
7.097168922424316,8.498645782470703,2.442624092102051,0.0,0.4000000059604645
7.097168922424316,8.498645782470703,2.449024200439453,0.0,0.4000000059604645
...
<<CTRL-C>>
$ ros2 topic echo /turtle1/pose --csv > mydata.csv
<<nothing happens>>
<<CTRL-C>>

The second command above creates a file called mydata.csv. You can look at it using a CLI utility called less (press q to quit), or open it with your favorite spreadsheet tool.

Now that we’ve looked at ros2 topic echo let’s take a look at a few other useful topic sub commands.

5.5.7. Getting basic performance statistics on a topic#

One thing you may have noticed is that topics can output a lot of data! More complex robots, like a self driving car, can saturate a high speed internet connection with how much data it produces. There are two topic sub commands that can be used to diagnose performance issues.

The first sub command is topic hz which is the abbreviation of Hertz, the unit of frequency. The hz sub command will tell you how often a particular topic produces a message.

Similarly there is the topic bw sub command, where bw stands for bandwidth, which is a engineering term related to the volume of data being produced. A high bandwidth connection can move more data, like high definition video, than a low bandwidth data, which might move a radio show.

Let’s take a look at the help for these two commands:

$ ros2 topic hz --help
usage: ros2 topic hz [-h] [--window WINDOW] [--filter EXPR] [--wall-time]
                     topic_name

Print the average publishing rate to screen

positional arguments:
  topic_name            Name of the ROS topic to listen to (e.g. '/chatter')

optional arguments:
  -h, --help            show this help message and exit
  --window WINDOW, -w WINDOW
                        window size, in # of messages, for calculating rate
                        (default: 10000)
  --filter EXPR         only measure messages matching the specified Python
                        expression
  --wall-time           calculates rate using wall time which can be helpful
                        when clock is not published during simulation
$ ros2 topic bw --help
usage: ros2 topic bw [-h] [--window WINDOW] topic

Display bandwidth used by topic

positional arguments:
  topic                 Topic name to monitor for bandwidth utilization

optional arguments:
  -h, --help            show this help message and exit
  --window WINDOW, -w WINDOW
                        window size, in # of messages, for calculating rate
                        (default: 100)

Both bw and hz follow the same pattern: they simply take in a topic name followed by a few optional arguments. The only argument worth noting is the window argument. Both of these commands calculate statistics for a series of messages; how many messages to use in calculating those statistics is the window size. The default value for window is 100, so when you call ros2 topic bw it will first collect 100 messages then use that data to calculate the average message size. Let’s give it a shot (use TAB to complete and CTRL-C to exit).

$ ros2 topic hz /turtle1/pose
average rate: 60.021
	min: 0.001s max: 0.073s std dev: 0.00731s window: 65
average rate: 61.235
	min: 0.001s max: 0.073s std dev: 0.00523s window: 128
$ ros2 topic bw /turtle1/pose
Subscribed to [/turtle1/pose]
average: 1.44KB/s
	mean: 0.02KB/s min: 0.02KB/s max: 0.02KB/s window: 46
average: 1.52KB/s
	mean: 0.02KB/s min: 0.02KB/s max: 0.02KB/s window: 100

As we can see above, the hz command says that the topic is publishing messages at 60.021, where the unit is hz, or 60.021 times a second. Notice that the command gives the publishing frequency as an average, followed by the minimum, maximum, and standard deviation, in seconds. The bw sub command is very similar and we can see that the topic is producing 1.44 kilobytes of data per second.

5.5.8. Publishing a message to a topic using the CLI#

The last sub command for the topic command is pub, which simply means publish. It allows you to publish a command to any ROS topic from the command line. While you shouldn’t need to use this command regularly it can be particularly handy for testing and debugging when you are building a robot system.

The pub sub command has a number of optional arguments that allow you to send one or more messages, and with different quality of service (QoS) presets. The format of the command is ros2 topic pub TOPIC_NAME MESSAGE_TYPE VALUES, which means for it to work successfully you must include a target topic, the topic’s message type, and finally the message’s values. The values for the message are specified in the YAML format and we can use the interface show command to understand the format.

To illustrate the utility of this command we’ll issue a message to rotate and stop our turtle by publishing to the /turtle1/cmd_vel/ topic. Let’s first take a look at the topic pub documentation before we construct our command:

$ ros2 topic pub --help
usage: ros2 topic pub [-h] [-r N] [-p N] [-1] [-n NODE_NAME]
                      [--qos-profile {system_default,sensor_data,services_default,parameters,parameter_events,action_status_default}]
                      [--qos-reliability {system_default,reliable,best_effort}]
                      [--qos-durability {system_default,transient_local,volatile}]
                      topic_name message_type [values]

Publish a message to a topic

positional arguments:
  topic_name            Name of the ROS topic to publish to (e.g. '/chatter')
  message_type          Type of the ROS message (e.g. 'std_msgs/String')
  values                Values to fill the message with in YAML format (e.g.
                        "data: Hello World"), otherwise the message will be
                        published with default values

optional arguments:
  -h, --help            show this help message and exit
  -r N, --rate N        Publishing rate in Hz (default: 1)
  -p N, --print N       Only print every N-th published message (default: 1)
  -1, --once            Publish one message and exit
  -n NODE_NAME, --node-name NODE_NAME
                        Name of the created publishing node
  --qos-profile {system_default,sensor_data,services_default,parameters,parameter_events,action_status_default}
                        Quality of service preset profile to publish with
                        (default: system_default)
  --qos-reliability {system_default,reliable,best_effort}
                        Quality of service reliability setting to publish with
                        (overrides reliability value of --qos-profile option,
                        default: system_default)
  --qos-durability {system_default,transient_local,volatile}
                        Quality of service durability setting to publish with
                        (overrides durability value of --qos-profile option,
                        default: system_default)

Since we want to manually move our turtle we will use the optional --once flag, meaning “publish one message then exit”. It is worth noting that the message type used to command the velocity of the turtle is complex in that it is made up of other message types so we’ll have to query the base message type.

Here’s a rough summary of what we will do:

  • Print the cmd_vel topic type using ros2 topic type, which is geometry_msgs/msg/Twist

  • Determine the structure of the Twist message type using interface show.

  • Determine the structure of the Vector3, which is part of the Twist message type using inteface show command a second time.

  • Create the YAML syntax for our command. Note the YAML syntax below as it is rather tricky! The YAML is wrapped in single quotes and a top level set of curly braces, while subsequent levels follow the pattern of name:value, and name:{name1:val1,name2:val2} for nested types like the Twist command.

  • Issue the command using ros2 topic pub.

$ ros2 topic type /turtle1/cmd_vel
geometry_msgs/msg/Twist
$ ros2 interface show geometry_msgs/msg/Twist
# This expresses velocity in free space broken into its linear and angular parts.

Vector3  linear
Vector3  angular
$ ros2 interface show geometry_msgs/msg/Vector3
# This represents a vector in free space.

float64 x
float64 y
float64 z

$ ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

If you did everything correctly you should have moved around the turtle on the screen, like so:

../_images/pub_once.png

The turtle (and commonly the real robots which it is meant to emulate) require a steady stream of commands to operate continuously. So, to get the turtle to keep moving, you can run:

$ ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"

Note that the difference here is the removal of the --once option and the addition of the --rate 1 option, which tells ros2 topic pub to publish the command in a steady stream at 1 Hz.

../_images/pub_stream.png

5.5.9. Clean up#

At this point you’ll have a lot of nodes running. Don’t forget to stop them by entering Ctrl+C in each terminal.

5.5.10. Summary#

Nodes publish information over topics, which allows any number of other nodes to subscribe to and access that information. In this tutorial you examined the connections between several nodes over topics using rqt_graph and command line tools. You should now have a good idea of how data moves around a ROS 2 system.