函數意義:
先了解這個 http://wiki.ros.org/roscpp/Overview/Publishers%20and%20Subscribers ros的消息訂閱和釋出機制官方教程,最簡單的模闆如下:
//Publishing to a Topic
ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", );
std_msgs::String str;
str.data = "hello world";
pub.publish(str);
//check errors in pub
if (!pub)
{
...
}
ros::Publisher advertise(const std::string& topic, uint32_t **queue_size**, bool latch = false);
...
//Subscribing to a Topic
void callback(const std_msgs::StringConstPtr& str)
{
...
}
ros::Subscriber sub = nh.subscribe("my_topic", , callback);
關于std_msgs::StringConstPtr& str的了解
避免了複制,節省了時間,以下是元解釋。
**When messages are automatically generated into C++ code, there are several typedefs defined. One of them is ::Ptr, which is typedef-ed to be a boost::shared_ptr, and another is ::ConstPtr which is boost::shared_ptr
By passing a const pointer into the callback, we avoid doing a copy. While this might not make much difference for std_msgs::String, it can make a huge difference for sensor_msgs::PointCloud2.**
& 表示引用
ROS消息回調處理函數。它倆通常會出現在ROS的主循環中,程式需要不斷調用ros::spin() 或 ros::spinOnce(),兩者差別在于前者調用後不會再傳回,也就是你的主程式到這兒就不往下執行了,而後者在調用後還可以繼續執行之後的程式。
好,我們繼續,如果你的程式寫了相關的消息訂閱函數,那麼程式在執行過程中,除了主程式以外,ROS還會自動在背景按照你規定的格式,接受訂閱的消息,但是所接到的消息并不是立刻就被處理,而是必須要等到ros::spin()或ros::spinOnce()執行的時候才被調用,這就是消息回到函數的原理。
差別
就像上面說的,ros::spin() 在調用後不會再傳回,也就是你的主程式到這兒就不往下執行了,而 ros::spinOnce() 後者在調用後還可以繼續執行之後的程式。
其實看函數名也能了解個差不多,一個是一直調用;另一個是隻調用一次,如果還想再調用,就需要加上循環了。
這裡一定要記住,ros::spin()函數一般不會出現在循環中,因為程式執行到spin()後就不調用其他語句了,也就是說該循環沒有任何意義,還有就是spin()函數後面一定不能有其他語句(return 0 除外),有也是白搭,不會執行的。ros::spinOnce()的用法相對來說很靈活,但往往需要考慮調用消息的時機,調用頻率,以及消息池的大小,這些都要根據現實情況協調好,不然會造成資料丢包或者延遲的錯誤。
常見使用方法
這裡需要特别強調一下,如果大兄弟你的程式寫了相關的消息訂閱函數,那千萬千萬千萬不要忘了在相應位置加上ros::spin()或者ros::spinOnce()函數,不然你是永遠都得不到另一邊發出的資料或消息的,部落客血的教訓,萬望緊記。。。
publish client
#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", );
ros::Rate loop_rate();
int count = ;
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 ;
}
subscribe client:
#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", , chatterCallback);
/**
* ros::spin() 将會進入循環, 一直調用回調函數chatterCallback(),每次調用1000個資料。
* 當使用者輸入Ctrl+C或者ROS主程序關閉時退出,
*/
ros::spin();
return ;
}
ros::spinOnce()
對于ros::spinOnce()的使用,雖說比ros::spin()更自由,可以出現在程式的各個部位,但是需要注意的因素也更多。比如:
1 對于有些傳輸特别快的消息,尤其需要注意合理控制消息池大小和ros::spinOnce()執行頻率; 比如消息送達頻率為10Hz, ros::spinOnce()的調用頻率為5Hz,那麼消息池的大小就一定要大于2,才能保證資料不丢失,無延遲。
/接收端/
#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", , chatterCallback);
ros::Rate loop_rate();
while (ros::ok())
{
/*...TODO...*/
ros::spinOnce();
loop_rate.sleep();
}
return ;
}
ros::spinOnce()用法很靈活,也很廣泛,具體情況需要具體分析。但是對于使用者自定義的周期性的函數,最好和ros::spinOnce并列執行,不太建議放在回調函數中;
/*...TODO...*/
ros::Rate loop_rate();
while (ros::ok())
{
/*...TODO...*/
user_handle_events_timeout(...);
ros::spinOnce();
loop_rate.sleep();
}
Reference:https://www.cnblogs.com/liu-fa/p/5925381.html