[ROS]ros通信机制进阶

1.初始化

    /*
        作用:ROS初始化函数

        参数:
            1.argc  --- 封装实参个数(n+1)   
            2.argv  --- 封装参数的数组
            3.name  --- 为节点命名(唯一性),节点不可重名
            4.options   --- 节点启动选项

            返回值:void

        使用:
            1.argc与argv的使用
                如果按照ROS中的特定格式传入实参,那么ROS可以加以使用,比如用来设置全局参数、给节点重命名...
            2.options的使用
                节点名称需要保证唯一,会导致一个问题;同一个节点不能重复启动。
                结果:ROS中当有重名的节点启动时,之前的节点就会被关闭。
                需求:特定场景下,需要一个节点多次启动且能正常运行,怎么办?
                解决:设置启动项    ros::init(argc,argv,"chang_bgColor",ros::init_options::AnonymousName);
                    当创建ROS节点时,会在用户自定义的节点名称后缀随机数,从而避免重名问题。
    */
void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);

2.话题与服务相关对象

在roscpp中,话题和服务的相关对象一般由NodeHandle创建。NodeHandle有一个重要作用是可以用于设置命名空间。

    /*
        作用:创建发布者对象

        模板:被发布的消息的类型

        参数:
            1.话题名称
            2.队列长度
            3.latch(可选)   如果设置为true,会保存为发布方的最后一条消息,并且
                新的订阅对象连接到发布方时,发布方会将这条消息发送给订阅者

        使用:
            latch设置为true的作用?
            以静态地图发布为例,方案1:可以使用固定频率发送地图数据,但是效率太低;方案2:可以将
            地图发布对象的latch设置为true,并且发布方只发布一次数据,每当订阅者连接时,将地图数
            据发送给订阅者(只发送一次),这样提高数据的发送效率。
    */
template <class M>
Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)

3.回旋函数

在ROS程序中,频繁的使用了ros::spin()和ros::spinOnce()两个回旋函数,可以用于处理回调函数。

        spinOnce()

/**
 * \brief 处理一轮回调
 *
 * 一般应用场景:
 *     在循环体内,处理所有可用的回调函数
 * 
 */
ROSCPP_DECL void spinOnce();

        spin()

/** 
 * \brief 进入循环处理回调 
 */
ROSCPP_DECL void spin();

二者相同点:二者都用于处理回调函数

二者不同点:ros::spin()是进入了循环执行回调函数,而ros::spinOnce()只会执行一次回调函数(没有循环执行回调函数)。在ros::spin()后的语句不会执行,而ros::spinOnce()后的语句可以执行。

4.时间

ROS中时间相关的API是极其常用,比如:获取当前时刻、持续时间的设置、执行频率、休眠、定时器...都与时间相关。

时刻、持续时间、持续时间与时刻运算、设置运行频率、定时器

#include "ros/ros.h"

/*
    需求1:演示时间相关操作(获取当前时刻+设置指定时刻)
    实现:
        1.准备(头文件、节点初始化、NodeHandle创建...)
        2.获取当前时刻
        3.设置制定时刻

    需求2:程序执行中停顿5秒
    实现:
        1.创建持续时间对象
        2.休眠

    需求3:已知程序开始运行的时刻和程序运行的时间,求运行结束的时间
    实现:
        1.获取开始执行的时刻
        2.模拟运行时间(N秒)
        3.计算结束时刻=开始+持续时间
    注意:
        1.时刻与持续时间可以执行加减
        2.持续时间也可以执行加减
        3.时刻之间只可以相减,不可以相加。

    需求4:每隔1秒钟,在控制台输出一段文本
    文本:
        策略1:ros::Rate(1)
        策略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[])
{
    /* code */
    setlocale(LC_ALL,"");
    // 1.准备(头文件、节点初始化、NodeHandle创建...)
    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,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::Time sum=begin+stop;//不可以相加
    ros::Duration du2=begin-stop;
    ROS_INFO("时刻之间相减:%.2f",du2.toSec());
    //持续时间与持续时间
    ros::Duration du3=du1+du2;//5
    ros::Duration du4=du1-du2;//10
    ROS_INFO("du1+du2=%.2f",du3.toSec());
    ROS_INFO("du1-du2=%.2f",du4.toSec());


    //--------------------------------------------------------------------------
    ROS_INFO("------------------------定时器--------------------------");
    /*
        ros::Timer createTimer(ros::Duration period, //时间间隔---1s
        const ros::TimerCallback &callback,          //回调函数---封装业务
        bool oneshot = false,                        //是否是一次性
        bool autostart = true)                       //自动启动
    */
    //ros::Timer timer=nh.createTimer(ros::Duration(1),cb);
    //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;
}

5.其他函数

在发布实现时,一般会循环发布消息,循环的判断条件一般由节点状态来控制,C++中可以通过ros::ok()来判断节点状态是否正常,导致节点退出的原因主要有如下几种:

        节点接收到关闭信息,比如常用的ctrl+c快捷键就是关闭节点的信号;

        同名节点启动,导致现有节点退出;

        程序中的其他部分调用了节点关闭相关的API(C++是ros::shutdown());

日志相关的函数也是极其常用的,在ROS中日志被划分为如下级别:

        DEBUG(调试):只在调试时使用,此类消息不会输出到控制台;

        INFO(信息):标准信息,一般用于说明系统内正在执行的操作;

        WARN(警告):提醒一些异常情况,但程序仍然可以执行;

        ERROR(错误):提示错误信息,此类错误会影响程序运行;

        FATAL(严重错误):此类错误将阻止节点接续运行。

节点状态判断

/** \brief 检查节点是否已经退出
 *
 *  ros::shutdown() 被调用且执行完毕后,该函数将会返回 false
 *
 * \return true 如果节点还健在, false 如果节点已经火化了。
 */
bool ok();

节点关闭函数

/*
*   关闭节点
*/
void shutdown();

日志函数

#include "ros/ros.h"

/*
    ROS中日志:
        演示不同级别日志的基本使用

*/

int main(int argc, char *argv[])
{
    /* code */
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"hello_log");
    ros::NodeHandle nh;

    //日志输出
    ROS_DEBUG("调试信息");
    ROS_INFO("一般信息");
    ROS_WARN("警告信息");
    ROS_ERROR("错误信息");
    ROS_FATAL("严重错误");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值