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 EasyUI 中文API Button使用实例
Apr 14 Javascript
JQuery中$之选择器用法介绍
Apr 05 Javascript
jQuery EasyUI API 中文文档 - Parser 解析器
Sep 29 Javascript
JavaScript判断一个URL链接是否有效的实现方法
Oct 08 Javascript
js window.print实现打印特定控件或内容
Sep 16 Javascript
前台js调用后台方法示例
Dec 02 Javascript
JS实现颜色动态淡化效果
Mar 06 Javascript
解决vue router使用 history 模式刷新后404问题
Jul 19 Javascript
微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】
Dec 09 Javascript
require.js 加载过程与使用方法介绍
Oct 30 Javascript
Vue 3.x+axios跨域方案的踩坑指南
Jul 04 Javascript
vue 函数调用加括号与不加括号的区别
Oct 29 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函数获取当前运行的环境 来进行判断执行逻辑(小技巧)
2013/06/25 PHP
采用ThinkPHP中F方法实现快速缓存实例
2014/06/13 PHP
Yii框架防止sql注入,xss攻击与csrf攻击的方法
2016/10/18 PHP
jQuery maxlength文本字数限制插件
2010/04/16 Javascript
JavaScript通过正则表达式实现表单验证电话号码
2014/03/07 Javascript
使用jquery.upload.js实现异步上传示例代码
2014/07/29 Javascript
jQuery实现仿微软首页感应鼠标变化滑动窗口效果
2015/10/08 Javascript
JS快速实现移动端拼图游戏
2016/09/05 Javascript
HTML5+Canvas调用手机拍照功能实现图片上传(上)
2017/04/21 Javascript
Swiper自定义分页器使用详解
2017/12/28 Javascript
angularjs 的数据绑定实现原理
2018/07/02 Javascript
微信小程序 腾讯地图显示偏差问题解决
2019/07/27 Javascript
基于JavaScript或jQuery实现网站夜间/高亮模式
2020/05/30 jQuery
Vue+Openlayers自定义轨迹动画
2020/09/24 Javascript
python的文件操作方法汇总
2017/11/10 Python
Python模拟脉冲星伪信号频率实例代码
2018/01/03 Python
pandas.DataFrame.to_json按行转json的方法
2018/06/05 Python
Python异步操作MySQL示例【使用aiomysql】
2019/05/16 Python
python pandas 时间日期的处理实现
2019/07/30 Python
用Python自动清理电脑内重复文件,只要10行代码(自动脚本)
2021/01/09 Python
英国简约舒适女装品牌:Great Plains
2018/07/27 全球购物
趣天网日本站:Qoo10 JP
2019/09/18 全球购物
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
学生党员思想汇报范文
2014/01/09 职场文书
手工社团活动方案
2014/02/17 职场文书
环保建议书200字
2014/05/14 职场文书
关于爱国的标语
2014/06/24 职场文书
软件测试专业推荐信
2014/09/18 职场文书
党员个人查摆剖析材料
2014/10/16 职场文书
活动简报范文
2015/07/22 职场文书
MySQL基础(一)
2021/04/05 MySQL
css display table 自适应高度、宽度问题的解决
2021/05/07 HTML / CSS
HashMap实现保存两个key相同的数据
2021/06/30 Java/Android
SQL Server2019数据库备份与还原脚本,数据库可批量备份
2021/11/20 SQL Server
无线电知识基础入门篇
2022/02/18 无线电
mysql数据库隔离级别详解
2022/06/16 MySQL