当前位置:网站首页>ROS通信机制进阶
ROS通信机制进阶
2022-07-27 05:21:00 【三个刺客】
常用API
初始化
/*
作用:ROS初始化
参数:
param argc 封装实参个数(n+1)
param argv 封装参数的数组
param name 节点名称,需要保证其唯一性,不允许包含命名空间
param options 节点启动选项,被封装进了ros::init_options
返回值:void
使用
1.argc与argv的使用
如果按照ROS中的特定格式传入参数,那么ROS可以加以使用,比如用来设置全局参数,给节点重命名
2.options的使用
节点名称需要保证唯一,会导致一个问题:同一个节点不能重复启动
结果:ROS中当有重名的节点启动时,之前的节点会关闭
需求:特定场景下,需要一个节点多次启动且能正常运行,怎么办
解决:设置启动项 ros::init_options::AnonymousName
当创建ROS节点时,会在用户自定义的节点名称后缀随机数,从而避免重名问题
*/1.roscore
2.rosrun plumbing_pub_sub demo01_pub _length:=2
3.rosparam list

2.options的使用
节点名称需要保证唯一,会导致一个问题:同一个节点不能重复启动
结果:ROS中当有重名的节点启动时,之前的节点会关闭
需求:特定场景下,需要一个节点多次启动且能正常运行,怎么办
解决:设置启动项 ros::init_options::AnonymousName
当创建ROS节点时,会在用户自定义的节点名称后缀随机数,从而避免重名问题
ros::init(argc,argv,"erGouZi",ros::init_options::AnonymousName);
此时可看到同一个节点后面有两个随机数,从而避免重名问题
话题与服务相关对象
在 roscpp 中,话题和服务的相关对象一般由 NodeHandle 创建。
NodeHandle有一个重要作用是可以用于设置命名空间
latch的使用
int main(int argc,char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"erGouZi",ros::init_options::AnonymousName);
ros::NodeHandle nh;
/*
作用:创建发布者对象
模板:被发布的消息类型
参数:
1.话题名称
2.队列长度
3.latch 如果设置为true,会保存发布方的最后一条消息,并且
新的订阅对象连接到发布方时,发布方会将这条消息发送给订阅者
使用:
latch设置为true的作用?
以静态地图为例,方案1:可以使用固定频率发布数据,但是效率低;方案2:可以将
地图发布对象的latch设置为true,并且发布方只发布一次数据,每当订阅者连接时,将地图数据发送给订阅者,这样提高了数据的发送效率
*/
ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10,true);
std_msgs::String msg;
//要求以10HZ的频率发布数据
ros::Rate rate(1);
int count = 0;
ros::Duration(3).sleep();
while (ros::ok())
{
count++;
//msg.data = "hello";
std::stringstream ss;
ss <<"hello ---> " << count;
msg.data = ss.str();
if(count <=10)
{
pub.publish(msg);
ROS_INFO("send data:%s",ss.str().c_str());
}
pub.publish(msg);
ROS_INFO("send data:%s",ss.str().c_str());
rate.sleep();
ros::spinOnce();
ROS_INFO("一轮回调执行完毕....");
}
}
回旋函数
在ROS程序中,频繁的使用了 ros::spin() 和 ros::spinOnce() 两个回旋函数,可以用于处理回调函数。spinOnce()和spin()函数比较
相同点:二者都用于处理回调函数;
不同点:ros::spin() 是进入了循环执行回调函数,而 ros::spinOnce() 只会执行一次回调函数(没有循环),在 ros::spin() 后的语句不会执行到,而 ros::spinOnce() 后的语句可以执行。
时间
注意事项都在代码中,如下
#include "ros/ros.h"
/*
需求:演示时间相关操作(获取当前时刻 + 设置指定时刻)
实现:
1.准备(头文件、节点初始化、NodeHandle创建)
2.获取当前时刻
3.设置指定时刻
需求2:程序执行中停顿5秒
实现:
1.创建持续时间对象
2.休眠
需求3:已知程序开始运行的时刻和程序运行的时间,求运行结束的时刻
实现:
1获取开始执行的时刻
2模拟运行时间(N秒)
3计算结束时刻 = 开始 + 持续时间
注意:
1.时刻与持续时间可以执行加减
2.持续时间之间也可以执行加减
3.时刻之间可以相减,不可以相加
需求4:每隔1s,在控制台输出一段文本
实现:
策略1:ros::Rate()
策略2:定时器
注意:
创建:nh.createTimer()
参数1:时间间隔
参数2:回调函数(时间事件 TimerEvent)
参数3:是否执行一次
参数4:是否自动启动(当设置为false,需要手动调用timer.start())
定时器启动后:ros::spin()
*/
//回调函数
void cb(const ros::TimerEvent& event){
ROS_INFO("-----------------");
ROS_INFO("函数被调用的时刻:%.2f",event.current_real.toSec());
}
int main(int argc, char *argv[])
{
//1.准备(头文件、节点初始化、NodeHandle创建)
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//注意:必须调用。否则会导致时间API调用失败(在NodeHandle会初始化时间操作)
//2.获取当前时刻
//now函数会将当前时刻封装并返回
//当前时刻:now被调用执行的那一刻
//参考系:1970年01月01日 00:00:00
ros::Time right_now = ros::Time::now();
ROS_INFO("当前时刻:%.2f",right_now.toSec());
ROS_INFO("当前时刻:%d",right_now.sec);
ros::Time t1(20,312345678);
ros::Time t2(100.35);
ROS_INFO("t1 = %.2f",t1.toSec());
ROS_INFO("t2 = %.2f",t2.toSec());
//----------------------------------------------------------------------
ROS_INFO("------------------持续时间--------------------");
ros::Time start = ros::Time::now();
ROS_INFO("开始休眠:%.2f",start.toSec());
ros::Duration du(4.5);
du.sleep();
ros::Time end = ros::Time::now();
ROS_INFO("休眠结束:%.2f",end.toSec());
//----------------------------------------------------------------------
ROS_INFO("------------------时间运算--------------------");
//1获取开始执行的时刻
ros::Time begin = ros::Time::now();
//2模拟运行时间(N秒)
ros::Duration du1(5);
//3计算结束时刻 = 开始 + 持续时间
ros::Time stop = begin + du1;//也可以减
ROS_INFO("开始时刻:%.2f",begin.toSec());
ROS_INFO("结束时刻:%.2f",stop.toSec());
//时刻与时刻运算
ros::Duration du2 = begin - stop;
ROS_INFO("时刻相减:%.2f",du2.toSec());
//持续时间与持续时间的运算
ros::Duration du3 = du1 + du2;
ros::Duration du4 = du1 - du2;
ROS_INFO("du1 + du2 = %.2f",du3.toSec());
ROS_INFO("du1 - du2 = %.2f",du4.toSec());
//----------------------------------------------------------------------
ROS_INFO("------------------定时器--------------------");
/*
Timer createTimer(Duration period, //时间间隔 1s
void(T::*callback)(const TimerEvent&) const, T* obj, //回调函数 封装业务
bool oneshot = false, //是否是一次性 true只执行一次 false 循环执行
bool autostart = true) const //自动启动
*/
//ros::Timer timer = nh.createTimer(ros::Duration(1),cb,true);
ros::Timer timer = nh.createTimer(ros::Duration(1),cb,false,false);
timer.start(); //手动启动
ros::spin(); //需要回旋
return 0;
}
ROS 中内置了专门的定时器,可以实现与 ros::Rate 类似的效果:
ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败
// ROS 定时器
/**
* \brief 创建一个定时器,按照指定频率调用回调函数。
*
* \param period 时间间隔
* \param callback 回调函数
* \param oneshot 如果设置为 true,只执行一次回调函数,设置为 false,就循环执行。
* \param autostart 如果为true,返回已经启动的定时器,设置为 false,需要手动启动。
*/
//Timer createTimer(Duration period, const TimerCallback& callback, bool oneshot = false,
// bool autostart = true) const;
// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing);
ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,true);//只执行一次
// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,false,false);//需要手动启动
// timer.start();
ros::spin(); //必须 spin
注意:
创建:nh.createTimer()
参数1:时间间隔
参数2:回调函数(时间事件 TimerEvent)
参数3:是否执行一次
参数4:是否自动启动(当设置为false,需要手动调用timer.start())
定时器启动后:ros::spin()
节点退出原因
导致节点退出的原因主要有如下几种:
- 节点接收到了关闭信息,比如常用的 ctrl + c 快捷键就是关闭节点的信号;
- 同名节点启动,导致现有节点退出;
- 程序中的其他部分调用了节点关闭相关的API(C++中是ros::shutdown(),python中是rospy.signal_shutdown())
另外,日志相关的函数也是极其常用的,在ROS中日志被划分成如下级别:
- DEBUG(调试):只在调试时使用,此类消息不会输出到控制台;
- INFO(信息):标准消息,一般用于说明系统内正在执行的操作;
- WARN(警告):提醒一些异常情况,但程序仍然可以执行;
- ERROR(错误):提示错误信息,此类错误会影响程序运行;
- FATAL(严重错误):此类错误将阻止节点继续运行。
使用示例:
#include "ros/ros.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_log");
ros::NodeHandle nh;
ROS_DEBUG("调试信息"); //不会打印在控制台
ROS_INFO("一般信息"); //默认白色字体
ROS_WARN("警告信息"); //默认黄色字体
ROS_ERROR("错误信息"); //默认红色字体
ROS_FATAL("严重错误"); //默认红色字体
return 0;
}
边栏推荐
猜你喜欢

安全帽反光衣检测识别数据集和yolov5模型

2022.6.10 stm32mp157 serial port clock learning

What has been updated in the Chinese version of XMIND mind map 2022 v12.0.3?

Stm32-fsmc extended memory SRAM

PS 2022 updated in June, what new functions have been added
![[first song] machine learning of rebirth - linear regression](/img/70/3efd9eacf88f55022eb52d096926f7.png)
[first song] machine learning of rebirth - linear regression

What tools are needed to make video post effects?

Unity 引擎开始从 Mono 迁移到 .NET CoreCLR

WebODM win10安装教程(亲测)

socket 长链接
随机推荐
Dynamic planning for solving problems (6)
一张图看懂指针
Dynamic planning for solving problems (4)
Man moon myth reading notes
Dynamic planning for solving problems (3)
力扣题解 二叉树(5)
Force buckle 110. Balanced binary tree
Live Home 3D Pro interior home design tool
What has been updated in the Chinese version of XMIND mind map 2022 v12.0.3?
AE 3D particle system plug-in: Trapcode particle
WebODM win10安装教程(亲测)
[5.20 special] MATLAB, I'm confessing to you
安全帽反光衣检测识别数据集和yolov5模型
遥感影像识别进展2022/5/5
力扣第一周错题集
Summary of the use of C # Jason code in TCP communication
非重叠矩形中的随机点(力扣每日一题)
Solve binary tree (7)
Force deduction problem solving monotonous stack
数据库索引的一些说明以及使用