⛄
new_Базовый курс по ROS
  • Обложка
  • Урок 1. Введение в ROS
    • Что такое ROS ?
    • Знакомство с роботом TurtleBro
    • Настройка ПК
    • Установка ROS
    • Настройка робота TurtleBro
    • Настройка VSCode
    • Практические задания
  • Урок 2. Базовый понятия ROS
    • Основы теории управления
    • Сущности ROS как элементы ТАУ
    • Базовые утилиты ROS
    • Практические задания
  • Урок 3. Издатель
    • Издатель (Publisher)
    • Издатель команд для робота
    • Практические задания
  • Урок 4. Подписчик
    • Подписчик (Subscriber)
    • Подписчик на данные робота
    • Практические задания
  • Урок 5. Подписчик и Издатель
    • Взаимодействие Подписчика и Издателя в рамках одной ноды. Часть 1
    • Практические задания
    • Взаимодействие Подписчика и Издателя в рамках одной ноды. Часть 2
    • Практические задания
      • Решение
  • Урок 6. Работа с Arduino
    • Работа с Arduino
    • Создание Издателя
    • Создание Подписчика
    • Практические задания
  • Курсовая работа
    • Задание
  • Итог
    • Заключение
Powered by GitBook
On this page
  • Введение
  • Пишем первую программу
  • Запускаем программу
  • Исправляем предупреждение

Was this helpful?

  1. Урок 3. Издатель

Издатель (Publisher)

PreviousПрактические заданияNextИздатель команд для робота

Last updated 1 year ago

Was this helpful?

Введение

Издатель - это инструмент, который передает сигналы внутри системы управления.

В зависимости от того что это за сигналы, в терминах теории управления мы можем говорить о входящих или исходящих сигналах, но в ROS инструментом, который передает эти сигналы всегда является Издатель.

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

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

Сейчас мы не будем разбирать Издателя, делающий что-то связанное с реальным роботом. Для простоты мы смоделируем элементарный пример с которого начинаются все языки программирования. А именно напишем программу выводящую на экран “Hello ROS”.

Пишем первую программу

Сформулируем задачу более определенно: Мы будем писать Издатель, который публикует строку “Hello ROS” в топик с именем: “welcome_topic”.

Назовем нашу программу: publisher.py и сохраним ее в папку ros-cource в корневой папке.

Все эти ROS-сущности: топик, Издатель, тип данных - строка, уже описаны в библиотеке по работе с ROS для Python. Она называется rospy и по умолчанию ставится вместе с установкой ROS. Для того, чтобы просто использовать эти сущности в нашей программе, нам надо подключить эту библиотеку:

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy

Теперь давайте определим тип и структуру данных, которые мы будем передавать при помощи Издателя. Раз мы хотим напечатать строку “Hello ROS”, то тип данных с очевидностью будет строка. Для того чтобы бы мы могли использовать структуру данных ROS в Python, ее надо сначала импортировать. Давайте сделаем это:

from std_msgs.msg import String

Как вы видите есть отличие в написании. Строка в Python называется str, строка в ROS называется String с большой буквы. Если сейчас вам это кажется непривычным, не волнуйтесь - к этому дуализму структур данных вы довольно быстро привыкните.

Теперь давайте создадим и зарегистрируем в ROS нашу ноду. Как вы помните ноды это и есть отображение в ROS наших программ. Для создания ноды в rospy есть стандартный метод init_node(). Как это принято в Python, доступ к методам и объектам внутри библиотеки, происходит по их полному имени, через точку после названия библиотеки. Назовем нашу ноду welcome_node вот так:

rospy.init_node("welcome_node")

Теперь давайте создадим объект Издатель. Для простоты назовем экземпляр этого объекта pub

pub = rospy.Publisher

Теперь, нам необходимо указать название топика в который издатель будет публиковать данные и название структуры этих данных. Это welcome_topic и String:

pub = rospy.Publisher("/welcome_topic", String)

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

Теперь нам надо создать объект нашей структуры данных String и заполнить ее значением “Hello robot”:

s = String()
s.data = "Hello robot"

Тут мы создаем новый объект класса String и присваиваем значение “Hello robot” переменной data этого объекта.

Теперь давайте напишем основной цикл нашей программы.

Для программ под ROS рекомендуется такая структура основного цикла:

while not rospy.is_shutdown():

Такой вид цикла позволит нам корректно выйти из нашей программы по нажатию Ctrl+C

В самом цикле, мы будем публиковать значение нашей структуры данных s при помощи созданного нами Издателя pub:

pub.publish(s)

publish - это метод класса Издатель и он просто публикует структуру данных которую вы передаете ему в качестве аргумента, в соответствии с теми параметрами которые мы указали при инициализации, т.е. структура будет String, а публиковать ее надо в топик "welcome_topic"

Вот и все! Мы написали первую программу для ROS! Давайте сохраним ее, запустим и посмотрим как она работает.

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String

rospy.init_node("welcome_node")
pub = rospy.Publisher("/welcome_topic", String)

s = String()
s.data = "Hello ROS"

while not rospy.is_shutdown():
    pub.publish(s)

Запускаем программу

Запустим roscore и оставим его запущенным в окне терминала. Откроем новый терминал и напишем python3 и полный путь до файла с нашей программой:

python3 ros_course/publisher.py

Запустилось, но выдает предупреждение о котором мы предупреждали.

ros_course/publisher.py:8: SyntaxWarning: 
The publisher should be created with an explicit keyword argument 
'queue_size'. Please see http://wiki.ros.org/rospy/Overview/Publishers%20and%20Subscribers 
for more information.  pub = rospy.Publisher("/welcome_topic", String)

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

Для тестирования нашей программы мы будем использовать уже известные нам сервисные утилиты - rostopic и rosnode.

Давайте посмотрим какие ноды и топики есть сейчас в системе. Для этого в новом окне терминала вызовем:

rosnode list && echo && rostopic list

---------------------------------------
/rosout
/welcome_node

/rosout
/rosout_agg
/welcome_topic

Мы видим две новые записи, это записи /welcome_node и /welcome_topic

/welcome_node - это та самая нода, которую мы создали в нашей программе;

/welcome_topic - это топик, в который мы публикуем наше значение.

Т.е. мы запустили нашу программу и она инициализировала в системе свою ноду и зарегистрировала топик. А как проверить, что программа работает так как мы хотим, т.е. публикует Hello ROS в топик /welcome_topic ?

Для этого снова воспользуемся утилитой rostopic и напишем:

rostopic echo /welcome_topic

------------------------------
data: "Hello ROS"
---
data: "Hello ROS"
---
data: "Hello ROS"
---

Отлично ! Мы видим череду сообщений "Hello ROS", а это значит, что все работает так как надо!

Исправляем предупреждение

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

Допишем в инициализацию Издателя параметр размера очереди сообщений queue_size и поставим его равным 10.

pub = rospy.Publisher("welcome_topic", String, queue_size=10)

Подробнее про этот и другие дополнительные параметры инициализации Издателя и Подписчика вы можете почитать здесь:

И вишенка на торте нашей программы - поставим частоту публикации сообщения “Hello ROS”

В ROS есть несколько способов обеспечить требуемую частоту публикации, и сейчас мы воспользуемся самым простым, но не самым точным из всех - методом sleep() библиотеки rospy.

Этот метод приостанавливает работу программы на то количество секунд, которое мы передаем ему в качестве аргумента. Давайте напишем rospy.sleep(1) т.е. мы хотим, чтобы сразу после публикации сообщения наша программа "засыпала" на 1 секунду.

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String

rospy.init_node("welcome_node")
pub = rospy.Publisher("welcome_topic", String, queue_size=10)

s = String()
s.data = "Hello ROS"

while not rospy.is_shutdown():
    pub.publish(s)
    rospy.sleep(1)

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

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

Для того, чтобы убедиться, что публикация в топик /welcome_topic действительно идёт один раз в секунду воспользуемся новым параметром утилиты rostopic:

rostopic hz /welcome_topic

--------------------------
average rate: 0.999
	min: 1.001s max: 1.001s std dev: 0.00000s window: 2
average rate: 0.999
	min: 1.001s max: 1.001s std dev: 0.00012s window: 3
average rate: 0.999
	min: 1.001s max: 1.001s std dev: 0.00021s window: 4
average rate: 0.999
	min: 1.001s max: 1.001s std dev: 0.00020s window: 5
average rate: 0.999
	min: 1.001s max: 1.001s std dev: 0.00019s window: 6

Писать мы будем на языке Python с использованием , но вы можете использовать любую другую среду разработки под Python (PyCharm, Notepad+ и прочее).

IDE Visual Studio Code
http://wiki.ros.org/rospy/Overview/Publishers%20and%20Subscribers