Работа с Service

Модель коммуникации в режиме Сервис представляет собой двунаправленную синхронную связь между клиентом (Service Client), создающим запрос, и сервером (Service Server), отвечающим на запрос.

Данный способ удобно использовать для периодической передачи данных, или когда существует потребность в синхронной связи (режим запрос-ответ).

Сервер отвечает только тогда, когда есть запрос (Service Request) и клиент, который может получить ответ (Service Response). В отличие от модели работы с топиками, модель сервис работает с "одноразовыми" соединениями. Поэтому, когда цикл запрос и ответ завершен, соединение между двумя нодами будет прервано.

Описание формата сервиса

Формат запроса и ответа, задается специальным парным Сообщением (Message), в котором есть два сообщения: первое для запроса (Service Request), второе для ответа (Service Response). Файлы с описанием сервисов хранятся в директории srv и имеют расширение .srv Подробное описание файла доступно на странице wiki http://wiki.ros.org/rosbuild/srv

В файле описания сервиса первая часть (до разделителя ---) это описание сообщения запроса, далее описание сообщения ответа.

Например srv/AddToInts.srv

uint32 x

uint32 y

---

uint32 sum

При этом, имя файла AddToInts.srv соответсвует имени Сервиса AddToInts.

Примеры работы на Python

При использовании python на основании данных из файла srv создаются (при билде пакета) дополнительные python файлы, содержащие описание типа сервиса, сообщение для запроса и сообщение для ответа.

my_package/srv/AddToInts.srv → my_package.srv.AddToInts
my_package/srv/AddToInts.srv → my_package.srv.AddToIntsRequest
my_package/srv/AddToInts.srv → my_package.srv.AddToIntsResponse

Более подробно про работу и настройку файлов .srv можно посмотреть в wiki http://wiki.ros.org/ROS/Tutorials/CreatingMsgAndSrv#Creating_a_srv

Для создания сервера, выполняющего обработку запросов, используем класс rospy.Service

rospy.Service(name, service_class, handler)
  • name Название сервиса (его адрес)
  • service_class тип обрабатываемых сообщений (должно совпадать с именем файлы .srv)
  • handler функция обработчик запроса

Пример сервера src/add_two_ints_server.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy

from ros_book_samples.srv import AddTwoInts, AddTwoIntsResponse

def handle_add_two_ints(req):
    print "Returning [%s + %s = %s]"%(req.x, req.y, (req.x + req.y))
    return AddTwoIntsResponse(req.x + req.y)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    print "Ready to add two ints."
    rospy.spin()

if __name__ == "__main__":
    add_two_ints_server()

При создании запроса на URL /add_two_ints, с типом AddTwoIntsRequest произойдет суммирование двух чисел.

Пример клиента src/add_two_ints_client.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy

from ros_book_samples.srv import AddTwoInts

def add_two_ints_client(x, y):

    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp = add_two_ints(x, y)
        return resp.sum

    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

if __name__ == "__main__":
    print add_two_ints_client(10, 22)

Запуск примеров возможен или через прямой запуск скриптов python

python src/ros_book_samples/src/add_two_ints_server.py
python src/ros_book_samples/src/add_two_ints_client.py

или через запуск утилитой rosrun. Для этого .py файл должны быть с флагом исполнения (chmod +x)

rosrun ros_book_samples add_two_ints_server.py
rosrun ros_book_samples add_two_ints_client.py

При запуске клиента и сервера в консоле можно увидеть

Для сервера
Ready to add two ints.

Returning [10 + 22 = 32]

Для клиента
rosrun ros_book_samples add_two_ints_client.py
32

Использование Service в новых пакетах

Для использования Service в новых пакетах необходимо удостовериться, что установлены все зависимости и внесены изменения в конфигурацию make.

В файле CMakeLists.txt необходимо внести изменения:

# Проверяем, что пакет message_generation подключен
find_package(catkin REQUIRED
    COMPONENTS message_generation)

# Declare the service files to be built
add_service_files(FILES
    AddTwoInts.srv
)  

# Actually generate the language-specific message and service files
generate_messages(DEPENDENCIES std_msgs sensor_msgs)

# Declare that this catkin package's runtime dependencies
catkin_package(
    CATKIN_DEPENDS message_runtime std_msgs
)

Файл package.xml должен содержать следующие строчки:

<build_depend>message_generation</build_depend>
<build_depend>message_runtime</build_depend>
<exec_depend>message_generation</exec_depend>
<exec_depend>message_runtime</exec_depend>

Консольная утилита rosservice

Для отладки и тестирования сервисов ROS существует специальная консольная утилита rosservice:

rosservice call Выполнение запроса к серверу
rosservice find Поиск сервиса по типу
rosservice info Выводит информацию о сервисе
rosservice list Выводит список запущенных сервисов
rosservice type Выводит тип сообщений используемый сервисом
rosservice uri  Выводит RPC URL сервиса

Примеры использования rosservice:

rosservice call

Вызов сервиса service_name c аргументами service-args:

rosservice call /service_name service-args

Вызов сервиса add_two_ints с аргументами 1 и 2:

rosservice call /add_two_ints 1 2

Для сложных сообщений аргументы с параметрами возможно писать в YAML синтаксисе, например:

rosservice call /add_two_ints "{x: 1, y: 2}"

Подробно об использовании YAML http://wiki.ros.org/ROS/YAMLCommandLine.

rosservice list

rosservice list

Выводит список активных сервисов.

rosservice type

rosservice type /service_name

Выводит тип обрабатываемого сообщения.

$ rosservice type add_two_ints | rossrv show

result:
int64 a
int64 b
---
int64 sum

Пример выводит описание типа сообщения для сервиса.

results matching ""

    No results matching ""