Edited at

オンデマンドサブスクライブによるデータ通信量節約

More than 5 years have passed since last update.

ROSではpub/sub型のメッセージ通信を行うことで異なるノード間のデータ受け渡しを実現している。

基本的には以下の手順でデータが授受される。


  1. 送信側が送信可能であることをbroadcastする(pub->advertise)

  2. 受信側が送信側のデータを購読(sub->subscribe)

  3. 送信側がデータを送信(pub->publish)

  4. 受信側がデータを受信しコールバック関数が呼ばれる

基本的には何かのデータを使いたくなったらサブスクライブして、データが来たらコールバックで処理するという形でよい。

しかしながら、以下のような場合

img1.png

重い処理をオンデマンドにする、すなわち処理結果を使うノードがsubscribeしたときだけカメラ画像をサブスクライブし、自身がpublishするようにすれば、カメラ画像の取得と重い画像処理をする回数を必要最小限にすることができる。

このためには画像の重い画像処理ノードを以下のように書けばいい。

class ImageProc {

ros::NodeHandler _n;
ros::Publisher _pub;
ros::Subscriber _sub;
public:
ImageProc(){
_n.advertise("image_proc_result",10);
void callback(typeof(msg) msg){
// 重い処理 例:SIFT特徴点抽出
_pub.publish(result);
}

void checkSubscribers(){
if(_pub.getNumSubscribers() == 0) {
if(_sub) { // 誰も自身をサブスクライブしなかったら自身もサブスクライブを止めてコールバックが呼ばれないようにする
_sub.shutdown();
ROS_INFO("unsubscribe");
}
} else {
if (!_sub){
_sub = _n.subscribe("camera_image", 1, &ImageProc::callback, this);
ROS_INFO("subscribe");
}
}
}

int main(int argc, char *argv[]){
ros::init (argc, argv, "image_proc");
ImageProc imgproc;
ros::Rate r(10);

while(ros::ok()){
ros::spinOnce();
imgproc.checkSubscribers(); // ポーリング毎に自身のサブスクライバを確認
r.sleep();
}

return 0;
}

まあ、当たり前ですね。