Services in ROS 2

The ROS 2 services allow to nodes to communicate. The services make posible to send messages and receive them. The services follow the client - server structure.

Request and reply is done via a Service, defined by a pair of messages: one is the request message and one is the reply message. A providing ROS 2 node offers a service under a string name, the client calls the service by sending a request message.

A node is a process that perform computation. They are combined together and communicate with one another. For example, one node can control a laser, one node can control wheel motors, one node performs localization... all the nodes can build a robot. There is additional fault tolerance as crashes are isolated to individual nodes

In this tutorial an example included in the ROS 2 pre-build binaries will be used.

The example is available at https://github.com/ros2/examples.

Try to understand what happens in each line

Original file: https://github.com/ros2/examples

#include <iostream>

#include "rclcpp/rclcpp.hpp"

#include "example_interfaces/srv/add_two_ints.hpp"

void handle_add_two_ints(
  const std::shared_ptr<rmw_request_id_t> request_header,
  const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
  std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{
  (void)request_header;
  std::cout << "Incoming request" << std::endl;
  std::cout << "a: " << request->a << " b: " << request->b << std::endl;
  response->sum = request->a + request->b;
}

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("add_two_ints_server");

  node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", handle_add_two_ints);

  rclcpp::spin(node);

  return 0;
}

Original file: https://github.com/ros2/examples

#include <iostream>

#include "rclcpp/rclcpp.hpp"

#include "example_interfaces/srv/add_two_ints.hpp"

example_interfaces::srv::AddTwoInts_Response::SharedPtr send_request(
  rclcpp::Node::SharedPtr node,
  rclcpp::client::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client,
  example_interfaces::srv::AddTwoInts_Request::SharedPtr request)
{
  auto result = client->async_send_request(request);
  // Wait for the result.
  if (rclcpp::spin_until_future_complete(node, result) ==
    rclcpp::executor::FutureReturnCode::SUCCESS)
  {
    return result.get();
  } else {
    return NULL;
  }
}

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("add_two_ints_client");

  auto client = node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");
  auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
  request->a = 2;
  request->b = 3;

  auto result = send_request(node, client, request);
  if (result) {
    printf("Result of add_two_ints: %zd\n", result->sum);
  } else {
    printf("add_two_ints_client was interrupted. Exiting.\n");
  }

  return 0;
}

To check this example you need two terminals at least. Remember to execute the next bash file in all the terminals you are going to use ROS 2:

$ . ~/ros2_wp/install/setup.bash

Execute the server:

$ add_two_ints_server

It is normal not to see anything and that the terminal is locked. You need a client to send information by executing the following in another terminal:

$ add_two_ints_client

This command will send to the server two integer values. In this case a: 2 and b: 3. The server will print the values that have received, will add the two values and send the result to the client:

Incoming request
a: 2 b: 3

The result will be displayed on the client:

Result of add_two_ints: 5

Do you need more computing capacity in your robots? Stay tuned