# 12.1 编写Publisher Node

**节点**(Node) 是指 ROS 网络中可执行文件。接下来，我们将会创建一个发布器节点("talker")，它将不断的在 ROS 网络中广播消息。

切换到之前创建的 `beginner_tutorials package` 路径下：

```bash
$ roscd beginner_tutorials
```

## 12.1.1 **源代码**

首先,创建一个'scipts'文件夹来存储我们的Python脚本：

```
$ mkdir scripts
$ cd scripts
```

然后下载`talk.py`脚本到`scripts`文件夹下，并为该脚本增加执行权限。

```
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py
```

你可以用`$ rosed beginner_tutorials 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
```

## 12.1.2 代码说明

现在，我们来分段解释代码。

```
#!/usr/bin/env python
```

每个Python ROS Node都会在这个顶部有这个声明。该语句确保脚本作为Python脚本执行。

```
import rospy
from std_msgs.msg import String
```

如果您正在编写ROS节点，则需要导入rospy。

发表消息时需使用标准消息类型，我们需要导入`std_msgs.msg`

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

这部分代码定义了talker与ROS其余部分的接口。`pub = rospy.Publisher("chatter", String, queue_size=10)` ,它声明节点在chatter话题上发布String类型的消息。 String对应std\_msgs.msg.String。queue\_size对应发布序列的大小。

`rospy.init_node(NAME, ...)`告诉rospy你的节点名--直到rospy获得这些信息，它才能开始与ROS Master进行通信。在本例中，我们的节点名为talker(节点名需符合基本的命名规范，如不能包含"/")

`anonymous = True` 通过在NAME的末尾添加随机数确保您的节点具有唯一的名称。参考rospy文档中的[Initialization and Shutdown - Initializing your ROS Node ](http://wiki.ros.org/rospy/Overview/Initialization%20and%20Shutdown#Initializing_your_ROS_Node)查找更多关于节点初始化的内容。

```
    rate = rospy.Rate(10) # 10hz
```

该代码创建一个名为rate的 Rate对象。该对象的sleep()方法提供了一种简便方法去实现期望的循环速率。本例中一秒循环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()检查循环是否退出（e.g. Ctrl-C）。在本例中，调用`pub.publish(hello_str)`发布一个字符串到chatter话题上。while循环中调用rate.sleep（），以10hz的速率保持循环。

该循环同时也调用了 `rospy.loginfo(str)`,其执行三重任务：将消息打印到屏幕，将过程写到节点的log文件，同时写到rosout。rosout对于调试非常方便：您可以使用rqt\_console调用消息，而不必使用Node的输出来查找控制台窗口。

`std_msgs.msg.String` 是一种非常简单的消息类型，所以你可能想知道发布更复杂的类型是什么样子。一般的经验法则是构造函数的参数与.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（）之后意外地继续执行代码。

接下来我们要编写一个节点来接收这个消息。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://songapore.gitbook.io/ros-tutorials/12-bian-xie-jian-dan-de-publisher-he-subscriberpython/12.1-bian-xie-publisher-node.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
