ROS Navigation Stack について1

以下,ROS Navigation Stackに関して調べたことをまとめておきます.
マッピングを実装して使えるようになるには,何らかのセンシング手段が必要で,まだちょっとハードルが高そうなので,ひとまずオドメトリのみを用いたロボットの自立制御ができるようにします.

move_base周辺のシステム構成図

f:id:rkoichi2001:20170208075021p:plain
引用:http://wiki.ros.org/move_base


上記ダイアグラムは本家から持ってきたものですが,今回深くいじるところは"move_base"と書かれている正方形のボックス内の要素になります.move_baseというコンポーネント自体は,各要素をバインドしているコンポーネントになってまして,細かい挙動の実装を持っているというよりは,必要に応じてそれぞれのコンポーネントAPIをコールしてあげるようなつくりになってます.で,上記の図の登場人物をざっくり説明しますと....

move_baseとつながる部品群

amcl : モンテカルロローカリゼーション

 自己位置推定用の部品です.オドメトリ(超ざっくりいうと車輪の回転数の積分)だけだと当然ながら誤差が少しずつ大きくなってくるので,自分以外の情報を使って実世界に対する自分の相対位置を更新する必要があるのですが,この部品がそれをやってます.ROSのチュートリアルを見る限り,現状2Dレーザスキャナのみの対応になるみたいです.事前に作った地図に対して,レーザスキャナで走行中にとった周囲環境の形状をマッチングしながら自分の位置を推定します.が,今回は使いません.まだ未完成なので...

sensor transform : センサとロボットの座標変換

 センサはふつう車両の基準位置からずれているとおもいますが,この部品が座標変換してくれます.つまり,センサでとった値(センサの座標系からみた値)をロボット基準(ロボットの座標系から見た値)に引き戻してくれます.今回はオドメトリ情報しか使わないので,使いません.

odometry source : オドメトリ生成

 超ざっくりいうと,車輪の回転数の積分をしながら,ロボットがどのくらいすすんだか,どこに行ったかを推定します.今回必須です.

base controller : ロボットの制御調整コントローラ

 move_baseから出てくる情報は,「1m/sですすめ」とか「1deg/sでまわれ」とかっていう割とハイレベルな指令ですが,当然この指令をもとにモータを駆動させないといけません.ここではArduinoで作ったモータコントローラを使います.

map server : 走行環境に関する地図情報保持部品

 amclの説明で少し触れましたが,マッチングするもととなる地図情報です.ただ,地図が大きくなってくると必要な部分だけ持ってこないと大きすぎるので,map serverは現状走っていると思われる周辺の地図を返してくれます.今回は使いません.

sensor sources : センサー

 そのまんま,センサーです.今回は使いません.

ということで難しい要素はすべて排除して,「なにもない平面世界でロボットを意図した通りに動かす.ただし,オドメトリの誤差は無視する」ということを今週の目標とします.
簡略化したシステム図は下記のようになります.すっきりしましたね(笑)

move_base周辺のシステム構成図(今週実験で使うシステム構成図)

f:id:rkoichi2001:20170208081409p:plain

move_baseへの入力/出力情報

"odom" nav_msgs/Odometry : 文字通りオドメトリ情報です.2D平面上の座標(x, y, θ)です.この情報自体は,自作エンコーダとヨーレートセンサーの値を積分して求めます.
"move_base_simple/goal" geometry_msgs/PoseStamped : 最終目的座標(xgoal, ygoal, θgoal)です.
"cmd_vel" geometry_msgs/Twist : 駆動部に対する制御指令です.Twistというのは,つまるところ(vx, vy, vθ)です.

 ざっくり入出力の説明をすると,move_baseに対してはユーザリクエストとして言ってほしい場所の座標を指定します.そうすると,あとは move_base がうまいことやってくれます(笑).というのはざっくりすぎるのでちょっとフローをまとめて見ました.下記の図に記されているように,ユーザが目的地点の(x, y, θ)を指定すると,グローバル座標系でのパスが生成されます.ここからは,赤矢印のループに従ってある意味でフィードバックループが回り,目的地まで到達することになります.


f:id:rkoichi2001:20170210074532p:plain

move_baseによってバインドされている構成要素とその役割

global_planner : 与えられた地図上の一点に対して,そこへ移動するための経路を生成します.

 ここで生成される経路はglobal_costmapに基づいて生成されるまっぷなので,動的な障害物(人・自動車とか)は気にしません.

local_planner : global_plannnerが静的な地図に基づいてゴールまでの経路を求めるのに対して,local_plannerはもっと小さいウィンドウでの軌道を生成します.

 また,local_plannerはlocal_costmapに基づいて生成されますが,この地図上にはセンサーで取得した動的な障害物も含まれます.global_plannerで軌道を生成しているのに,なぜもう一度軌道を作成するのか?という点ですが,global_plannerで生成した軌道はロボットの制御精度や動的な障害物を考慮できていません.なので,ロボットが完璧に制御できて,なおかつ動的な障害物が全くなければglobal_plannerの生成した軌道のみで事足りるのかもしれませんが,実際にはそんなことはないわけで.local_plannerは対象領域をもっと絞って,動的な障害物等も考慮しながらその領域内て軌道を生成します.ただ,local_plannerで生成した軌道はある程度global_plannerに沿ったもの出ないと意味がないので,そこはglobal_plannerの生成軌道とlocal_plannerの生成軌道の差分に重みをつけて一つの要素として考慮しています.

global_costmap : 静的地図.動的な障害物は考慮されてません.
local_costmap : 動的地図.ロボット周辺のその時その時の地図.センサー取得値もマッピングされているので,動的な障害物も考慮されてます.
recovery_behaviors : リカバリ時の挙動を決定します.

各要素の詳細説明は後述します.