2.ROS编程学习:话题通信c++
ros—melodic vocode开发
话题通信机制
ROS Master通过roscore实现,故通过编程实现的是发布者、订阅者、和消息,如海龟的计算图。
1.首先建立功能包
功能包的名字为sub_pub,在src中建立两个cpp文件。
2.c++发布者实现:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
头文件:
(1)调用ros库
(2)调用标准信息库中的字符串
(3)进行字符串拼接用到的string stream字符串流。
主函数:
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ros::init(argc,argv,"publisher");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
std_msgs::String msg;
ros::Rate rate(10);
int count = 0;
while (ros::ok())
{
count++;
std::stringstream ss;
ss << "hello -->" << count;
msg.data = ss.str();
pub.publish(msg);
ROS_INFO("发布数据:%s", msg.data.c_str());
rate.sleep();
}
return 0;
}
int main(int argc, char *argv[])
注意用main自动补齐需要去掉const。
setlocale(LC_ALL, "");
防止ROS_INFO在终端出现中文乱码现象。
ros::init(argc,argv,"publisher");
ros::NodeHandle n;
创建节点并初始化,创建节点句柄管理节点。
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
在ROS Master中注册publisher(发布者),发布以chongfu为话题的string字符串类型的消息(通过泛型操作<std_msgs::String>),其中pub和chongfu可以自定义名称。1000,如果出现网络阻塞,会让最新的1000个消息储存在队列中。
std_msgs::String msg;
初始化string类型的消息,其中此类型在标准消息类型库中调用。
ros::Rate rate(10);
rate.sleep();
两行代码配合控制循环的延时(发布频率),HZ为单位,10,每秒十次。
while (ros::ok())
while循环的条件为ros::ok(),用来检查ros系统状态,是否运行。
int count = 0;
count++;
为了记下循环次数,声明变量,同时每次while循环右加1,先赋值在加。
std::stringstream ss;
ss << "hello -->" << count;
msg.data = ss.str();
通过stringstream拼接字符串,同时给消息赋值。
pub.publish(msg);
发布消息。
ROS_INFO("发布数据:%s", msg.data.c_str());
终端显示,需要转化为c语言的字符串。
3.c++订阅方实现
#include "ros/ros.h"
#include "std_msgs/String.h"
void huidiao(const std_msgs::String::ConstPtr & msggg)
{
ROS_INFO("订阅的数据为:%s", msggg->data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "subscriber");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chongfu", 1000, huidiao);
ros::spin();
return 0;
}
与发布者不同的是:
(1)订阅者有回调函数,函数作用是将从发布者收集到的string消息打印出来。
void huidiao(const std_msgs::String::ConstPtr & msggg)
{
ROS_INFO("订阅的数据为:%s", msggg->data.c_str());
}
(2)创建了一个订阅者
ros::Subscriber sub = n.subscribe("chongfu", 1000, huidiao);
其中话题名必须和发布者相同,同时1000的作用与发布者类似,接收消息队列的大小,最后一个参数是回调函数。(这里不需要泛型操作去设定消息的类型,与发布者不同)
尝试加上了<std_msgs::String>,没出现问题。
ros::Subscriber sub = n.subscribe<std_msgs::String>("chongfu", 1000, huidiao);
(3)spin急转身
ros::spin();
不像发布者通过一个while循环通过ros::ok()条件不停的发布消息,需要不停的回头重复订阅才能不断地接收到消息,如果不回头,直接return 0运行结束了。
4.CMakeList.txt配置
add_executable(pub src/pub.cpp)
add_executable(sub src/sub.cpp)
第一个参数定可执行文件名称,第二个参数定参与编译.cpp文件位置。
target_link_libraries(pub
${catkin_LIBRARIES}
)
target_link_libraries(sub
${catkin_LIBRARIES}
)
设置链接库,全是默认的链接库。
5.通过catkin_make编译,roscore,rosrun运行
(1)开一个终端,开启ros master
roscore
(2)在工作空间catkin_ws下开一个终端,编译。
catkin_make
(3) 在工作空间catkin_ws下开一个终端,运行发布者。
source ./devel/setup.bash
rosrun sub_pub pub
(4) 在工作空间catkin_ws下开一个终端,运行订阅者。
source ./devel/setup.bash
rosrun sub_pub sub
通过尝试订阅者先运行发布者后运行、发布者先运行订阅者后运行、发布者运行中断再运行,皆能运行没有报错。
但会出现一个问题,先开启订阅者后开启发布者还会出现消息数据丢失(不是从1开始),解决方法:再消息发布之前(while循环之前)加入:
ros::Duration(3.0).sleep();
加入一个延时三秒即可。
6.启动计算图
rqt_graph
7.总结
发布者实现流程
头文件 -->ROS 节点--> ROS 句柄-->建立发布者-->发布消息
订阅者实现流程
头文件 -->ROS 节点--> ROS 句柄-->建立订阅者-->处理消息
注意的点
怎么解决控制台乱码问题?
c++必须进行CMakeList.txt配置后进行编译。
ros::spin();不停回头,循环等待回调函数。
ros::ok();作为发布者whlie的循环条件。