СВЯЗЬ В ROS (ROBOT OS)

Операционная система роботов (ROS) - это не фактическая операционная система, а структура и набор инструментов, которые обеспечивают функциональность операционной системы в гетерогенном компьютерном кластере. Его полезность не ограничивается роботами, но большинство предоставляемых инструментов ориентировано на работу с периферийным оборудованием.

Чтобы узнать больше о ROS и процессе установки - Введение в ROS

Теперь я расскажу, как можно установить связь между узлами в ROS с помощью простого издателя и подписчика.

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

Предположим, есть человек (с именем-менеджером), который управляет системой распределения, в которой, если человек (г-н X) хочет что-то дать, он должен сказать менеджеру, что хочет что-то дать с открытого счета (с именем A), и если мужчина (г-н Y) хочет забрать эти предметы, он должен сначала сообщить менеджеру, что все, что поступает на открытый счет A, предоставит мне, чтобы каждый раз, когда предметы будут поступать на счет A, менеджер предоставит мистеру Y.
Диаграмма ниже графический вид этой модели -

На этой диаграмме г-н X отдает еду на счет A, а г-н Y берет.

Теперь давайте свяжем это с ROS -
менеджеры - главный узел
Мистер X - издатель
Мистер Y - подписчик
открыть аккаунт A - Тема
еда - тип сообщения

Теперь пора перейти к собственно коду, я собираюсь написать издателя и подписчика на C ++. Есть два узла: один - говорящий, а другой - слушатель, говорящий отправит сообщение в тему разговора, а слушатель получит это сообщение, подписавшись на тему разговора.
Прежде всего, перейдите в каталог рабочей области / src и создайте два файла с именем говорящего .cpp и listener.cpp.

1. Издатель

Поместите этот код в talker.cpp -

А теперь давайте разберемся с кодом.

#include "ros/ros.h"

ros / ros.h - это удобный компонент, включающий все заголовки, необходимые для использования наиболее распространенных общедоступных частей системы ROS.

#include "std_msgs/String.h"

Сюда входит сообщение std_msgs / String, которое находится в пакете std_msgs. Это заголовок, автоматически сгенерированный из файла String.msg в этом пакете.

ros::init(argc, argv, "talker");

Инициализировать ROS. Это позволяет ROS выполнять переназначение имен через командную строку - на данный момент это не важно. Здесь мы также указываем имя нашего узла. Имена узлов должны быть уникальными в работающей системе.

Используемое здесь имя должно быть базовым именем, т.е. в нем не может быть / в.

ros::NodeHandle n;

Создайте дескриптор узла этого процесса. Первый созданный NodeHandle фактически выполнит инициализацию узла, а последний разрушенный очистит все ресурсы, которые этот узел использовал.

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

Сообщите мастеру, что мы собираемся опубликовать сообщение типа std_msgs / String в теме разговора. Это позволяет мастеру сообщать всем узлам, которые слушают болтовню, что мы собираемся опубликовать данные по этой теме. Второй аргумент - размер нашей очереди публикации. В этом случае, если мы публикуем слишком быстро, оно буферизует максимум 1000 сообщений перед тем, как начать выбрасывать старые.
`NodeHandle :: Advertise ()` возвращает объект `ros :: Publisher`, который обслуживает две цели: 1) он содержит метод publish (), который позволяет вам публиковать сообщения в теме, в которой оно было создано, и 2) когда оно выходит за рамки, оно автоматически не рекламируется.

ros::Rate loop_rate(10);

Объект `ros :: Rate` позволяет вам указать частоту, с которой вы хотите зацикливаться. Он будет отслеживать, сколько времени прошло с момента последнего вызова `Rate :: sleep ()`, и засыпать в течение правильного времени.

В этом случае мы говорим, что хотим работать на частоте 10 Гц.

while(ros::ok()){
......

По умолчанию roscpp установит обработчик SIGINT, который обеспечивает обработку Ctrl-C, что приведет к тому, что ros :: ok () вернет false, если это произойдет.

std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();

Мы транслируем сообщение в ROS с помощью адаптированного к сообщениям класса, обычно генерируемого из файла msg. Возможны более сложные типы данных, но пока мы будем использовать стандартное сообщение String, которое имеет один член: данные.

chatter_pub.publish(msg);

Теперь мы фактически транслируем сообщение всем, кто подключен.

ROS_INFO("%s", msg.data.c_str());

ROS_INFO и друзья - наша замена printf / cout.

ros::spinOnce();

Вызов `ros :: spinOnce ()` здесь не требуется для этой простой программы, потому что мы не получаем никаких обратных вызовов. Однако, если бы вы добавили подписку в это приложение и не указали бы здесь `ros :: spinOnce ()`, ваши обратные вызовы никогда бы не вызывались. Итак, добавьте это для хорошей меры.

loop_rate.sleep();

Теперь мы используем объект ros :: Rate, чтобы засыпать на оставшееся время, чтобы достичь нашей скорости публикации 10 Гц.

2. подписчик

Теперь давайте напишем узел подписчика, поместите этот код в listener.cpp -

Теперь давайте разберем его по частям, игнорируя некоторые части, которые уже были объяснены выше.

void chatterCallback(const std_msgs::String::ConstPtr& msg){
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

Это функция обратного вызова, которая будет вызываться при поступлении нового сообщения по теме болтовни.

ros::Subscriber sub = n.subscribe("chatter", 1000,
chatterCallback);

Подписывайтесь на тему болтовни с мастером. ROS будет вызывать функцию chatterCallback () всякий раз, когда приходит новое сообщение. Второй аргумент - это размер очереди, на случай, если мы не можем обрабатывать сообщения достаточно быстро. В этом случае, если очередь достигает 1000 сообщений, мы начнем выбрасывать старые сообщения по мере поступления новых.
`NodeHandle :: subscribe ()` возвращает объект `ros :: Subscriber`, который вы должны удерживать до, пока вы не захотите отказаться от подписки. Когда объект Subscriber разрушен, он автоматически откажется от подписки на тему болтовни.

ros::spin();

ros :: spin () входит в цикл, вызывая обратные вызовы сообщений как можно быстрее.

Примечание -

Здесь количество слушателей обсуждения темы - один, но количество подписчиков темы может быть больше одного, и все подписчики получат одно и то же сообщение.

3. Строительные узлы

Пришло время построить нашу программу -

добавьте эти строки в свой CMakeLists.txt

Чтобы узнать основы CMake, я бы посоветовал вести блог Дерека Моллоя на CMake.

Теперь давайте запустим нашу программу

Убедитесь, что roscore запущен и работает:

$ roscore

Сделайте свою программу

# In your catkin workspace
$ cd ~/catkin_ws
$ catkin_make
$ source ./devel/setup.bash

Теперь запустите узел говорящего

$ rosrun talker_listener talker

Вы увидите что-то похожее на:

[INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
[INFO] [WallTime: 1314931832.775497] hello world 1314931832.77
[INFO] [WallTime: 1314931833.778937] hello world 1314931833.78
[INFO] [WallTime: 1314931834.782059] hello world 1314931834.78

Узел издателя запущен и работает. Теперь нам нужен подписчик для получения сообщений от издателя.

$ rosrun talker_listener listener

Вы увидите что-то похожее на:

[INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I heard hello world 1314931969.26
[INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I heard hello world 1314931970.26
[INFO] [WallTime: 1314931971.266348] /listener_17657_1314931968795I heard hello world 1314931971.26
[INFO] [WallTime: 1314931972.270429] /listener_17657_1314931968795I heard hello world 1314931972.27

Здесь мы видим, что слушатель получает сообщения hello world.

Если вам понравился этот пост, поставьте лайк и поделитесь этой историей. Спасибо!
- Шубхам Маддхашия