Сервисы
Что вы узнаете в этом разделе:
- Что такое сервисы в ROS и чем они отличаются от топиков
- Модель взаимодействия Request-Response
- Что такое клиент и сервер сервиса
- Как работать с сервисами через консоль (CLI)
- Как просмотреть список доступных сервисов
- Как получить информацию о сервисе и вызвать его
Сервис (Service)
Ранее мы познакомились с такой сущностью как топики. По сути, работа с ними, это широко используемая Publisher-Subscriber модель коммуникации. Одни программы постоянно публикуют данные, другие эти данные получают. Использовать ее удобно, когда у нас есть постоянный поток данных (например данные датчиков и тп).
Но это не единственная модель коммуникации. Сегодня мы поговорим об еще одной модели взаимодействия между модулями в ROS, это модель Сервис (Service), которая использует паттерн взаимодействия Request-Response.
Эта модель коммуникации очень похожа на "удаленный" вызов функции. Одна программа вызывает функцию создавая Запрос (ServiceRequest), а другая программа получая запрос, формирует Ответ (ServiceResponse), и возвращает ее программе вызвавшей сервис.
Аналогия из жизни: Сервис можно сравнить с походом в ресторан. Клиент (Service client) делает заказ (запрос) официанту: "Принесите мне пиццу". Официант (сервер, Service server) передает заказ на кухню, получает готовое блюдо (ответ) и приносит его клиенту. Это взаимодействие "вопрос-ответ": клиент задает вопрос и ждет конкретный ответ. В отличие от топиков, где данные "текут" постоянно, сервис работает по принципу "спросил-получил ответ". Это как звонок в службу поддержки: вы звоните, задаете вопрос, получаете ответ и разговор заканчивается.
Запрос и Ответ обычно содержат переменные, необходимы для работы программы, но также они могут быть пустыми.
Мы можем выделить еще два определения, которые касаются Сервисов
- Клиент (Service client) -- это программа, которая создает Запрос, и отправляет его на Сервер.
- Сервер (Service server) -- это программа, которая ожидает Запрос от Клиента, производит вычисления и отправляет результат вычислений Ответ (в том числе и "пустым" ответом).

Работа с сервисами через cli
Для работы с сервисами есть утилита ros2 service
Запустим команду и посмотрим вывод основных параметров
ros2 service
===
Основные команды:
call Вызов сервиса
info Получение информации о сервисе
list Список доступных сервисов
Получение списка доступных сервисов
Выполним команду
ros2 service list
===
/board_info
....
/camera/list_parameters
...
/domain_id
/power/reset
/reset
...
/start_motor
/stop_motor
Получение информации о сервисе
Мы получили список названий доступных сервисов (запущенных). Разобраться, какие сервисы что делают, можно в инструкции к Роботу или в описании установленных и запущенных пакетов.
Например, в инструкции указано, что сервис /start_motor (std_srvs/srv/Empty) запустит мотор лидара.
Посмотрим информацию о сервисе.
ros2 service info /stop_motor
===
Type: std_srvs/srv/Empty
Clients count: 0
Services count: 1
Мы получили тип сообщения std_srvs/srv/Empty (пустое сообщение) которое нам необходимо использовать для вызова сервиса.
Вызов сервиса
Вызовем сервис остановки мотора лидара с "пустым" сообщением.
ros2 service call /stop_motor std_srvs/srv/Empty "{}"
===
waiting for service to become available...
requester: making request: std_srvs.srv.Empty_Request()
response:
std_srvs.srv.Empty_Request()
При выполнении команды мы видим создание пустого запроса std_srvs.srv.Empty_Request() и получение ответа std_srvs.srv.Empty_Request(). После получения ответа, лидар должен перестать вращаться.
В данном случае сервис используется без параметров (у функции остановить мотор нет параметров), также сервису нечего сообщить о результате своей работы.
Рассмотрим пример вызова сервиса, которые вернет параметры системной платы Turtlebro.
Для этого вызовем сервис /board_info
ros2 service call /board_info turtlebro/srv/BoardInfo "request: {}"
waiting for service to become available...
requester: making request: turtlebro.srv.BoardInfo_Request(request=std_msgs.msg.Empty())
response:
turtlebro.srv.BoardInfo_Response(mcu_id=std_msgs.msg.String(data='002300533034510A30323536'), firmware_version=std_msgs.msg.String(data='TB2_microros'))
Мы получили данные о серийном номере MCU и версии системной прошивки платы
- mcu_id: 002300533034510A30323536
- firmware_version: TB2_microros