ROS學習之 cpp訊息釋出者和訊息訂閱者
阿新 • • 發佈:2019-01-28
wiki連結: http://wiki.ros.org/roscpp/Overview/Publishers%20and%20Subscribers
ros::NodeHandle,ros::NodeHandle::advertise() API:
http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::Publisher API:
http://docs.ros.org/api/roscpp/html/classros_1_1Publisher.html
建立一個控制代碼來向話題釋出訊息,使用ros::NodeHandle類,參見: http://wiki.ros.org/roscpp/Overview/NodeHandles
NodeHandle::advertise()方法被用來建立一個ros::Publisher物件,該物件用於在話題上釋出訊息。
ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::String str;
str.data = "hello world";
pub.publish(str);
當一個節點內部存在對於同一個話題的訊息釋出者和訂閱者時,roscpp會跳過序列化和去序列化的過程(節省了處理過程和延遲)。
該方法只適用於以共享指標釋出的訊息
ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::StringPtr str(new std_msgs::String); //訊息指標
str->data = "hello world";
pub.publish(str);
advertise()簡單版的原型:
template<class M>
ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);
引數說明: M,必須,這是一個模版引數,用於指定釋出話題的具體訊息的型別
topic,必須,釋出話題的名稱
queue_size,必須,訊息佇列的長度。如果釋出訊息的速度超過roscpp可以釋出訊息的速度,roscpp將丟棄最開始的訊息
latch,可選,使能連線的latching(門閂,彈簧鎖)。當一個連線被latched,最後被髮布的訊息將被儲存,自動釋出給以後再訂閱該話題的訂閱者。
ros::Publisher 是內部引用的,也就是可以快速複製,而無需建立新的ros::Publisher.當所有ros::Publisher副本被銷燬時,話題將被關閉。
幾個例外:
1、ros::shutdown()呼叫,它將關閉所有publishers
2、ros::Publisher::shutdown()呼叫,將關閉這一個話題,如果有的話。
3、對同一話題,同一訊息的多次呼叫NodeHandle::advertise()將產生對該話題的很多Publisher,它們被視為相互的副本。
ros::Publisher實現了==,!=,和<操作符,也能用std::map,和std::set等
可以使用ros::Publisher::getTopic()函式獲取一個topic話題
publish()自己本身很快,它1.將訊息序列化進一個buffer;2.將buffer壓入一個佇列以備後續處理。
這個佇列之後被roscpp的內部執行緒處理,它將此佇列送入每個連線此話題的subscriber,這一步中的佇列長度取決於advertise()呼叫queue_size引數.
如果佇列長度溢位,最老的訊息將在新訊息加入佇列之前被丟棄。
注意:還有一個OS級的佇列在傳輸層,比如TCP/UDP傳送buffer.
ros::NodeHandle,ros::NodeHandle::subscribe() API:
http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::Subscriber API:
http://docs.ros.org/api/roscpp/html/classros_1_1Subscriber.html
建立一個控制代碼來向話題訂閱訊息,使用ros::NodeHandle類,參見: http://wiki.ros.org/roscpp/Overview/NodeHandles
一個簡單的訂閱的全域性函式:
void callback(const std_msgs::StringConstPtr& str)
{
...
}
...
ros::Subscriber sub = nh.subscribe("my_topic", 1, callback);
template<class M>
ros::Subscriber subscribe(const std::string& topic, uint32_t queue_size, <callback, which may involve multiple arguments>, const ros::TransportHints& transport_hints = ros::TransportHints());
引數說明:M,不必要,模版引數,說明訊息的型別。對於subscribe()函式,不必顯式定義訊息的型別,編譯器可以從回撥函式的引數中來推測出訊息的型別。
topic,訂閱的話題
queue_size,roscpp使用該引數將此長度的訊息佇列傳遞給回撥函式。
<callback>,訊息處理回撥函式
transport_hints,對roscpp傳輸層的具體指定
void callback(const boost::shared_ptr<Message const>&);
一般函式的使用最為簡單。
例子如上。
2)類成員方法
類成員方法的使用也很簡單,在呼叫時要加入類物件的引數
void Foo::callback(const std_msgs::StringConstPtr& message)
{
}
...
Foo foo_object;
ros::Subscriber sub = nh.subscribe("my_topic", 1, &Foo::callback, &foo_object);
3)仿函式物件(一個類的使用看上去像一個函式,包括 boost::bind)
一個仿函式物件是一個定義了operator()函式的類。
class Foo
{
public:
void operator()(const std_msgs::StringConstPtr& message)
{
}
};
傳遞給subscribe()函式的仿函式必須copyable,使用下述語法呼叫:
ros::Subscriber sub = nh.subscribe<std_msgs::String>("my_topic", 1, Foo());
注意:使用仿函式時,必須顯式地宣告訊息型別模版引數,因為在此種情況下,編譯器不會推測出訊息型別。
MessageEvent API: http://docs.ros.org/api/roscpp_traits/html/classros_1_1MessageEvent.html
MessageEvent類允許從一個訂閱回撥函式中提取訊息的元資料資訊。
使用語法如下:
void callback(const ros::MessageEvent<std_msgs::String const>& event)
{
const std::string& publisher_name = event.getPublisherName(); //一些關於此訊息事件的元資料資訊
const ros::M_string& header = event.getConnectionHeader();
ros::Time receipt_time = event.getReceiptTime();
const std_msgs::StringConstPtr& msg = event.getMessage(); //從訊息事件中獲取訊息,然後可以進行相應處理
}
一、釋出一個話題
其它相關連結:ros::NodeHandle,ros::NodeHandle::advertise() API:
http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::Publisher API:
http://docs.ros.org/api/roscpp/html/classros_1_1Publisher.html
建立一個控制代碼來向話題釋出訊息,使用ros::NodeHandle類,參見: http://wiki.ros.org/roscpp/Overview/NodeHandles
NodeHandle::advertise()方法被用來建立一個ros::Publisher物件,該物件用於在話題上釋出訊息。
ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::String str;
str.data = "hello world";
pub.publish(str);
1、內部執行緒釋出
該方法只適用於以共享指標釋出的訊息
ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::StringPtr str(new std_msgs::String); //訊息指標
str->data = "hello world";
pub.publish(str);
2、釋出訊息可選項
template<class M>
ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);
引數說明: M,必須,這是一個模版引數,用於指定釋出話題的具體訊息的型別
topic,必須,釋出話題的名稱
queue_size,必須,訊息佇列的長度。如果釋出訊息的速度超過roscpp可以釋出訊息的速度,roscpp將丟棄最開始的訊息
latch,可選,使能連線的latching(門閂,彈簧鎖)。當一個連線被latched,最後被髮布的訊息將被儲存,自動釋出給以後再訂閱該話題的訂閱者。
3、釋出者控制代碼的其它操作
幾個例外:
1、ros::shutdown()呼叫,它將關閉所有publishers
2、ros::Publisher::shutdown()呼叫,將關閉這一個話題,如果有的話。
3、對同一話題,同一訊息的多次呼叫NodeHandle::advertise()將產生對該話題的很多Publisher,它們被視為相互的副本。
ros::Publisher實現了==,!=,和<操作符,也能用std::map,和std::set等
可以使用ros::Publisher::getTopic()函式獲取一個topic話題
4、publish()行為和訊息佇列
roscpp中的publish()是非同步的,只有當話題有訂閱者時才會工作(釋出訊息)。publish()自己本身很快,它1.將訊息序列化進一個buffer;2.將buffer壓入一個佇列以備後續處理。
這個佇列之後被roscpp的內部執行緒處理,它將此佇列送入每個連線此話題的subscriber,這一步中的佇列長度取決於advertise()呼叫queue_size引數.
如果佇列長度溢位,最老的訊息將在新訊息加入佇列之前被丟棄。
注意:還有一個OS級的佇列在傳輸層,比如TCP/UDP傳送buffer.
二、訂閱一個話題
其它相關連結:ros::NodeHandle,ros::NodeHandle::subscribe() API:
http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::Subscriber API:
http://docs.ros.org/api/roscpp/html/classros_1_1Subscriber.html
建立一個控制代碼來向話題訂閱訊息,使用ros::NodeHandle類,參見: http://wiki.ros.org/roscpp/Overview/NodeHandles
一個簡單的訂閱的全域性函式:
void callback(const std_msgs::StringConstPtr& str)
{
...
}
...
ros::Subscriber sub = nh.subscribe("my_topic", 1, callback);
1、對訂閱者的操作
一個簡單的ros::NodeHandle::subscribe()函式的原型如下:template<class M>
ros::Subscriber subscribe(const std::string& topic, uint32_t queue_size, <callback, which may involve multiple arguments>, const ros::TransportHints& transport_hints = ros::TransportHints());
引數說明:M,不必要,模版引數,說明訊息的型別。對於subscribe()函式,不必顯式定義訊息的型別,編譯器可以從回撥函式的引數中來推測出訊息的型別。
topic,訂閱的話題
queue_size,roscpp使用該引數將此長度的訊息佇列傳遞給回撥函式。
<callback>,訊息處理回撥函式
transport_hints,對roscpp傳輸層的具體指定
2、回撥函式原型
一個回撥函式的原型如下:void callback(const boost::shared_ptr<Message const>&);
3、回撥函式的型別
1)一般函式一般函式的使用最為簡單。
例子如上。
2)類成員方法
類成員方法的使用也很簡單,在呼叫時要加入類物件的引數
void Foo::callback(const std_msgs::StringConstPtr& message)
{
}
...
Foo foo_object;
ros::Subscriber sub = nh.subscribe("my_topic", 1, &Foo::callback, &foo_object);
3)仿函式物件(一個類的使用看上去像一個函式,包括 boost::bind)
一個仿函式物件是一個定義了operator()函式的類。
class Foo
{
public:
void operator()(const std_msgs::StringConstPtr& message)
{
}
};
傳遞給subscribe()函式的仿函式必須copyable,使用下述語法呼叫:
ros::Subscriber sub = nh.subscribe<std_msgs::String>("my_topic", 1, Foo());
注意:使用仿函式時,必須顯式地宣告訊息型別模版引數,因為在此種情況下,編譯器不會推測出訊息型別。
4、訊息事件類[ROS 1.1+]
MessageEvent API: http://docs.ros.org/api/roscpp_traits/html/classros_1_1MessageEvent.html
MessageEvent類允許從一個訂閱回撥函式中提取訊息的元資料資訊。
使用語法如下:
void callback(const ros::MessageEvent<std_msgs::String const>& event)
{
const std::string& publisher_name = event.getPublisherName(); //一些關於此訊息事件的元資料資訊
const ros::M_string& header = event.getConnectionHeader();
ros::Time receipt_time = event.getReceiptTime();
const std_msgs::StringConstPtr& msg = event.getMessage(); //從訊息事件中獲取訊息,然後可以進行相應處理
}