Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Подписчик (Python)

Что вы узнаете в этом разделе:

  • Как создать программу-подписчик на Python
  • Как подписаться на топик и получать данные
  • Структуру программы-подписчика в ROS2
  • Как обрабатывать входящие сообщения в callback-функции
  • Как проверить работу подписчика вместе с издателем
  • Разницу между издателем и подписчиком

Программа подписчик на Python

В прошлой части, мы создали пример на python программы Издателя. В этой части мы разберем как самостоятельно создать программу Подписчика.

Аналогия из жизни: Если издатель — это радиовещательная станция, которая постоянно передает сигнал, то подписчик — это радиоприемник, который настраивается на нужную частоту и слушает передачи. Подписчик не может контролировать, когда придут данные, он просто ждет и обрабатывает их, когда они появляются. Это похоже на подписку на новостную рассылку: вы подписываетесь один раз, а затем автоматически получаете все новые письма.

Мы создадим нашу программу на основе официальной документации. Наш подписчик подпишется на топик temp и выведет полученную информацию на экран.

Сохраним код из примера в файл в файл /home/pi/ros2-base/chapter4/temp_topic_subscriber.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import Float32


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            Float32,
            'temp',
            self.listener_callback,
            10)

    def listener_callback(self, msg):
        self.get_logger().info(f'CPU temp: {msg.data}')



def main(args=None):
    
    rclpy.init(args=args)
    minimal_subscriber = MinimalSubscriber()
    
    try:
        rclpy.spin(minimal_subscriber)
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    main()

Запустим программу Подписчик

ssh pi@turtlebro01.local
cd ros2-base/chapter4
python3 temp_topic_subscriber.py

Мы увидим, что ничего не происходит (данные не выводятся). Но в топик temp никто не публикует данные, поэтому запустим пример Издателя из прошлого урока.

ssh pi@turtlebro01.local
cd ros2-base/chapter2
python3 temp_topic_publisher.py

После запуска Издателя, в окне терминала с Подписчиком, начнут выводится полученные данные

[INFO] [1756820712.936384050] [minimal_subscriber]: I heard: "50.099998474121094"
[INFO] [1756820712.939289173] [minimal_subscriber]: I heard: "50.599998474121094"
[INFO] [1756820713.391311101] [minimal_subscriber]: I heard: "50.099998474121094"
[INFO] [1756820713.890021376] [minimal_subscriber]: I heard: "50.099998474121094"
[INFO] [1756820714.390069102] [minimal_subscriber]: I heard: "50.099998474121094"
[INFO] [1756820714.890540083] [minimal_subscriber]: I heard: "51.099998474121094"
[INFO] [1756820715.390026962] [minimal_subscriber]: I heard: "49.70000076293945"

Мы убедились, что наш пример работает. При этом у нас получилось, что одна наша программа передает данные температуры, а другая программа их получает и выводит на экран.

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

ros2 topic pub /temp std_msgs/msg/Float32 "data: 55.0"

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

Разбор программы Подписчика

Представленный код, очень похож на пример Издателя, который мы разбирали в прошлом части. Блок "скелета" приложения ROS вообще не отличается.

Рассмотрим только функции __init__(self): и listener_callback(self, msg)

Первая, это код инициализации ноды подписчика __init__(self):

#инициализация ноды, через инициализацию родительского класса.
#в параметрах, указываем имя ноды.
super().__init__('minimal_subscriber')

#создание подписчика. В атрибутах мы указываем, Float32 -- тип сообщения 
#temp -- название топика
#self.listener_callback -- функция которая должна вызываться когда в топике 
#появились данные. self. в начале, указывает что функция принадлежит классу
#10 -- размер очереди
self.subscription = self.create_subscription(
    Float32,
    'temp',
    self.listener_callback,
        10)

Подробная документация по методам create_subscription из официальной API документации.

Функция обработчик полученных данных из топика listener_callback(self, msg)

# Параметре функции msg находится сообщение из топика
# необходимого нам типа
def listener_callback(self, msg):
    # выводим сообщение о температуре через сообщение в логи
    self.get_logger().info(f'CPU temp: {msg.data}')

Финальный пример программы, доступен в разделе примеры на GitHub turtlebro2-examples

Дополнительные материалы

Подробнее о примере Издателя и Подписчика, в официальной документации: http://docs.ros.org/en/lunar/api/rospy/html/rospy.topics.Subscriber-class.html

Официальной инструкции по работе с топиками.

Официальную инструкцию к пакету rclpy https://docs.ros.org/en/rolling/p/rclpy/.

Примеры использования библиотек https://github.com/ros2/examples/tree/humble