ROS1入门——编写自定义话题Topic

1. 引言

通过上一篇,我们对ros里面的节点有了基本的了解,下面是一个关于如何在ROS1环境中创建和使用自定义话题(Topic)的介绍。我们将通过创建一个简单的发布者-订阅者系统来演示这个过程,以帮助大家理解话题。关于底层原理这里不做过多的介绍,我们通过示例来理解这一过程。

2. 创建工作空间并初始化

2.1 进入工作空间

打开终端,并输入:

cd catkin_ws/src/

前提是你已经创建好了工作空间,如果还没创建好工作空间,请看第一篇博文,链接如下:https://blog.csdn.net/winner0111/article/details/141788364?spm=1001.2014.3001.5501

2.2 创建功能包

之后我们在这个目录下创建一个功能包,在终端接着输入:

catkin_create_pkg topic_ws rospy roscpp std_msgs
2.3 编写消息类型

为了发送数据,我们需要定义一个消息类型。在catkin_ws目录下创建一个名为msg的新目录,并在此目录中创建一个.msg文件,命名为CustomMessage.msg。定义一个简单的消息结构:

string field1
int32 field2
2.4 编译工作空间

在这里我们可以先对工作空间进行编译,以便于新建的功能包能进入ROS的软件包列表 :

cd ..
catkin_make
2.5 编写发布者话题

在工作空间catkin_ws文件目录下创建文件夹scripts,进入该文件夹,在该文件夹下使用python编写发布者话题,我们可以参照以下顺序编写代码:

  • 导入需要的库
  • 初始化节点
  • 声明需要发布的话题名称以及需要能发布消息的对象
  • 开启循环,不停地使用上述对象发布消息包

因此代码可以按照以下流程来写:

(1)指示操作系统使用环境中的Python解释器来执行此脚本,指定解码方式。

#!/usr/bin/env python
#encoding=utf-8

(2)导入ROS Python接口库rospy以及自定义消息类型CustomMessage,CustomMessage是在之前创建的消息文件中定义的消息类型。

import rospy
from my_first_package.msg import CustomMessage

(3)定义一个名为talker的函数,这个函数要包含所有用于发布消息的代码。

def talker():
	pub = rospy.Publisher('custom_topic', CustomMessage, queue_size=10)

这里创建一个发布者对象pub,它将消息发布到名为custom_topic的话题上,发布的消息类型为CustomMessage。queue_size参数设置了发布缓存队列的大小,这里是10个消息。

之后初始化一个名为talker的ROS节点。anonymous=True意味着如果存在多个同名节点运行,ROS会给它们加上不同的后缀来区分。

    rospy.init_node('talker', anonymous=True)

再创建一个Rate对象,用于控制循环的频率。这里设置的是每秒1次,即1Hz;实例化了一个CustomMessage对象msg,并定义了一个计数变量i。

    rate = rospy.Rate(1) # 1hz
    msg = CustomMessage()
    i = 0

定义一个循环,只要ROS没有请求关闭节点,就一直运行下去。设置msg对象的两个字段。field1是一个字符串,包含“Hello World”加上当前循环次数i;field2则直接赋值为当前循环次数i。使用ROS的日志功能打印出msg的内容。还有发布消息msg到custom_topic话题,让当前线程休眠足够的时间以达到指定的循环频率,增加循环计数器i的值,以便在下次循环中使用新的值。

    while not rospy.is_shutdown():
        msg.field1 = "Hello World %s" % i
        msg.field2 = i
        rospy.loginfo(msg)
        pub.publish(msg)
        rate.sleep()
        i += 1

定义Python程序的标准入口点,即如果这个脚本被作为主程序运行,则调用talker()函数。try…except块用来处理ROSInterruptException异常,这种异常通常在用户请求节点退出时抛出,如按下Ctrl+C。

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

最后组装形成以下代码:

#!/usr/bin/env python
#encoding=utf-8
import rospy
from my_first_package.msg import CustomMessage

def talker():
    pub = rospy.Publisher('custom_topic', CustomMessage, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(1) # 1hz
    msg = CustomMessage()
    i = 0
    while not rospy.is_shutdown():
        msg.field1 = "Hello World %s" % i
        msg.field2 = i
        rospy.loginfo(msg)
        pub.publish(msg)
        rate.sleep()
        i += 1

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

至此,发布者节点编写完毕,我们在脚本所在目录下给对应的脚本赋权之后即可直接执行。

2.6 编写订阅者节点

同样在scripts目录中创建一个名为listener.py的Python脚本。流程与编写发布者节点的时候类似,这里不做赘述。我们编写代码如下:

#!/usr/bin/env python
#encoding=utf-8
import rospy
from my_first_package.msg import CustomMessage

def callback(data):
    rospy.loginfo("I heard %s", data)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("custom_topic", CustomMessage, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()

同样赋权完成之后,该脚本可以直接执行。

2.7 测试发布者和订阅者

为了更新ros功能包的各项依赖,我们对工作空间继续编译,打开终端输入:

cd ~/catkin_ws
catkin_make

之后逐个启动,在终端输入:

cd scripts/
python talker.py

新建终端,启动另一个节点:

cd ~/catkin_ws/src/scripts/
python listener.py

最后我们在两个终端里面能看到发布者不断发布消息,而订阅者不断接收到消息。

3. 示例中节点和话题的区别

3.1 节点(Node)

在ROS中,节点是指一个执行特定任务的进程。每个节点都是一个独立的执行单元,可以与其他节点协作完成复杂的任务。节点是ROS应用程序的基本构建块,通过编写节点,开发者能够实现多种功能,包括但不限于:

  • 发布数据:节点可以发布数据到一个或多个话题中,供其他节点订阅。
  • 订阅数据:节点可以从一个或多个话题中订阅数据,处理接收到的信息。
  • 提供服务:节点可以提供服务(Service),其他节点可以通过调用这些服务来请求执行特定的操作。
  • 调用服务:节点也可以调用其他节点提供的服务,获取所需的结果或数据。

为了使一个进程成为ROS中的有效节点,必须通过rospy.init_node()函数来初始化它。这个函数需要一个节点的名称作为参数,并且可以设置节点是否匿名。如果设置为匿名,ROS将会自动为该节点添加一个随机的后缀,以确保每个节点的名字是唯一的,这对于调试和并发测试特别有用。

节点可以通过ROS的API与其他节点进行通信。在前面的代码示例中,talker节点通过调用rospy.init_node(‘talker’, anonymous=True)来初始化,并开始执行发布消息的任务。

3.2 话题(Topic)

话题是ROS中的通信机制之一,它允许节点之间以异步的方式发送和接收消息。话题类似于一种通信频道,节点可以通过发布或订阅的方式与话题进行互动。话题上的消息发布遵循发布-订阅模式:

  • 发布者(Publisher):发布者节点向话题发送消息,这些消息可以被一个或多个订阅者接收。
  • 订阅者(Subscriber):订阅者节点监听特定的话题,并接收该话题上的所有消息。

发布者并不关心是否有订阅者在接收消息,同样,订阅者也不关心是谁发布了消息。这种解耦使得系统更加灵活和健壮。此外,ROS还支持消息的持久化存储,即使没有订阅者,消息也会被暂时保存,直到有订阅者连接上来。

在示例中,custom_topic是一个话题,talker节点作为发布者,向custom_topic发布CustomMessage类型的消息。任何订阅了custom_topic的节点,都可以接收这些消息。

3.3 示例总结

在给定的代码示例中,talker节点通过rospy.Publisher创建了一个发布者对象,并指定了要发布消息的话题名称custom_topic和消息类型CustomMessage。接着,talker节点进入一个循环,不断更新消息的内容,并将其发布到话题上。订阅了custom_topic话题的节点(如listener节点)可以接收这些消息,并对其进行处理。

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值