提示:一定要在工作空间中的src目录下,创建一个功能包,依赖是roscpp rospy std_msgs,然后在生成的功能包中的src文件夹下创建本文中的代码,代码创建后需要修改Cmakelist.txt文件后方可正常运行.
前言
这篇内容主要是介绍一下ROS通讯方式中最常用的一种:话题通信.然后通过一个示例来巩固学习效果,最后做一个进阶,订阅ROS下小乌龟的位置信息,并在终端中显示出来.
提示:以下是本篇文章正文内容,下面案例可供参考
一、话题通信是什么?
个人理解是 :
- 有节点在master上注册并发布消息
- 另外节点也在master上注册,并订阅想要得到的节点消息
- 订阅节点和发布节点布局限于是一对一,可以一对多
- 原理图如下:
原理图解释:(解释中的标号不代表原理图中的标号)
1 发布者和订阅者使用RPC通信在master中注册信息;
2 master匹配发布者和订阅者的注册信息,然后将对应的发布者RPC端口号发送给订阅者;
3 订阅者通过RPC端口号连接发布者,然后发布者将TCP的端口号发布给订阅者;
4 订阅者使用TCP通信连接发布者;
5 订阅者和发布者通过TCP通信,进行数据交互;
6 当发布者和订阅者建立了连接以后,即使master关闭,两者依然可以通信.
二、代码示例
1.创建一个发布者
创建发布者的架构如下:
- 包含对应的头文件;
- 初始化节点;
- 创建节点句柄;
- 使用advertise创建要发布的话题,并设置话题类型,名称,缓.存数;
- 创建被发布的消息类型
- 设置话题数据发布频率;
- 创建话题发布循环;
- 发布消息;
- 在话题发布循环中添加rate.sleep();
代码如下(示例):
#include "ros/ros.h"
#include"std_msgs/String.h"
#include<sstream>
/*
发布方实现:
1 包含头文件
2.初始化ROS节点
3.创建节点句柄
4.创建发布对象
5.编写发布逻辑并发布数据
code */
int main(int argc, char *argv[])
{
//初始化节点
ros::init(argc,argv,"pub_node");
//创建节点句柄
ros::NodeHandle nh;
//创建发布者对象 advertise语句格式 <消息类型>("话题",缓存数量(缓存机制,先进显出,超过后最先进得被删除))
ros::Publisher pub=nh.advertise<std_msgs::String>("pub_topic",10);
//编写发布逻辑并发布消息
//先创建被发布的消息
std_msgs::String msg;
//设置发布数据频率 10hz,并在消息后添加编号,
//添加计数器
int count;
ros::Rate rate(10);
ros::Duration(3.0).sleep(); //休眠延迟消息发布
//编写循环,循环发布消息数据
while (ros::ok())
{
setlocale(LC_ALL,"");
count++;
//实现字符串与编号拼接
std::stringstream ss; //创建一个ss对象
ss <<"hello ---->"<<count;
msg.data=ss.str();
pub.publish(msg);
//在终端中添加发布日志
ROS_INFO("发布的数据是:%s",ss.str().c_str());
rate.sleep();
}
return 0;
}
完成代码后,修改功能包中的Cmakelist.txt代码,修改的第一个位置是在# add_executable(${PROJECT_NAME}_node src/com_test_pub_node.cpp)
后面添加
add_executable(pub src/pub.cpp)
这里面的pub是编译好的项目名,后面的pub.cpp是写的发布者程序名.
修改的第二个位置是:在
#target_link_libraries(${PROJECT_NAME}_node #${catkin_LIBRARIES} #)
后面添加
target_link_libraries(pub
${catkin_LIBRARIES}
)
然后保存Cmakelist.txt文件,返回工作空间,编译之后,在工作空间中输入
source ./devel/setup.bash
rosrun com_test_pub pub
这里的com_test_pub是创建的功能包,pub是创建的发布者项目名
即可看到如下
运行效果:
2.创建一个订阅者
订阅者的架构与发布者架构相似:
1.包含头文件
2. 初始化ROS节点
3. 创建ROS句柄
4. 创建订阅者话题
5. 处理订阅到的话题中的数据
6. 创建一个spin()函数
7.
订阅者代码如下(示例):
#include"ros/ros.h"
#include"std_msgs/String.h"
/*
1 包含头文件
2 初始化ROS节点
3 创建节点句柄
4 创建订阅者对象
5 订阅数据处理
6 声明一个spin函数
*/
void doMsg(const std_msgs::String::ConstPtr &msg){
//通过msg参数获取并操作订阅到的数据
setlocale(LC_ALL,"");
ROS_INFO("订阅的数据:%s",msg->data.c_str());
}
int main(int argc, char *argv[])
{
//初始化ROS节点
ros::init(argc,argv,"listen");
// 创建ROS 句柄
ros::NodeHandle nh;
//创建订阅者对象 使用subscribe句式进行话题订阅(需要订阅的话题名称,缓存数两,回调函数(处理接收到的话题数据))
ros::Subscriber listen= nh.subscribe("pub_topic",10,doMsg);//
ros::spin(); //语句执行完之后回头一下 处理回调函数
return 0;
}
同样,订阅者创建完以后,也要在Cmakelist.txt文件中的对应位置添加:(可以写在发布者的add_executable和target_link_libraries的后面)
add_executable(listen src/listen.cpp)
target_link_libraries(listen
${catkin_LIBRARIES}
)
然后保存Cmakelist.txt文件,返回工作空间,编译之后,在工作空间中输入
source ./devel/setup.bash
rosrun com_test_pub pub
在新开一个终端进入同一个工作空间中输入
source ./devel/setup.bash
rosrun com_test_pub listen
这里的com_test_pub是创建的功能包,listen是创建的订阅者项目名
即可看到如下
运行效果:
注意
注意:
先启动订阅者,在启动发布者,这时订阅者终端在接受数据时,可能会出现前几条数据接受不到原因是发布者已经发布出来了数据,但是这时候还没有在master里面注册成功,所以订阅者收不到前几条消息.
解决方法是:在发布者里面加入休眠
注册后,加入休眠 ros::Duration(3.0).sleep(); 延迟第一条数据的发送
进阶
然后进阶一下,订阅一个小乌龟的位置节点,并在终端中显示位置节点中的数据,废话不多说,上代码:
#include "ros/ros.h"
#include"std_msgs/String.h"
#include"turtlesim/Pose.h"
void doMsg(const turtlesim::PoseConstPtr &Msg){
float x,y,theta,line_ve;
x=Msg->x;
y=Msg->y;
theta=Msg->theta;
line_ve=Msg->linear_velocity;
ROS_INFO("I heard pose x:[%f] y:[%f] theta:[%f] ve:[%f]",x, y, theta, line_ve);
}
int main(int argc, char *argv[])
{
//初始化节点 定义turtle_pos为设置订阅的节点名
ros::init(argc,argv,"turtle_pos");
//创建ROS句柄
ros::NodeHandle nh;
//创建订阅话题
ros::Subscriber pos = nh.subscribe("turtle1/pose",100,doMsg);
ros::spin();
return 0;
}
同样,也要在Cmakelist.txt文件中的对应位置添加:(可以写在发布者的add_executable和target_link_libraries的后面)
add_executable(turtlesimPos src/turtlesim_pos_lis.cpp)
target_link_libraries(turtlesimPos
${catkin_LIBRARIES}
)
然后编译工作空间,在终端中输入
source ./devel/setup.bash
接下来的操作步骤:
- 启动roscore ,在终端中输入
roscore
- 新开一个终端,或者使用
ctrl+shift+T
,打开一个新终端,启动小乌龟节点,在终端中输入rosrun turtlesim turtlesim_node
- 同样的方法,在新开一个终端启动键盘控制节点
rosrun turtlesim turtle_teleop_key
,这个时候可以用键盘控制小乌龟了, - 开启一个新终端中,输入
rosrun com_test_pub turtlesimPos
就可以在终端中看到下图
至此,ROS的话题通讯已经完成,可以订阅想要的到的话题数据了.
代码下载连接
此文中的代码已经上传,可以直接通过传送门下载:传送门
<- - - 如有侵权,请联系删除- - ->
<每天进步一点点>