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

来源:互联网 发布:淘宝卖三无产品犯法吗 编辑:程序博客网 时间:2024/05/29 17:36

既对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/)

-------------------------------------------------------------------------------------------
(如有不妥之处,恳请批评指正)
                                             
0 0
原创粉丝点击