Подписчик (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