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 相关文章推荐
一个cssQuery对象 javascript脚本实现代码
Jul 21 Javascript
js跟随滚动条滚动浮动代码
Dec 31 Javascript
使用node.js 获取客户端信息代码分享
Nov 26 Javascript
jQuery EasyUI Dialog拖不下来如何解决
Sep 28 Javascript
Angular中使用$watch监听object属性值的变化(详解)
Apr 24 Javascript
Node.js编写CLI的实例详解
May 17 Javascript
webpack打包单页面如何引用的js
Jun 07 Javascript
解析Vue.js中的组件
Feb 02 Javascript
vue2.0 根据状态值进行样式的改变展示方法
Mar 13 Javascript
Vue 样式绑定的实现方法
Jan 15 Javascript
vue-resourc发起异步请求的方法
Feb 11 Javascript
react中props 的使用及进行限制的方法
Apr 28 Javascript
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
计数器详细设计
2006/10/09 PHP
PHP的FTP学习(一)
2006/10/09 PHP
php数据库连接时容易出错的特殊符号问题
2010/09/01 PHP
基于php缓存的详解
2013/05/15 PHP
PHP预定义变量9大超全局数组用法详解
2016/04/23 PHP
thinkphp5 + ajax 使用formdata提交数据(包括文件上传) 后台返回json完整实例
2020/03/02 PHP
javascript 学习之旅 (2)
2009/02/05 Javascript
JavaScript 继承详解(二)
2009/07/13 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
在JavaScript中操作时间之getYear()方法的使用教程
2015/06/11 Javascript
JavaScript的MVVM库Vue.js入门学习笔记
2016/05/03 Javascript
Bootstrap源码解读表单(2)
2016/12/22 Javascript
Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案
2017/03/13 Javascript
Angular实现较为复杂的表格过滤,删除功能示例
2017/12/23 Javascript
Vuejs 单文件组件实例详解
2018/02/09 Javascript
如何为你的JavaScript代码日志着色详解
2019/04/08 Javascript
layui switch 开关监听 弹出确定状态转换的例子
2019/09/21 Javascript
json_decode 索引为数字时自动排序问题解决方法
2020/03/28 Javascript
jQuery 函数实例分析【函数声明、函数表达式、匿名函数等】
2020/05/19 jQuery
vue中后端做Excel导出功能返回数据流前端的处理操作
2020/09/08 Javascript
[01:03]DOTA2新的征程 你的脚印值得踏上
2014/08/13 DOTA
[01:32]2016国际邀请赛中国区预选赛CDEC战队教练采访
2016/06/26 DOTA
Python常用模块用法分析
2014/09/08 Python
Python实现Youku视频批量下载功能
2017/03/14 Python
Python多重继承的方法解析执行顺序实例分析
2018/05/26 Python
Python实现基于POS算法的区块链
2018/08/07 Python
python 并发编程 非阻塞IO模型原理解析
2019/08/20 Python
Python实现代码统计工具
2019/09/19 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
HTML5高仿微信聊天、微信聊天表情|对话框|编辑器功能
2018/04/23 HTML / CSS
上课随便讲话检讨书
2014/09/12 职场文书
校园文化艺术节宣传标语
2014/10/09 职场文书
实习生个人总结范文
2015/02/28 职场文书
三八节活动主持词
2015/07/04 职场文书
房屋买卖定金协议书
2016/03/21 职场文书
nginx sticky实现基于cookie负载均衡示例详解
2022/12/24 Servers