Создание и вызов сервисов

Если необходимо передавать информацию только по запросу, то используются сервисы (services). В этом случае клиентская нода пересылает сообщение запрос (request message), а нода сервис отвечает на запрос, посылая сообщение ответ (reply message).

Наш сервис будет принимать на вход два числа и возвращать их сумму.

mkdir ~/ros/my_ws/src/service
cd ~/ros/my_ws/src/service
catkin_create_pkg summator_msgs std_msgs roscpp message_generation message_runtime
catkin_create_pkg summator_service roscpp
catkin_create_pkg summator_client roscpp
mkdir summator_msgs/srv

summator_msgs/srv/Add2Ints.srv

int64 a
int64 b
---
int64 sum

Этот файл описывает формат сообщений, которыми будут обмениваться наши ноды. Он разделен на две части — запрос и ответ.

summator_msgs/CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(summator_msgs)

find_package(catkin REQUIRED COMPONENTS
  message_generation
  message_runtime
  roscpp
  std_msgs
)

add_service_files(
  FILES
  Add2Ints.srv
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES summator_msgs
#  CATKIN_DEPENDS message_generation message_runtime roscpp std_msgs
#  DEPENDS system_lib
)

include_directories(
  ${catkin_INCLUDE_DIRS}
)

summator_msgs/package.xml

<?xml version="1.0"?>
<package>
  <name>summator_msgs</name>
  <version>0.0.0</version>
  <description>The summator_msgs package</description>
  <maintainer email="user@todo.todo">user</maintainer>
  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>message_runtime</run_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>std_msgs</run_depend>

  <export>
  </export>
</package>

summator_service/src/summator_service.cpp

#include "ros/ros.h"
// Этот файл создастся автоматически во время сборки из файла Add2Ints.srv
#include "summator_msgs/Add2Ints.h"

bool add(summator_msgs::Add2Ints::Request  &req,
         summator_msgs::Add2Ints::Response &res)
{
  res.sum = req.a + req.b;
  ROS_INFO("Returning [%ld + %ld = %ld]", (long int)req.a, (long int)req.b, (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

summator_service/CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(summator_service)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  summator_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES summator_service
#  CATKIN_DEPENDS roscpp
#  DEPENDS system_lib
)

include_directories(
  ${catkin_INCLUDE_DIRS}
)

add_executable(summator_service_node src/summator_service.cpp)

add_dependencies(summator_service_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(summator_service_node
  ${catkin_LIBRARIES}
)

summator_service/package.xml

<?xml version="1.0"?>
<package>
  <name>summator_service</name>
  <version>0.0.0</version>
  <description>The summator_service package</description>
  <maintainer email="user@todo.todo">user</maintainer>
  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>summator_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>summator_msgs</run_depend>

  <export>
  </export>
</package>

summator_client/src/summator_client.cpp

#include "ros/ros.h"
// Этот файл создастся автоматически во время сборки из файла Add2Ints.srv
#include <summator_msgs/Add2Ints.h>
#include <cstdlib>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_client");
  if (argc != 3)
  {
    ROS_INFO("usage: summator_client X Y");
    return 1;
  }

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<summator_msgs::Add2Ints>("add_two_ints");
  summator_msgs::Add2Ints srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  ROS_INFO("Requesting %ld+%ld", (long int)srv.request.a, (long int)srv.request.b);

  if (client.call(srv))
  {
    ROS_INFO("%ld + %ld = %ld", (long int)srv.request.a, (long int)srv.request.b, (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

summator_client/CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(summator_client)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  summator_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES summator_client
#  CATKIN_DEPENDS roscpp
#  DEPENDS system_lib
)

include_directories(
  ${catkin_INCLUDE_DIRS}
)

add_executable(summator_client_node src/summator_client.cpp)

add_dependencies(summator_client_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
target_link_libraries(summator_client_node
  ${catkin_LIBRARIES}
)

summator_client/package.xml

<?xml version="1.0"?>
<package>
  <name>summator_client</name>
  <version>0.0.0</version>
  <description>The summator_client package</description>
  <maintainer email="user@todo.todo">user</maintainer>
  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>summator_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>summator_msgs</run_depend>

  <export>
  </export>
</package>
.
├── summator_client
│   ├── CMakeLists.txt
│   ├── include
│   │   └── summator_client
│   ├── package.xml
│   └── src
│       └── summator_client.cpp
├── summator_msgs
│   ├── CMakeLists.txt
│   ├── include
│   │   └── summator_msgs
│   ├── package.xml
│   ├── src
│   └── srv
│       └── Add2Ints.srv
└── summator_service
    ├── CMakeLists.txt
    ├── include
    │   └── summator_service
    ├── package.xml
    └── src
        └── summator_service.cpp

Теперь можно скомпилировать воркспейс.

cd ~/ros/my_ws
catkin_make

И проверить. Запускаем каждую команду в отдельном терминале:

roscore
# rosrun summator_service summator_service_node
[ INFO] [1472376080.566648113]: Ready to add two ints.
# rosrun summator_client summator_client_node 1 1
[ INFO] [1472376098.419337334]: Requesting 1+1
[ INFO] [1472376098.420931418]: 1 + 1 = 2

Смотри также: 1. Writing a Simple Service and Client (C++) 1. Параметр сервер (Parameter Server)