1. 初始化:
//2.初始化ROS节点
/*
作用:ROS初始化函数
参数:
1. argc ----封装实参个数(n+1)
2. argv ----封装参数的数组
3. name ----为节点命名(唯一性)
4. options ----节点启动选项
返回值:void
使用:
1. argc 与 argv
如果按照ROS中的特定格式传入实参,那么ROS可以加以使用,比如用来设置全局参数、给节点重命名
2. option 的使用
节点名称需要保证唯一,会导致一个问题:同一个节点不能重复启动。
结果:ROS中当有重名的节点启动时,之前的节点会被关闭。
需求:特定场景下,需要一个节点多次启动且能正常运行,怎么办?
解决:设置启动项 ros::init_options::AnonymousName
当创建ROS节点时,会在用户自定义的节点名称后缀随机数,从而避免重名问题
*/
视频讲解:https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=125&spm_id_from=pageDriver
2. 话题与服务相关对象
//4.创建发布者对象
作用:创建发布者对象
模板:被发布的消息的类型
参数:
1.话题名称
2.队列长度
3.latch(可选) 如果设置为true,会保存发布方的最后一条消息,并且
新的订阅对象连接到发布方时,发布方会将这条消息发送给订阅者
使用:
latch 设置为 true 的作用:
以静态地图发布为例,方案1:可以使用规定频率发送地图数据,但是效率低;方案二:可以将
地图发布对象的 latch 设置为 true ,并且发布方只发送一条数据,每当订阅者连接时,
将地图数据发送给订阅者(只发送一次),这样提高了数据的发送效率。
视频讲解:https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=126&spm_id_from=pageDriver
3. 回调函数
ros::spin() 和 ros::spinOnce() 两个回旋函数,可以用于处理回调函数。
相同点: 二者都用于处理回调函数;
不同点: ros::spin() 是进入了循环执行回调函数,而 ros::spinOnce() 只会执行一次回调函数(没有循环),在 ros::spin() 后的语句不会执行到,而 ros::spinOnce() 后的语句可以执行。
4. 时间
注意:
创建:nh.createTimer( )
参数1:时间间隔
参数2:回调函数(时间事件 TimeEvent)
参数3:是否只执行1次
参数4:是否自动启动(当设置为 false ,需要手动调用 timer.start() )
定时器启动后:ros::spin()
#include "ros/ros.h"
/*
需求1:演示时间相关的操作(获取当前时刻 + 设置制定时刻)
实现:
1.准备(头文件、节点初始化、NodeHandle创建...)
2.获取当前时刻
3.设置指定时刻
需求2: 程序执行中停顿5秒
实现:
1.创建持续时间对象
2.休眠
需求3:已知程序开始运行的时刻,和程序运行的时间,求运行结束的时刻
实现:
1.获取开始执行的时刻
2.模拟运行时间(N秒)
3.计算结束时刻 = 开始 + 持续时间
注意:
1.时刻与持续时间可以执行加减
2.持续时间之间也可以执行加减
3.时刻之间值可以相减不可相加
需求4:每隔一秒,再控制台输出一段文本
实现:
策略1:ros::Rate()
策略2:定时器
*/
//后面定时器中的回调函数:
void cb(const ros::TimerEvent& event){
ROS_INFO("----------------------");
}
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);
// 3.设置指定时刻
ros::Time t1(20,3123456789); //逗号(秒,纳秒)
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::Time sun = begin + stop; //不可以相加,会抛异常
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("------------------------定时器---------------------------");
/*
ros::Timer = nh.createTimer(ros::Duration period, //时间间隔 --- 1s
const ros::TimerCallback &callback, //回调函数 ---- 封装业务
bool oneshot = false, //是否一次性 默认false
bool autostart = true) //是否自动启动 默认true
*/
ros::Timer timer = nh.createTimer(ros::Duration(1),cb); //参数:时间间隔,回调函数
ros::spin();// 需要回旋
return 0;
}
输出:
注:
“持续时间"那里会停顿5秒;定时器会以1s的频率输出”--------------"
定时器:ros::Timer timer = nh.createTimer(ros::Duration(1),cb,false,true)
将第四个参数改为true时,需要后面加上:
timer.start(); //手动启动
补充:在上述例子中回调函数那里改为:
void cb(const ros::TimerEvent& event){
ROS_INFO("----------------------");
ROS_INFO("函数被调用的时刻:%.2f",event.current_real.toSec());
}
则输出:
5. 其他函数
5.1 节点关闭:
在发布实现时,一般会循环发布消息,循环的判断条件一般由节点状态来控制,C++中可以通过 ros::ok() 来判断节点状态是否正常,而 python 中则通过 rospy.is_shutdown() 来实现判断,导致节点退出的原因主要有如下几种:
- 节点接收到了关闭信息,比如常用的 ctrl + c 快捷键就是关闭节点的信号;
- 同名节点启动,导致现有节点退出;
- 程序中的其他部分调用了节点关闭相关的API (C++中是ros::shutdown(),python中是rospy.signal_shutdown())
例:(执行50次结束循环)
if (count >= 50)
{
ros::shutdown();
}
5.2 日志相关:
- DEBUG(调试): 只在调试时使用,此类消息不会输出到控制台;
- INFO(信息): 标准消息,一般用于说明系统内正在执行的操作;
- WARN(警告): 提醒一些异常情况,但程序仍然可以执行;
- ERROR(错误): 提示错误信息,此类错误会影响程序运行;
- FATAL(严重错误): 此类错误将阻止节点继续运行。
#include "ros/ros.h"
/*
ROS中的日志:
演示不同级别日志的基本使用
*/
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;
}
输出: