Navigation Stack を理解する - 2.2 move_base: ソフトウェア構成をみる

# 目次
1. [導入](http://qiita.com/MoriKen/items/0b75ab291ab0d95c37c2)
2. move_base (ナビゲーション)
 3. [ROSで遊んでみる](http://qiita.com/MoriKen/items/8387b279e968368783f1)
 4. [ソフトウェア構成をみる](http://qiita.com/MoriKen/items/d5cd6208143d6c40caff)　← いまココ
3. amcl (自己位置推定)
 4. [ROSで遊んでみる](http://qiita.com/MoriKen/items/87be494f048ea03fdab8)
 4. [ソフトウェア構成をみる](http://qiita.com/MoriKen/items/26483e86fb556f0dc5ce)
 5. [原理をみる (準備編)](http://qiita.com/MoriKen/items/239f69df2921cc64bd62)
 6. [原理をみる (応用編)](http://qiita.com/MoriKen/items/dfb6eb168649873589f0)
4. gmapping (地図生成)
 1. [ROSで遊んでみる](http://qiita.com/MoriKen/items/74cbff9198f82f2b7ea8)
 2. [ソフトウェア構成をみる](http://qiita.com/MoriKen/items/65ac41abca9fdf6051be)
 3. [原理をみる(応用編)](http://qiita.com/MoriKen/items/0f2550a2adbdcd3da04e)
 4. 原理をみる(準備編 その1)
 5. 原理をみる(準備編 その2)

# はじめに
[Navigation Stack を理解する 2.1 move_base: ROSで遊んでみる]() の続きです．[move_base](http://wiki.ros.org/move_base) ソフトウェアの構成とメッセージのやりとりを覗いてみます．

- ROS Wiki の図中
![00_位置づけ1.png](https://qiita-image-store.s3.amazonaws.com/0/110138/70b024c4-d3eb-b273-f816-008c4869afdd.png)


- 導入部で示したパッケージの図中
![00_位置づけ2.png](https://qiita-image-store.s3.amazonaws.com/0/110138/eaadb799-d9a5-d041-03cd-251a7f9d5349.png)

# 環境
- OS: Ubuntu 14.04
- ROS: Indigo
- モデル：[Husky](http://wiki.ros.org/Robots/Husky)
- パッケージ：[husky_navigation](http://wiki.ros.org/husky_navigation)
- チュートリアル：[Husky Move Base Demo](http://wiki.ros.org/husky_navigation/Tutorials/Husky%20Move%20Base%20Demo)
![husky-grass](http://wiki.ros.org/Robots/Husky?action=AttachFile&do=get&target=husky-grass.png)

# rqt_graph をベースにソフトウェアの構成を見る
# 素のrqt_graph を見る
下記コマンドを実行するとメッセージのやりとりを含めたソフトウェア構成図が出てきます．

```
$ rqt_graph
```

![09.5_rqt_graph.png](https://qiita-image-store.s3.amazonaws.com/0/110138/06123816-dab0-0cad-52d5-513b0657a56d.png)

ドーンって感じです．初めて使った時，ド素人の私にはもうわけが分からんという状態でした．こういう構成図をパッと理解できる世のGeekには，本当に頭が上がらないです…

## 簡易版rqt_graph を見る
というわけで，ひとまず全体像を理解する上で重要そうな最小限の構成要素を，自分なりにピックアップして作図し直したものが下図です．ただし，本当は変換が必要だったり，正確にメッセージを追うと経路が複雑になってしまうような詳細部分は，意図的に省略しました．

![09_rqt_graph風.png](https://qiita-image-store.s3.amazonaws.com/0/110138/17e715d7-6e27-5b73-68f8-a00056060242.png)

まだ少しごちゃついていますが，少しだけすっきりしたかな，というところです．各ノードの役割は図中に記載の通りです．目標姿勢が入力されたら，move_base を起点に反時計回りにループが形成されているようなイメージです．

目標姿勢は`/move_base_simple/goal`というトピックをsubscribe することで設定され，そこから内部的には`MoveBaseAction` という[actionlib](http://wiki.ros.org/actionlib) が走ります．actionlib は非同期で実行されるので，ナビゲーションの途中状態においても，move_base は他の指令を受け取ることができます．例えば，まだ目標に到達していない状態でも，目標を上書き更新することが可能です．複数の目標を順番に指定して経路を生成するケースでは，好きなタイミングで目標を切り替えられる点で，使い勝手が良い仕様と言えます．

## /odom フレーム？ /odom トピック？
ここで，念のため注意点です．オドメトリの原点を指すフレーム名と，オドメトリによる現時刻における積分値が格納されるトピック名が，まったく同じ`/odom` であることです．いや，分かっている人からしたら当たり前なことなのかもしれませんが，少なくとも素人でかつ頭の回転も早くない小生にとっては，初見で混乱したことを覚えております汗．
その上，よりにもよって片方は「オドメトリの原点」，もう片方は「オドメトリの先」を意味する情報であり，同一の名称を持つにも関わらず互いに反対の意味を持っていることで，（大変不甲斐ないことですが）私の脳内での混乱は激しさを増すばかりでした汗．

という経緯もありまして，敢えて図中の「トピック」と「フレーム」を異なる書式にすることで，異なる実体を指すことを強調しています．これにより，初見での混乱を少しでも軽減できればと思っています．

![10_rqt_graph風_odom.png](https://qiita-image-store.s3.amazonaws.com/0/110138/701af47c-b7ef-27e7-33ec-4e777a29a1c1.png)

# 経路探索
ここまで，move_base と他のノードとのやり取りについてみました．その中を覗くと，更に細分化された機能に分解されます．ROS Wikiの図のうち，下図の4つの赤い円で囲ったところを見ていきます．
![12_move_base_planners_open.png](https://qiita-image-store.s3.amazonaws.com/0/110138/92f83c5a-590f-b42b-01d2-73108603b0c1.png)

## コストマップと経路計画
大別すると，コストマップを管理する機能(costmap)と，経路計画(planner)を行う機能です．前者は，センサ情報をもとに検出された障害物に近いほど値が大きくなるコスト情報で，後者はそのコスト情報を使って障害物を回避しながら経路計画を行います．

## 大域的探索と局所的探索
かつ，それぞれが大域(global)と局所(local)について実行する機能を備えています．大域的な処理については，事前に得られた地図などの情報を元に，予め壁や障害物があるところにコストを割り振り，経路を決定するものです．局所的な処理については，現在得られたセンサ情報を元に，事前知識では存在しない障害物（歩行中の人など）を検知し，リアルタイムに経路を補正する役割を担っています．

## 大域と局所の比較
上述した情報がどのように異なるのか，rvizのキャプチャを含む図で確認してみます．まず，rvizの表示項目のうち，`Global Costmap`, `Global Costmap`, `Global Costmap`, `Global Costmap`が該当するチェック項目です．見たい項目に応じて，チェックの有無を切り替えながら挙動を確認してみましょう．

![12.0_rviz_planners_global_local.png](https://qiita-image-store.s3.amazonaws.com/0/110138/39ff667f-aca4-f216-05d0-cd9eabd878b2.png)

下図がまとめです．左が大域的探索の場合，右が局所的探索の場合です．

![12_move_base_planners_global_local.png](https://qiita-image-store.s3.amazonaws.com/0/110138/bc0c0383-04da-339e-4030-4679dd7169b7.png)

画像内で青く色づいているところがコストマップです．左側ではこれまでの移動によって蓄積された情報に対してより広い範囲で，右側では現在センサ(Husky のモデルではLRF)で得られた情報を元にコストマップが生成されています．

コストマップの内訳は，ざっくり下記のとおりです．

- 黄色：障害物
- シアン：ロボットの領域から逆算して，侵入したら障害物と衝突する領域
- 青：ぶつからないかもしれないけど，すれすれを通るのも怖いのでできれば避けたい領域

シアンの領域については，/footprint という情報を元に算出します．これは，ロボットを外側から囲った領域を地面に投影したようなものです．事前に設定しておくものですが，その辺りの定義の仕方は[costmap_2d](http://wiki.ros.org/costmap_2d) に譲ります．

さらに，特に青の領域は，障害物から離れる毎に徐々に小さくなるような関数となっているようです．これの詳細も，[costmap_2d](http://wiki.ros.org/costmap_2d) に記載されています．

そして，経路計画自体もrviz 上で確認できます．大域的経路計画は`NavfnRos`，局所的経路計画は`DWSPlannerROS`で行われています．それぞれの経路情報は，`/move_base/NavfnRos/plan`，`/move_base/DWAPlannerROS/local_plan`に格納されています．図で言うと，ロボットの下に見える緑の線が大域的経路，赤い線が局所的経路です．緑の線に追従するように赤い線が逐次的に更新されるようなイメージです．ただし，大域的経路の周辺に障害物が現れたら，赤い線は一時的に緑の線からは遠のくことになりますが，障害物を回避した後は再び緑の線を追従するような挙動を示します．

これらの探索アルゴリズムについての直感的な説明は，[原, "ROSの活用による屋外の歩行者空間に適応した自律移動ロボットの開発", ロボット工学セミナー, 2015.](http://www.slideshare.net/hara-y/ros-slam-navigation-rsj-seminar) に分かりやすく記載されています．

DWAに関するサンプルと元論文の解説まで含めた詳細な情報は，[Atsushi(ブログプロフィールより), "Dynamic Window ApproachのMATLAB サンプルプログラム", MyEnigma, 2014.](http://myenigma.hatenablog.com/entry/20140624/1403618922)に記載されています．このブログには他のロボット関連の技術に関するサンプルが豊富に掲載されており，非常に参考になります．

# 積み状態からの回復
さて，まだ下図の赤い楕円で囲った[rotate_recovery](http://wiki.ros.org/rotate_recovery) が残っています．これについて見てみます．
![13_move_base_recovery_open.png](https://qiita-image-store.s3.amazonaws.com/0/110138/5d8f4794-5f83-d752-7104-7cab83694cfc.png)

大域的探索においては少なくても事前情報の範囲で障害物にぶつからないように経路探索をすることは前述のとおりです．しかし，局所的探索においては，障害物の出現位置によっては，当初進めると思っていたのにそれ以上進めなくなってしまう状況が起こりえます．通せんぼ状態です．

そういう状態から，頑張って抜けだそうとするための仕組みが，[rotate_recovery](http://wiki.ros.org/rotate_recovery) です．その場旋回が可能なディファレンシャルドライブ型，あるいはオムニドライブ型のロボットであることが前提です．

コストマップをクリアしたり，その場を一周してどこか通り道がないかを探します．コストマップをクリアしているのは，通せんぼをしている領域を少なくすることで，隙間を縫うような経路を見つけられるのではないか，という発想があると解釈できます．

![14.0_rotate_recovery_cost_clear.png](https://qiita-image-store.s3.amazonaws.com/0/110138/7eeaa0d8-7944-5b75-fc35-1e3d23300dcd.png)

上図は極端に書いたので気づくと思われますが，当然衝突のリスクが大きくなります．動かなくなるよりは，スレスレでも前に進めた方がずっとましということです．

さて，ROS Wikiの図を参考にすると，流れは次のとおりです．
![14_rotate_recovery.png](https://qiita-image-store.s3.amazonaws.com/0/110138/6dbccf9d-c93a-fd9c-d33d-1ede027e9d6e.png)

1. できれば避けたいと思っていたコストマップ領域を少し狭めて，その場で局所的探索を行い，隙間を通れるところが無いか確認する
2. 1. で失敗したら，一周回りなが局所的探索を行い，隙間を通れるところが無いか確認する
3. 2. で失敗したら，1. よりももっとコストマップ領域を狭めて，その場で局所的探索を行い，隙間を通れるところが無いか確認する
2. 3. で失敗したら，2. と同様の局所的探索を行う
3. 4. で失敗したら，潔く諦めます

上記フローのうち 1. ～4. のどこかで隙間を見つけられれば，再び元のナビゲーションに復帰します．

なお，`rotate_recovery` はあくまでリカバリ用プラグインの一つで，回復行動を自分で定義してプラグイン化すれば，任意の構成のロボットでも適用可能です．

# オドメトリの問題点
さて，ここまでで`move_base` については，何となく分かった気になれたと思います．
冒頭でも記述したとおり，ここでのチュートリアルでは自己位置推定がオドメトリのみです．

![05_初期位置.png](https://qiita-image-store.s3.amazonaws.com/0/110138/0e9bfbe3-8061-405c-c26b-191f2a87b0c4.png)
※/world という記述は，私が便宜的にワールド座標系の原点を表すために用意したもので，実際にrviz等で確認されるものではありません．

つまり，ワールド座標系の原点と，オドメトリの原点がずっと同一であることを想定しています．
![06_オドメトリのみ.png](https://qiita-image-store.s3.amazonaws.com/0/110138/f35f03da-a3b5-f959-363d-c9e1a26f4aed.png)

しかし，実際には様々な外乱の蓄積によって，ワールド座標系とオドメトリの原点はずれていくことになります．
![07_現実はずれている.png](https://qiita-image-store.s3.amazonaws.com/0/110138/40a3eada-b7ed-a304-3f74-3e7cdeaea151.png)

そこで，センサ情報と地図情報のマッチングによって，ワールド座標系の原点とオドメトリの原点との間のずれを補正しようという発想に至ります．そのためのパッケージが[amcl](http://wiki.ros.org/amcl) となります．本パッケージが何を行っているのか，次項以降で見てみることとします．

# おわりに
以上が，当方が理解している範囲での，move_baseに関するメモです．私が初めてこれを使って，rqt_graphを打った時に大群に出くわしたような感覚で面を食らってしまったのを覚えており，もう少しシンプルにした記事があったらいいのにな，という思いを元と書き起こしました．

原理的な記述は他の文献に預けたので，次節ではamclで自己位置推定を行う部分の解説をします．

Next: [3.1 amcl: ROSで遊んでみる](http://qiita.com/MoriKen/items/87be494f048ea03fdab8)
Prev: [2.1 move_base: ROSで遊んでみる](http://qiita.com/MoriKen/items/8387b279e968368783f1)

# 参考文献
1. [S Thrun, et al., "Probabilistic Robotics", the MIT Press, 2005.](http://www.probabilistic-robotics.org/)
1. [原, "ROSの活用による屋外の歩行者空間に適応した自律移動ロボットの開発", ロボット工学セミナー, 2015.](http://www.slideshare.net/hara-y/ros-slam-navigation-rsj-seminar)
1. [Atsushi(ブログプロフィールより), "Dynamic Window ApproachのMATLAB サンプルプログラム", MyEnigma, 2014.](http://myenigma.hatenablog.com/entry/20140624/1403618922)
2. [ROS Wiki.](http://wiki.ros.org)
3. ["ros-planning/navigation", github.](https://github.com/ros-planning/navigation)
3. ["husky_navigation", github.](http://wiki.ros.org/husky_navigation/)