ROS 自定义消息发布器和订阅器测试 +代码详解(入门级)

既对ros tutorial 上的例子有了一定的了解之后,今天对发布器和订阅器代码(http://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29)进行了研究,同时稍作改动进行了验证

发布器-------------------------------------------------------------------------------------------------------------
<pre name="code" class="cpp">#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Int16.h"//因为后面我要用到整形的msg,此处要加上Int的头文件,不加后面会报错
#include <sstream>
int main (int argc,char **argv)
{
   ros::init(argc,argv,"input");//初始化ROS, 是确切说明节点名字的地方, 节点的名字必须唯一, 
                                //它允许ROS通过命令行重新命名
   ros::NodeHandlen;//创建了该节点的一个句柄 

   ros::Publisherinput_pub = n.advertise<std_msgs::String>("chatter1",1000);
   ros::Publisherinput_pub = n.advertise<std_msgs::String>("chatter2",1000);
        /*尖括号里为发布的数据类型(调试的时候第一个就忘了改), 即消息Message ,我再这里想要在一个节点(node)上发布两个话题(topic)
        圆括号中”chatter1”&”chatter2”为发布的话题的名称, 即Topic也可以写成ros::Publisher chatter_pub; chatter_pub= n.advertise<...>...       (引自ROS 代码解析)*/
   ros::Rate  loop_rate(10);   
       /*一个ros::Rate对象允许user制定循环的频率它将会记录从上次调用Rate::sleep()到现在为止的时间, 并且休眠正确的时
       intcount = 0; 我的代码里没有用到计数,值得注意的是源代码的count 变量一定程度上反应了代码的执行过程(通过观察输出结果可以明白)*/
   int a b,c;
   while (ros::ok())//默认情况下,roscpp将会安装一个SIGINT监听,
                   //它使当Ctrl-C按下时,ros::ok()将会返回 0
{  
     std_msgs::Int16msg1;
     std_msgs::Stringmsg2; //此处定义msg1 和msg2,注意类型不一致
     msg2.data="hello!I am Baymax!";
     std::cin>>a>>b;  //获取键盘的输入值,经过我的验证,如果不输入数据,程序会在这里等待
     c=a+b;
     msg1.data=c;
//    ROS_INFO("%s", msg.data.c_str());  此处可以百度c_str的含义做更深入了解
     ROS_INFO("%s", msg2.data.c_str()); //输出 msg2的信息
     input_pub.publish(msg1);
     input_pub.publish(msg2); //发布信息
     ros::spinOnce();  // 可以查询spinOnce做进一步了解,此处为调用一次回调函数,关于回调函数可以从订阅节点处做直观了解
     loop_rate.sleep(); //休眠一下, 使程序满足前面所设置的 10Hz的要求
  }
  return 0;
}
订阅器--------------------------------------------------------------------------
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Int16.h"//因为后面我要用到整形的msg,此处要加上Int的头文件,不加后面会报错
void chatterCb1(const std_msgs::Int16::ConstPtr& msg1) // 此处我设定了两个回调函数
{   ROS_INFO("I heard you said answer is : [%s]", msg1->data);  } 
void chatterCb2(const std_msgs::String::ConstPtr& msg2)
{   ROS_INFO("I heard: [%s]", msg->data.c_str());  } 
int main(int argc, char **argv)
{
   ros::init(argc, argv, "output");// 初始化节点(node)
   ros::NodeHandle n;
   ros::Subscriber sub1 = n.subscribe("chatter1", 1000, chatterCb1);
   ros::Subscriber sub2 = n.subscribe("chatter2", 1000, chatterCb2); //订阅节点,触发回调
   ros::spin();
   return 0;
}

1.ros::spinOnce() 和ros::spin()的区别

ROS 监视器和你订阅的topic链接,消息到达时,他会把消息加入到队列中,但不会立即处理消息。在读到ros::spin()之后ros才开始执行回调函数。而spinOnce 是指调用一次回调函数,spin则不停的调用回调函数,直到node被关闭的时候才会停止。

2.定义特定的时间间隔来处理回调函数

问题提出:如果你的信息的到达速度是100HZ,你每5HZ调用一次spinonce()函数,如果你的订阅器缓冲区大小为1,那么你丢掉了95/100的信息。因此协调好订阅发布的频率是非常重要的。

使用定时器是一种很好的办法,在这里介绍一种经常使用的Ros::rate工具。
ros::Rate r(100);
while (ros::ok())
{
  libusb_handle_events_timeout(...); // Handle USB events
  ros::spinOnce();                   // Handle ROS events
  r.sleep();
}
这里保证了while()大循环的频率是100HZ,这是通过ros::Rate 和 r.sleep函数配对实现的
在其他的工程中,可能main函数被包括在了其他GUI界面的程序里面,如果仍然希望做到上面的设定频率,只需要按照他的格式,找到一个地方写ros::spinOnce()函数就可以了。
void timerCb(int value) { ros::spinOnce(); }
glutTimerFunc(10, timerCb, 0);
glutMainLoop(); // Never returns

(出处:http://answers.ros.org/question/11887/significance-of-rosspinonce/)

-------------------------------------------------------------------------------------------
(如有不妥之处,恳请批评指正)

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值