参考:http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber(python)  

1 编写Publisher节点

  节点是连接到ROS网络的可执行文件的ROS术语。在这里,我们创建一个不断广播消息的发布者(“talker”)节点。创建一个ros包,也可以用现有的ros包,比如:  
roscd beginner_tutorials
  创建包的方法参考之前的文章《ROS中编写服务器和客户端的方法(C++版)》  

1.1 代码

  首先创建一个‘script’的路径来保存python代码  
mkdir scripts
cd scripts
  然后,新建一个文件,命名为talker.py,复制以下代码进去:  
#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String
 
def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    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
 

1.2 代码解释

  让我们来一行一行地看代码意义  
#!/usr/bin/env python
  每个python版本的ROS节点在开头都有这样一个声明,表示这个文件是python类型  
import rospy
from std_msgs.msg import String
  如果要写ROS节点,需要导入rospy。std_msgs.msg的目的是可以使用std_msgs/String消息类型来发布  
     pub = rospy.Publisher('chatter', String, queue_size=10)
     rospy.init_node('talker', anonymous=True)
  这部分代码定义了talker与其它ROS节点的通讯。   pub = rospy.Publisher("chatter", String, queue_size=10) 表示你正在使用String类型的消息来发布你的节点到chatter。String就是std_msgs.msg.String类。如果任何订阅者都没有足够快地接收到消息,queue_size将会限制队列消息的数量。在旧的ROS版本中,忽略掉了这一点。   下一行是非常重要的,因为它告诉rospy你的ros节点名字,直到rospy有了这个信息,它不能够和ROS Master开始通讯。在这个例子中,你的节点名字是talker   anoymous=True 通过在你名字的后边添加一个随机数,来保证你的节点独一无二。  
     rate = rospy.Rate(10) # 10hz
  这一行创建速率对象rate.在其方法sleep()的帮助下,它提供了一个以一定速率循环的方便的方法。参数10表示我们期望以每秒循环10次(只要我们的处理时间不超过1/10秒)  
     while not rospy.is_shutdown():
         hello_str = "hello world %s" % rospy.get_time()
         rospy.loginfo(hello_str)
         pub.publish(hello_str)
         rate.sleep()
  这个循环是一个相当标准的rospy结构:检查rospy.is_shutdown标志位然后开始工作(‘work’)。你必须检查is_shutdown()来确定你的成熟是否应该退出(例如有Ctrl-C操作或其它)。在这个例子中,‘work’是调用pub.publish(hello_str)来发布一个字符串到chatter话题。循环调用rate.sleep(),睡眠足够的时间,以便通过循环来保持所需的速率。   (你可以运行rospy.sleep()和time.sleep()来达到相同的定时效果)   循环中海油rospy.loginfo(str),这条执行三重任务:消息打印到屏幕上,写入到节点的日志文件中,并且被写入rosout。rosout可以方便的进行调试:你可以使用rqt_console来提取消息,而不必使用节点的输出找到控制台窗口。   std_msgs.msg.String是一个非常简单的消息类型,所以你可能会想知道发布更复杂的类型是什么样子。一般的经验是构造函数args与.msg文件中的顺序相同。你也可以传递任何参数,也可以直接初始化字段。  
msg = String()
msg.data = str
  或者可以初始化一些值,剩余的采用默认值:  
String(data=str)
  你可能会好奇剩余的几行代码:  
     try:
         talker()
     except rospy.ROSInterruptException:
         pass
  除了标准的Python_main_检查之外,他会捕获一个rospy.ROSInterruptException异常,当Ctrl-C被按下或者Node被关闭时,它将以rospy.sleep()和rospy.Rate.sleep()的方法抛出。引发这个异常的原因是因为在sleep()之后不会再继续执行代码。   现在,让我们来写一个节点来接收这条消息。  

2.写一个Subscriber节点

 

2.1 代码

  还是在上一节文件夹中,建立一个listener.py的文件,复制以下代码:  
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
 
def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
    
def listener():
 
    # In ROS, nodes are uniquely named. If two nodes with the same
    # node are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('listener', anonymous=True)
 
    rospy.Subscriber("chatter", String, callback)
 
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()
 
if __name__ == '__main__':
    listener()
 

2.2 代码解释

  listener.py与talker.py文件类似,在listener中会引入一种新的基于回调机制callback来订阅消息。  
     rospy.init_node('listener', anonymous=True)
 
     rospy.Subscriber("chatter", String, callback)
 
     # spin() simply keeps python from exiting until this node is stopped
     rospy.spin()
  这个声明表示你的节点订阅消息类型为std_msgs.msgs.String的chatter主题。当接收到新的消息时,回调callback将作为第一个参数被调用。   我们也改变了对rospy.init_node()的调用,我们添加了anonymous=True关键字参数。ROS要求每个节点都有唯一的名称,如果有相同名称的节点出现,则会突破前一个节点。这样就可以很容易地从网络上启动故障的节点。anonymous=True标志高速rospy为节点生成唯一的名称,以便可以轻松地运行多个listener.py节点。   最后添加rospy.spin()只是为了让你的节点退出,直到节点已经关闭。与roscpp不同,rospy.spin()不影响用户回调函数,因为它们有自己的线程。  

3 构建自己的节点

  我们使用CMake作为我们的构建系统,是的,即使对于python节点也必须使用它。这是为了确保自动生成的消息和服务的python代码被创建。   运行到catkin工作空间,然后运行catkin_make:  
cd ~/catkin_ws
catkin_make
  然后分别在三个不同的终端运行下边的指令  
roscore
rosrun beginner_tutorials talker.py
rosrun beginner_tutorials listener.py
  运行结果如下