ROSの奇妙な通信遅延

こんにちは，KIYです．ロボットの研究をしています．
私は普段あまりROSを使っていないくて素人なんですが，ROS Advent Calendarに空きがあると聞いたので，枯れ木も山のにぎわいと思って参加することにしました．


# 三行要約
・ROS(indigo, kinetic)ノード間通信で，あるデータサイズと周期で遅延が発生する
・誰か対処方法知っていたら教えてください
・ROS2では同じ現象は起きないようでした

__(12/14 23:20追記) 対処法をご指摘頂いて解決しました．コメント欄を参照してください__

# 本文
ここから本文です．

## 背景
ROSの通信遅延については色々と調べられていて，私の知る限りでも

- yonekenさんが[nodeとかnodeletとかの通信遅延を評価されていたり](https://github.com/yoneken/measure_message_passing)
- Maruyamaさんたちが[ROS2を評価した論文](https://dl.acm.org/citation.cfm?id=2968502)を書かれたり
 
というのがあります．他にも多分色々とあるのですが，今回の問題については私が以前調べた限りでは見つからなかったのと，
ROSに詳しい[同僚](https://www.slideshare.net/hara-y/ros-nav-rsj-seminar)に聞いてみたのですが，知らないそうだったので，ここに書いてみます．常識だったらすみません．

## 最初の発見
あるプロジェクトでヒューマノイドロボットを動かしていた時に，動きが妙にカクカクするという問題がありました．その時は，joint_state_publisherを使って数百Hzで関節角の目標値を送っていたと記憶しています．共同研究者の方から，ROSからのデータ配信が遅れているからではないかと指摘されまして，データを集めてできたのが下のグラフです．

![plot_data.png](https://qiita-image-store.s3.amazonaws.com/0/22967/cd85195a-6285-3b86-2a2e-9a30a0d591a6.png)

これはSubscriberのコールバックにメッセージが届いた時刻を記録したものです．
データのサイズが小さい時(一部の関節角データのみ送っていた時)は特に問題なかったのですが，全身の関節角を送ってデータのサイズを大きくすると，メッセージがいくつもまとめて受信されるということが分かりました．これがカクカクの原因だったわけです．

この時私は，ROSはデータのサイズが大きくなると，数十msの遅延が発生するんだ，いけてないなー，と思っていました．しかし，後で気づくのですが，問題はそんなに単純では無かったのです．

## さらなる発見

上記の経験から，私は低遅延のプロセス間通信も必要だよね，と考えて，ROSライクなAPIを持つ共有メモリベースの独自の低遅延プロセス間通信を作って使っていました．今年それについて[論文](http://furo.org/irie/papers/rsj2017_irie.pdf)を書いたのですが，その時に改めてROSの通信遅延を測定したところ，

- 誤: データが大きくなると遅延が発生する
- 正: ある範囲のデータサイズ(数KB～数十KB)とデータ送信周期(数十Hz以上？)の場合に目立った遅延が発生する

ということが分かりました．どういうプロセスで発生しているのか等，私は把握できておりません．どなたか原因や対処方法などご存知でしたら教えていただけるとうれしいです．
[Maruyamaさんたちの論文](https://dl.acm.org/citation.cfm?id=2968502)では色々なデータサイズで実験しているのですが，通信周期が10Hzということで，この現象は発生していないのではと思います．

## 実験
というわけで今回改めて測定してみましたのでその結果を載せます．
せっかくROS2が正式リリースされたとのことなので，ROS2でも測ってみました．
測定条件は下記のとおりです．

- データ送信周期100HzでLaserScan型を送る
- 送信時にタイムスタンプをつけて，受信時の時刻と比較する
- LaserScan::rangesの数を変えて，データサイズを変えてみる
- 200回送信して平均，最大，標準偏差を記録
- ROS1はkinetic, ROS2はardent，いずれもaptでインストール
- PC環境はCore-i7 6950X, RAM128GB，Ubuntu16.04 x64

というわけで結果とグラフです．

### Kinetic
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/9873ff6d-1056-c81d-52e3-acda96136d95.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/4a6e6eaf-7c1d-2c49-f7c7-32c3a660dcc3.png)

1kと10kの場合に，遅延とその分散が大きいことがわかります．これは例のまとまってデータが受信されるという現象が発生しているためです．

### Ardent
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/6a85a27f-ef08-11c6-f12c-05354c052e2d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/29facf27-f1fc-abbb-d72f-1040a2b7753c.png)

一方，Ardentでは，同じ設定の下では奇妙な通信遅延は発生していないことがわかります．
ただ，データサイズが1mバイトになると，100Hzでの送信は間に合っていないようで，200個メッセージを送信したのですが，14個は受信されませんでした．

なお，これがROS2の最高のパフォーマンスとは限らないということはご承知おきいただきたいと思います．
私はROS2は今回初めて触ってみたので，DDS側で共有メモリトランスポートが使われているのかどうかなど，どう動いているのか把握できていません．
設定や使うDDS実装によっても結果は変わるのではないかと思います．また機会があれば詳しく調べてみたいと思います．


### Kinetic (10Hz)
ちなみに10Hzの場合は下記のように特に異変はなさそうです．(軸のスケールが10分の1なのに注意)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/2ddd1ad0-25ee-4408-0252-16d24a55d5e9.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/22967/09487482-fc4b-e81f-fefe-c031240248cb.png)


## まとめ
ROS1で，データサイズが数キロバイトの場合に奇妙な通信遅延が発生することがあることを紹介しました．
ROS2では同じ現象は発生せず，解決されているようです．ROS2の正式リリースをお慶び申し上げ，今後のさらなる発展を祈念しまして，筆を置きたいと思います．
拙い文章をお読みくださってありがとうございました．