Google Cartographer チューニングガイド

##目的
Google Cartographerのチューニングガイドを翻訳しました。

原文：[googlecartographer Beginnings of a tuning guide](https://github.com/googlecartographer/cartographer_ros/blob/master/docs/source/tuning.rst
)
Github:[cartographer_ros](https://github.com/googlecartographer/cartographer_ros)

##チューニング
Cartographerをチューニングすることは残念ながら、本当に難しいことです。
多くのパラメータは相互作用を持っています。
チューニングガイドは具体的な例を使って、基本的な方針を説明します。

###2個のシステム
Cartographerは、2個の連携したシステムに分けることができます。

1つは、local SLAM(frontendとも呼ぶ)です。これはsubmapsを結びつけ、相互に矛盾なく構築します。
しかし、時間が経つと徐々に誤差が蓄積されていきます。
2Dでは["trajectory_builder_2d.lua"](https://github.com/googlecartographer/cartographer/blob/master/configuration_files/trajectory_builder_2d.lua)
3Dでは["trajectory_builder_3d.lua"](https://github.com/googlecartographer/cartographer/blob/master/configuration_files/trajectory_builder_3d.lua)
に多くのオプションを見つけることができます。

もう１つが、global SLAM(backendとも呼ぶ)です。
これはbackgroundのthreadsの中で、主にloop closureの拘束を見つけます。
submapsに対して、scan-matchingを行います。
また、他のsensor dataを取り入れ、高Levelで観測し、最も矛盾のないglobal解を見つけだします。3Dでは重力方向を見つけます。
多くのオプションを["sparse_pose_graph.lua"](https://github.com/googlecartographer/cartographer/blob/master/configuration_files/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](https://github.com/googlecartographer/cartographer/pull/428)にあります。
一般的に、特定のrosbagではなく、常にプラットフォームのために、チューニングを試みてください。