ROS Filesystem Concepts: Packages | Metapackages | Manifest | msg | srv

For rosbuild, see: rosbuild/msg

ROS uses a simplified messages description language for describing the data values (aka messages) that ROS nodes publish. This description makes it easy for ROS tools to automatically generate source code for the message type in several target languages. Message descriptions are stored in .msg files in the msg/ subdirectory of a ROS package.

There are two parts to a .msg file: fields and constants. Fields are the data that is sent inside of the message. Constants define useful values that can be used to interpret those fields (e.g. enum-like constants for an integer value).

Message types are referred to using package resource names. For example, the file geometry_msgs/msg/Twist.msg is commonly referred to as geometry_msgs/Twist.

Command-line Tools

rosmsg prints out message definition information and can find source files that use a message type.

Message Description Specification

The format of this language is simple: a message description is a list of data field descriptions and constant definitions on separate lines.

Fields

Each field consists of a type and a name, separated by a space, i.e.:

fieldtype1 fieldname1
fieldtype2 fieldname2
fieldtype3 fieldname3

For example:

int32 x
int32 y

Field Types

Field types can be:

  1. a built-in type, such as "float32 pan" or "string name"
  2. names of Message descriptions defined on their own, such as "geometry_msgs/PoseStamped"
  3. fixed- or variable-length arrays (lists) of the above, such as "float32[] ranges" or "Point32[10] points"
  4. the special Header type, which maps to std_msgs/Header

When embedding other Message descriptions, the type name may be relative (e.g. "Point32") if it is in the same package; otherwise it must be the full Message type (e.g. "std_msgs/String"). The only exception to this rule is Header.

NOTE: you must not use the names of built-in types or Header when constructing your own message types.

Built-in types:

Primitive Type

Serialization

C++

Python2

Python3

bool (1)

unsigned 8-bit int

uint8_t (2)

bool

int8

signed 8-bit int

int8_t

int

uint8

unsigned 8-bit int

uint8_t

int (3)

int16

signed 16-bit int

int16_t

int

uint16

unsigned 16-bit int

uint16_t

int

int32

signed 32-bit int

int32_t

int

uint32

unsigned 32-bit int

uint32_t

int

int64

signed 64-bit int

int64_t

long

int

uint64

unsigned 64-bit int

uint64_t

long

int

float32

32-bit IEEE float

float

float

float64

64-bit IEEE float

double

float

string

ascii string (4)

std::string

str

bytes

time

secs/nsecs unsigned 32-bit ints

ros::Time

rospy.Time

duration

secs/nsecs signed 32-bit ints

ros::Duration

rospy.Duration

  1. bool was introduced in ROS 0.9
  2. bool in C++ is aliased to uint8_t because of array types: std::vector<bool> is in fact a specialized form of vector that is not a container. See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2160.html for more information.

  3. uint8 has special meaning in Python. uint8[] is treated as a Python bytes so that it is compatible with other byte-oriented APIs in Python.

  4. unicode strings are currently not supported as a ROS data type. utf-8 should be used to be compatible with ROS string serialization. In python 2, this encoding is automatic for unicode objects, but decoding must be done manually. In python 3, when using str, both encoding and decoding using 'utf-8' in the generated message code.

Deprecated:

  • char: deprecated alias for uint8
  • byte: deprecated alias for int8

Array handling

Array Type

Serialization

C++

Python2

Python3

fixed-length

no extra serialization

0.11+: boost::array<T, length>, otherwise: std::vector<T>

tuple (1)

variable-length

uint32 length prefix

std::vector<T>

tuple (1)

uint8[]

see above

as above

str

bytes (2)

bool[]

see above

std::vector<uint8_t>

list of bool

  1. In rospy, arrays are deserialized as tuples for performance reasons, but you can set fields to tuples and lists interchangeably.

  2. rospy treats uint8[] data as a bytes, which is the Python representation for byte data. In Python 2, this is the same as str.

rospy can also deserialize arrays into numpy data structures. Please consult the rospy documentation for more information.

Field Names

The field name determines how a data value is referenced in the target language. For example, a field called 'pan' would be referenced as 'obj.pan' in Python, assuming that 'obj' is the variable storing the message.

Field names must be translated by message generators to several target languages, so we restrict field names to be an alphabetical character followed by any mixture of alphanumeric and underscores, i.e. [a-zA-Z]\w*. It is recommended that you avoid using field names that correspond to keywords in common languages -- although those names are legal, they create confusion as to how a field name is translated.

ROS provides the special Header type to provide a general mechanism for setting frame IDs for libraries like tf. While Header is not a built-in type (it's defined in std_msgs/msg/Header.msg), it is commonly used and has special semantics. If the first field of your .msg is:

Header header

It will be resolved as std_msgs/Header.

Header.msg:

#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
string frame_id

The special nature of Header is mainly for historical reasons, such as preserving recorded data.

Constants

Each constant definition is like a field description, except that it also assigns a value. This value assignment is indicated by use of an equal '=' sign, e.g.

constanttype1 CONSTANTNAME1=constantvalue1
constanttype2 CONSTANTNAME2=constantvalue2

For example:

int32 X=123
int32 Y=-123
string FOO=foo
string EXAMPLE="#comments" are ignored, and leading and trailing whitespace removed

Notes:

  • With the exception of time and duration, you may declare any built-in type as a constant.

  • string constants are assigned the value of everything to the right of the equals sign, with leading and trailing whitespace removed. As such, you cannot leave a comment on a string constant definition.

  • Integer constants must be specified in decimal (base 10).

Building .msg Files

The ROS Client Libraries implement message generators that translate .msg files into source code. These message generators must be invoked from your build script, though most of the gory details are taken care of by including some common build rules. By convention, all .msg files are stored in a directory within your package called "msg," and you can build all of them by editing the CMakeLists.txt file and the catkin/package.xml file.

Open package.xml, and make sure these two lines are in it:

  <build_depend>message_generation</build_depend>
  <run_depend>message_runtime</run_depend>

Note that at build time, we need "message_generation", while at runtime, we only need "message_runtime".

Open CMakeLists.txt in your favorite text editor (rosed from the previous tutorial is a good option).

Add the message_generation dependency to the find package call which already exists in your CMakeLists.txt so that you can generate messages. You can do this by simply adding message_generation to the list of COMPONENTS such that it looks like this:

# Do not just add this line to your CMakeLists.txt, modify the existing line
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)

You may notice sometimes your project builds fine even if you did not call find_package with all dependencies. This is because catkin combines all your projects into one, so if an earlier project calls find_package, yours is configured with the same values. But forgetting the call means your project can easily break when build in isolation.

Also make sure you export the message runtime dependency.

catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)

Find the following block of code:

# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )

Uncomment it by removing the # symbols and then replace the stand in Message*.msg files with your .msg file, such that it looks like this:

add_message_files(
  FILES
  Num.msg
)

Find the following block of code:

# generate_messages(
#    DEPENDENCIES
#    std_msgs  # Or other packages containing msgs
# )

Uncomment it by removing the # symbols and then replace std_msgs with the messages your messages depend on, such that it looks like this:

 generate_messages(
   DEPENDENCIES
   std_msgs
)

By adding the .msg files manually, we make sure that CMake knows when it has to reconfigure the project after you add other .msg files.

Also see: catkin/CMakeLists.txt#msgs_srvs_actions

Client Library Support

In Python, the generated Python message file (e.g. std_msgs.msg.String) provides nearly all the information you might want about a .msg file. You can examine the __slots__ and _slot_types and other fields to introspect information about messages.

Wiki: msg (last edited 2023-01-31 07:47:25 by DanielBerninghoff)