タミヤMidnight PUMPKINをJetRacerにしてAI自動運転（ソフトウェア編）

# はじめに

* 2部構成の後半、今回はソフトウェア編。
 * 「[タミヤMidnight PUMPKINをJetRacerにしてAI自動運転（ハードウェア編）](https://qiita.com/Nabeshin/items/99ddcdf8e6a4038e5844)」
 * 「タミヤMidnight PUMPKINをJetRacerにしてAI自動運転（ソフトウェア編）」
* 前回の記事でタミヤのMidnight PUMPKINをJetRacer化するハードウェアの組み立て編を記載した。
* 今回はソフトウェア編として、JetRacerの環境構築から、実際にAIを用いて自動運転を行うまでの手順を記載する。

![IMG_2766D.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/1c36ab47-fe93-4fd3-bd4d-77276029534f.jpeg)

# 用意するもの
* Jetson NanoとmicroSDカード
 * Midnight PUMPKINに乗っける前に環境をセットアップしておくと作業しやすい。
* Wi-Fi接続できるノートPC
 * ここからJetRacerを制御する。
 * 実際のコースに持って行って結構な時間、細かい作業をするため、ノートPCが望ましい。
 * （ノートPCが無くても頑張れば何とかなるが、ラジコンとPCの間を100回位行ったり来たりする事になる。。。）
 * ブラウザは「Google Chrome」をインストールしておく。


# Jetson Nanoの環境構築
* 公式ドキュメント
 * https://github.com/NVIDIA-AI-IOT/jetracer/blob/master/README.md
 * 「Setup」の「3. Follow the [software setup](https://github.com/NVIDIA-AI-IOT/jetracer/blob/master/docs/software_setup.md)」


![スクリーンショット 2020-04-29 13.30.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/97479836-abaa-a536-3114-7938aba6f091.png)


以下、一部公式とは異なるが、自分がやった手順を記載する。
（この方がシンプルだと思う。）

## Step1. microSDカードの作成

必要なToolが予めインストールされた状態のubuntuイメージファイル（JetCard）がNVIDIAから提供されているのでこれをmicroSDに焼く。

* 1. JetCardのイメージファイル[jetcard_v0p0p0.img](https://drive.google.com/open?id=1wXD1CwtxiH5Mz4uSmIZ76fd78zDQltW_)を自分のマシン(Win, Linux, Mac)にダウンロードする。
* 2. 32GBのmicroSDカードを自分のマシンに挿入。
* 3. [Etcher](https://www.balena.io/etcher/)を使ってイメージファイルをmicroSDカードに書き込む。
 * だいたい1時間くらいかかるので、焼いてる間は他の事やってましょう。
* 4. 自分のマシンからmicroSD カードを取り外せば出来上がり。
 * ここで作られるubuntu環境の**ログインアカウント及びパスワードは「jetson」**

## Step2. Jetson Nano(Ubuntu)の起動

* 1. Step1で作成したmicroSDカードをJetson Nanoに差込む。
* 2. Jetson Nanoに電源ケーブルと、HDMIケーブル、USBキーボード、USBマウス、USB Wi-Fiドングルをつなぎ、電源ON。
* 3. ubuntuが起動したらログインし、右上のWi-Fiアイコンから自宅のWi-Fi環境に接続する。
 * ubuntuのログインパスワードは、上述の「jetson」。
 * 自宅のアクセスポイント名を選択し、パスワードを入力。

![Screenshot from 2020-04-29 03-15-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/e8460bf0-e7e4-68ba-33d9-4737f2c83726.png)


## Step3. Pythonパッケージの追加
Wi-Fiに接続し、インターネットにアクセスできる状態で以下を実行する。

* 1. JetCam Pythonパッケージのインストール
 * JetCamってのは、JetRacerがカメラを操作するためのパッケージ。

~~~
jetson@jetson:~$ cd
jetson@jetson:~$ git clone https://github.com/NVIDIA-AI-IOT/jetcam
jetson@jetson:~$ cd jetcam
jetson@jetson:~/jetcam$ sudo python3 setup.py install
~~~

* 2. torch2trtパッケージのインストール
 * torch2trt ってのは、TensorRTのPython APIパッケージ。

~~~
jetson@jetson:~$ cd
jetson@jetson:~$ git clone https://github.com/NVIDIA-AI-IOT/torch2trt
jetson@jetson:~$ cd torch2trt
jetson@jetson:~/torch2trt$ sudo python3 setup.py install
~~~

* 3. JetRacerパッケージのインストール
 * これが本丸のパッケージ。

~~~
jetson@jetson:~$ cd
jetson@jetson:~$ git clone https://github.com/NVIDIA-AI-IOT/jetracer
jetson@jetson:~$ cd jetracer
jetson@jetson:~/jetracer$ sudo python3 setup.py install
~~~

## Step4. ubuntuをWi-Fiアクセスポイント化する。
* これは必須ではないが、やっておくと作業が捗る。
 * Jetson NanoがWi-Fiのアクセスポイントになるので、Wi-Fiが使えない環境でもJetson NanoとノートPCだけでJetRacerを走らせられる。
 * 初めてのコースを学習させる際、100個以上のカメラ画像を学習させる必要がある。Wi-Fiルータから距離が離れると転送遅延が発生して作業がなかなか終わらないが、それが無くなる。

* 1. デスクトップ右上のWi-Fiアイコンから「Edit Connections」を選択。

![Screenshot18-08-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/16f0e4c6-14f3-e9aa-0fe6-f3f4f913af88.png)

* 2. 「＋」を選択し、追加する接続の種類を「Wi-Fi」を選択。

![Screenshot18-09-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/547ca56e-69fd-1004-6f09-789bbd65cacc.png)

* 3. 適当な接続名を入力し、「Wi-Fi」タブに情報を入力。
 * 後でノートPCから接続する時に覚えやすいようにSSIDは「JetsonWifi」とする。

![Screenshot18-10-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/a2782b87-97a6-330f-42af-ba6d2e9c1111.png)

* 4. 「Wi-Fi Security」タブに情報を入力。
 * 後でノートPCから接続する時に覚えやすいようにパスワードにする。
 * 一応、パスワードは8文字程度にしておく。
 * 最後に「Save」してクローズ。

![Screenshot18-10-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/f0aee31b-5555-1d5e-b9b2-90873344f443.png)

* 5. デスクトップ右上のWi-Fiアイコンから「Create Wi-Fi Network」を選択。
 * Connection のプルダウンから先ほど作成した「UbuntuSoftAP」を選択し、「Create」

![Screenshot from 2020-04-29 18-35-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/6d33acd4-2194-196e-48d6-3cd23724796f.png)

![Screenshot from 2020-04-29 18-35-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/3cb87eaf-5fda-6b2e-4a60-5aa8f303585e.png)

これで、ubuntuがWi-Fiアクセスポイントになった。


* 6. デスクトップ上で右クリック、「Open Terminal」でターミナルを開き、Jetson NanoのIPアドレスを表示する。
 * この後ノートPCからSSID:「JetsonWifi」に接続した状態でJetson Nanoに接続するために使う。
 * 自分の環境では「192.168.55.1」になった。

~~~
jetson@jetson:~$ ifconfig

...

l4tbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.55.1  netmask 255.255.255.0  broadcast 192.168.55.255

...

~~~

## Step5. Jetson Nanoのパワーモードの設定
* Jetson Nanoには２つのパワーモードが用意されているので、用途に応じて適切な方を選ぶ。
 * 1つは低消費電力の「5W」
 * もう1つは最大パフォーマンスを出せる「MAXN」
* JetRacerにコースを学習させる作業は「MAXN」で動かさないと時間がかかり過ぎてやってられない。
* [前回の記事](https://qiita.com/Nabeshin/items/99ddcdf8e6a4038e5844)で記載した5V3A相当のモバイルバッテリが用意できている場合は、迷わず「MAXN」にする。
 * ターミナルを起動し、以下のコマンドで設定を「MAXN」に変更する。

~~~
jetson@jetson:~$ sudo nvpmodel -m 0
jetson@jetson:~$ sudo nvpmodel -q
NV Power Mode: MAXN
0
~~~

以上でJetson Nanoの環境セットアップは終了。

Jetson Nanoがセットアップできたら、[前回の記事](https://qiita.com/Nabeshin/items/99ddcdf8e6a4038e5844)の要領でマシンを組み立てる。

# JetRacerの起動

* モバイルバッテリでJetson Nanoを起動する。
 * 電力が足りていれば、ubuntuが起動して、Wi-FiドングルのLEDが点滅する。
 * 足りて無い、ubuntuのブートシーケンスの途中でストップし、Wi-FiドングルのLEDは点灯しない。
 * （自分は最初5V3Aのバッテリを用意したが、電源ケーブルが細くて起動できなかった。十分太いケーブルが必要。）
 * （すぐに用意できない場合は、以下のコマンドで一旦5Wモードに戻し、行けるところまで先に進めてみるしかない。）

~~~
jetson@jetson:~$ sudo nvpmodel -m 1
jetson@jetson:~$ sudo nvpmodel -q
NV Power Mode: 5W
1
~~~

# ノートPCからJupyterLabに接続

* ノートPCを起動し、Wi-Fiアクセスポイント名「JetsonWifi」に接続する。
 * パスワードは先ほど自分で設定したものを入力。 
* ブラウザ（Google Chrome）を起動し、以下のURLにアクセスする。
 * **[jetson_ip_address]** は、先ほど調べておいたJetson NanoのIPアドレスに置き換える。
 * 自分の場合、http://192.168.55.1:8888

~~~
http://[jetson_ip_address]:8888
~~~


* JupyterLabのログイン画面が表示されるので、パスワード「jetson」を入力する。
 * ブラウザをSafariにして開くと何故か「please use a different workspace」というエラーで、ログインできなかった。
 * ブラウザをGoogle Chromeに変えたら何も問題なくログインできたので、特に深追いしない。
* ログインすると以下のような画面が表示される。

![スクリーンショット 2020-04-30 12.00.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/bc4c3020-5ef8-393d-8f16-dabaab13119a.png)

以下、主に使う機能について軽く触れておく。
このあたりの説明は、NVIDIAの無料教材[「Jetson NanoでAIを始める」](https://courses.nvidia.com/courses/course-v1:DLI+C-RX-02+V1-JA/about)に色々書かれている。

* ファイルブラウザ
 * 左側にJetson Nanoのディレクトリが表示されており、ダブルクリックでフォルダ、ファイルが開ける。
* ツールバー
 * 「Kernel」でJupyter Notebookのプログラムを停止したり、再起動できる。
* Terminalタブ
 * 最初に表示されている「Launcher」タブの「Terminal」をクリックすると、以下のようなシェルが起動する。
 * ブラウザだけでubuntuをシャットダウンしたり、上述のパワーモード（MAXN、5W）を変更したり出来るので便利。

![スクリーンショット 2020-04-30 19.32.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/6cc9f984-3436-2c91-f2ea-100a2a46446c.png)



# NOTE
* この後記載するJupyter NoteBook **「*.ipynb」** は、排他的に実行する前提で作られているようである。
 * カメラのリソース解放が無いので、新たに別のを動かそうとするとカメラが使えなかったりする。
* なので、次の **「*.ipynb」** を実行する前に、必ず「Kernel」でJupyter Notebookのプログラムを停止する必要がある。



# JetRacerの基本動作
* 1. ファイルブラウザで **~/jetracer/notebooks** まで移動する。
* 2. **basic_motion.ipynb** というJupyter NoteBookをダブルクリックで開く。
 * このファイルは、Jetson NanoからPCA9685を介してラジコンを制御する部分の基本動作を確認するコード。
 * 簡単なコードなので、ここで色々とファイル構成を辿ってみると良い。
 * 上位クラスのRaceCarがsteering, throttleの2種類の属性を持ち、それぞれ-1から1の値を取る。
 * 下位クラスのNvidiaRaceCarがPCA9685のハード依存部で、I2Cアドレス、チャンネル番号、PWM出力補正などの役割を担う。
 * traitletsという仕組みがって、値のチェックをしたり、変更検知してイベント通知をしたりする。
 * なので、steering, throttleの値が変わると、この仕組みによってラジコンの動きが変わる。
* 3. ドキュメントに沿って内容を確認しながら上から順次コードを実行する。
 * ドキュメントを読みながら、上下キーでアクティブになる領域を切り替える。
 * コードの領域が選択されている状態で「Ctrl + Enter」すると、そのコードが実行される。
 * ラジコンの回路をJetson Nano側からの入力に繋いでおけば、パラメータに応じて実際にラジコンが動く。
 * **（throttleに値が設定されるといきなり走り出すので、事故らないように注意！！）**

![スクリーンショット 2020-04-30 19.34.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/c12fc83d-bce7-c81e-d480-b09d29eca43b.png)


# AIにコースを学習させる
快適に作業するため、事前にJetson Nanoのパワーモードを「MAXN」にしておく。

~~~
> sudo nvpmodel -m 0
~~~

* 1. 同じくファイルブラウザで **~/jetracer/notebooks** まで移動する。
* 2. **interactive_regression.ipynb** というJupyter NoteBookをダブルクリックで開く。
* 3. ドキュメントに沿って内容を確認しながら上から順次コードを実行する。
 * そのまま実行すると個々にWidgetが表示された後、最後にまとめて全Widgetを再び表示する。
 * 気持ち悪いので、こんな感じで自分は個々の表示を切っている。
 * また、最後に **print('DONE.')** を入れておくと、処理が終わったかどうかが分かるので便利。

~~~
#display(data_collection_widget)
print('DONE.')
~~~


![スクリーンショット 2020-04-30 19.35.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/1d983186-3467-80af-a476-149cb9b7ad19.png)

* 4. 正常に全部実行できると、最後に全部入りのWidgetが表示される。

![スクリーンショット 2020-04-30 19.39.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/9334b9ee-a4cb-f2e8-ea02-11e1b63776aa.png)

* 5. この状態でカメラの画像を使ってAIにコースを学習させる。
 * 左端の領域が、現在のカメラ映像が映し出されている。
 * この画像に対し、車が目指す位置をX,Y座標の数値として関連付けていくつもデータを取っていき、最後にAIに学習させる。
 * 進むべき位置をマウスでポチッとクリックすると、即座に右側に記録したデータが表示される。
 * 収集したデータ数は、「count」に表示される。

![スクリーンショット 2020-04-30 19.54.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/28f46c85-a240-a24a-1e52-fac9abe3cbfb.png)

* 6. 走らせるコースで十分特徴的なデータが得られるまで、この一連の作業をひたすら繰り返す。
 

![IMG_2762D.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/03aafecc-6e18-577d-01cb-4394f59d47fd.jpeg)

* 7. 一通りデータ収集が出来たら、AIに学習させる。
 * 「epochs」に試行回数を設定する。最初は、とりあえず10くらい？
 *  （よく分からないが、学習させ過ぎると良く無いみたいなことがどっかに書かれていたので、どうなるか後で試してみよう。）
 * 「train」で学習スタート。進捗バーが最後まで行ったら終了。

![スクリーンショット 2020-04-30 19.55.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/5d381593-90e1-b306-dfe5-f3ea185e2749.png)

* 8. 学習状況の確認。
 * 学習が終わると、右側に新しくライブ表示枠が追加される。
 * リアルタイムにAIの判断結果が青い丸で重畳表示され、車が進むべき方向として適切かどうかチェックできる。
 * コースをぐるっと映し出してみて、とんでもない方向に行かないかチェックする。
 * 学習不足な箇所があれば追加でデータを収集し、うまく行くまで学習させる。
 * サーボのゲイン調整との兼ね合いもあるが、特にコーナリングは念入りに学習させないとうまく曲がらないので、何度かトライしてみると良い。
 * コードを見る感じ、デフォルトではX座標しか見てないっぽいので、目一杯ステアリングを切りたい場合は画像左右の端をクリックすると良い。
 * 満足できる結果が得られたら、最後に「save model」で保存して終了。

![スクリーンショット 2020-04-30 19.55.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/b2f1a15c-b9d3-422c-7761-77e99129c033.png)



# いよいよ自動運転
この実行にはそんなに電力を使わないので、Jetson Nanoのパワーモードを「5W」に戻しておく。
あとレースするなら軽量化のために軽いバッテリに交換する。

~~~
> sudo nvpmodel -m 1
~~~


* 1. 同じくファイルブラウザで **~/jetracer/notebooks** まで移動する。
* 2. **road_following.ipynb** というJupyter NoteBookをダブルクリックで開く。
* 3. ドキュメントに沿って内容を確認しながら上から順次コードを実行する。
 * モデルの生成には若干時間がかる。

![スクリーンショット 2020-04-30 20.10.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/8c25302d-c74b-d7c7-19b8-60d5577e10ff.png)

* 4. 最後、ここのコードを実行することで自動走行スタート。
 * 最終的にゲインを調整する余地があるので、最初は小さめにしてテストし、大丈夫だったら徐々に上げて行く。 
 * throttleについては、最初はラジコンのプロポで人間が制御して安全を確かめてからAIに任せた方が良いかも。
 * ちなみに他のコードと違い、このコードは終了しない。

![スクリーンショット 2020-04-30 20.12.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/ba79853a-1b15-0550-62be-898ec179d742.png)

* 5. 走行停止と、再スタート。
 * このコードの実行を止めるとラジコンも停止する。
 * ゲイン調整して再スタートもできる。


![スクリーンショット 2020-04-30 20.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/7c62e6dd-a7df-28af-d24c-c5f2e0af997a.png)


# シャットダウン
* Jetson Nanoを終了したい場合は、Terminalを開いて終了させる。

~~~
jetson@jetson:~$ sudo poweroff
~~~

![スクリーンショット 2020-04-30 20.17.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283854/751abacf-5631-3438-2f2f-3253b3a7a37e.png)