Writing a Simple Publisher and Subscriber

Writing the Publisher Node

#!/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

Code Explained

import rospy
from std_msgs.msg import String

You need to import rospy if you are writing a ROS Node. The std_msgs.msg import is so that we can reuse the std_msgs/String message type (a simple string container) for publishing.

    pub = rospy.Publisher(‘chatter‘, String, queue_size=10)
    rospy.init_node(‘talker‘, anonymous=True)

This section of code defines the talker‘s interface to the rest of ROS. pub = rospy.Publisher("chatter", String, queue_size=10) declares that your node is publishing to the chatter topic using the message type String. String here is actually the class std_msgs.msg.String. The queue_size argument is New in ROS hydro and limits the amount of queued messages if any subscriber is not receiving the them fast enough. In older ROS distributions just omit the argument. The next line, rospy.init_node(NAME), is very important as it tells rospy the name of your node -- until rospy has this information, it cannot start communicating with the ROS Master. In this case, your node will take on the name talker. NOTE: the name must be a base name, i.e. it cannot contain any slashes "/".

rate = rospy.Rate(10) # 10hz

This line creates a Rate object rate. With the help of its method sleep(), it offers a convenient way for looping at the desired rate. With its argument of 10, we should expect to go through the loop 10 times per second (as long as our processing time does not exceed 1/10th of a second!)

    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

This loop is a fairly standard rospy construct: checking the rospy.is_shutdown() flag and then doing work. You have to check is_shutdown() to check if your program should exit (e.g. if there is a Ctrl-C or otherwise). In this case, the "work" is a call to pub.publish(hello_str) that publishes a string to our chatter topic. The loop calls r.sleep(), which sleeps just long enough to maintain the desired rate through the loop.

(You may also run across rospy.sleep() which is similar to time.sleep() except that it works with simulated time as well (see Clock).)

This loop also calls rospy.loginfo(str), which performs triple-duty: the messages get printed to screen, it gets written to the Node‘s log file, and it gets written to rosout. rosout is a handy for debugging: you can pull up messages using rqt_console instead of having to find the console window with your Node‘s output.

std_msgs.msg.String is a very simple message type, so you may be wondering what it looks like to publish more complicated types. The general rule of thumb is that constructor args are in the same order as in the .msg file. You can also pass in no arguments and initialize the fields directly, e.g.

msg = String()
msg.data = str

or you can initialize some of the fields and leave the rest with default values:

String(data=str)

You may be wondering about the last little bit:

    try:
        talker()
    except rospy.ROSInterruptException:
        pass

In addition to the standard Python __main__ check, this catches a rospy.ROSInterruptException exception, which can be thrown by rospy.sleep() and rospy.Rate.sleep() methods when Ctrl-C is pressed or your Node is otherwise shutdown. The reason this exception is raised is so that you don‘t accidentally continue executing code after the sleep(). Now we need to write a node to receive the messages.

Writing the Subscriber Node

#!/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()

Don‘t forget to make the node executable:

$ chmod +x listener.py
    rospy.init_node(‘listener‘, anonymous=True)

    rospy.Subscriber("chatter", String, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

This declares that your node subscribes to the chatter topic which is of type std_msgs.msgs.String. When new messages are received, callback is invoked with the message as the first argument.

We also changed up the call to rospy.init_node() somewhat. We‘ve added the anonymous=True keyword argument. ROS requires that each node have a unique name. If a node with the same name comes up, it bumps the previous one. This is so that malfunctioning nodes can easily be kicked off the network. The anonymous=True flag tells rospy to generate a unique name for the node so that you can have multiple listener.py nodes run easily.

The final addition, rospy.spin() simply keeps your node from exiting until the node has been shutdown. Unlike roscpp, rospy.spin() does not affect the subscriber callback functions, as those have their own threads.

Examining

$ rosrun beginner_tutorials talker.py
[INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
[INFO] [WallTime: 1314931832.775497] hello world 1314931832.77
[INFO] [WallTime: 1314931833.778937] hello world 1314931833.78
[INFO] [WallTime: 1314931834.782059] hello world 1314931834.78
[INFO] [WallTime: 1314931835.784853] hello world 1314931835.78
[INFO] [WallTime: 1314931836.788106] hello world 1314931836.79
$ rosrun beginner_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
[INFO] [WallTime: 1314931972.270429] /listener_17657_1314931968795I heard hello world 1314931972.27
[INFO] [WallTime: 1314931973.274382] /listener_17657_1314931968795I heard hello world 1314931973.27
[INFO] [WallTime: 1314931974.277694] /listener_17657_1314931968795I heard hello world 1314931974.28
[INFO] [WallTime: 1314931975.283708] /listener_17657_1314931968795I heard hello world 1314931975.28
时间: 2024-10-27 10:33:23

Writing a Simple Publisher and Subscriber的相关文章

ROS学习 Writing a Simple Publisher and Subscriber & Examining them

本文主要部分全部来源于ROS官网的Tutorials. 创建Publisher Node roscd beginner_tutorials mkdir -p src gedit src/talker.cpp & 复制如下代码,其大致流程如下: Initialize the ROS system Advertise that we are going to be publishing std_msgs/String messages on the chatter topic to the mast

【11】Writing a Simple Publisher and Subscriber (C++)

Publisher #include "ros/ros.h" #include "std_msgs/String.h" #include <sstream> int main(int argc, char **argv) { ros::init(argc, argv, "talker");   //1.启动该节点 2.并设置其名称(名称要唯一) ros::NodeHandle n; //设置节点句柄 ros::Publisher ch

Writing a Simple Publisher and Subscriber (Python)

Writing a Service Node Here we'll create the service ("add_two_ints_server") node which will receive two ints and return the sum. Change directory into the beginner_tutorials package, you created in the earlier tutorial, creating a package: $ ro

Writing a Simple Service and Client (C++)

Here we'll create the service ("add_two_ints_server") node which will receive two ints and return the sum. Change directories to your beginner_tutorials package you created in your catkin workspace previous tutorials: roscd beginner_tutorials Wr

Writing a Simple Action Server using the Execute Callback

fibonacci_server.cpp /* 黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*) */ #include <ros/ros.h> #include <actionlib/server/simple_action_server.h>//action lib #include <learning_actionli

2018-11-3 星期六

English: listening.speaking.reading.writing.translation 1. Do you drink a lot of water? Well, I would like to think myself as a person who drinks a lot of water, but that is not true. Sometimes I got so busy. Sometimes I got occupied that I forgot to

Publisher/Subscriber(发布/订阅者)消息模式开发流程

该模式的作用是发布者和订阅者 可以相互发送消息 发布者和订阅者都充当 生产者和消费者 发布者 package publisher.to.subscriber; import java.awt.font.TextMeasurer; import javax.jms.Connection;import javax.jms.Destination; import javax.jms.JMSException;import javax.jms.MapMessage;import javax.jms.Me

Apache POI – Reading and Writing Excel file in Java

来源于:https://www.mkyong.com/java/apache-poi-reading-and-writing-excel-file-in-java/ In this article, we will discuss about how to read and write an excel file using Apache POI 1. Basic definitions for Apache POI library This section briefly describe a

A Simple make file tutorial

A Simple Makefile Tutorial Makefiles are a simple way to organize code compilation. This tutorial does not even scratch the surface of what is possible using make, but is intended as a starters guide so that you can quickly and easily create your own