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 相关文章推荐
jquery加载页面的方法(页面加载完成就执行)
Jun 21 Javascript
关于onScroll事件在IE6下每次滚动触发三次bug说明
Sep 21 Javascript
jquery简单实现滚动条下拉DIV固定在头部不动
Nov 25 Javascript
javascript判断是手机还是电脑访问网页的简单实例分享
Jun 03 Javascript
使用JavaScript进行进制转换将字符串转换为十进制
Sep 21 Javascript
JS实现仿腾讯微博无刷新删除微博效果代码
Oct 16 Javascript
jquery输入数字随机抽奖特效的简单实现代码
Jun 10 Javascript
js实现倒计时及时间对象
Nov 15 Javascript
jQuery排序插件tableSorter使用方法
Feb 10 Javascript
Angular项目从新建、打包到nginx部署全过程记录
Dec 09 Javascript
关于vue里页面的缓存详解
Nov 04 Javascript
vue 中 elment-ui table合并上下两行相同数据单元格
Dec 26 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
[原创]php简单隔行变色功能实现代码
2016/07/09 PHP
Laravel 框架控制器 Controller原理与用法实例分析
2020/04/14 PHP
javascript 装载iframe子页面,自适应高度
2009/03/20 Javascript
JavaScript经典效果集锦
2010/07/06 Javascript
Javascript 类、命名空间、代码组织代码
2011/07/31 Javascript
javascript学习笔记(九) js对象 设计模式
2012/06/19 Javascript
jQuery实现向下滑出的二级菜单效果实例
2015/08/22 Javascript
javascript中select下拉框的用法总结
2016/01/07 Javascript
JavaScript实现斗地主游戏的思路
2016/02/29 Javascript
layer弹出层框架alert与msg详解
2017/03/14 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
浅谈jquery fullpage 插件增加头部和版权的方法
2018/03/20 jQuery
浅谈React 服务器端渲染的使用
2018/05/08 Javascript
浅谈vue 单文件探索
2018/09/05 Javascript
详解如何解决vue开发请求数据跨域的问题(基于浏览器的配置解决)
2018/11/12 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
vue中npm包全局安装和局部安装过程
2019/09/03 Javascript
Vue2.0 ES6语法降级ES5的操作
2020/10/30 Javascript
Python正则获取、过滤或者替换HTML标签的方法
2016/01/28 Python
用python写的一个wordpress的采集程序
2016/02/27 Python
Python编程使用*解包和itertools.product()求笛卡尔积的方法
2017/12/18 Python
浅谈pandas中Dataframe的查询方法([], loc, iloc, at, iat, ix)
2018/04/10 Python
Python实现判断一行代码是否为注释的方法
2018/05/23 Python
Python判断字符串是否为空和null方法实例
2020/04/26 Python
Python Mock模块原理及使用方法详解
2020/07/07 Python
scrapy-redis分布式爬虫的搭建过程(理论篇)
2020/09/29 Python
Python爬虫之Selenium设置元素等待的方法
2020/12/04 Python
python wsgiref源码解析
2021/02/06 Python
web页面录屏实现
2019/02/12 HTML / CSS
施华洛世奇澳大利亚官网:SWAROVSKI澳大利亚
2017/01/06 全球购物
如何为DataGridView添加一个定制的Column Type
2014/01/21 面试题
高分子材料个人求职信范文
2013/09/25 职场文书
运动会领导邀请函
2014/01/10 职场文书
2014年民主评议党员个人总结
2014/09/24 职场文书
小学感恩节活动策划方案
2014/10/06 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS