Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Создание клиента (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