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.
clear("node_1"); clear("node_2"); clear("node_3");
Относитесь, чтобы работать с Основными сообщениями ROS 2, чтобы исследовать, как сообщения ROS 2 представлены в MATLAB.