当前位置:网站首页>【ROS进阶篇】第一讲 常用API介绍
【ROS进阶篇】第一讲 常用API介绍
2022-06-25 22:13:00 【生如昭诩】
【ROS进阶篇】第一讲 常用API介绍
前言
在先前的博客中,我们通过十一节的教程实现了对于ROS的基础入门教学,从ROS的诞生、作用到基础的使用方法,我们通过C++的编程和命令行两种方式对ROS的通讯机制进行了深入的分析,并且介绍了诸如TF坐标变换、参数使用、launch文件等功能包和扩展库的使用方法,进阶篇则主要目的是脱离先前的角度,从宏观的角度考虑问题,更加清晰的掌握ROS的生态系统,并重点研究几个工具的使用教程,本节内容主要是对于ROS中常用API的介绍与总结。包括关于初始化、通讯、循环、时间和一些节点状态和日志输出的使用方法。
常用API
1. 初始化
- ROS节点的初始化相关API
/** @brief ROS初始化函数。 * * 该函数可以解析并使用节点启动时传入的参数(通过参数设置节点名称、命名空间...) * * 该函数有多个重载版本,如果使用NodeHandle建议调用该版本。 * * \param argc 参数个数 * \param argv 参数列表 * \param name 节点名称,需要保证其唯一性,不允许包含命名空间 * \param options 节点启动选项,被封装进了ros::init_options * */
void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);
2. 通讯
话题通讯
- 发布者:
/** * \brief 根据话题生成发布对象 * * 在 ROS master 注册并返回一个发布者对象,该对象可以发布消息 * * 使用示例如下: * * ros::Publisher pub = handle.advertise<std_msgs::Empty>("my_topic", 1); * * \param topic 发布消息使用的话题 * * \param queue_size 等待发送给订阅者的最大消息数量 * * \param latch (optional) 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者 * * \return 调用成功时,会返回一个发布对象 * * */
template <class M>
Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)
- 发布消息
/** * 发布消息 */
template <typename M>
void publish(const M& message) const
- 订阅者
/** * \brief 生成某个话题的订阅对象 * * 该函数将根据给定的话题在ROS master 注册,并自动连接相同主题的发布方,每接收到一条消息,都会调用回调 * 函数,并且传入该消息的共享指针,该消息不能被修改,因为可能其他订阅对象也会使用该消息。 * * 使用示例如下: void callback(const std_msgs::Empty::ConstPtr& message) { } ros::Subscriber sub = handle.subscribe("my_topic", 1, callback); * * \param M [template] M 是指消息类型 * \param topic 订阅的话题 * \param queue_size 消息队列长度,超出长度时,头部的消息将被弃用 * \param fp 当订阅到一条消息时,需要执行的回调函数 * \return 调用成功时,返回一个订阅者对象,失败时,返回空对象 * void callback(const std_msgs::Empty::ConstPtr& message){...} ros::NodeHandle nodeHandle; ros::Subscriber sub = nodeHandle.subscribe("my_topic", 1, callback); if (sub) // Enter if subscriber is valid { ... } */
template<class M>
Subscriber subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(const boost::shared_ptr<M const>&), const TransportHints& transport_hints = TransportHints())
服务通讯
- 服务器
/** * \brief 生成服务端对象 * * 该函数可以连接到 ROS master,并提供一个具有给定名称的服务对象。 * * 使用示例如下: \verbatim bool callback(std_srvs::Empty& request, std_srvs::Empty& response) { return true; } ros::ServiceServer service = handle.advertiseService("my_service", callback); \endverbatim * * \param service 服务的主题名称 * \param srv_func 接收到请求时,需要处理请求的回调函数 * \return 请求成功时返回服务对象,否则返回空对象: \verbatim bool Foo::callback(std_srvs::Empty& request, std_srvs::Empty& response) { return true; } ros::NodeHandle nodeHandle; Foo foo_object; ros::ServiceServer service = nodeHandle.advertiseService("my_service", callback); if (service) // Enter if advertised service is valid { ... } \endverbatim */
template<class MReq, class MRes>
ServiceServer advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&))
- 客户端
/** * @brief 创建一个服务客户端对象 * * 当清除最后一个连接的引用句柄时,连接将被关闭。 * * @param service_name 服务主题名称 */
template<class Service>
ServiceClient serviceClient(const std::string& service_name, bool persistent = false,
const M_string& header_values = M_string())
- 发送请求
/** * @brief 发送请求 * 返回值为 bool 类型,true,请求处理成功,false,处理失败。 */
template<class Service>
bool call(Service& service)
- 等待服务
/** * ros::service::waitForService("addInts"); * \brief 等待服务可用,否则一致处于阻塞状态 * \param service_name 被"等待"的服务的话题名称 * \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭 * \return 成功返回 true,否则返回 false。 */
ROSCPP_DECL bool waitForService(const std::string& service_name, ros::Duration timeout = ros::Duration(-1));
/** * client.waitForExistence(); * \brief 等待服务可用,否则一致处于阻塞状态 * \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭 * \return 成功返回 true,否则返回 false。 */
bool waitForExistence(ros::Duration timeout = ros::Duration(-1));
3. 循环
- 目的:处理回调函数
- spinOnce()
/** * \brief 处理一轮回调 * * 一般应用场景: * 在循环体内,处理所有可用的回调函数 * */
ROSCPP_DECL void spinOnce();
- spin()
/** * \brief 进入循环处理回调 */
ROSCPP_DECL void spin();
- 区别:
- ros::spin()是进入了循环执行回调函数,在 ros::spin() 后的语句不会执行到
- ros::spinOnce() 只会执行一次回调函数(没有循环),而 ros::spinOnce() 后的语句可以执行。
4. 时间
- 获取时刻/设置指定时刻:
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败
ros::Time right_now = ros::Time::now();//将当前时刻封装成对象
ROS_INFO("当前时刻:%.2f",right_now.toSec());//获取距离 1970年01月01日 00:00:00 的秒数
ROS_INFO("当前时刻:%d",right_now.sec);//获取距离 1970年01月01日 00:00:00 的秒数
ros::Time someTime(100,100000000);// 参数1:秒数 参数2:纳秒
ROS_INFO("时刻:%.2f",someTime.toSec()); //100.10
ros::Time someTime2(100.3);//直接传入 double 类型的秒数
ROS_INFO("时刻:%.2f",someTime2.toSec()); //100.30
- 设置时间间隔:
ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());
ros::Duration du(10);//持续10秒钟,参数是double类型的,以秒为单位
du.sleep();//按照指定的持续时间休眠
ROS_INFO("持续时间:%.2f",du.toSec());//将持续时间换算成秒
ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());
- 时间运算:
ROS_INFO("时间运算");
ros::Time now = ros::Time::now();
ros::Duration du1(10);
ros::Duration du2(20);
ROS_INFO("当前时刻:%.2f",now.toSec());
//1.time 与 duration 运算
ros::Time after_now = now + du1;
ros::Time before_now = now - du1;
ROS_INFO("当前时刻之后:%.2f",after_now.toSec());
ROS_INFO("当前时刻之前:%.2f",before_now.toSec());
//2.duration 之间相互运算
ros::Duration du3 = du1 + du2;
ros::Duration du4 = du1 - du2;
ROS_INFO("du3 = %.2f",du3.toSec());
ROS_INFO("du4 = %.2f",du4.toSec());
//PS: time 与 time 不可以运算
// ros::Time nn = now + before_now;//异常
- 设置运行频率:
ros::Rate rate(1);//指定频率
while (true)
{
ROS_INFO("-----------code----------");
rate.sleep();//休眠,休眠时间 = 1 / 频率。
}
- 定时器:
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
// 回调函数
void doSomeThing(const ros::TimerEvent &event){
ROS_INFO("-------------");
ROS_INFO("event:%s",std::to_string(event.current_real.toSec()).c_str());
}
5. 节点
- 节点的状态可以控制循环的条件,在常见的使用中常利用
ros::ok()
来判断,即节点是否关闭(ctrl+c)或者由于同名起动导致退出
/** \brief 检查节点是否已经退出 * * ros::shutdown() 被调用且执行完毕后,该函数将会返回 false * * \return true 如果节点还健在, false 如果节点已经火化了。 */
bool ok();
- 调用了节点关闭API:shutdown()
/* * 关闭节点 */
void shutdown();
6. 日志
- DEBUG(调试):只在调试时使用,此类消息不会输出到控制台;
ROS_DEBUG("hello,DEBUG"); //不会输出
- INFO(信息):标准消息,一般用于说明系统内正在执行的操作;
ROS_INFO("hello,INFO"); //默认白色字体
- WARN(警告):提醒一些异常情况,但程序仍然可以执行;
ROS_WARN("Hello,WARN"); //默认黄色字体
- ERROR(错误):提示错误信息,此类错误会影响程序运行;
ROS_ERROR("hello,ERROR");//默认红色字体
- FATAL(严重错误):此类错误将阻止节点继续运行;
ROS_FATAL("hello,FATAL");//默认红色字体
总结
- 声明:本节博客部分参考了CSDN用户赵虚左的ROS教程,关于API的参考网站也可以参考如下:
- http://wiki.ros.org/APIs
- https://docs.ros.org/en/api/roscpp/html/
边栏推荐
- 手工制作 pl-2303hx 的USB转TTL电平串口的电路_过路老熊_新浪博客
- postman如何测试需要登录的接口
- ValueError: color kwarg must have one color per data set. 9 data sets and 1 colors were provided
- Redis之内存淘汰机制
- [转载]RSLOGIX 5000实例教程
- Using swiper to realize the rotation chart
- smt贴片加工行业常见术语及知识汇总
- 详细讲解局部变量、全局变量、静态变量三种类型
- 关于scrapy爬虫时,由spider文件将item传递到管道的方法注意事项
- Common knowledge points in JS
猜你喜欢
文献调研(三):数据驱动的建筑能耗预测模型综述
(转载)进程和线程的形象解释
STEP7 master station and remote i/o networking_ Old bear passing by_ Sina blog
10.4.1 data console
POSTMAN测试出现SSL无响应
Literature research (I): hourly energy consumption prediction of office buildings based on integrated learning and energy consumption pattern classification
手工制作 pl-2303hx 的USB转TTL电平串口的电路_过路老熊_新浪博客
用frp搭建云电脑
EasyConnect连接后显示未分配虚拟地址
Literature research (III): overview of data-driven building energy consumption prediction models
随机推荐
Literature research (I): hourly energy consumption prediction of office buildings based on integrated learning and energy consumption pattern classification
Find the minimum value of flipped array [Abstract bisection]
Building cloud computers with FRP
10.4.1 données intermédiaires
SMT操作员是做什么的?工作职责?
14.1.1 promethues monitoring, four data types metrics, pushgateway
DNS复习
别再吃各种维生素C片了,这6种维生素C含量最高的水果
Shredding Company poj 1416
Realize the conversion between analog quantity value and engineering quantity value in STEP7_ Old bear passing by_ Sina blog
【微信公众号H5】 生成带参数进入公众号关注页的二维码 监听用户关注公众号事件 自定义菜单栏 (服务端)
Hand made pl-2303hx USB to TTL level serial port circuit_ Old bear passing by_ Sina blog
Simulation connection between WinCC and STEP7_ Old bear passing by_ Sina blog
ssh的复习
10.3.1、FineBI_ Installation of finebi
文獻調研(三):數據驅動的建築能耗預測模型綜述
How to configure SQL Server 2008 Manager_ Old bear passing by_ Sina blog
Circuit de fabrication manuelle d'un port série de niveau USB à TTL pour PL - 2303hx Old bear passing Sina blog
网络连接验证
Sword finger offer 48 Longest substring without duplicate characters