ros::spin() 和 ros::spinOnce()函数的区别及详解


Posted in Javascript onOctober 01, 2016

1 函数意义

首先要知道,这俩兄弟学名叫ROS消息回调处理函数。它俩通常会出现在ROS的主循环中,程序需要不断调用ros::spin() 或 ros::spinOnce(),两者区别在于前者调用后不会再返回,也就是你的主程序到这儿就不往下执行了,而后者在调用后还可以继续执行之后的程序。

其实消息回调处理函数的原理非常简单。我们都知道,ROS存在消息发布订阅机制,什么?不知道?不知道还不快去:http://wiki.ros.org/ROS/Tutorials (ROS官方基础教程) 瞅瞅。

好,我们继续,如果你的程序写了相关的消息订阅函数,那么程序在执行过程中,除了主程序以外,ROS还会自动在后台按照你规定的格式,接受订阅的消息,但是所接到的消息并不是立刻就被处理,而是必须要等到ros::spin()或ros::spinOnce()执行的时候才被调用,这就是消息回到函数的原理,怎么样,简单吧,至于为什么这么设计?咳咳,嗯,肯定有他的道理。。。

2 区别

就像上面说的,ros::spin() 在调用后不会再返回,也就是你的主程序到这儿就不往下执行了,而 ros::spinOnce() 后者在调用后还可以继续执行之后的程序。

其实看函数名也能理解个差不多,一个是一直调用;另一个是只调用一次,如果还想再调用,就需要加上循环了。

这里一定要记住,ros::spin()函数一般不会出现在循环中,因为程序执行到spin()后就不调用其他语句了,也就是说该循环没有任何意义,还有就是spin()函数后面一定不能有其他语句(return 0 除外),有也是白搭,不会执行的。ros::spinOnce()的用法相对来说很灵活,但往往需要考虑调用消息的时机,调用频率,以及消息池的大小,这些都要根据现实情况协调好,不然会造成数据丢包或者延迟的错误。

3 常见使用方法

这里需要特别强调一下,如果大兄弟你的程序写了相关的消息订阅函数,那千万千万千万不要忘了在相应位置加上ros::spin()或者ros::spinOnce()函数,不然你是永远都得不到另一边发出的数据或消息的,博主血的教训,万望紧记。。。

3.1 ros::spin()

ros::spin()函数用起来比较简单,一般都在主程序的最后,加入该语句就可。例子如下:

发送端:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;
  while (ros::ok())
  {
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    /**
     * 向 Topic: chatter 发送消息, 发送频率为10Hz(1秒发10次);消息池最大容量1000。
     */
    chatter_pub.publish(msg);
    loop_rate.sleep();
    ++count;
  }
  return 0;
}

接收端:

#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  /**
   * ros::spin() 将会进入循环, 一直调用回调函数chatterCallback(),每次调用1000个数据。
   * 当用户输入Ctrl+C或者ROS主进程关闭时退出,
   */
  ros::spin();
  return 0;
}

3.2 ros::spinOnce()

对于ros::spinOnce()的使用,虽说比ros::spin()更自由,可以出现在程序的各个部位,但是需要注意的因素也更多。比如:

1 对于有些传输特别快的消息,尤其需要注意合理控制消息池大小和ros::spinOnce()执行频率; 比如消息送达频率为10Hz, ros::spinOnce()的调用频率为5Hz,那么消息池的大小就一定要大于2,才能保证数据不丢失,无延迟。

/**接收端**/<br>#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  /*...TODO...*/ 
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 2, chatterCallback);
  ros::Rate loop_rate(5);
  while (ros::ok())
  {
    /*...TODO...*/ 
    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}

2 ros::spinOnce()用法很灵活,也很广泛,具体情况需要具体分析。但是对于用户自定义的周期性的函数,最好和ros::spinOnce并列执行,不太建议放在回调函数中;

/*...TODO...*/
ros::Rate loop_rate(100);
while (ros::ok())
{
  /*...TODO...*/
  user_handle_events_timeout(...);
  ros::spinOnce();         
  loop_rate.sleep();
}
Javascript 相关文章推荐
JavaScript 新手24条实用建议[TUTS+]
Jun 21 Javascript
javascript中直接引用Microsoft的COM生成Word
Jan 20 Javascript
JavaScript正则表达式匹配 div  style标签
Mar 15 Javascript
浅谈angularJS中的事件
Jul 12 Javascript
JS扩展类,克隆对象与混合类实例分析
Nov 26 Javascript
React Native 集成jpush-react-native的示例代码
Aug 16 Javascript
webpack4.x开发环境配置详解
Aug 04 Javascript
vue+axios+element ui 实现全局loading加载示例
Sep 11 Javascript
vue中利用simplemde实现markdown编辑器(增加图片上传功能)
Apr 29 Javascript
推荐几个不错的console调试技巧实现
Dec 20 Javascript
JS跨浏览器解析XML应用过程详解
Oct 16 Javascript
详解Vue项目的打包方式(生成dist文件)
Jan 18 Vue.js
javascript代码调试之console.log 用法图文详解
Sep 30 #Javascript
JS实现表单多文件上传样式美化支持选中文件后删除相关项
Sep 30 #Javascript
微信小程序 Audio API详解及实例代码
Sep 30 #Javascript
微信小程序 Record API详解及实例代码
Sep 30 #Javascript
微信小程序 Image API实例详解
Sep 30 #Javascript
微信小程序 wx.request(object) API详解及实例代码
Sep 30 #Javascript
JavaScript 链式结构序列化详解
Sep 30 #Javascript
You might like
PHP 判断变量类型实现代码
2009/10/23 PHP
thinkPHP5.0框架URL访问方法详解
2017/03/18 PHP
PHP下 Mongodb 连接远程数据库的实例代码
2017/08/30 PHP
Thinkphp开发--集成极光推送
2017/09/15 PHP
Extjs Ext.MessageBox.confirm 确认对话框详解
2010/04/02 Javascript
ajax 缓存 问题 requestheader
2010/08/01 Javascript
JavaScript中的Function函数
2015/08/27 Javascript
限制只能输入数字的实现代码
2016/05/16 Javascript
Javascript中arguments对象的详解与使用方法
2016/10/04 Javascript
利用jQuery解析获取JSON数据
2017/04/08 jQuery
深入理解Vue.js源码之事件机制
2017/09/27 Javascript
详解JavaScript中的数组合并方法和对象合并方法
2018/05/11 Javascript
vue+webpack模拟后台数据的示例代码
2018/07/26 Javascript
JS使用canvas中的measureText方法测量字体宽度示例
2019/02/02 Javascript
JS面向对象之多选框实现
2020/01/17 Javascript
jQuery实现获取多选框的值示例
2020/02/07 jQuery
通过实例了解Nodejs模块系统及require机制
2020/07/16 NodeJs
[46:02]DOTA2上海特级锦标赛D组资格赛#2 Liquid VS VP第二局
2016/02/28 DOTA
Python时间获取及转换知识汇总
2017/01/11 Python
《与孩子一起学编程》python自测题
2018/05/27 Python
python 实现简单的FTP程序
2019/12/27 Python
Python基于smtplib协议实现发送邮件
2020/06/03 Python
Python类class参数self原理解析
2020/11/19 Python
咖啡为什么会有酸味?你喝到的咖啡為什麼是酸的?
2021/03/17 冲泡冲煮
不同浏览器对CSS3和HTML5的支持状况
2009/10/31 HTML / CSS
推荐一些比较有用的css3新属性
2014/11/11 HTML / CSS
HTML5之SVG 2D入门9—蒙板及mask元素介绍与应用
2013/01/30 HTML / CSS
面向对象编程的优势是什么
2015/12/17 面试题
超市5.1促销活动
2014/01/15 职场文书
高三政治教学反思
2014/02/06 职场文书
《雾凇》教学反思
2014/02/17 职场文书
2015年毕业生自荐信范文
2015/03/24 职场文书
童年读书笔记
2015/06/26 职场文书
退休劳动合同怎么写?
2019/10/25 职场文书
详解CSS玩转图片Base64编码
2021/05/25 HTML / CSS
css弧边选项卡的项目实践
2023/05/07 HTML / CSS