# Introduction to msg and srv interfaces¶

INCOMPLETE: this is a draft of an upcoming tutorial for creating and using custom ROS interfaces.

Disclaimer: The code provided is to support the explanation, it is likely outdated and should not be expected to compile as is

• msg: msg files are simple text files that describe the fields of a ROS message. They are used to generate source code for messages in different languages.

• srv: an srv file describes a service. It is composed of two parts: a request and a response. The request and response are message declarations.

msgs are just simple text files with a field type and field name per line. The field types you can use are:

• int8, int16, int32, int64 (plus uint*)

• float32, float64

• string

• other msg files

• variable-length array[], fixed-length array[C], bounded-length array[<=C]

Here is an example of a msg that uses a string primitive, and two other msgs:

string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist


srv files are just like msg files, except they contain two parts: a request and a response. The two parts are separated by a ‘—’ line. Here is an example of a srv file:

float64 A
float64 B
---
float64 Sum


In the above example, A and B are the request, and Sum is the response.

msg files are stored in the msg directory of a package, and srv files are stored in the srv directory.

## Creating a msg package¶

NOTE: only ament_cmake packages can generate messages currently (not ament_python packages).

For this tutorial we will use the packages stored in the rosidl_tutorials repository.

cd ~/ros2_overlway_ws/src
git clone -b rosidl_tutorials https://github.com/ros2/tutorials.git
cd rosidl_tutorials/rosidl_tutorials_msgs


### Creating a msg file¶

Here we will create a message meant to carry information about an individual.

Open msg/Contact.msg and you will see:

bool FEMALE=true
bool MALE=false

string first_name
string last_name
bool gender
uint8 age


This message is composed of 5 fields:

• first_name: of type string

• last_name: of type string

• gender: of type bool, that can be either MALE or FEMALE

• age: of type uint8

There’s one more step, though. We need to make sure that the msg files are turned into source code for C++, Python, and other languages.

### Building msg files¶

Open the package.xml, and make sure it contains the following lines:

<buildtool_depend>rosidl_default_generators</buildtool_depend>

<exec_depend>rosidl_default_runtime</exec_depend>

<member_of_group>rosidl_interface_packages</member_of_group>


Note that at build time, we need “rosidl_default_generators”, while at runtime, we only need “rosidl_default_runtime”.

Open the CMakeLists.txt and make sure that the following lines are uncommented.

Find the package that generates message code from msg/srv files:

find_package(rosidl_default_generators REQUIRED)


Declare the list of messages you want to generate:

set(msg_files
"msg/Contact.msg"
)


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.

Generate the messages:

rosidl_generate_interfaces(${PROJECT_NAME}${msg_files}
)


Also make sure you export the message runtime dependency:

ament_export_dependencies(rosidl_default_runtime)


### Creating an srv file¶

We will now add a srv declaration to our package.

Open the srv/AddTwoFloats.srv file and paste this srv declaration:

float64 a
float64 b
---
float64 sum


### Building srv files¶

Declare the service in the CMakeLists.txt:

set(srv_files


Modify the existing call to rosidl_generate_interfaces to generate the service in addition to the messages:

rosidl_generate_interfaces(${PROJECT_NAME}${msg_files}
${msg_files} DEPENDENCIES rosidl_tutorials_msgs )  Now we can start writing code that uses this message. Open src/publish_address_book.cpp: #include <iostream> #include <memory> #include "rclcpp/rclcpp.hpp" #include "rosidl_tutorials/msg/address_book.hpp" #include "rosidl_tutorials_msgs/msg/contact.hpp" using namespace std::chrono_literals; class AddressBookPublisher : public rclcpp::Node { public: AddressBookPublisher() : Node("address_book_publisher") { address_book_publisher_ = this->create_publisher<rosidl_tutorials::msg::AddressBook>("address_book"); auto publish_msg = [this]() -> void { auto msg = std::make_shared<rosidl_tutorials::msg::AddressBook>(); { rosidl_tutorials_msgs::msg::Contact contact; contact.first_name = "John"; contact.last_name = "Doe"; contact.age = 30; contact.gender = contact.MALE; contact.address = "unknown"; msg->address_book.push_back(contact); } { rosidl_tutorials_msgs::msg::Contact contact; contact.first_name = "Jane"; contact.last_name = "Doe"; contact.age = 20; contact.gender = contact.FEMALE; contact.address = "unknown"; msg->address_book.push_back(contact); } std::cout << "Publishing address book:" << std::endl; for (auto contact : msg->address_book) { std::cout << "First:" << contact.first_name << " Last:" << contact.last_name << std::endl; } address_book_publisher_->publish(msg); }; timer_ = this->create_wall_timer(1s, publish_msg); } private: rclcpp::Publisher<rosidl_tutorials::msg::AddressBook>::SharedPtr address_book_publisher_; rclcpp::timer::TimerBase::SharedPtr timer_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto publisher_node = std::make_shared<AddressBookPublisher>(); rclcpp::spin(publisher_node); return 0; }  #### The code explained¶ #include "rosidl_tutorials/msg/address_book.hpp"  We include the header of our newly created AddressBook msg. #include "rosidl_tutorials_msgs/msg/contact.hpp"  Here we include the header of the Contact msg in order to be able to add contacts to our address_book. using namespace std::chrono_literals; class AddressBookPublisher : public rclcpp::Node { public: AddressBookPublisher() : Node("address_book_publisher") { address_book_publisher_ = this->create_publisher<rosidl_tutorials::msg::AddressBook>("address_book");  We create a node and an AddressBook publisher. auto publish_msg = [this]() -> void {  We create a callback to publish the messages periodically auto msg = std::make_shared<rosidl_tutorials::msg::AddressBook>();  We create an AddressBook message instance that we will later publish. { rosidl_tutorials_msgs::msg::Contact contact; contact.first_name = "John"; contact.last_name = "Doe"; contact.age = 30; contact.gender = contact.MALE; contact.address = "unknown"; msg->address_book.push_back(person); } { rosidl_tutorials_msgs::msg::Contact person; contact.first_name = "Jane"; contact.last_name = "Doe"; contact.age = 20; contact.gender = contact.FEMALE; contact.address = "unknown"; msg->address_book.push_back(contact); }  We create and populate Contact messages and add them to our address_book message. std::cout << "Publishing address book:" << std::endl; for (auto contact : msg->address_book) { std::cout << "First:" << contact.first_name << " Last:" << contact.last_name << std::endl; } address_book_publisher_->publish(msg);  Finally send the message periodically. timer_ = this->create_wall_timer(1s, publish_msg);  Create a 1second timer to call our publish_msg function every second Now let’s build it! We need to create a new target for this node in the CMakeLists.txt: add_executable(publish_address_book src/publish_address_book.cpp ) ament_target_dependencies(publish_address_book "rclcpp" )  In order to use the messages generated in the same package we need to use the following cmake code: get_default_rmw_implementation(rmw_implementation) find_package("${rmw_implementation}" REQUIRED)
get_rmw_typesupport(typesupport_impls "${rmw_implementation}" LANGUAGE "cpp") foreach(typesupport_impl${typesupport_impls})
${PROJECT_NAME}${typesupport_impl}