目录
3.编译并产生中间文件,下位C++和python生成的中间文件
话题通信
ROS中话题通信是以发布订阅的方式实现不同节点之间数据交互的通信模式。话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,即一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景广泛,比如:
机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。
话题通信大多应用于不断更新的、少逻辑处理的数据传输场景。
话题通信理论模型
图片取自于b站教学视频:
038话题通信_理论模型_Chapter2-ROS通信机制_哔哩哔哩_bilibili
话题通信基本操作(python)
需求:编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 接收方
- 数据(此处为普通文本)
流程:
- 编写发布方实现;
- 编写订阅方实现;
- 为python文件添加可执行权限;
- 编辑配置文件;
- 编译并执行。
发布方实现
#! /usr/bin/env python
import rospy
from std_msgs.msg import String #发布的消息的类型
if __name__ == "__main__":
#初始化ROS节点
rospy.init_node("sanDai")#传入节点名称
#创建发布者对象
pub = rospy.Publisher("che",String,queue_size=10)
#编写发布逻辑并发送数据
#创建数据
msg = String()
#指定发布频率
rate = rospy.Rate(1)#1s一次 1hz
#设置计数器
count = 0
#使用循环发布数据
while not rospy.is_shutdown():
count += 1
msg.data = "hello" + str(count)
#发布数据
pub.publish(msg)
rospy.loginfo("发布的数据:%s",msg.data) #日志输出
rate.sleep()#休眠
订阅方实现
#! /usr/bin/env python
#导包
import rospy
from std_msgs.msg import String #导入消息格式
#回调函数处理数据
def doMsg(msg):
rospy.loginfo("我订阅的数据:%s",msg.data)
if __name__ == "__main__":
#初始化ROS节点
rospy.init_node("huaHua")
#创建订阅者对象
sub = rospy.Subscriber("che",String,doMsg,queue_size=10)
#spin函数
rospy.spin()
打开终端,调用rosrun指令,结果如下:
计算图
调用指令rpt_graph,可以看到ROS节点之间的关系
注:ROS具有解耦合性,也就是说,即使是用C++写的发布方和用python写的订阅方也可以进行连接完成话题通信。
话题通信_自定义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]
Header标头
案例:自定义msg,包含姓名、身高、年龄等
流程:
- 创建和定义msg文件
- 编辑配置文件
- 编译生成可以被 Python 或 C++ 调用的中间文件
1.定义msg文件
功能包下新建 msg 目录,添加文件 Person.msg
string name
uint16 age
float64 height
2.编辑配置文件
package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
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
)
3.编译并产生中间文件,下位C++和python生成的中间文件
案例:话题通信自定义msg调用(Python)
要求:发布方以1HZ的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 接收方
- 数据(此处为自定义消息)
流程:
- 编写发布方实现;
- 编写订阅方实现;
- 为python文件添加可执行权限;
- 编辑配置文件;
- 编译并执行。
0.准备工作——vscode配置
为了方便代码提示以及误抛异常,需要先配置 vscode,将前面生成的 python 文件路径配置进 settings.json
{
"python.autoComplete.extraPaths": [
"/opt/ros/noetic/lib/python3/dist-packages",
"/xxx/yyy工作空间/devel/lib/python3/dist-packages"
]
}
1.发布方
#! /usr/bin/env python
#导包
import rospy
from plumbing_pub_sub.msg import Person
if __name__ == "__main__":
#初始化ROS节点
rospy.init_node("daMa")
#创建发布者对象
pub = rospy.Publisher("jiaoSheTou",Person,queue_size=10)
#组织发布逻辑并发布数据
#创建Person数据
p = Person()
p.name = "奥特曼"
p.age = 8
p.height = 1.85
#创建 Rate 对象
rate = rospy.Rate(1)
#循环发布数据
while not rospy.is_shutdown():
pub.publish(p)
rospy.loginfo("发送的数据:%s,%d,%.2f",p.name,p.age,p.height)
rate.sleep()
2.订阅方
#! /usr/bin/env python
#导包
import rospy
from plumbing_pub_sub.msg import Person
def doPerson(p):
rospy.loginfo("小伙子的数据:%s,%d,%.2f",p.name,p.age,p.height)
if __name__ == "__main__":
#初始化ROS节点
rospy.init_node("daYe")
#创建订阅者对象
sub = rospy.Subscriber("jiaoSheTou",Person,doPerson)
#处理订阅的数据
#spin()
rospy.spin()
在配置完权限及相关文件后,在终端中调用命令得到的效果如下: