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

Подписчик и Издатель (Вариант2)

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

  • Что такое "асинхронный" подход обработки данных
  • Как хранить состояние программы между вызовами функций
  • Как использовать таймеры для независимой публикации данных
  • Разницу между синхронным и асинхронным подходами
  • Когда использовать каждый из подходов

Программа Подписчика и Издателя

Рассмотрим подход, который можно назвать "асинхронным". Входящие топики никак не влияют на работу выходящих топиков, обработка данных и публикация происходит по таймеру с необходимой нам частотой.

Для этого добавим в программу переменную "хранилище" имени пользователя, так как нам необходимо хранить "состояние" программы.

    # Хранилище для имени пользователя
    self.user_name = "Nobody"  # Значение по умолчанию

Функцию обработки данных от Подписчика, упростим. Она будет проверять и обновлять переменную с именем пользователя

    #Обновляем имя пользователя, когда мы его получили
    def name_callback(self, msg):
        name = msg.data
        
        if name:  # Проверяем, что имя не пустое
            self.user_name = name
            self.get_logger().info(f'User name updated to: {name}')

А для публикации данных, воспользуемся таймером, с частотой 2 герца и функцией публикации данных publish_greeting

        self.timer = self.create_timer(0.5, self.publish_greeting)
......

    def publish_greeting(self):
        #Публикует приветствие с текущим именем пользователя
        greeting = f"Hello, {self.user_name}"
        
        greeting_msg = String()
        greeting_msg.data = greeting
        
        self.publisher.publish(greeting_msg)
        self.get_logger().info(f'Published: "{greeting}"')    

Полный код получившейся "асинхронной" программы

#!/usr/bin/env python3

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

class GreetingNode(Node):
    def __init__(self):
        super().__init__('greeting_node')

        # Хранилище для имени пользователя
        self.user_name = "Nobody"  # Значение по умолчанию
        
        # Создаем подписчика на топик /name
        self.subscription = self.create_subscription(
            String,
            '/name',
            self.name_callback,
            10  # Размер очереди
        )
        
        # Создаем издателя для топика /greeting
        self.publisher = self.create_publisher(
            String,
            '/greeting',
            10  # Размер очереди
        )
        
        # Создаем таймер для публикации приветствия каждые 0.5 секунды
        self.timer = self.create_timer(0.5, self.publish_greeting)

        self.get_logger().info('Greeting node started!')

    #Обновляем имя пользователя, когда мы его получили
    def name_callback(self, msg):
        name = msg.data
        
        if name:  # Проверяем, что имя не пустое
            self.user_name = name
            self.get_logger().info(f'User name updated to: {name}')

    def publish_greeting(self):
        #Публикует приветствие с текущим именем пользователя
        greeting = f"Hello, {self.user_name}"
        
        greeting_msg = String()
        greeting_msg.data = greeting
        
        self.publisher.publish(greeting_msg)
        self.get_logger().info(f'Published: "{greeting}"')            

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

if __name__ == '__main__':
    main()

Запустим ее и сразу увидим что начинаются публиковаться сообщения с заданной частотой. В самом начале работы программы, имя пользователя Nobody

python3 pub-sub2.py
[INFO] [1757346870.166230525] [greeting_node]: Greeting node started!
[INFO] [1757346870.650511581] [greeting_node]: Published: "Hello, Nobody"
[INFO] [1757346871.150480584] [greeting_node]: Published: "Hello, Nobody"
[INFO] [1757346871.650390068] [greeting_node]: Published: "Hello, Nobody"
[INFO] [1757346872.150407664] [greeting_node]: Published: "Hello, Nobody"

Опубликуем новое имя

ros2 topic pub /name "std_msgs/msg/String" 'data: 'Иван''
[INFO] [1757346877.562927934] [greeting_node]: User name updated to: Иван
[INFO] [1757346877.650443192] [greeting_node]: Published: "Hello, Иван"
[INFO] [1757346878.150455047] [greeting_node]: Published: "Hello, Иван"

Программа работает, как мы и ожидали. Постоянно идут данные, а при поступлении нового имени приветствие меняется.

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