目录
参考学习资料:B站赵虚左的ROS课程
一、以话题通信的c++初始化节点api进阶使用
1.初始化节点代码提示与c++话题通信例程
初始化函数的代码提示:(可通过ctrl+shift+空格查看代码提示)
void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);
之前练习的话题通信的c++实现例程:
2.ROS编程学习:话题通信c++_机械专业的计算机小白的博客-优快云博客https://blog.youkuaiyun.com/wzfafabga/article/details/127081895
2.初始化节点使用进阶
pub.cpp
修改内容:
ros::init(argc,argv,"publisher");
ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
// ros::init(argc,argv,"publisher";
ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
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();
ros::spinOnce();
}
return 0;
}
3.初始化节点参数解读
一.概念
1.ROS初始化函数
void init(int &argc, char **argv, const std::__cxx11::string &name, uint32_t options = 0U)
ros::init(argc,argv,"publisher");
2.参数
argc 封装实参的个数,n+1个,因为第一个参数为文件名,并不是想要配置的参数.
argv 封装实参的数组,第0个元素为文件名.
name 为节点命名,这个必须具有唯一性,如果启动一个节点后,再启动相同的节点前一个节点会被shudown.
options 特定情况下,同一个节点要启动两次,而且需要都正常运行.原理是每个节点名后自动添加一个随机数,让其节点名不同.
3.返回值:空void
二.用法
argc+argv: ①通过主函数中的int argc, char *argv[]传入实参②按照特定格式传入实参,ROS加以使用,实现设置全局参数,给节点重命名。
options:实现相同节点多次启动ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
主函数中的argc和argv的用法详见如下优化客户端部分,如下这个服务通信例子调用了实参个数和实参组成的数组。
4.初始化节点加options参数效果
初始化节点加了options的结果:
启动ROS Master
roscore
启动发布者节点
rosrun sub_pub pub
再次启动相同的发布者节点
rosrun sub_pub pub
两个节点能一起运行
查看所有节点名
rosnode list
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws$ rosnode list
/publisher_1666695811703949824
/publisher_1666695832571769067
/rosout
发现创建的发布者节点名/publisher后面自动加了随机数,使得节点不重名,以至于能一起运行。
二、话题通信发布方对象进阶
1.创建发布者代码提示与c++话题通信例程
.创建发布者代码提示(可通过ctrl+shift+空格查看代码提示)
ros::Publisher advertise<M>(const std::__cxx11::string &topic, uint32_t queue_size, bool latch = false)
利用到c++实现的话题通信中的创建发布者部分
2.创建发布者api进阶
pub.cpp
改动的部分:
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000,true);
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
// ros::init(argc,argv,"publisher";
ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
ros::NodeHandle n;
// ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000,true);
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();
ros::spinOnce();
}
return 0;
}
latch参数介绍:
其中最后一个参数是latch是一个布尔值,它的作用是在发布方停止发布消息时保留最后一次的发布消息留给订阅者,这是为了防止发布方不停的发布消息导致占用性能,在处理静态数据时需要这个参数为true。如果latch为false,发布方停止发布数据时,订阅方是接收不到消息的。
例子小车路径规划时,地图是不变的,故没必要不停的刷新地图,造成性能的浪费,故在地图的发布方的latch参数设置为true。
改动pub.cpp使得其发布10条消息停止发布
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
// ros::init(argc,argv,"publisher";
ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
ros::NodeHandle n;
// ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000,true);
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();
if(count <= 10)
{
pub.publish(msg);
ROS_INFO("发布数据:%s", msg.data.c_str());
rate.sleep();
}
// pub.publish(msg);
// ROS_INFO("发布数据:%s", msg.data.c_str());
// rate.sleep();
ros::spinOnce();
}
return 0;
}
3.改进后结果分析
启动ROSMaster
roscore
启动发布者,发布10条消息停止发布
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws$ rosrun sub_pub pub
[ INFO] [1666786808.842602969]: 发布数据:hello -->1
[ INFO] [1666786808.943626137]: 发布数据:hello -->2
[ INFO] [1666786809.043588395]: 发布数据:hello -->3
[ INFO] [1666786809.143665020]: 发布数据:hello -->4
[ INFO] [1666786809.243587508]: 发布数据:hello -->5
[ INFO] [1666786809.342738647]: 发布数据:hello -->6
[ INFO] [1666786809.443286320]: 发布数据:hello -->7
[ INFO] [1666786809.543143779]: 发布数据:hello -->8
[ INFO] [1666786809.642728771]: 发布数据:hello -->9
[ INFO] [1666786809.742740936]: 发布数据:hello -->10
启动订阅者,订阅到最后一条数据
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws$ rosrun sub_pub sub
[ INFO] [1666787054.272108779]: 订阅的数据为:hello -->10
三、回头函数加深理解
1.ros::spinOnce();
回一次头且写在ros::spinOnce();后面的代码还会运行。
实验:
pub.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
// ros::init(argc,argv,"publisher";
ros::init(argc,argv,"publisher",ros::init_options::AnonymousName);
ros::NodeHandle n;
// ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000);
ros::Publisher pub = n.advertise<std_msgs::String>("chongfu",1000,true);
std_msgs::String msg;
ros::Rate rate(1);
int count = 0;
while (ros::ok())
{
count++;
std::stringstream ss;
ss << "hello -->" << count;
msg.data = ss.str();
if(count <= 10)
{
pub.publish(msg);
ROS_INFO("发布数据:%s", msg.data.c_str());
rate.sleep();
}
// pub.publish(msg);
// ROS_INFO("发布数据:%s", msg.data.c_str());
// rate.sleep();
ros::spinOnce();
ROS_INFO("实验:看看这行代码运行情况");
}
return 0;
}
ros::spinOnce();效果,看出回一次头下面的代码正常运行
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws$ rosrun sub_pub pub
[ INFO] [1666787480.639928822]: 发布数据:hello -->1
[ INFO] [1666787481.641120474]: 实验:看看这行代码运行情况
[ INFO] [1666787481.641195387]: 发布数据:hello -->2
[ INFO] [1666787482.640193316]: 实验:看看这行代码运行情况
[ INFO] [1666787482.640266774]: 发布数据:hello -->3
[ INFO] [1666787483.640754102]: 实验:看看这行代码运行情况
[ INFO] [1666787483.640828620]: 发布数据:hello -->4
[ INFO] [1666787484.640382732]: 实验:看看这行代码运行情况
[ INFO] [1666787484.640486097]: 发布数据:hello -->5
2.ros::spin();
不停回头,不停在回调函数中循环,意味着节点不停,回调函数循环不停,所以不停回头函数后的代码不能运行。
实验:
sub.cpp
#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<std_msgs::String>("chongfu", 1000, huidiao);
ros::spin();
ROS_INFO("实验:看看这行代码运行情况");
return 0;
}
启动订阅者和发布者
rosrun sub_pub sub
rosrun sub_pub pub
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws$ rosrun sub_pub sub
[ INFO] [1666787805.552861795]: 订阅的数据为:hello -->1
[ INFO] [1666787806.306914044]: 订阅的数据为:hello -->2
[ INFO] [1666787807.307552251]: 订阅的数据为:hello -->3
[ INFO] [1666787808.306867980]: 订阅的数据为:hello -->4
[ INFO] [1666787809.307330567]: 订阅的数据为:hello -->5
[ INFO] [1666787810.307291604]: 订阅的数据为:hello -->6
[ INFO] [1666787811.307101347]: 订阅的数据为:hello -->7
[ INFO] [1666787812.307234292]: 订阅的数据为:hello -->8
[ INFO] [1666787813.307128563]: 订阅的数据为:hello -->9
[ INFO] [1666787814.307039999]: 订阅的数据为:hello -->10
回头函数后面的代码没有运行。