Пример совместной независимой работы

На предыдущем уроке мы создали пример в котором Подписчик и Издатель работают совместно. А именно, Подписчик вызывает Издателя. На этом уроке мы попрактикуемся создавать примеры, в которых Подписчик и Издатель будут действовать независимо.

Давайте разберемся в чем принципиальная разница зависимой и независимой работы. В примере предыдущего урока Подписчик вызвал метод greeter.sayHello и передавал ей данные, которые он получал из топика /name. Функция greeter.sayHello в свою очередь форматировала полученные от Подписчика данные и передавала их в Издатель для публикации в топик /greeting. Как вы видите вся логика программы увязана с получением данных в топике/name. Т.е. если данные в этот топик не поступают, то и функция greeter.sayHello не вызывается и Издатель не публикует ничего в топик /greeting.

Теперь, давайте создадим программу, которая будет принимать данные из одного топика, и сохранять эти данные в некую переменную, чтобы другие методы нашей программы могли этими данными пользоваться. Давайте слегка модифицируем пример из прошлого урока. Мы так-же будем получать в топик /name данные типа String с именем человека, и возвращать приветствие в виде Hello, Имя в топик /greeting . Однако сейчас сохранять данные "Имя" мы будем в переменную класса, а публиковать приветствие будем используя это "Имя" но в другом цикле.

Файл lesson6/string_pubsub_async.py

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

from std_msgs.msg import String

class GreetingWorker(object):

    def __init__(self):
        self.pub = rospy.Publisher('/greeting', String, queue_size=10)
        self.sub = rospy.Subscriber('/name', String, self.cbName)
        self.rate = rospy.Rate(1)
        self.name = ""
        self.run()

    def cbName(self, income_msg):
        self.name = income_msg.data

    def pubGreet(self):
        self.pub.publish('Hello, {}'.format(self.name))

    def run(self):
        while not rospy.is_shutdown():
            self.pubGreet()
            self.rate.sleep()

if __name__ == '__main__':

    rospy.init_node('greeting_indep_node')
    rospy.loginfo('Start Greeting Node')
    greeter = GreetingWorker()
    rospy.spin()

В этом примере мы создали класс GreetingWorker который выполняет обработку получения данных в топик /name с последующей публикацией в топик /greeting. Обратите внимание, что мы сначала инициализировали Подписчика, а потом указали одну из функций класса cbName() как callback функцию этого Подписчика. cbName получает данные из Подписчика и сохраняет их в переменную name экземпляра класса.

В методе конструктора класса __init__ мы создали объект pub в котором инициализировали объект Издатель. В функции pubGreet мы публикуем данные взятые из переменной self.name передавая их в качестве аргумента в self.pub.publish ().

Запустим наш скрипт.

python3 lesson6/string_pubsub_async.py

Откроем вывод топика /greeting

rostopic echo /greeting

Отправим тестовые данные в топик /name

rostopic pub /name std_msgs/String "Robot" -r10

В терминале вывода топика /greeting мы увидим что данные начали публиковаться

Hello, Robot

Hello, Robot

Hello, Robot

Обратите внимание, что данные публикуются из терминала в топик /name с частотой 10 герц, а публикуются нашим скриптом в топик /greetings с частотой rospy.Rate(1) - один герц. Это наглядно видно если вы посмотрите с какой частотой идут публикации в топик /name и /greetings открыв rostopic echo name и rostopic echo greetings в соседних терминалах.

Мы написали и разобрали пример python программы которая подписывается на данные, обрабатывает их и публикует их в другой топик и делает это в независимом режиме. Большинство программ в ROS, функционируют по аналогичному принципу. Весь вопрос в сложности обработки этих данных.

Пример взаимодействия Подписчика и Издателя с сохранением состояния: https://youtu.be/YmQJgBIiSSs

results matching ""

    No results matching ""