Топик, Издатель (Publisher)

В ROS программы, отправляющие сообщения, принято называть Издатель (Publisher), а программы которые получают данные принято называть Подписчик (Subscriber). При этом в архитектуре ROS - Подписчик и Издатель могут быть как разные программы запущенные на одном компьютере, так и разные программы, запущенные на разных устройствах.

Немного теории. Мы будем писать наши программы на языке Python и для того, чтобы наши программы могли коммуницировать с ROS, нам необходимо подключить специальную библиотеку rospy, которая реализует основные функции связи с ROS для Python. В частности, для создания Издателя(Publisher) мы будем использовать метод библиотеки rospy, который так и называется Publisher. Как вы могли узнать из курса Python, для вызова методов библиотеки надо пользоваться следующей конструкцией: <имя библиотеки>.<имя метода>(аргументы метода). В нашем случае это будет выглядеть так: rospy.Publisher('/cpu_temp', Float32, queue_size=1). Где аргументы это: '/cpu_temp' - имя топика, в который мы хотим публиковать, Float32 - тип данных который мы хотим публиковать, queue_size=1 - количество одновременных сообщений которое можно публиковать в этот топик.

Если вы хотите более подробно узнать о возможностях и методах библиотеки rospy или любого из ее классов, смотрите официальную документацию:

http://wiki.ros.org/rospy

Она клевая и понятная, но на английском.

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

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

Вот пример кода, который мы будем использовать далее:

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import Float32

rospy.init_node('temp_publisher')
pub = rospy.Publisher('/cpu_temp', Float32, queue_size=1)
rate = rospy.Rate(1)
temp = Float32()

def getCPUTemp():
    data = open('/sys/class/thermal/thermal_zone0/temp', 'r').read()
    return round(float(int(data)/1000.0),1)

while not rospy.is_shutdown():
    temp.data = getCPUTemp()
    pub.publish(temp)
    rate.sleep()

Пока не особо вдаваясь в подробности как именно работает код, скопируем его в Visual Studio Code и сохраним его на вашем роботе (именно на нем мы хотим считать температуру) в файл/home/pi/base-ros/lesson2/temp_topic_publisher.py

Значение температуры Raspberry Pi "публикует" в "специальный" файл:/sys/class/thermal/thermal_zone0/temp Для того, чтобы получить это значение мы должны прочитать его из этого файла стандартными средствами Python.

data = open('/sys/class/thermal/thermal_zone0/temp', 'r').read()

Значение температуры в данном файле записано в миллиградусах, поэтому, чтобы получить более привычные нам градусы Цельсия, разделим это значение на 1000.

Запустим .py файл через ssh

ssh pi@turtlebro37.local

cd base-ros/lesson2
python3 temp_topic_publisher.py

Запустили, и на первый взгляд ничего не произошло (в том числе вывода ошибки, что уже хорошо). Откроем новое окно (Ctrl-Alt-T) терминала, снова подключимся к роботу и попробуем разобраться что изменилось в системе.

Мы собирались передавать данные о температуре, в ROS есть специальный механизм для такого вида взаимодействия. Он называется "топик". В данной модели взаимодействия есть Издатель - скрипт, который публикует данные в топик. И есть Подписчики - скрипты, которые могут получать данные из этого топика.

Чтобы данные можно было различать, у топиков есть уникальные имена. Давайте выполним команду rostopic list которая выводит список всех существующих топиков (покажет имена):

rostopic list


/bat
/cmd_vel
/diagnostics
/imu
/joint_states
/cpu_temp
/odom
/rosout
/rosout_agg
/scan
/tf
/tf_static

Мы увидели список топиков. В этом списке есть топик /cpu_temp, посмотрим что это такое:

rostopic info /cpu_temp

Type: std_msgs/Float32

Publishers: 
 * /temp_publisher (http://192.168.1.73:45151/)

Subscribers: None

Из описания нам видно, что в этом топике есть данные типа std_msgs/Float32 а информацию об этом публикует Издатель (Publisher) с именем /temp_publisher, это и есть "результат" работы нашего скрипта.

И самое интересное -- давайте посмотрим какая температура CPU нашего робота.

Выполним команду rostopic echo <имя топика>

rostopic echo /cpu_temp

data: 52.5999984741
---
data: 52.5999984741
---
data: 52.0999984741
---
data: 52.0999984741
---
data: 52.0999984741
---
data: 52.5999984741

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

Подведем краткий итог. Мы написали скрипт на python, который запускается на роботе и публикует данные в топик с выбранным именем. При помощи утилиты rostopic , мы смогли его найти в списке и при помощи утилитыechoсмогли "посмотреть" полученную информацию.

Давайте немного вернемся назад, и более внимательно разберем наш python скрипт. Сейчас, зная что он делает, это будет не сложно.

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

# Импорт python библиотеки ROS
import rospy

# Импорт типа сообщения ROS Float32 из пакета std_msgs
from std_msgs.msg import Float32

# Инициализация ноды с именем temp_publisher
rospy.init_node('temp_publisher')

# Создадим обьект Publisher, из библиотеки rospy, который будет
# публиковать в топик /cpu_temp данные формата Float32
pub = rospy.Publisher('/cpu_temp', Float32, queue_size=1)

# Установить частоту публикации данных
rate = rospy.Rate(1)

# Инициализировать пустой обьект Float32
temp = Float32()

# Функция получения данных с датчика температуры
# платы RaspberryPi. Функция возвращает температуру в градусах
def getCPUTemp():
    data = open('/sys/class/thermal/thermal_zone0/temp', 'r').read()
    return round(float(int(data)/1000.0),1)

# Рабочий цикл всей программы. Выполнять цикл пока программу
# пока не остановили
while not rospy.is_shutdown():
    # Получить данные температуры, и присвоить ее переменной temp.data
    temp.data = getCPUTemp()
    # Опубликовать сообщение temp
    pub.publish(temp)
    # Ожидать, пока не пройдет время необходимое для работы с
    # выбранной частотой.
    rate.sleep()

Итак мы создали и запустили нашу первую программу Издатель для ROS

Про базовые утилиты ROS вы можете узнать здесь: https://youtu.be/v0RIdmc--UE

Пример создания простой программы Издателя: https://youtu.be/t17WIlZJDuo

results matching ""

    No results matching ""