目的
Google Cartographerのチューニングガイドを翻訳しました。
原文:googlecartographer Beginnings of a tuning guide
Github:cartographer_ros
チューニング
Cartographerをチューニングすることは残念ながら、本当に難しいことです。
多くのパラメータは相互作用を持っています。
チューニングガイドは具体的な例を使って、基本的な方針を説明します。
2個のシステム
Cartographerは、2個の連携したシステムに分けることができます。
1つは、local SLAM(frontendとも呼ぶ)です。これはsubmapsを結びつけ、相互に矛盾なく構築します。
しかし、時間が経つと徐々に誤差が蓄積されていきます。
2Dでは"trajectory_builder_2d.lua"
3Dでは"trajectory_builder_3d.lua"
に多くのオプションを見つけることができます。
もう1つが、global SLAM(backendとも呼ぶ)です。
これはbackgroundのthreadsの中で、主にloop closureの拘束を見つけます。
submapsに対して、scan-matchingを行います。
また、他のsensor dataを取り入れ、高Levelで観測し、最も矛盾のないglobal解を見つけだします。3Dでは重力方向を見つけます。
多くのオプションを"sparse_pose_graph.lua"の中で見つけることができます。
要約すると、
local SLAMの仕事はよいsubmapsを生成する動作をし、
global SLAMは相互に最も矛盾ないように結びつける動作をします。
Local SLAMのチューニング
ここでは例として、
cartographer(commit ea7c39b)
cartographer_ros(commit 44459e1)
test data(b2-2016-04-27-12-31-41.bag)
を見ていきます。
開始時の設定では、rosbagの中で、いくつかかなり早いところで滑り出します。
backpackがドイツ博物館の傾斜を通過しているとき、平らな平面という2Dの仮定に反していました。レーザのスキャンデータの中で、矛盾する情報がSLAMに渡されるのが見えます。しかし、point cloud matchingの信頼が高く、その他のセンサーはかなり強く無視しています。私たちの目標はチューニングを通して、状況を改善することです。
特定のsubmapだけを見ると、エラーは全て1つのsubmapに含まれています。
時間が経っていくと、global SLAMは、異常が起きたと判断し、部分的な修正を行います。破損したsubmapはずっと破損しています。
ここでの問題は、submapの中で滑りが起きているため、local SLAMの問題です。
それでは、global SLAMをoffにして、チューニングの邪魔をしないようにしましょう。
SPARSE_POSE_GRAPH.optimize_every_n_scans = 0
submapsの修正サイズ
Local SLAMは時間が経つと誤差が蓄積しますが、loop closureだけはこの累積誤差を解消することができます。Submapsの解像度は、この累積誤差よりも十分に小さくなくてはならず、それによって局所的な修正をします。
一方、loop closureが正しく動作するためには、submapsのサイズは、十分に大きくするべきです。
submapsの大きさはTRAJECTORY_BUILDER_2D.submaps.num_range_dataで設定します。この例の個々のsubmapsを見ると、2つの制約条件を満たしているため、このパラメータは十分にチューニングできていると見なします。
Scan matchersの選択
Local SLAMの背景にある考え方は、レンジファインダ以外のセンサのデータを使って、次のスキャンをsubmapに挿入する場所を予測することです。その時、CeresScanMatcherは、事前に、スキャンがsubmapと整合がとれる最もよい場所を見つけます。
これはsubmapと、scanのサブピクセル位置合わせとの補完によって行います。これは高速ですが、submapsの解像度よりも著しく大きなエラーを補正することはできません。もし、sensorの設定とタイミングが妥当な場合、CeresScanMatcherだけを使用することが通常お勧めとなります。
もし、他のセンサがない場合、信頼性がない場合、Cartographerは、RealTimeCorrelativeScanMatcherも提供しています。
これは、scanがloop closureのsubmapsに対して合致するか、というやり方と同様のアプローチを使いますが、現状のsubmapに対しても一致をします。
その時、Bestの合致が、事前のCeresScanMatcherに使われます。このscan matcherは高コストで、基本的にレンジファインダーでない他のセンサーからの信号を無効にしますが、特徴が豊富な環境ではロバストです。
correlative scan matcherのチューニング
TODO
CeresScanMatcherのチューニング
我々の例では、scan matcherは、scoreに影響を与えることなく、前方向・後ろ方向に、合致を動かす自由度があります。
我々は、scan matcherが過去から逸脱した状況では、ペナルティを課したいとおもいます。
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight、と、rotation_weightという2個のパラメータでコントロールします。値を大きくすると、結果を過去から遠ざけることが高コストになります。
言い換えると、scan matchingは、高いスコアを生成する別の場所を受け入れる必要があります。
指導目的で、過去から本当に高コストなものを、逸脱させましょう:
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1e3
これにより、optimizerは、とても自由にscan matcherの結果を上書きできます。
この姿勢の結果は、過去に近い姿勢になりますが、depth sensorで動作させると矛盾し、明らかに破損します。この値を検証すると、2e2が良い結果となります。
ここで、scan matcherが回転を伴う場合には、依然として、結果をわずかに間違えています。rotation_weightを4e2に設定すると、妥当な結果が得られます。
検査
我々がこの特定の問題にオーバーチューンしていないことを確認するために、他の収集データに対してその設定で実行する必要があります。
今回は、例としてb2-2016-04-05-14-44-52.bagの開始時に、新しいパラメータではスリップすることが露呈し、translation_weightを1e2に下げる必要がありました。この設定は、合致した条件では悪化しますが、もはやスリップしません。
確認する前に、比較するために全ての重みを正規化しました。
このチューニングの結果がPull requests #428にあります。
一般的に、特定のrosbagではなく、常にプラットフォームのために、チューニングを試みてください。