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 新手学习常见问题解决方法
Apr 18 Javascript
使用Java实现简单的server/client回显功能的方法介绍
May 03 Javascript
window.location.href = window.location.href 跳转无反应 a超链接onclick事件写法
Aug 21 Javascript
js使用数组判断提交数据是否存在相同数据
Nov 27 Javascript
如何判断元素是否为HTMLElement元素
Dec 06 Javascript
$(document).ready(function() {})不执行初始化脚本
Jun 19 Javascript
容易造成JavaScript内存泄露几个方面
Sep 04 Javascript
JavaScript代码性能优化总结篇
May 15 Javascript
mpvue跳转页面及注意事项
Aug 03 Javascript
JavaScript实现随机点名器实例详解
May 07 Javascript
在微信小程序中渲染HTML内容3种解决方案及分析与问题解决
Jan 12 Javascript
JavaScript点击按钮生成4位随机验证码
Jan 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
phpmyadmin里面导入sql语句格式的大量数据的方法
2010/06/05 PHP
记录PHP错误日志 display_errors与log_errors的区别
2012/10/09 PHP
destoon实现商铺管理主页设置增加新菜单的方法
2014/06/26 PHP
php使用ob_flush不能每隔一秒输出原理分析
2015/06/02 PHP
jQuery find和children方法使用
2011/01/31 Javascript
table insertRow、deleteRow定义和用法总结
2014/05/14 Javascript
jQuery实现平滑滚动到指定锚点的方法
2015/03/20 Javascript
JavaScript实现把rgb颜色转换成16进制颜色的方法
2015/06/01 Javascript
jQuery多个版本和其他js库冲突的解决方法
2016/08/11 Javascript
JavaScript-html标题滚动效果的简单实现
2016/09/08 Javascript
nodejs中向HTTP响应传送进程的输出
2017/03/19 NodeJs
使用vue实现grid-layout功能实例代码
2018/01/05 Javascript
jQuery无冲突模式详解
2019/01/17 jQuery
浅谈对于react-thunk中间件的简单理解
2019/05/01 Javascript
8 个有用的JS技巧(推荐)
2019/07/03 Javascript
使用flow来规范javascript的变量类型
2019/09/12 Javascript
微信小程序实现导航栏和内容上下联动功能代码
2020/06/29 Javascript
Python操作SQLite简明教程
2014/07/10 Python
python基础教程之Hello World!
2014/08/29 Python
零基础写python爬虫之urllib2中的两个重要概念:Openers和Handlers
2014/11/05 Python
win10环境下python3.5安装步骤图文教程
2017/02/03 Python
Python3匿名函数用法示例
2018/07/25 Python
解决django 新增加用户信息出现错误的问题
2019/07/28 Python
如何解决django-celery启动后迅速关闭
2019/10/16 Python
Python迭代器iterator生成器generator使用解析
2019/10/24 Python
Python实现数值积分方式
2019/11/20 Python
python中count函数简单用法
2020/01/05 Python
30行Python代码实现高分辨率图像导航的方法
2020/05/22 Python
Trench London官方网站:高级风衣和意大利皮夹克
2020/07/11 全球购物
查询优化的一般准则有哪些
2015/03/08 面试题
施工安全责任书
2014/04/14 职场文书
怎样拟定创业计划书
2014/05/01 职场文书
幼儿园安全生产月活动总结
2014/07/05 职场文书
爱鸟护鸟的宣传语
2015/07/13 职场文书
2016年党员公开承诺书范文
2016/03/24 职场文书
JDK8中String的intern()方法实例详细解读
2022/09/23 Java/Android