自宅での自動操縦。 パート1-トレーニングデータの募集

こんにちは、Habr。 これは、無人車両に関するレポート後のチュートリアルです。機器のコストをかけずに物事を行う(開始する)方法です。 すべてのコードはgithubで利用できます。とりわけ、このようなクールな画像を簡単に生成する方法を学習します。


SLAM軌跡+マップの例


行こう!


簡単に


トピックに精通している人向けの要約:従来、機械学習に基づいて自動操縦のトレーニングサンプルを設定するには、 かなり情報量の多いCANバスとそのインターフェイスを備え特別装備の車が必要でしたが、これは高価です。 私たちはそれをより簡単に無料で行います-フロントガラス上のスマートフォンから同じ基本的なデータを収集します。 どんな車にも適し、装備の変更はありません。 このシリーズでは、ビデオを使用して、各瞬間のステアリングターンを計算します。 この段落ですべてが明確な場合は、 すぐに導入部を飛び越えてアプローチの本質に移ることができます。


なぜ、なぜ、より詳細に


したがって、数年前、大企業の深刻なリソースがなければ、自動操縦のトピックに入る理由はありませんでした-LIDARセンサーだけで数万ドルかかりましたが、ニューラルネットワークの最近の革命はすべてを変えました。 一対のウェブカメラからの最も単純なセンサーのセットを持ついくつかの人々のスタートアップは、有名ブランドと結果の品質と同等の条件で競います。 特に、非常に多くの高品質のコンポーネントがすでにパブリック ドメインにあるので、ぜひ試してみてください。


オートパイロットは、センサーデータを制御アクション(ステアリングホイールの回転と必要な加速/減速)に変換します。 Googleのようなレーザー距離計システムでは、次のようになります。


方向へのセンサー


センサーの最もシンプルなバージョンは、フロントガラスを通して「見える」ビデオカメラです。 誰もがすでに携帯電話にカメラを持っているので、私たちは彼と協力します。


ビデオカらのレーン


畳み込みニューラルネットワークは 、生のビデオから制御信号を計算するのにうまく機能しますが、他の機械学習アプローチと同様に、正しい結果を予測する方法を教える必要があります。 トレーニングを行うには、(a)モデルアーキテクチャを選択し、(b)モデルのさまざまな入力状況と、各モデルの「正解」(ステアリング角度やアクセルポジションなど)を示すトレーニングサンプルを作成する必要があります。 トレーニングサンプルのデータは、通常、マシンが人によって制御されるレースから記録されます。 つまり、ドライバーはロボットに機械の操作方法をデモンストレーションします。


パブリックドメインには多くの優れたニューラルネットワークアーキテクチャがありますが、データの状況はもっと悲しくなります。1つ目はデータが十分ではないことです。2つ目は、ほとんどすべてのサンプルが米国のものであり、これらの場所と多くの違いがあります。


オープンデータの不足は簡単に説明できます。 まず、データはアルゴリズムとモデルの専門知識と同じくらい貴重な資産であるため、誰も急いで共有することはありません。


ロケットエンジンはモデルであり、燃料はデータです。
アンドリュー・ン

第二に、データを収集するプロセスは、特に「額」で行動する場合、安価ではありません。 その好例がUdacityです。 彼らは、ステアリングとガス/ブレーキがデジタルバスに接続されている車モデルを特別に選択し、バスへのインターフェイスを作成し、そこからデータを直接読み取りました。 アプローチのプラスは、高品質のデータです。 マイナスは深刻なコストであり、大部分の非専門家を遮断します。 実際、 CANであっても、すべての現代車が必要なすべての情報を書き込むわけではなく、インターフェイスをいじる必要があります。


簡単に行います。 「生の」データ(現在は単なるビデオ)をDVRとしてフロントガラス上のスマートフォンで記録し、そこから必要な情報(オートパイロットをトレーニングできる速度とターン)を「絞り込み」ます。 その結果、ほとんど無料のソリューションが得られます。フロントガラスに電話の所有者がいる場合は、ボタンを押すだけで作業中のトレーニングデータを収集できます。


このシリーズでは、ビデオから回転角度を「絞り」ます。 すべての手順は、 githubコードを使用して自分で簡単に繰り返すことができます。


挑戦する


問題を解決します。



期待される結果:



すぐに少し単純化します-ステアリング角度の代わりに、水平面内の角速度を計算します。 これは、次のシリーズで行う並進速度を知っている場合、ほぼ同等の情報です。


解決策


このソリューションは、公開されているコンポーネントから組み立てて、少し仕上げます。


カメラの軌道を復元する


最初のステップは、ビデオ用のSLAMライブラリ (同時ローカリゼーションとマッピング、同時ローカリゼーションとマップ構築)を使用して 3次元空間でカメラパスを復元することです。 出力では、各(ほぼニュアンスを参照)フレームに対して、6つの位置パラメーターを取得します:3Dオフセットと3 方向角


SLAM軌道のみの例


optical_trajectoriesモジュールは、 optical_trajectoriesこの部分を担当しoptical_trajectories


ニュアンス:



道路の平面を決定する


3次元空間でのカメラの軌跡は良好ですが、それでも最終的な質問に直接答えることはできません。左または右に回転し、どのくらいの速さです。 結局のところ、SLAMシステムには「ロードプレーン」、「トップボトム」などの概念がありません。 この情報は、「生の」3Dパスから抽出する必要もあります。


ここでは簡単な観察が役立ちます。 通常、道路垂直よりも水平方向にはるかに長く延びています。 もちろん例外もありますが 、無視する必要があります。 その場合、軌道の水平面として最も近い平面(つまり、最小の再構成誤差を与える平面)を取得できます。


軌跡のすべての3D点に沿った主成分の優れた方法で水平面を選択します。最小の固有値を持つ方向を削除すると、残りの2つが最適な平面を提供します。


支配的なな飛行機


optical_trajectoriesモジュールは、プレーン割り当てロジックも担当しoptical_trajectories


ニュアンス:



回転角を計算する


水平面v 1およびv 2の基本ベクトル(前の部分から最大の固有値を持つ2つの主要コンポーネント)がわかっているので、カメラの光軸を水平面に投影します。


水平投影方程式


したがって、カメラの3次元の向きから、車の方位角を取得します(一般的なケースではカメラ軸と車軸が一致しないため、未知の定数に正確です)。 回転の強さ(つまり、角速度)にのみ関心があるため、この定数は必要ありません。


隣接するフレーム間の回転角度は、学校の三角法によって与えられます(最初の要因は回転の絶対値で、2番目は左右の方向を決定する記号です)。 ここで、a tは、時間tでの射影ベクトルaを意味します。


水平投影方程式


計算のこの部分は、 optical_trajectoriesモジュールによっても実行されます。 出力は、次の形式のJSONファイルです。


 { "plane": [ [ 0.35, 0.20, 0.91], [ 0.94, -0.11, -0.33] ], "trajectory": [ ..., { "frame_id": 6710, "planar_direction": [ 0.91, -0.33 ], "pose": { "rotation": { "w": 0.99, "x": -0.001, "y": 0.001, "z": 0.002 }, "translation": [ -0.005, 0.009, 0.046 ] }, "time_usec": 223623466, "turn_angle": 0.0017 }, ..... } 

コンポーネント値:



ノイズを取り除く


私たちはほとんどそこにいますが、問題は残っています。 結果の(これまでの)角速度グラフを見てみましょう:


フレーム間の生の回転


ビデオで視覚化する:



一般に、回転の方向は正しく決定されていますが、多くの高周波ノイズがあることがわかります。 ローパスフィルターであるガウスぼかしでこれを削除します。


コードのスムージングは​​、 smooth_heading_directionsモジュールによって実行されます


フィルター後の結果:


フレーム間で平滑化



トレーニング済みのモデルを「フィード」して、適切な結果に依存することはすでに可能です。


可視化


明確にするために、JSON軌跡ファイルのデータに従って、上記のデモのように、ソースビデオに仮想ステアリングホイールを重ね合わせて、正しく回転しているかどうかを確認できます。 render_turningモジュールrender_turningます。


フレームごとのグラフも簡単に作成できます。 たとえば、matplotlibがインストールされたIPythonラップトップの場合:


 import matplotlib %matplotlib inline import matplotlib.pyplot as plt import json json_raw = json.load(open('path/to/trajectory.json')) rotations = [x['turn_angle'] for x in json_raw['trajectory']] plt.plot(rotations, label='Rotations') plt.show() 

今のところすべてです。 次のシリーズでは、速度を制御する方法も学習するために翻訳速度を決定しますが、今のところプルリクエストを歓迎します。



Source: https://habr.com/ru/post/J325704/


All Articles