Создание сервисов (Python)
Что вы узнаете в этом разделе:
- Как создать сервер сервиса на Python
- Структуру программы-сервера в ROS2
- Как обрабатывать запросы и формировать ответы
- Как найти подходящие типы сообщений для сервисов
- Как протестировать работу сервиса через консоль
- Основные методы работы с сервисами в rclpy
Пример Сервиса (Service) на Python
Рассмотрим создание простого сервиса, который будет складывать два числа. Клиент отправляет два числа, которые необходимо сложить, в сервер производит сложение и возвращает результат сложения.
Такую программу, можно считать "каноничной" демонстрацией работы сервиса. Также данный пример нам удобно реализовать, так как сообщения для такой программы уже созданы, и нам не нужно их создавать.
Найдем подходящие нам сообщения для сервиса. Используем дополнительный ключ --only-srvs, для того, чтобы получить только сервисы
ros2 interface list --only-srvs
===
action_msgs/srv/CancelGoal
....
example_interfaces/srv/AddTwoInts
example_interfaces/srv/SetBool
example_interfaces/srv/Trigger
....
Необходимое нам сообщение example_interfaces/srv/AddTwoInts рассмотрим его структуру.
ros2 interface show example_interfaces/srv/AddTwoInts
int64 a
int64 b
---
int64 sum
До символов --- мы видим описание Запроса (переменные a и b, тип int64), а после идет Ответ (int64 sum)
Создадим сервер (Service server)
Сервер должен "постоянно" работать, ожидая запрос. При получении запроса, необходимо сложить два числа, и вернуть результат операции.
Создадим файл chapter6/minimal-service.py
from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node
class MinimalService(Node):
def __init__(self):
super().__init__('minimal_service')
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
self.get_logger().info("Service AddTwoInts is ready")
def add_two_ints_callback(self, request, response):
response.sum = request.a + request.b
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
return response
def main(args=None):
rclpy.init(args=args)
minimal_service = MinimalService()
try:
rclpy.spin(minimal_service)
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
Скелет программы аналогичен тому, с которым мы работали с топиками.
В начале, мы импортируем библиотеки ROS и сообщение сервиса AddTwoInts
from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node
Блок "запуска" ноды, также аналогичен рассмотренным ранее, поменялось только имя созданного класса.
def main(args=None):
rclpy.init(args=args)
minimal_service = MinimalService()
try:
rclpy.spin(minimal_service)
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
Рассмотрим с комментариями тело самой программы. Методы инициализации __init__(self) и основной рабочий метод сервиса add_two_ints_callback
def __init__(self):
#Инициализируем ноду
super().__init__('minimal_service')
#Создаем сервис. Указав параметры
# `AddTwoInts` Тип сервиса
# `add_two_ints` Название сервиса
# `add_two_ints_callback` Имя функции, которую необходимо запустить
# когда поступи Запрос от Клинта
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
# Функция "реализатор" сервиса, выполняет сложение
def add_two_ints_callback(self, request, response):
#Операция сложения, где
#request - объект из Запроса
#response - объект Ответа
response.sum = request.a + request.b
self.get_logger().info(f'Incoming request a: {request.a} b: {request.b}')
#Возврат ответа (суммы)
return response
Запустим нашу программу
python3 ./minimal-service.py
[INFO] [1758020610.453802380] [minimal_service]: Service AddTwoInts is ready
Мы видим, что сервис запустился, и программа ожидает запросы.
Найдем наш сервис
ros2 service list | grep add
===
/add_two_ints
Наш сервис появился в списке. Используя CLI, создадим запрос к сервису.
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts '{"a": 1, "b": 5}'
===
waiting for service to become available...
requester: making request: example_interfaces.srv.AddTwoInts_Request(a=1, b=5)
response:
example_interfaces.srv.AddTwoInts_Response(sum=6)
Мы видим формирование запроса (a=1, b=5) и получения результата (sum=6)
В консоле, где работает программа сервер, мы видим вывод сообщение, что получен запрос с параметрами a: 1 b: 5
[INFO] [1758020904.243744414] [minimal_service]: Incoming request
a: 1 b: 5
Мы удостоверились, что программа работает верно, и мы можем использую CLI протестировать ее.