简单话题通信
话题通信用于不断更新的,少逻辑处理的数据传输场景。编写程序时,关注三方面:发布者、订阅者和通信数据。
对于简单的话题通信,即仅一段普通文本,其他步骤与前相同,这里仅整理出代码:
- 发布方
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*
发布方实现:
1.包含头文件
ROS中文本类型 ---> std_msgs/String.h
2.初始化ROS节点
3.创建节点句柄
4.创建发布者对象
5.编写发布逻辑并发布数据
*/
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化ROS节点(创建节点)
ros::init(argc,argv,"erGouZi");
//3.创建节点句柄
ros::NodeHandle nh;
//4.创建发布者对象
ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10);
//5.编写发布逻辑并发布数据
//要求以10HZ的频率发布数据,并且hello文本后要添加编号
//先创建被发布的信息
std_msgs::String msg;
//发布频率
ros::Rate rate(10);
//设置编号
int count = 0;
//编写循环,循环中发布数据
while (ros::ok())
{
count++;
//实现字符串拼接
std::stringstream ss;
ss <<"hello ---> " << count;
//msg.data="hello";
msg.data = ss.str();
pub.publish(msg);
//添加日志
ROS_INFO("发布的数据是:%s",ss.str().c_str());
rate.sleep();
ros::spinOnce();//官方建议,处理回调函数
}
return 0;
}
- 订阅方
#include "ros/ros.h"
#include "std_msgs/String.h"
/*
订阅方实现:
1.包含头文件
ROS中文本类型 ---> std_msgs/String.h
2.初始化ROS节点
3.创建节点句柄
4.创建订阅者对象
5.处理订阅到的数据
6.声明spin函数,spin函数会回头反复执行doMsg函数
*/
void doMsg(const std_msgs::String::ConstPtr &msg){
//通过msg获取并操作订阅到的数据
ROS_INFO("翠花订阅的数据:%s",msg->data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化ROS节点
ros::init(argc, argv, "cuiHua");
//3.创建节点句柄
ros::NodeHandle nh;
//4.创建订阅者对象
ros::Subscriber sub = nh.subscribe("fang",10,doMsg);
//5.处理订阅到的数据
ros::spin();
return 0;
}
- TIPS
①const删去;
②有时,提示ros/ros.h No such file or dirctory…,此时注意检查CMakeList.txt中,find_package中出现的重复,删去内容较少的即可;
③订阅方对订阅到的数据进行处理时用到了回调函数,之后需加ros::spin();保证回调函数的正常运行
④使用rostopic echo <话题名>
来对没有日志输出的发布方是否正确发布信息进行检测,如本项目使用rostopic echo fang
⑤关于订阅者接收到的信息前几条数据丢失,是因为发布方发布数据时,还未完成注册,解决方法是,在信息发布之前,先休息一段时间ros::Duration(3).sleep(); //休眠3s
⑥防止中文乱码setlocale(LC_ALL," ");
⑦使用rqt_graph
查看计算图
自定义话题通信
ROS中std_msgs中已经封装了一些原生的数据类型,但是由于描述性较差,在多数情况下需要自定义消息,对于自定义消息的话题通信,需要以下三个步骤来完成准备工作:
- 按照固定格式创建msg文件
功能包下新建msg文件,本项目新建person.msg,内容为
string name
int32 age
float32 height
- 编辑配置文件
(1)在package.xml中添加以下依赖:<build_depend>message_generation</build_depend> <build_export_depend>std_msgs</build_export_depend>
(2)在CMakeList.txt文件中进行以下修改:
①find package下添加message_generation
;
②add message_files下释放注释,并写入自己的message文件名:person.msg
;
③generatio_message下释放注释;
④catkin_package下释放CATKIN_DEPENDS行,并添加message_runtime
; - 编译生成可被python或C++调用的中间文件
编译一下即可生成中间文件,其中C++所需中间文件卫devel/include/plumbing_pub_sub下的person.h;python所需的中间文件为devel/lib/python2.7(不同版本,这里数字可能不同)/msg下的_person.py。
接下来需要对vscode进行配置,这里仅介绍C++的情况:
需将前边生成的head文件路径配置进c_cpp_properties.json的includePath中,可按系列步骤进行:
①将deve/include/plumbing_pub_sub在集成终端中打开(注意右键时,应在plumbing_pub_sub上右击);
②使用pwd
命令打印路径;
③将路径粘贴到.cscode/c_cpp_properties中的includePath路径下(可仿照前几行将include/后改称**,意为包含include文件夹下的所有文件)
之后分别完成发布方和订阅方的实现
- 发布方
- 新建文件
在功能包下src文件夹中新建文件demo03_pub_person.cpp; - 编辑代码
键入代码:(见第3点后边) - 配置CMakeList.txt
①add_excutable…同前规则add_executable(demo03_pub_person src/demo03_pub_person.cpp)
;
②target_link_libraries…同前规则target_link_libraries(demo03_pub_person ${catkin_LIBRARIES} )
;
③释放add_dependencies,并修改参数(建议复制出新的一行进行释放):第一个参数修改为映射名,第二个参数为${PROJECT_NAME}_generate_message_cpp
(没看懂):
add_dependencies(demo03_pub_person ${PROJECT_NAME}_generate_message_cpp)
#保证编译时,先编译msg文件再编译发布文件,防止出现逻辑错误。
#include "ros/ros.h"
#include "plumbing_pub_sub/person.h"
/*
发布方:发布人的消息
1.包含头文件
#include "plumbing_pub_sub/person.h"
2.初始化ROS节点
3.创建节点句柄
4.创建发布者对象
5.编写发布逻辑,发布数据
*/
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ROS_INFO("这是消息的发布方");
//2.初始化ROS节点
ros::init(argc,argv,"banZhuRen");
//3.创建节点句柄
ros::NodeHandle nh;
//4.创建发布者对象
ros::Publisher pub = nh.advertise<plumbing_pub_sub::person>("liaoTian",10);
//5.编写发布逻辑,发布数据
//5-1.创建被发布的数据
plumbing_pub_sub::person person;
person.name = "张三";
person.age = 1;
person.height = 1.73;
//5-2.设置发布频率
ros::Rate rate(1);
//5-3.循环发布数据
while(ros::ok()){
//修改数据
ros::Duration(3).sleep();
//核心:发布数据
pub.publish(person);
ROS_INFO("发布的消息:%s,%d,%.2f",person.name.c_str(),person.age,person.height);
//休眠
rate.sleep();
//建议
person.age += 1;
ros::spinOnce();
}
return 0;
}
- 订阅方
- 新建文件
略; - 编辑代码
见第3点后; - 配置CMakeList.txt
和发布方配置时完全相同,修改以下文件名即可。
#include "ros/ros.h"
#include "plumbing_pub_sub/person.h"
/*
发布订阅方:订阅消息
1.包含头文件
#include "plumbing_pub_sub/person.h"
2.初始化ROS节点
3.创建节点句柄
4.创建订阅者对象
5.编写回调函数,处理订阅数据
6.调用spin()函数,spin()函数保证回调函数的正常运行
*/
void doPerson(const plumbing_pub_sub::person::ConstPtr &person){
ROS_INFO("订阅人的信息:%s,%d,%.2f",person->name.c_str(),person->age,person->height);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ROS_INFO("订阅方实现");
// 2.初始化ROS节点
ros::init(argc,argv,"jiaZhang");
// 3.创建节点句柄
ros::NodeHandle nh;
// 4.创建订阅者对象
ros::Subscriber sub = nh.subscribe("liaoTian",10,doPerson);
// 5.编写回调函数,处理订阅数据
// 6.调用spin()函数,spin()函数保证回调函数的正常运行
ros::spin();
return 0;
}
编译后运行程序,记得先运行roscore。
参考:Autolabor