ROS1重温:常用API以及其可选参数的亮点


初始化函数 init() 之 option

void ros::init	(int& 					argc,
				char ** 				argv,
				const std::string & 	name,
				uint32_t 				options = 0 
)	
  • options 是4个参数中的可选项,当在 init() 函数中加入参数 ros::init_options::AnonymousName 时,同一个节点在同一时间段可以运行多个,因为这一参数会将这些节点名称之后添加随机数用于区分。
  • 常用于:一个节点需要同时启动多个
    init() 需要注意:该函数可能会在运行过程中修改一些参数:
    • argc:参数量会减少。
    • 在使用 launch 文件启动该节点时,该节点默认会传入三个参数,分别是 程序文件路径、节点名称、log文件路径
    • 在运行 init() 之后会将 argc 值减2,argv 中存储节点名称和log记录的下标进行互换
    • init() 库函数说明
 * This function will parse any ROS arguments (e.g., topic name
 * remappings), and will consume them (i.e., argc and argv may be modified
 * as a result of this call).

中文释义:
*此函数将解析任何ROS参数(例如,主题名称

*重新映射),并将使用它们(即,可能会修改argc和argv

*作为该调用的结果)。

消息打印格式(以 ROS_INFO_STREAM 为例)

此处直接跳转至chill_chill博主的文章:ROS_INFO_STREAM输出彩色信息


话题发布者 NodeHandle::advertise() 函数之 latch

Publisher ros::NodeHandle::advertise(const std::string & 	topic,
									uint32_t 				queue_size,
									bool 					latch = false 
)	
  • latch 是3个参数中的可选项,当该参数值设置为true时,在发布者运行情况下,无论发布者是否在发布数据,新注册的订阅者均能接收到发布者最后发布的数据,即此时发布者总会保存队列中最新的一个数据。
  • 常用于:发布者只发布一次或者运行时偶尔发布数据,但有在新的订阅者加入时,均能够获得发布者最新的一个消息。
    • 例如,机器人导航中用到的静态地图,只需启动时发布一次即可,新加入的订阅者需要时都可以获取到。

话题订阅者回旋函数之 spin()、spinOnce()

  • spin():当执行到该语句时,程序会卡在此处不再继续执行之后的操作,转而开始重复调用回调函数( 专指订阅者中的 callback 函数)
    • 最初在学这一块儿的时候,会想:那我把 sipon() 放到循环里呢?这里就涉及到编程的循环语法上,循环语句只是重复执行一块儿代码,抛开 sipn() 函数本身的功能,当执行到 spin() 时又会重新执行该片段的程序,就等同于执行之后的程序
  • spinOnce():只调用一次回调函数,并继续执行之后的操作
    • 把 spinOnce() 嵌套入循环中时,会起到循环调用回调函数的功能
  • 综上,二者的功能只能算是 spinOnce() + 循环 ≈ spin(),只有循环调用回调函数这一条功能一样,其他功能不同

时间函数

基本函数之ros::Time::now()、ros::Time()、ros::Duration()、ros::Rate()

  • 时间函数在使用之前需要进行初始化
ros::Time::init();

一般情况下,在编写 ROS 程序时不会单独去写这一行,因为在初始化句柄 NodeHandle 的同时会对时间函数也进行初始化,所以为了减少代码量,只需要初始化句柄即可

  • ros::Time::now(): 获取当前的时刻,默认单位为 秒( s ),是以 1970年01月01日 00:00:00 为初始时间
  • ros::Time(): 设置指定时刻,该函数主要有两种形式,如下所示,结果均相同
      1. 指定秒值和纳秒值,时刻值为二者相加所得值
      1. 直接指定时刻值
// 参数1单位为s,参数2单位为ns,即指定时刻为 参数1+参数2
ros::Time t1(10, 123456789);    

// 直接指定时刻
ros::Time t2(10.123456789);   
  • ros::Duration(): 设置持续时间,使用 sleep() 函数来直观展示持续时间,样例如下:
// 持续时间
ROS_INFO("现在时刻:%.2f,开始休眠...", ros::Time::now().toSec());
ros::Duration du(3.5);  // 设置休眠时间
du.sleep(); // 休眠
ROS_INFO("现在时刻:%.2f,休眠结束。", ros::Time::now().toSec());
  • 时间运算(用到的自变量如下)

    ros::Time start_time = ros::Time::now();
    ros::Duration duration_time1(5);
    ros::Duration duration_time2(3);
    
    • 时刻之间,只可进行相运算,结果的数据类型为持续时间(ros::Duration()

      // 时刻之间,只可进行相减运算
      ROS_INFO("时间间隔为 %.2f", (end_time - start_time).toSec());   
      
    • 持续时间之间,可进行加减运算,结果的数据类型为持续时间(ros::Duration()

      // 持续时间之间,可进行相加减运算
      ROS_INFO("持续时间之和为 %.2f", (duration_time1 + duration_time2).toSec()); 
      ROS_INFO("持续时间之和为 %.2f", (duration_time1 - duration_time2).toSec());
      
    • 时刻与持续时间之间,可进行加减运算,结果的数据类型为时刻(ros::Time()

      // 时刻与持续时间,可以进行加减运算
      ros::Time end_time = start_time + duration_time1;  
      ROS_INFO("开始时刻为 %.2f", start_time.toSec());
      ROS_INFO("结束时刻为 %.2f", end_time.toSec());
      
  • ros::Rate(): 设置运行频率,当一个周期循环的时间满足频率,则通过使用 sleep() 函数来满足

ros::Rate r(10);	// 指定以 10Hz 的频率运行
while(ros::ok())
{
	r.sleep(); // 如果一个周期内时间未用完,则休眠一定时间以满足频率
}

定时器函数 creatTimer()


Timer ros::NodeHandle::createTimer	(	Duration 				period,
										const TimerCallback & 	callback,
										bool 					oneshot = false,
										bool 					autostart = true 
)	
  • Duration: 时间间隔
  • callback: 定时器回调函数
  • oneshot: 若为 true,回调函数只执行一次
  • autostart: 若为 false,需要运行 start() 启动,如下
// onshot 与 autostart 均为 false 的情况,需要手动启动
ros::Timer timer = nh.createTimer(ros::Duration(1), eventCallback, false, false);  

timer.start();  // 手动启动

由于定时器函数可能会涉及到回调函数,所以需要加入回旋函数 spin() 或 spiOnce() 来调用回调函数

  • 时间API 参考代码如下:
#include "ros/ros.h"

void eventCallback(const ros::TimerEvent &event)
{
    ROS_INFO("定时器回调函数,被调用时间:%.2f", event.current_real.toSec());
}

int main(int argc, char *argv[])
{
    // 设置中文编码
    setlocale(LC_ALL, "");
    // ros初始化
    ros::init(argc, argv, "api_time_node");
    // 句柄初始化
    ros::NodeHandle nh; // 句柄初始化时,会同时运行 ros::Time::init();,可以尝试注释该行运行看一看
    // ros::Time::init();

    // 获取当前时间
    ros::Time right_now = ros::Time::now(); // 从初始时间1970年01月01日 00:00:00,到现在所经历的时间
    std::cout << "ros::Time::now() = " << right_now << std::endl;
    ROS_INFO("当前时间(浮点型):%.2f", right_now.toSec());
    ROS_INFO("当前时间(整型):%d", right_now.sec);

    // 设置指定时刻
    ros::Time t1(10, 123456789); // 参数1单位为s,参数2单位为ns,即指定时刻为 参数1+参数2
    ros::Time t2(10.123456789);  // 直接指定时刻
    ROS_INFO("t1 = %.2f", t1.toSec());
    ROS_INFO("t2 = %.2f", t2.toSec());

    // 持续时间
    ROS_INFO("现在时刻:%.2f,开始休眠...", ros::Time::now().toSec());
    ros::Duration du(3.5); // 设置休眠时间
    // du.sleep(); // 休眠
    ROS_INFO("现在时刻:%.2f,休眠结束。", ros::Time::now().toSec());

    // 时间运算
    ros::Time start_time = ros::Time::now();
    ros::Duration duration_time1(5);
    ros::Duration duration_time2(3);
    ros::Time end_time = start_time + duration_time1; // 时刻与持续时间,可以进行加减运算
    ROS_INFO("开始时刻为 %.2f", start_time.toSec());
    ROS_INFO("结束时刻为 %.2f", end_time.toSec());
    ROS_INFO("时间间隔为 %.2f", (end_time - start_time).toSec());               // 时刻之间,只可进行相减运算
    ROS_INFO("持续时间之和为 %.2f", (duration_time1 + duration_time2).toSec()); // 持续时间之间,可进行相加减运算
    ROS_INFO("持续时间之和为 %.2f", (duration_time1 - duration_time2).toSec());

    // 定时器
    // ros::Timer timer = nh.createTimer(ros::Duration(1), eventCallback);  // 默认情况
    // ros::Timer timer = nh.createTimer(ros::Duration(1), eventCallback, true);    // onshot 为 true,只启动一次回调函数
    ros::Timer timer = nh.createTimer(ros::Duration(1), eventCallback, false, false);   // onshot 与 autostart 均为 false 的情况,需要手动启动
    timer.start();  // 手动启动

    ros::spin();

    return 0;
}

程序中断函数 shutdown()

  • 一般用于需要自动结束当前节点的程序,调用方式为直接在需要结束程序之后加如下一行:
ros::shutdown();	// 结束当前节点程序

日志输出函数

  • 共有5个级别,依次如下
    // 日志输出
    ROS_DEBUG("调试信息");  // 默认情况下不会显示在控制台
    ROS_INFO("一般信息");
    ROS_WARN("警告信息");
    ROS_ERROR("错误信息");
    ROS_FATAL("严重错误信息");
  • 显示DEBUG的方法;
    • 全局设置:sudo vim $ROS_ROOT/config/rosconsole.config ,将 log4j.logger.ros=INFO 改为 log4j.logger.ros=DEBUG
    • 单一节点设置: rqt_logger_level,找到对应节点名进行设置 (必须是正处于运行状态的节点。另一种在代码中添加打印信息的方式,比较繁琐且会使得代码冗杂,不推荐,此处也不细说,想尝试的可以自行查找)
  • 建议:
    • 不要因为 WARN 是带颜色的打印信息好区分而疯狂用,如果是在开发大工程,这样的打印信息会在后期非常痛苦。
    • 如果相区分打印信息可以用 DEBUG, 也是带颜色的,但默认情况是 INFO 需要手动调整打印等级,所以后期与其他模块对接也会方便很多
  • 建议是啥信息就选择相应的打印等级,慎重使用 ROS_ERROR、ROS_FATAL 这是代表错误的打印信息
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值