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.

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:

  1. stamp, a two-integer time stamp which expresses a moment in time in seconds and nanoseconds;

  2. 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:

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 the header field from the camera image to the header 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!