ROS — Урок 11 — Написание простого publisher и subscriber (Python)



Содержание

1. Написание простого publisher и subscriber (Python)

Описание: На этом уроке рассказывается, как написать узлы издателя(publisher) и подписчика(subscriber) на Python.

1.1 Написание Узла Издателя (Publisher Node)

В ROS, узел (node) — это термин для обозначения исполняемого файла, который подключён к сети ROS. Попробуем создать узел издателя («болтун» («talker»)), который будет постоянно транслировать сообщения.

Перейдите в каталог в пакета beginner_tutorials, созданный в начале этого курса:

roscd beginner_tutorials

1.1.1 Код

Создайте внутри пакета beginner_tutorials файл nodes/talker.py и вставьте в него следующий код:

Для создания и запуска редактирования файла воспользуйтесь командами:

$ mkdir nodes
$ touch nodes/talker.py
$ rosed beginner_tutorials talker.py
#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')
import rospy
from std_msgs.msg import String
def talker():
    pub = rospy.Publisher('chatter', String)
    rospy.init_node('talker')
    while not rospy.is_shutdown():
        str = "hello world %s"%rospy.get_time()
        rospy.loginfo(str)
        pub.publish(String(str))
        rospy.sleep(1.0)
if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException: pass

Не забудьте сделать файл узла исполняемым файлом:

$ chmod +x nodes/talker.py

1.1.2 Разъяснение кода

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

#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')

Каждый узел ROS, в самом верху, будет иметь это объявление. Первая строчка делает ваш сценарий исполняемым, а вторая (как описывается в руководстве PythonPath) говорит roslib считать файл manifest.xml и добавить все зависимости, перечисленные в нём, в ваш PYTHONPATH. Это будет важно для следующей секции кода.

import rospy
from std_msgs.msg import String

Ваш код уже может импортировать стандартные библиотеки Python, такие как sys и time, но roslib.load_manifest() позволит найти rospy и std_msgs, которые были объявлены в качестве зависимостей в manifest.xml. Вы должны импортировать rospy, если вы пишете ROS узел. Импорт std_msgs.msg объясняется тем, что теперь мы можем использовать тип сообщения std_msgs/String (простой контейнер для строк) для публикации.

def talker():
    pub = rospy.Publisher('chatter', String)
    rospy.init_node('talker')

Эта часть кода, определяет интерфейс узла talker к остальный ROS.
pub = rospy.Publisher(‘chatter’, String) — заявляет, что ваш узел публикует сообщения на тему «chatter», используя для этого сообщения типа String. String здесь, на самом деле, класс std_msgs.msg.String.

Следующая строчка, rospy.init_node(NAME), очень важна, так как она говорит rospy имя вашего узла — пока rospy не имеет этой информации, он не может начать общаться с Мастером ROS (ROS Master). В этом случае, ваш узел возьмет на имя ‘talker’.
Примечание: имя должно быть базовым, т.е. оно не должно содержать косую черту «/».

    while not rospy.is_shutdown():
        str = "hello world %s"%rospy.get_time()
        rospy.loginfo(str)
        pub.publish(String(str))
        rospy.sleep(1.0)

Этот цикл является довольно стандартной rospy конструкцией: проверка флага rospy.is_shutdown(), а затем выполнение основной работы. Вы должны проверить is_shutdown(), чтобы узнать, должна ли ваша программа завершить работу (например, по нажатию Ctrl-C или по другой причине). В данном случае, «основная работа» — это вызов метода pub.publish(String(str)), который публикует в нашей теме chatter вновь созданную строку сообщения. Затем, в цикле вызывается rospy.sleep(), которая похожа на time.sleep(), за исключением того, что она работает с имитацией времени (см. Clock).

Этот цикл, также вызывает rospy.loginfo(str), который выполняет тройные обязанности: сообщение выводится на экран, так же оно будет записано в файл журнала (log-файл) узла, и ещё, оно будет записано в rosout. rosout очень удобно для отладки: можно дотянуться до сообщения, используя rxconsole вместо того, чтобы искать окно консоли с выдачей узла.

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

msg = String()
msg.data = str

или вы можете инициализировать некоторые из полей, а остальные оставить со значениями по-умолчанию:

String('data'=str)

Вы можете задаваться вопросом о последних строчках:

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException: pass

В дополнение к стандартной проверке Python __main__, этот код перехватывает исключение rospy.ROSInterruptException, которое может быть вызвано методами rospy.sleep() и rospy.Rate.sleep(), когда нажата Ctrl-C или ваш узел неожиданно завершил работу. Это исключение присутствует для того, чтобы вы случайно не продолжили выполнение кода после sleep().

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

1.2 Написание подписчика узела (Subscriber Node)

1.2.1 Код

Создайте в пакете beginner_tutorials файл nodes/listener.py и вставьте в него следующий код:

#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')
import rospy
from std_msgs.msg import String
def callback(data):
    rospy.loginfo(rospy.get_name()+"I heard %s",data.data)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()

Не забудьте сделать файл узла исполняемым файлом:

$ chmod +x nodes/listener.py

1.2.2 Разъяснение кода

Код для listener.py похож на talker.py, за исключением того, что мы добавили метод callback для подписки на сообщения.

    rospy.Subscriber("chatter", String, callback)

Эта строчка заявляет, что ваш узел поддерживает подписывается на тему chatter, которая относится к типу std_msgs.msgs.String. Когда новое сообщение будет получено, будет вызван метод callback с сообщением в качестве первого аргумента.

Мы также несколько изменили код вызова rospy.init_node(). Мы добавили аргумент anonymous=True. ROS требует, чтобы каждый узел имел уникальное имя. Если появляется узел с таким же именем, то он выбивает предыдущий. Это связано с тем, что неисправность узлов может легко завалить всю сеть. Флаг anonymous=True говорит, чтобы rospy сгенерировал уникальное имя для этого узла, так что вы сможете легко запустить в работу сразу несколько узлов listener.py.

И последнее добавление, rospy.spin() просто удерживает ваш узел от выхода, пока узел не будет отключен. В отличие от roscpp, rospy.spin() не влияет на функцию callback подписчика, так как те имеют свои собственные потоки.

1.3 Сборка ваших узлов

Мы используем CMake в качестве нашей системы сборки, да, вы должны использовать его даже для узлов Python. Это делается для того, чтобы убедиться, что создается автоматически сгенерированный Python-код для сообщений и сервисов. Мы также используем Makefile для удобства.

roscreate-pkg автоматически создаёт Makefile, так что вам не придется его редактировать.

Теперь запустите:

$ make

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

Ссылки
http://www.ros.org/wiki/ROS/Tutorials/WritingPublisherSubscriber(python)


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение