5.7. Message types#
As you’ve already seen in several examples, ROS provides standardized data formats for its messages so that different nodes, potentially written in different programming languages and by different developers, can all talk to one another.
You can think of messages as structured data which assign specific values to specific fields.
Each message belongs to a message type which fully specifies which fields can/must be used in the message.
Note that each field has a type as well, which can be a simple primitive (uint32
for 32-bit integer, string
for strings of text, etc.), but also a different message type (e.g., std_msgs/msg/Header
).
This way, more complex messages can be composed of simpler messages.
If you are familiar with object oriented programming in many programming languages, a helpful analogy may be that message types are “classes” or “structs” that define the fields, where as messages are “objects” or “instances” that assign actual values to those fields.
Note
The fact that ROS messages provide a standardized interface for common types of information is one of the key strengths of ROS! Using standardized messages ensures that nodes from different development teams can interoperate.
To make this all work, ROS uses standard messages, and communication protocols built on top of those standard messages. Since there are many built-in messages, being able to find type information about a particular message, service, or action is key when developing and debugging your ROS system.
Warning
While it is possible for developers to design their own custom message types for specific use cases, you should try to avoid this as much as possible! If there is a suitable standard message type that does the job, just use that one! This will ensure interoperability with other nodes from other packages by other developers.
5.7.1. Inspecting message types from the CLI#
To help developers write both CLI command calls and develop client
code, the ROS CLI has the ros2 interface
command. We’ve touched on this command
briefly in other sections, as it is the go to tool for message type
information.
To better understand the interface
command let’s start by looking at its high
level help command to see what sub commands are available:
$ ros2 interface --help
usage: ros2 interface [-h]
Call `ros2 interface <command> -h` for more detailed
usage. ...
Show information about ROS interfaces
optional arguments:
-h, --help show this help message and exit
Commands:
list List all interface types available
package Output a list of available interface types within one package
packages Output a list of packages that provide interfaces
proto Output an interface prototype
show Output the interface definition
Call `ros2 interface <command> -h` for more detailed usage.
The interface command is all geared towards helping you understand
available message types. Let’s examine the list
sub command in depth. list
will list all of the available messages, services, and actions on your
system. This command has flags that can help you narrow down the scope of your
search. Even a basic ROS installation has a lot of messages, so a tool you
should get familiar with is grep
. grep
lets you search through some text to
find what you are looking for quickly and easily. You can grep in a case
insensitive manner using the -i
flag followed by the text you want to search
for. We can tie this CLI tool to our interface tool by using the UNIX pipe operator |
. The example below
shows you how to use the list operation and then how to use it to search:
$ ros2 interface list --only-msgs
Messages:
action_msgs/msg/GoalInfo
action_msgs/msg/GoalStatus
... <DOZENS OF DIFFERENT TYPES> ...
visualization_msgs/msg/MarkerArray
visualization_msgs/msg/MenuEntry
$ ros2 interface list --only-msgs | grep -i point
geometry_msgs/msg/Point
geometry_msgs/msg/Point32
geometry_msgs/msg/PointStamped
map_msgs/msg/PointCloud2Update
pcl_msgs/msg/PointIndices
rcl_interfaces/msg/FloatingPointRange
sensor_msgs/msg/PointCloud
sensor_msgs/msg/PointCloud2
sensor_msgs/msg/PointField
trajectory_msgs/msg/JointTrajectoryPoint
Using grep to search through CLI output is a common tactic used by developers to find just the specific information they need.
For example, the two sub commands package
(no s
) and packages
can be used to first determine what ROS packages are on
your system that define message types, and then to drill down into an individual package to determine what
messages are in that package.
$ ros2 interface packages
action_msgs
action_tutorials_interfaces
actionlib_msgs
builtin_interfaces
composition_interfaces
diagnostic_msgs
example_interfaces
geometry_msgs
lifecycle_msgs
logging_demo
map_msgs
nav_msgs
pcl_msgs
pendulum_msgs
rcl_interfaces
rosgraph_msgs
rqt_py_common
sensor_msgs
shape_msgs
std_msgs
std_srvs
stereo_msgs
tf2_msgs
trajectory_msgs
turtlesim
unique_identifier_msgs
visualization_msgs
Afterwards, use grep
just like before to search for your specific interest. The
example below shows you how to first determine if std_msgs
is installed and
then to find out what sort of array types it contains:
$ ros2 interface package std_msgs | grep -i array
std_msgs/msg/Int8MultiArray
std_msgs/msg/Int32MultiArray
std_msgs/msg/MultiArrayLayout
std_msgs/msg/UInt64MultiArray
std_msgs/msg/Float32MultiArray
std_msgs/msg/UInt16MultiArray
std_msgs/msg/UInt32MultiArray
std_msgs/msg/Int16MultiArray
std_msgs/msg/ByteMultiArray
std_msgs/msg/Int64MultiArray
std_msgs/msg/Float64MultiArray
std_msgs/msg/UInt8MultiArray
std_msgs/msg/MultiArrayDimension
Note
As you can see, there are already many different message types defined in ROS, divided over dozens of packages! Some packages provide messages for a very specific robotic component that your particular robot may or may not need to use.
For example, the stereo_msgs
package defines message types (and nodes) needed for operating a stereo camera (so basically two cameras that can be used to perceive depth).
A few packages on the other hand provide very generic and fundamental messages, which are often used by other packages to construct more complex messages.
For instance, geometry_msgs
provides interfaces for concepts related to physical 3D space, such as Pose
, Vector3
, Quaternion
and Twist
.
The std_msgs
package provide messages for many simple data types.
API reference of messages in the
std_msgs
packageAPI reference of messages in the
geometry_msgs
package
5.7.2. Inspecting the definition of a message type#
The next two commands are particularly helpful and you should remember them as they will make your life much easier. As we have discussed previously all message publication, service calls, and action calls in the CLI take in both the message type and data you want to transmit in YAML format.
But what if you don’t know the message format, and you don’t know a lot about YAML?
The interface show
and interface proto
commands make this process
easier by respectively telling you first the message type and then the message
format. Recall earlier in the chapter when we called the spawn
service on
our turtle simulation. We can use interface show
to tell us broadly about the
service and what each of the values mean. We can then use interface proto
,
short for prototype, to generate an empty message that we can fill
out. See the example below:
$ ros2 interface show turtlesim/srv/Spawn
float32 x
float32 y
float32 theta
string name # Optional. A unique name will be created and returned if this is empty
---
string name
$ ros2 interface proto turtlesim/srv/Spawn
"x: 0.0
y: 0.0
theta: 0.0
name: ''
"
$ ros2 service call /spawn turtlesim/srv/Spawn "{<copy and paste proto here>}"
You can see from the example above how handy these tools can be.
It is worth noting that you need to paste the prototype into a set of quotes and curly
braces for the call to work "{<prototype>}"
.
Tip
Don’t forget that you can often also “google” standard ROS message types. Since ROS message types tend to not change between versions (to avoid breaking everybody’s code), usually the online message documentation accurately reflect the message definition on your ROS installation.
If you want to be sure though, use the ros2 interface
command as you learned above.
For example, if you search online for “ROS camera message”,
you will probably quickly find the definition of the sensor_msgs/msg/Image
message type,
which includes some comments on the meaning of the specific fields.
E.g., width
and height
encode the image dimensions.
5.7.3. What units are used for the values in messages?#
While ROS interfaces do define the data type of each field in a message type, such as float32
for a 32-bit floating point value,
this does not tell you what units to use.
Warning
Inconsistency in units and conventions is a common source of integration issues for developers and can also lead to software bugs. It can also create unnecessary computation due to data conversion.
If you create your own nodes in the future, you would want to remain compatible with other nodes that publish or subscribe to the same message type.
If your node message is expected to define its units in meters
, your node’s code should not set those values as centimeters
or kilometers
!
In general, like most scientific literature, ROS uses the metric system as defined by the International System Of Units (SI). So, “meters”, “seconds”, “kilograms”, ampere”, etc. Angles are typically in “radians” (not “degrees”!), but temperature in “Celsius”. You can check REP 0103 - Standard Units of Measure and Coordinate Conventions, the reference for the units and coordinate conventions used within ROS.
Note
REP stands for ROS Enhancement Proposal, and are design documents used by the core ROS development community to discuss conventions and system designs. You can find an overview of REPs in the online Index of REPs.
5.7.4. The std_msgs/msg/Header
message#
A very important message in the std_msgs
package is the std_msgs/msg/Header
message.
If we look at the online ROS 2 documentation of this message,
we can see it has only two fields:
stamp
, a two-integer time stamp which expresses a moment in time in seconds and nanoseconds;frame_id
, a simple string that indicates a spatial “transformation frame”.
While this message type is almost never directly used for a topic,
it is often included in other message types as the very first field with the name header
.
The header provides standard metadata for higher-level stamped data types. The two fields together are used to communicate timestamped data in a particular physical coordinate frame.
For instance, if you look through the message types in the sensor_msgs
package,
you can find the std_msgs/msg/Header
message as a header
field in all message related to sensor data.
For example, you can find a header
field in:
sensor_msgs/msg/PointCloud2
for points cloud data, for example from a LiDAR scanner,sensor_msgs/msg/Image
, which contains a camera image,but also
sensor_msgs/msg/Temperature
.
All of these messages are in one way or another physical measurements, and this represents some physical observation at particular spatial location (indicated by the header’s frame_id
) and at a particular moment in time (indicated by the stamp
field).
But std_msgs/msg/Header
is also used by many other message types, because these describe information that is often computed on basis of the such sensor information.
For such information that describes some (derived) information about the physical world it is also necessary to keep track of the physical location and time from which this information originates.
Note
For example, let’s say your robot has a camera and uses its images to detect an object its needs to grasp and therefore has a node to estimate the objects pose. The node that does the pose estimation from the image should then:
subscribe to a
sensor_msgs/msg/Image
message to receive a camera image, which contains a header describing the camera’s physical location (frame_id
) and the moment when the image was captured (stamp
).publish a
geometry_msgs/msg/PoseStamped
containing the 3D pose of the detected object in the image. It can copy the values of theheader
field from the camera image to theheader
field of the produced pose, such that any later node using that information will know how old this information was, and relative to what camera location the spatial coordinates are expressed!
As you can hopefully see, having the stds_msgs/msg/Header
metadata unified across many different composite message types simplifies the design of code, and reduces the chance of errors!