ROS在同一节点同时订阅和发布消息

ROS版本: ROS Kinetic
操作系统:Ubuntu16.04 LTS

方法一,采用类的方法

参考网站
https://blog.csdn.net/ethan_guo/article/details/80226121
当然也可以用python 实现,我们与例程中的方法为例,这里只谈如何实现在类的订阅并讨论其机制。telker代码不变:

#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('hello', String, queue_size=1)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

以下是listener 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10)  #发布话题设为全局变量

class listener():
    def __init__(self):
        print("class comeing!")
        rospy.init_node('listener', anonymous=True)
        rospy.Subscriber("hello", String, self.callback,queue_size = 1)
    # spin() simply keeps python from exiting until this node is stopped

    def callback(self,data):
        rospy.loginfo( "I heard %s", data.data)
	print("call back comeing!")
        pub.publish(data.data)

if __name__ == '__main__':
    listener()
    print("class circulation!!")
    rospy.spin()

执行这两端代码,观察输出,可以发现只有在启动时,会执行

print("call back comeing!")
print("class comeing!")

这两段代码,而回调函数中的

print("call back comeing!")

会在每次订阅到发布的消息后执行,这里就涉及到rospy.spin()的工作机制,它并不是一直循环这个listener()类。而是循环进入类后的订阅函数,这个函数叫做ROS消息回调处理函数。可以参考官方网站查看其具体原理。

到这里其实还有一个小问题,那就是关于画图,如果我们想在回调函数中实现画图,或者在回调函数中修改变量的值,而在类的构造函数中执行与此变量有关的操作,那么我们只需要在类中加一个循环即可:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10)  #发布话题设为全局变量

class listener():
    def __init__(self):
        print("class comeing!")
        self.da = []
        rospy.init_node('listener', anonymous=True)
        rospy.Subscriber("hello", String, self.callback,queue_size = 1)
    # spin() simply keeps python from exiting until this node is stopped
        #############加入的循环####################
        while not rospy.is_shutdown():
	    print(self.da)#此处可以是画图的语句
        ##########################################
    def callback(self,data):
        rospy.loginfo( "I heard %s", data.data)
	self.da = data.data
	print("call back comeing!")
        pub.publish(data.data)

if __name__ == '__main__':
    listener()
    print("class circulation!!")
    rospy.spin()

这时候可以发现,回调函数中得到的变量在构造函数的循环中执行了。实时画图在后面的文章中讨论。

方法二,全局变量

下面介绍一下Python中用全局变量的方法实现.
以ros wiki上面的话题通信教程为例。
http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29
这里定义了talker 和 listener :
talker:

#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('pub1', String, queue_size=1)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

这里我么修改listener,在文件中加入了一个全局变量pub,然后直接将订阅的话题通过
pub再次发布出去,当然,这里只是个测试,实际中肯定是对该消息进行处理后再发布的,写改后的listener如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10)  #发布话题设为全局变量
def callback(data):
    rospy.loginfo( "I heard %s", data.data)
    pub.publish(data.data)
def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("pub1", String, callback,queue_size = 1)
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    listener()

这时,我们像教程中一样运行这两个程序结果并没有什么区别,但如果我们用rostopic list 查看,就会发现比原教程中多了一个话题,就是问在listener中发布的,接下来,我们创建一个listen_listener.py的文件来订阅这个话题:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

def callback(data):
    rospy.loginfo( "I heard %s", data.data)
def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("pub_with_sub", String, callback,queue_size = 1)
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    listener()

ok,别忘了将文件设置为可执行文件,这是后,我们同时打开这三个文件。会发现显示同样的内容。实际上是这样一个结构:
talker发布->listener订阅 再发布 -> listen_listener再订阅!

你可能感兴趣的:(机器人ROBOT)