Создание клиента (Python)
Что вы узнаете в этом разделе:
- Как создать клиент сервиса на Python
- Как формировать запросы к серверу
- Как ожидать доступности сервиса перед отправкой запроса
- Как обрабатывать ответы от сервера
- Разницу между синхронным и асинхронным вызовом сервиса
- Структуру программы-клиента в ROS2
Пример Клиента на Python
Мы вызывали сервис при помощи CLI, сейчас напишем клиент на python, который будет вызывать сервис add_two_ints
Создадим файл chapter6/minimal-client.py
from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node
class MinimalClientAsync(Node):
def __init__(self):
super().__init__('minimal_client_async')
self.cli = self.create_client(AddTwoInts, 'add_two_ints')
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info('service not available, waiting again...')
self.req = AddTwoInts.Request()
def send_request(self, a, b):
self.req.a = a
self.req.b = b
return self.cli.call_async(self.req)
def main():
rclpy.init()
minimal_client = MinimalClientAsync()
future = minimal_client.send_request(2, 7)
rclpy.spin_until_future_complete(minimal_client, future)
response = future.result()
minimal_client.get_logger().info(
f'Result of add_two_ints: for {minimal_client.req.a} + {minimal_client.req.b} = {response.sum}')
minimal_client.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Рассмотрим блоки кода и комментарии к ним, метод инициализации __init__
def __init__(self):
super().__init__('minimal_client_async')
#Создание клиента сервиса
#`AddTwoInts`, тип сообщения
#`add_two_ints`, имя сервиса
self.cli = self.create_client(AddTwoInts, 'add_two_ints')
#Цикл, который проверяет и ожидает когда будет доступен сервер
#Если отправить запрос до запуска сервера, будет ошибка
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info('service not available, waiting again...')
#Создание "пустого" запроса
self.req = AddTwoInts.Request()
Метод создания Запроса к серверу
#Параметры, переменные a, b
def send_request(self, a, b):
#Заполнение Запроса
self.req.a = a
self.req.b = b
#Отправка запроса и возращение результата
return self.cli.call_async(self.req)
Блок запуска и вывода результата
minimal_client = MinimalClientAsync()
#Создание запроса, с переменными 2 и 7
future = minimal_client.send_request(2, 7)
#Ожидание результата
#Ожидание "обернуто" в метод rclpy.spin_until_future_complete
#Так как мы не останавливаем работу основной ноды (rclpy.spin),
#что необходимо для работы таймеров, и работы с топиками
rclpy.spin_until_future_complete(minimal_client, future)
#Получение **Ответа**, после завершения вызова сервиса.
response = future.result()
minimal_client.get_logger().info(
f'Result of add_two_ints: for {minimal_client.req.a} + {minimal_client.req.b} = {response.sum}')
Запустим программу, и увидим результат выполнения сложения
python3 minimal-client.py
[INFO] [1758030881.075401754] [minimal_client_async]: Result of add_two_ints: for 2 + 7 = 9
После получения результата, программа завершается.
Дополнительные материалы
Официальной документации ROS https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html
Пример "синхронного" и "асинхронного" вызова сервиса https://docs.ros.org/en/rolling/How-To-Guides/Sync-Vs-Async.html
Код примеров https://github.com/voltbro/turtlebro2-examples/tree/master/ros2-base/chapter6
Python api https://github.com/ros2/examples/tree/jazzy/rclpy/services