ROS话题通信的理论查阅ROS话题通信流程理论
ROS话题通信的自定义数据的准备可以查阅ROS话题通信流程自定义数据格式
在ROS话题通信机制实现中,ROS master 不需要实现,且连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方(二狗子)
- 订阅方(翠花)
- 数据(此处为普通文本)
创建ROS工程
创建一个ROS工程包括以下几个步骤:
- 创建一个
topic_ws
的ROS工作空间 - 启动VScode
- VScode 编译ROS
- 创建ROS功能包
详细操作可以查阅VScode创建ROS项目 ROS集成开发环境
VScode 配置
为了方便代码提示以及避免误抛异常,需要先配置 vscode,将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:
发布方(二狗子)
-
基本流程
- 1.包含头文件
- 2.初始化 ROS 节点:命名(唯一)
- 3.实例化 ROS 句柄
- 4.实例化 发布者 对象
- 5.组织被发布的数据,并编写逻辑发布数据
-
代码实现
#include "ros/ros.h" #include "plumbing_pub_sub/Person.h" /* 1.包含头文件 2.初始化 ROS 节点:命名(唯一) 3.实例化 ROS 句柄 4.实例化 发布者 对象 5.组织被发布的数据,并编写逻辑发布数据 */ int main(int argc, char *argv[]) { //设置编码 setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) // 参数1和参数2 后期为节点传值会使用 // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一 ros::init(argc,argv,"banZhuRen"); //3.实例化 ROS 句柄 ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能 //4.实例化 发布者 对象 //泛型: 发布的消息类型 //参数1: 要发布到的话题 //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁) ros::Publisher pub = nh.advertise<plumbing_pub_sub::Person>("liaoTian",10); //5.组织被发布的数据,并编写逻辑发布数据 //数据(动态组织) plumbing_pub_sub::Person person; person.name = "ZhangSan"; person.age = 25; person.height = 1.75; // msg.data = "你好啊!!!"; int count = 0; //消息计数器 //逻辑(一秒1次) ros::Rate rate(1); ros::Duration(3.0).sleep(); //休眠3s等待 publisher 注册完成,不然订阅者读不到第一条消息 //节点不死 while (ros::ok()) { //发布消息 pub.publish(person); //加入调试,打印发送的消息 ROS_INFO("我叫:%s,今年%d岁,高%.2f米", person.name.c_str(), person.age, person.height); //根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率; rate.sleep(); //修改数据 person.age += 1; //暂无应用 ros::spinOnce(); } return 0; }
-
验证是否有问题
-
编辑配置文件
修改plumbing_pub_sub
功能包下的CMakeLists.txt,找到add_executable、add_dependencies和target_link_libraries,修改成如图所示:
-
按快捷键
ctrl + shift + B
编译 -
开启一个Terminal,运行 roscore 命令;再开启一个新的Terminal,运行
source ./devel/setup.bash rosrun plumbing_pub_sub demo_pub_person_c
;再开启一个Terminal,运行rostopic echo fang,查看订阅数据
-
订阅方(翠花)
-
基本流程
- 1.包含头文件
- 2.初始化 ROS 节点:命名(唯一)
- 3.实例化 ROS 句柄
- 4.实例化 订阅者 对象
- 5.处理订阅的消息(回调函数)
- 6.设置循环调用回调函数
-
代码实现
// 1.包含头文件 #include "ros/ros.h" #include "plumbing_pub_sub/Person.h" /* 1.包含头文件 2.初始化 ROS 节点:命名(唯一) 3.实例化 ROS 句柄 4.实例化 订阅者 对象 5.处理订阅的消息(回调函数) 6.设置循环调用回调函数 */ void doPerson(const plumbing_pub_sub::Person::ConstPtr &person) { //通过Person获取并操作订阅到的数据 ROS_INFO("订阅的人信息:%s, %d, %.2f", person->name.c_str(), person->age, person->height); } int main(int argc, char *argv[]) { setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) ros::init(argc, argv, "jiaZhang"); //3.实例化 ROS 句柄 ros::NodeHandle nh; //4.实例化 订阅者 对象 ros::Subscriber sub = nh.subscribe<plumbing_pub_sub::Person>("liaoTian", 10, doPerson); //5.处理订阅的消息(回调函数) //6.设置循环调用回调函数 ros::spin();//循环读取接收的数据,并调用回调函数处理 return 0; }
发布方的订阅方声明的话题必须一直,案例中的话题是 liaoTian
编辑配置文件
修改 plumbing_pub_sub
功能包下的CMakeLists.txt,找到add_executable、add_dependencies和target_link_libraries,修改成如图所示:
编译并执行
-
编译代码
按快捷键ctrl + shift + B
编译
-
执行代码
-
1.启动 roscore;
开启一个Terminal,启动 roscore
-
2.启动发布节点;
开启一个新的Terminalcd topic_ws/ source ./devel/setup.bash rosrun plumbing_pub_sub demo_pub_person_c
-
3.启动订阅节点。
cd topic_ws/ source ./devel/setup.bash rosrun plumbing_pub_sub demo_sub_person_c
-
注意
订阅的第一条数据丢失
- 原因:
发送第一条数据时, publisher 还未在 roscore 注册完毕,但是数据已经再发送 - 解决方法:
注册后,加入休眠 ros::Duration(3.0).sleep(); 延迟第一条数据的发送。