ROS机器人入门第五课:话题通信自定义msg

ROS机器人入门第五课:话题通信自定义msg

一、介绍

在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 激光雷达的信息… std_msgs 由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型

msgs只是简单的文本文件,每行具有字段类型和字段名称,可以使用的字段类型有:

  • int8, int16, int32, int64 (或者无符号类型: uint*)

  • float32, float64

  • string

  • time, duration

  • other msg files

  • variable-length array[] and fixed-length array[C]

ROS中还有一种特殊类型:Header,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头。

需求:创建自定义消息,该消息包含人的信息:姓名、身高、年龄等。

二、流程

  1. 按照固定格式创建 msg 文件
  2. 编辑配置文件
  3. 编译生成可以被 Python 或 C++ 调用的中间文件

(一)定义msg文件

功能包下新建 msg 目录,添加文件 person.msg

string name
uint16 age
float64 height

(二)编辑配置文件

  1. package.xml中添加编译依赖与执行依赖
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

在这里插入图片描述
2. CMakeLists.txt编辑 msg 相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

在这里插入图片描述

## 配置 msg 源文件
add_message_files(
  FILES
  Person.msg
)

在这里插入图片描述

# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

在这里插入图片描述

#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

在这里插入图片描述

(三)编译

ctrl + shift + B

编译后的中间文件查看:
Python 需要调用的中间文件(…/工作空间/devel/lib/python3/dist-packages/包名/msg)

在这里插入图片描述
后续调用相关 msg 时,是从这些中间文件调用的

三、话题通信自定义msg调用

需求:

编写发布订阅实现,要求发布方以1HZ(每秒1次)的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

  1. 发布方
  2. 接收方
  3. 数据(此处为自定义消息)

(一)调用流程

  1. 编写发布方实现;
  2. 编写订阅方实现;
  3. 为python文件添加可执行权限;
  4. 编辑配置文件;
  5. 编译并执行。
0.vscode配置

为了方便代码提示以及误抛异常,需要先配置 vscode,将前面生成的 python 文件路径配置进 settings.json

{
    "python.autoComplete.extraPaths": [
        "/opt/ros/noetic/lib/python3/dist-packages",
        "/xxx/yyy工作空间/devel/lib/python3/dist-packages"
    ]
}
1.发布方

这段代码是一个ROS(Robot Operating System)的Python节点,用于发布包含个人信息的消息。它导入了ROS的python库rospy和自定义的消息类型person。接下来,我会逐行提供详细的注释:

#! /usr/bin/env python
# - coding: utf-8 -*-

# 导入 rospy,这是编写 ROS 节点的python库。
import rospy
# 导入自定义的消息类型,person 是我们自定义的消息类型,它应该已经在 ROS 的 msg 包中定义。
from msg.msg import person

# __name__ == "__main__" 确保当这个脚本被执行而不是被导入时,以下代码块将被运行。
if __name__ == "__main__":
    # 1. 初始化 ROS 节点,名为 "talker_person_p"。
    rospy.init_node("talker_person_p")
    
    # 2. 创建发布者对象,它将发布 person 类型的消息到 "chatter_person" 话题,队列大小设置为 10。
    pub = rospy.Publisher("chatter_person", person, queue_size=10)
    
    # 3. 组织要发布的消息,创建一个 person 类型的实例 p,并设置其属性。
    p = person()
    p.name = "zhangsan"  # 设置人的名字为 "zhangsan"。
    p.age = 18           # 设置年龄为 18。
    p.height = 0.75      # 设置身高为 0.75 米。

    # 4. 编写消息发布逻辑。
    rate = rospy.Rate(1)  # 设置一个发布频率,1Hz,每秒发布一次。
    rospy.sleep(3)        # 休眠3秒,给ROS系统一些启动时间。
    
    # while 循环会在 ROS 节点没有被关闭的情况下持续运行。
    while not rospy.is_shutdown():
        pub.publish(p)  # 发布消息,将 person 实例 p 发布到 "chatter_person" 话题。
        rate.sleep()    # 使用前面设置的频率来休眠,确保以 1Hz 的频率发布消息。
        
        # rospy.loginfo 用于输出日志信息,这里输出了 person 实例 p 的所有信息。
        rospy.loginfo("姓名:%s, 年龄:%d, 身高:%.2f", p.name, p.age, p.height)

现在,让我详细解释一下你提问中的ros函数:

  • rospy.init_node("talker_person_p"): 这个函数初始化一个ROS节点,节点的名称是 "talker_person_p"。在ROS中,节点是运行的基本单元,每个节点都有自己的名字。
  • rospy.Publisher("chatter_person",person,queue_size=10): 这个函数创建一个Publisher对象,用于发布消息。它告诉ROS你想要发布“chatter_person”这个话题上的person类型消息。queue_size参数指定了消息队列的大小,这里设置为10,意味着如果数据处理不过来,它将缓存10条消息。
  • rospy.Rate(1): 这个函数设置了一个频率(1Hz),用于定时发布消息。
  • rospy.sleep(3): 使得节点休眠3秒钟。
  • rospy.is_shutdown(): 这个函数会检查你的ROS节点是否应该被关闭(例如,如果有人按下Ctrl+C或者如果ROS核心已经关闭)。
  • pub.publish(p): 通过前面创建的pub发布者对象,发布消息p
  • rate.sleep(): 根据之前定义的rate来使程序休眠,以保持1Hz的发布频率。
  • rospy.loginfo(...): 输出日志信息到命令行和ROS日志文件,便于调试和记录状态。

代码中需要改的地方:

  • from msg.msg import person :from 包名.msg import 自定义msg文件名
  • pub = rospy.Publisher("chatter_person", person, queue_size=10):pub = rospy.Publisher(“chatter_person”, 自定义msg文件名, queue_size=10)
  • p = person():p = 自定义msg文件名()
2.订阅方

这段代码定义了一个ROS(Robot Operating System)的Python订阅节点,用于订阅包含个人信息的消息。它同样使用了rospy库以及自定义的消息类型person。让我为你逐行提供注释:

#! /usr/bin/env python
# - coding: utf-8 -*-
"""
    订阅方:
        订阅消息
"""

# 导入ROS的Python库rospy。
import rospy
# 从msg包导入自定义的消息类型,person必须已经在ROS的msg包中定义了。
from msg.msg import person

# 定义回调函数doPerson,它将在接收到消息时被调用。
def doPerson(p):
    # 输出接收到的消息内容:人的名字、年龄和身高。
    rospy.loginfo("接收到的人的信息:%s, %d, %.2f", p.name, p.age, p.height)

# 确保当脚本被直接执行时,下面的代码块会运行。
if __name__ == "__main__":
    # 1. 初始化ROS节点,名称为"listener_person_p"。
    rospy.init_node("listener_person_p")
    
    # 2. 创建订阅者对象,订阅名为"chatter_person"的话题,消息类型为person。
    # doPerson是收到消息时要调用的回调函数。queue_size=10指定了消息队列的大小。
    sub = rospy.Subscriber("chatter_person", person, doPerson, queue_size=10)
    
    # 4. 调用rospy.spin()使得节点保持运行直到节点被显式地关闭或者Ctrl+C被按下。
    # 它让程序停留在一个循环中,等待和处理回调函数。
    rospy.spin()

现在,让我解释一下代码中使用的ROS函数及其功能:

  • rospy.init_node("listener_person_p"): 这个函数初始化一个ROS节点,节点的名称是"listener_person_p"。每个ROS节点都需要一个唯一的名字,这样它们就可以在ROS网络中被识别和通信。
  • rospy.Subscriber("chatter_person", person, doPerson, queue_size=10): 这个函数创建一个订阅者对象,用于订阅名为"chatter_person"的话题上的消息。这里指定消息类型为person,并且指定了一个回调函数doPerson,该函数会在接收到消息时被自动调用。queue_size参数用于控制消息队列的大小,防止处理速度跟不上接收速度导致的内存溢出。
  • rospy.spin(): 这个函数使得你的节点保持运行,等待消息的到来。它不会占用大量CPU资源,因为它会在没有消息到来时阻塞。这使得节点能够在接收到新消息时立即响应,同时也保持了低资源消耗。

简而言之,这段代码实现了一个ROS节点,它订阅了一个名为"chatter_person"的话题,用于接收包含个人信息的消息,并在接收到消息时通过日志输出这些信息。

3.权限设置

终端下进入 scripts 执行:chmod +x *.py

4.配置 CMakeLists.txt
catkin_install_python(PROGRAMS
  scripts/pub.py
  scripts/sub.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

在这里插入图片描述

5.执行

1.启动 roscore;

2.启动发布节点;

3.启动订阅节点。
在这里插入图片描述
4. 运行结果
在这里插入图片描述
PS:可以使用 rqt_graph 查看节点关系。
在这里插入图片描述

  • 35
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值