顾名思义,这是一个异步的消息传达过程
首先是消息的发布,接着是消息的订阅
话题发布
由发布者发布一个“消息”的数据结构,再由订阅者订阅这个消息结构。
再开始撰写一段程序之前,我们需要在程序代码中引入库→节点初始化→创建发布者→设定循环频率→初始化消息→发布消息。
引入库
c++ python
其中的geometry_msgs是再创建功能包时候输入的依赖,rospy和roscpp等等都是依赖。
节点初始化(定义函数,定义节点名称)
c++ python
这一部分中,节点的名字叫velocity_publisher,python与C++的定义方式是不同的python中函数的名字就是节点的名字。argc和argv其实是输入的参数,但是一般不输入。
定义发布者(Publisher)
包括发布器名称、话题名称、消息类型和队列长度(这一部分就有c类程序的影子了)
c++ python
发布器名称
等号左边是发布器的名称,turtle_vel_pub,之后的消息发布需要使用到该发布器发布。
这里就可以看出C++的程序要比python的麻烦c++的需要单独在定义一个节点句柄(一种特殊的指针)
话题名称
/turtle1/cmd_vel,这种命名方式猜测是不是按照文件夹的方式去定义名称,毕竟发布后还需要订阅,所以现在先猜测订阅的名字是/turtel1/...这种(这一猜想是正确地)。
类型
此外,除了geometry_msgs这种用于控制机器人运动的消息类型外还有很多其他消息类型,其各自还分为多种数据结构类型Twist只是geometry_msgs其中之一的数据结构(就两个可输入变量,线速度和角速度,这中消息类型),其具体的解释文档链接如下:
ROS相关消息类型&格式介绍_ros消息类型-CSDN博客
队列长度
这里暂定队列长度是10,这是因为,消息的发布是会受到通讯性能的影响的,一旦信号不好,TCP协议下是有可能,信息发布不出去的。这时候,publisher就会持续发送队列里最后10个消息以保证消息的时序新鲜性。同理队列长度越长,性能消耗占比越大,这就可以理解成缓存区域。
c++ python
在设置好队列之后,需要通过循环的方式去实现,这时候就需要设置好循环的频率。也就是在循环的过程中不停的发送以下信息。
消息发布
c++ python
定义消息名称
可以发现 这一部分定义了具体发布的消息的名称vel_msg,再传入线速度与角速度
消息发布
在利用之前定义的发布器turtle_vel_pub发布消息。
日志输出(非必要程序)
ROS_INFO与rospy.loginfo都是日志输出语句其实就是print。
延时
最后按照之前设置好的循环此时实现队列延时发布。
主程序调用段
这一部分是python程序特有的程序调用端,在之前的节点初始化时,Python程序中就用定义函数的方式定义了一个和节点名称相同的函数。
c++ python
---------------------------------------------------------------------------------------------------------------------------------
代码编译规则录入CMakeList.txt
代码完成后需要在对应的CMakeList.txt文件中录入我们编译好的代码。
c++ python
add_executable是将src文件夹下的velocity_publisher.cpp文件定义成名为velocity_publisher的可执行文件,再通过target_link_libraries将这可执行文件与ros 的数据库链接到一起。
这里需要注意的是,python文件不需要修改CMakeList.txt文件即可编译。但是py文件需要是可允许执行文件
话题发布节点运行
话题订阅
这部分的流程同样也是引入库→节点初始化→定义发布器→消息订阅
引入库
c++ python
这里的turtlesim和geometry_msgs、rospy和roscpp一样都是依赖,Pose则是turtlesim依赖下的一种消息类型,都是要在功能包建立的时候输入的,但是如果有遗落项应该是可以在CMakeList.txt中补全的,至于是否需要在其他位值补全代码还需要在之后的实验中验证。
CMakeList.txt文件
节点初始化(定义函数,定义节点名称)
c++ python
在这里我们定义节点的名称为pose_subscriber,而python函数的名字也是pose_subscriber,可以发现节点的名字是和在CMakeList.txt文件中定义的可执行文件的名字是一样的。
定义订阅者(subscriber)
包括订阅器名称、订阅的话题名称、消息类型、话题的队列长度以及回调函数(这一部分就有c类程序的影子了),此外和发布器的定一样C++程序依旧多了一个节点句柄的定义。
c++ python
订阅器名称
这一部分因为后续是直接订阅而不像消息发布的时候需要循环发布消息所以并没有像发布器一样顶一个确定的名字,我猜测如果需要定义的话在等号的左边定义一个和turtle_vel_pub类似的turtle_vel_sub即可。
订阅的话题名称
这里果然和之前猜测的一样,此处定义的话题名称是/turtle1/pose正与之前发布器定义的话题名称/turtle1/cmd_vel对应。
消息类型
这里C++程序中并没有定义消息的类型,Python中声明了消息类型,而C++程序则是通过回调函数中定义消息类型来实现整个订阅器消息类型的订阅。
队列长度
发布器会需要因为消息传送能力建立缓冲队列(队列的长度设置为10),同理订阅器也因为订阅端口的处理能力需要建立缓冲队列来存储最近的10个消息。特别的是python中没有设置缓冲队列,这一个遗留问题。
回调函数(PoseCallback)
日志输出
回调函数中封装的恰是是一个print程序,个人认为非必要,空函数也没关系,主要是需要回调这个一直等待,直到消息进入就启动的机制。
c++ python
死循环等待spin()
通常情况下,回调函数的使用需要搭配死循环函数spin()一起进行。spin函数是一个死循环,只有当目标消息队列输入进来才会调用回调函数,否则就不停的循环,C++hai需要一个返回值,但是python就可以不写这一步,这只是两种语言书写上的差异,并不影响整体的逻辑。
另外在定义订阅器的时候,python在该除定义了消息的类型,而C++并没有,C++实在回调函数顶一段定义了消息的类型。
c++ python
主程序调用段
和之前订阅器一样,这一部分是python程序特有的程序调用端,在之前的节点初始化时,Python程序中就用定义函数的方式定义了一个和节点名称相同的函数。
c++ python
---------------------------------------------------------------------------------------------------------------------------------
代码编译规则录入CMakeList.txt
代码完成后需要在对应的CMakeList.txt文件中录入我们编译好的代码。
c++ python
add_executable是将src文件夹下的pose_subscriber.cpp文件定义成名为pose_subscriber的可执行文件,再通过target_link_libraries将这可执行文件与ros 的数据库链接到一起。
这里需要注意的是,python文件不需要修改CMakeList.txt文件即可编译。但是py文件需要是可允许执行文件
话题发布、订阅节点编译
工作空间编译
工作空间文件夹下开启编译
ROS工作空间文件夹下启动终端输入catkin_make
环境变量设置
编译成功(无红色报错)后,设置环境变量
source devel/setuo.bash
这一句是如果已经将工作空间加入环境变量文件了的话可忽略,具体怎么把工作空间文件夹加入环境变量文件参考如下链接:
启动ros
这一步就不约束终端启动文件夹了
输入roscore
另开一个终端启动小海龟控制器,输入:
rosrun turtlesim turtlesim_node
话题发布节点启动
再开一个终端输入:
rosrun learning_me_topic velocity_publisher
这是我们做的话题发布器(懒得输入全称的话,就打几个字母,然后按一下TAB按键就自动补全)
这时候小海龟就回转圈圈了。
话题发布节点启动
接下来的订阅器的编译,再再新开一个终端
输入订阅器运行代码:
rosrun learning_me_topic pose_subscriber
这时候 订阅器就会实时显示海龟当前的位置,并做好记录文档,存放在。
python的编译
python的编译直接在可执行文件处改成“python文件名.py”
例如:rosrun learning_me_topic pose_subscriber.py