1、编写发布器节点
1.1 源代码
查看 talker.py 文件:
$ roscd dashgo_tutorials/scripts
$ cat 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 Node 都会在顶部有这个声明。 第一行确保脚本作为 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)
这部分代码定义了说话者与 ROS 其余部分的接口。 pub = rospy.Publisher(“chatter”,String, queue_size = 10)声明您的节点正在使用消息类型 String 发布到 chatter 主题。 这里的字符 串实际上是 std_msgs.msg.String 类。 如果任何用户没有足够快地接收它们,queue_size 参 数会限制排队的消息数量。
下一行 rospy.init_node(NAME,...)非常重要,因为它告诉 rospy 节点的名称 - 直到 rospy 获得这些信息,它不能开始与 ROS Master 进行通信。 在这种情况下,您的节点将采用名称 讲话者。 注:名称必须是基本名称,即不能包含任何斜线“/”。
anonymous = True 通过在 NAME 的末尾添加随机数确保您的节点具有唯一的名称。
rate = rospy.Rate(10) # 10h
此行创建一个 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()标志,然后开始工作。 你必须检查 is_shutdown()来检查你的程序是否应该退出(例如,如果有 Ctrl-C 或其他)。 在这种情况下,“工作”是对 pub.publish(hello_str)的调用,它向我们的聊天话题发布字符 串。循环调用 rate.sleep(),睡眠时间足够长,以便通过循环保持期望的速率。
这个循环还调用 rospy.loginfo(str),它执行三重任务:消息被打印到屏幕,它被写入 Node 的日志文件,并被写入到 rosout。 rosout 对于调试非常方便:您可以使用 rqt_console 调用消息,而不必使用 Node 的输出来查找控制台窗口。
std_msgs.msg.String 是一种非常简单的消息类型,因此您可能想知道发布更复杂的类型是 什么样子。一般的经验法则是构造函数的参数与.msg 文件中的顺序相同。您也可以不传入 参数并直接初始化字段,例如
msg = String()
msg.data = str
try:
talker()
except rospy.ROSInterruptException:
pass
除了标准的 Python __main__检查外,这还会捕获一个 rospy.ROSInterruptException 异常, 当按下 Ctrl-C 或您的 Node 以其他方式关闭时,rospy.sleep()和 rospy.Rate.sleep()方法 可能抛出 rospy.ROSInterruptException 异常。 引发这个异常的原因是,你不会在 sleep() 之后意外地继续执行代码。
2、编写订阅器节点
2.1 源代码
在 dashgo_tutorials/scripts 目录下查看 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 代码说明
下面我们将逐条解释代码,当然,之前解释过的代码就不再赘述了。
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 话题。 当收到新消息时,回调将 作为第一个参数与消息一起调用。
我们也改变了对 rospy.init_node()的调用。 我们添加了 anonymous = True 关键字参数。 ROS 要求每个节点都有唯一的名称。 如果一个名字相同的节点出现,它会颠覆之前的节点。 这样可以很容易地将故障节点从网络中踢出。 anonymous = True 标志告诉 rospy 为节点生 成一个唯一的名称,以便您可以轻松地运行多个 listener.py 节点。
最后加上,rospy.spin()只是让你的节点退出,直到节点关闭。 与 roscpp 不同, rospy.spin()不影响订阅者回调函数,因为这些函数有自己的线程。
3、给 talker.py 和 listener.py 文件添加执行权限
$ roscd dashgo_tutorials/scripts
$ chmod +x *
4、测试发布器和接收器
4.1 确保 roscore 可用,并运行:
$ roscore
4.2 启动发布器
$ rosrun dashgo_tutorials talker.py
将看到如下的输出信息:
[INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
[INFO] [WallTime: 1314931833.778937] hello world 1314931833.78
[INFO] [WallTime: 1314931836.788106] hello world 1314931836.79
4.3 启动订阅器
$ rosrun dashgo_tutorials listener.py
将会看到如下的输出信息:
[INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I
heard hello world 1314931969.26
[INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I
heard hello world 1314931970.26
[INFO] [WallTime: 1314931971.266348] /listener_17657_1314931968795I
heard hello world 1314931971.26
至此,已经测试完了发布器和订阅器(python)。