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

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.

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 usingros2 topic type
, which isgeometry_msgs/msg/Twist
Determine the structure of the
Twist
message type usinginterface show
.Determine the structure of the
Vector3
, which is part of theTwist
message type usinginteface 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
, andname:{name1:val1,name2:val2}
for nested types like theTwist
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:

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.

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.