Вызовите и предоставьте ROS 2 услуги

ROS поддерживает два основных коммуникационных механизма: темы и сервисы. Темы имеют издателей и подписчиков и используются для отправки и получения сообщений (см., обмениваются Данными с ROS 2 Издателя и Подписчики). Сервисы, с другой стороны, реализуют более трудную связь путем разрешения коммуникации ответа запроса. Сервисный клиент отправляет сообщение запроса в сервисный сервер и ожидает ответа. Сервер будет использовать данные в просьбе создать сообщение ответа и передает его обратно клиенту. Каждый сервис имеет тип, который определяет структуру сообщений запроса и ответа.

Эта сервисная коммуникация имеет следующие характеристики:

  • Запрос на обслуживание (или сервисный вызов) используется для непосредственной коммуникации. Один узел будет инициировать запрос, и только один узел получит запрос и передаст ответ обратно.

  • Сервисный клиент и сервисный сервер сильно связываются, когда сервисный вызов выполняется. Сервер должен существовать во время сервисного вызова и если запрос отправлен, клиент блокируется, пока ответ не получен.

Концепция сервисов проиллюстрирована в следующем изображении:

Этот пример показывает вам, как настроить сервисные серверы, чтобы рекламировать сервис к сети ROS. Кроме того, вы изучите, как использовать сервисные клиенты, чтобы вызвать сервер и получить ответ.

Необходимые условия: Начало работы с ROS 2, подключением к сети ROS 2, обмениваются данными с ROS 2 издателя и подписчики

Создайте сервисный сервер

Прежде, чем исследовать сервисные концепции, создайте демонстрационную сеть ROS 2 с тремя узлами, чтобы симулировать реалистическую сеть.

node_1 = ros2node("node_1");
node_2 = ros2node("node_2");
node_3 = ros2node("node_3");

Предположим, что вы хотите сделать простой сервисный сервер, который отображает "Сервисный клиент, вызывает", когда вы вызываете сервис. Создайте сервис с помощью ros2svcserver команда. Задайте сервисное имя, сервисный тип сообщения и узел, чтобы присоединить сервер. Также задайте функцию обратного вызова как exampleHelperROSEmptyCallback. Функции обратного вызова для сервисных серверов имеют очень определенную подпись. Для получения дополнительной информации см. документацию ros2svcserver.

testserver = ros2svcserver(node_1,"/service_example","std_srvs/Empty",@exampleHelperROS2EmptyCallback)
testserver = 
  ros2svcserver with properties:

      ServiceType: 'std_srvs/Empty'
      ServiceName: '/service_example'
    NewRequestFcn: @exampleHelperROS2EmptyCallback
          History: 'keeplast'
            Depth: 10
      Reliability: 'reliable'
       Durability: 'volatile'

Вы видите свой новый сервис, /test, когда вы перечисляете все сервисы в сети ROS.

ros2("service","list");
/_matlab_introspec__0/describe_parameters
/_matlab_introspec__0/get_parameter_types
/_matlab_introspec__0/get_parameters
/_matlab_introspec__0/list_parameters
/_matlab_introspec__0/set_parameters
/_matlab_introspec__0/set_parameters_atomically

Создайте сервисный клиент

Используйте сервисные клиенты, чтобы запросить информацию у сервисного сервера ROS 2. Чтобы создать клиент, использовать ros2svcclient с сервисом называют как аргумент.

Создайте сервисный клиент для /test сервис, что мы только создали и присоединяем его к различному узлу.

testclient = ros2svcclient(node_2,"/service_example","std_srvs/Empty")
testclient = 
  ros2svcclient with properties:

    ServiceType: 'std_srvs/Empty'
    ServiceName: '/service_example'
        History: 'keeplast'
          Depth: 10
    Reliability: 'reliable'
     Durability: 'volatile'

Создайте пустое сообщение запроса для сервиса. Используйте ros2message функционируйте и передайте клиент в качестве первого аргумента. Это создаст функцию запроса на обслуживание, которая имеет тип сообщения, который задан сервисом.

testreq = ros2message(testclient)
testreq = struct with fields:
    MessageType: 'std_srvs/EmptyRequest'

Убедитесь, что сервис соединяется с клиентом, ожидающим их, чтобы соединиться при необходимости.

waitForServer(testclient,"Timeout",3)

Когда это необходимо, чтобы получить ответ от сервера, используйте call функция, которая вызывает сервисный сервер и возвращает ответ. Сервисный сервер, который вы создали прежде, возвратит пустой ответ. Кроме того, это вызовет exampleHelperROSEmptyCallback функционируйте и отображается, строка "Сервисный клиент вызывает". Можно также задать Timeout параметр, который указывает, сколько времени клиент должен ожидать ответа. status и statustext выходные параметры предоставляют дополнительную информацию о состоянии ответа.

testresp = call(testclient,testreq,"Timeout",3)
testresp = struct with fields:
    MessageType: 'std_srvs/EmptyResponse'

Если вызов будет функционировать выше сбоев, он будет ошибка. Вместо ошибки, если вы предпочли бы реагировать на отказ вызова с помощью условных выражений, возвращают состояние и statustext выходные параметры от функции вызова. Состояние выход указывает, успешно выполнился ли вызов, в то время как statustext предоставляет дополнительную информацию. Подобные выходные параметры могут быть возвращены waitForServer.

numCallFailures = 0;
[testresp,status,statustext] = call(testclient,testreq,"Timeout",3);
if ~status
    numCallFailures = numCallFailues + 1;
    fprintf("Call failure number %d. Error cause: %s\n",numCallFailures,statustext)
else
    disp(testresp)
end
    MessageType: 'std_srvs/EmptyResponse'

Создайте сервис для добавления двух чисел

До сих пор сервисный сервер не сделал никакой значимой работы, но можно использовать сервисы для расчетов и манипулирования данными. Создайте сервис, который добавляет два целых числа.

Существует существующий сервисный тип, example_interfaces/AddTwoInts, то, что мы можем использовать для этой задачи. Можно смотреть структуру сообщений запроса и ответа путем вызова ros2 msg show. Запрос содержит два целых числа, a и b, и ответ содержит их сложение в sum.

ros2 msg show example_interfaces/AddTwoIntsRequest
int64 a
int64 b
---
int64 sum
ros2 msg show example_interfaces/AddTwoIntsResponse
int64 a
int64 b
---
int64 sum

Создайте сервисный сервер с этим типом сообщения и функцией обратного вызова, которая вычисляет сложение. Для вашего удобства, exampleHelperROS2SumCallback функционируйте уже реализует это вычисление. Задайте функцию как коллбэк.

sumserver = ros2svcserver(node_1,"/sum","example_interfaces/AddTwoInts",@exampleHelperROS2SumCallback)
sumserver = 
  ros2svcserver with properties:

      ServiceType: 'example_interfaces/AddTwoInts'
      ServiceName: '/sum'
    NewRequestFcn: @exampleHelperROS2SumCallback
          History: 'keeplast'
            Depth: 10
      Reliability: 'reliable'
       Durability: 'volatile'

Чтобы вызвать сервисный сервер, необходимо создать сервисный клиент. Обратите внимание на то, что этот клиент может быть создан где угодно в сети ROS 2. В целях этого примера мы создадим клиент для /sum сервис в MATLAB. Затем мы будем ожидать, чтобы гарантировать, что клиент связал с сервером.

sumclient = ros2svcclient(node_3,"/sum","example_interfaces/AddTwoInts")
sumclient = 
  ros2svcclient with properties:

    ServiceType: 'example_interfaces/AddTwoInts'
    ServiceName: '/sum'
        History: 'keeplast'
          Depth: 10
    Reliability: 'reliable'
     Durability: 'volatile'

waitForServer(sumclient,"Timeout",3);

Создайте сообщение запроса. Можно задать эти два целых числа, a и b, которые добавляются вместе, когда вы используете call команда.

sumreq = ros2message(sumclient);
sumreq.a = int64(2);
sumreq.b = int64(1);

Ожидание состоит в том, что сумма этих двух чисел будет 3. Чтобы вызвать сервис, используйте следующую команду. Сервисное сообщение ответа будет содержать sum свойство, которое хранит сложение a и b.

sumresp = call(sumclient,sumreq,"Timeout",3)
sumresp = struct with fields:
    MessageType: 'example_interfaces/AddTwoIntsResponse'
            sum: 3

Закройте сеть ROS 2

Удалите демонстрационные узлы и сервисные серверы от сети ROS 2.

clear("node_1");
clear("node_2");
clear("node_3");

Следующие шаги