JetBot をハード無改造で Donkey Car 化する

#この記事について

この記事は [AI RC Car Adventcalendar 2019](https://qiita.com/advent-calendar/2019/ai-rc-car) の７日目の記事です。今日は JetBot をハード無改造で Donkey Car 化する方法について書いてみます。

#Donkey Carについて簡単に

![IMG_4908.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/76fc417e-b11d-fdad-21ec-c3d145473c94.jpeg)

[Donkey Car](https://www.donkeycar.com/)は2017年に米オークランドで始まった趣味の AI カーレースのコミュニティ [DIY ROBOCARS](https://diyrobocars.com/)の入門機として開発されたものです。機体はRCカーをベースとして、ラズパイ or Jetson Nano、カメラ、モータドライバをのせたものが基本となります。カメラから入力した画像から [PilotNet](https://medium.com/syncedreview/how-a-deep-neural-network-trained-with-end-to-end-learning-steers-a-car-12b424699899) で推論を行いスロットルとステアリングの値を出力して、モータドライバに与えることで走行する仕組みです。

Donkey Carの組み立て方法やソフトウェアのインストール方法は[Donkey CarのDocsサイト](http://docs.donkeycar.com/)で公開されています。車体のキットは香港の [Robocar Store](https://www.robocarstore.com/)や日本の [FaBo Store](https://fabo.store/collections/donkeycar)で購入できます。

Donkey Carを始めること自体はそれほど難しいことではないのですが、元々レース目的であることもあり、RCカーがベースであるのでスピードが出過ぎて、日本の家屋事情では走行場所の確保に難儀されることでしょう。 私の普段は Donkey Car 本来の車体を使わずに、JetBot に Donkey Car のソフトウェアを移植したもので楽しんでいます。

#JetBotについて簡単に

![IMG_5236.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/889ef7b6-0318-1419-064c-0ae1f6b0d6a2.jpeg)

[JetBot](https://github.com/NVIDIA-AI-IOT/jetbot) は Maxwell 世代のGPUであるTegra X1を搭載した１ボードPC「Jetson Nano」を使って、画像認識可能なAIカーを組み立てるプロジェクトです。JetBotの仕様は[GitHubで公開されていて](https://github.com/NVIDIA-AI-IOT/jetbot)、そこに公開されているドキュメントにしたがって必要なパーツを購入/3Dプリントして組み立てるだけで、簡単にAIカーを作成できます。組み立てキットも[各所から購入できます](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetbot-ai-robot-kit/)。

JetBot はレースを目的としたものではなく、スピードも出ませんので、狭い場所でも動かすことができます。

#JetBotをDonkey Car化する

JetBotはデフォルトではPCなどのWebブラウザからJupyter labを使って制御します。今回はこの環境を壊さずに、適時 Donkey Car に切り替えられるようにします。

### virtualenvwrapper のインストール

Donkey Carソフトウェアのインストールが既存環境に影響を与えないように Python の仮想環境を用意します。以下の手順で virtualenvwrapper をインストールします。

```sh
$ sudo apt update
$ sudo apt install python3-virtualenv virtualenvwrapper
$ echo 'export WORKON_HOME=$HOME/.virtualenvs' >> ~/.bashrc
$ mkdir ~/.virtualenvs
$ source ~/.bashrc
```

### Donkey Car用の仮想環境作成

ここでは仮に "donkey" という名前で仮想環境を作成します。

```sh
$ mkvirtualenv donkey
```

作成した仮想環境に入るには workon コマンドを使います。仮想環境に入るとコマンドラインのプロンプトの前に仮想環境名がつきます。

```sh
$ workon donkey
(donkey) $
```

ちなみに仮想環境から抜けるには以下のようにします。

```sh
(donkey) $ deactivate
$ 
```

### 作成した仮想環境に Donkey Car のソフトウェアをインストールする

[本家のドキュメント](http://docs.donkeycar.com/guide/robot_sbc/setup_jetson_nano/)の手順にしたがって、Step2からインストール作業を実施してください。

インストールが完了したら、自分用の Donkey Car 環境を作成します。

```sh
(donkey) $ donkey createcar --path ~/mycar
```

### 足まわりの制御のセットアップ

標準のDonkey Carの足まわりはスロットル用のモーターとステアリング用のサーボモーターが別になっていますが、JetBotの場合は左右のDCモーターの差動によってスロットルとステアリングを制御します。

Donket Car のパーツ parts/actuator.py にはいちおうこのような構成のモータを制御するための TwoWheelSteeringThrottle クラスが用意されているので、これを利用することにします。

まず、Adafruit_MotorHAT パッケージをインストールします。

```sh
(donkey) $ pip install Adafruit-MotorHAT
```

次に、このパッケージを使った Donkey Car プログラムに若干問題があるので、以下の改造を加えます。

```
diff -ur donkeycar.org/donkeycar/parts/actuator.py donkeycar/donkeycar/parts/ac\
tuator.py
--- donkeycar.org/donkeycar/parts/actuator.py   2019-12-07 22:22:18.438620446 +\
0900
+++ donkeycar/donkeycar/parts/actuator.py       2019-11-24 10:26:04.518697679 +\
0900
@@ -265,9 +265,13 @@
         from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor
         import atexit

-        self.FORWARD = Adafruit_MotorHAT.FORWARD
-        self.BACKWARD = Adafruit_MotorHAT.BACKWARD
-        self.mh = Adafruit_MotorHAT(addr=0x60)
+        #self.FORWARD = Adafruit_MotorHAT.FORWARD
+        #self.BACKWARD = Adafruit_MotorHAT.BACKWARD
+        #self.mh = Adafruit_MotorHAT(addr=0x60)
+        self.FORWARD = Adafruit_MotorHAT.BACKWARD
+        self.BACKWARD = Adafruit_MotorHAT.FORWARD
+        self.RELEASE = Adafruit_MotorHAT.RELEASE
+        self.mh = Adafruit_MotorHAT(i2c_bus=1)

         self.motor = self.mh.getMotor(motor_num)
         self.motor_num = motor_num
@@ -276,6 +280,8 @@
         self.speed = 0
         self.throttle = 0

+    def turn_off_motors(self):
+        self.mh.getMotor(self.motor_num).run(self.RELEASE)

     def run(self, speed):
         '''
@@ -297,7 +303,9 @@


     def shutdown(self):
-        self.mh.getMotor(self.motor_num).run(Adafruit_MotorHAT.RELEASE)
+        #self.mh.getMotor(self.motor_num).run(Adafruit_MotorHAT.RELEASE)
+        self.mh.getMotor(self.motor_num).run(self.RELEASE)
+


 class Maestro:

```

次に、`mycar/manage.py` に TwoWheelSteeringThrottle を使うための修正を行います。

```
@@ -483,6 +483,20 @@
         V.add(left_motor, inputs=['left_motor_speed'])
         V.add(right_motor, inputs=['right_motor_speed'])

+    elif cfg.DRIVE_TRAIN_TYPE == "DC_TWO_WHEEL_AF":
+        from donkeycar.parts.actuator import TwoWheelSteeringThrottle, Adafrui\
t_DCMotor_Hat
+
+        left_motor = Adafruit_DCMotor_Hat(cfg.ADAFRUIT_MOTOR_NUM_LEFT)
+        right_motor = Adafruit_DCMotor_Hat(cfg.ADAFRUIT_MOTOR_NUM_RIGHT)
+        two_wheel_control = TwoWheelSteeringThrottle()
+
+        V.add(two_wheel_control,
+                inputs=['throttle', 'angle'],
+                outputs=['left_motor_speed', 'right_motor_speed'])
+
+        V.add(left_motor, inputs=['left_motor_speed'])
+        V.add(right_motor, inputs=['right_motor_speed'])
+
     elif cfg.DRIVE_TRAIN_TYPE == "SERVO_HBRIDGE_PWM":
         from donkeycar.parts.actuator import ServoBlaster, PWMSteering
         steering_controller = ServoBlaster(cfg.STEERING_CHANNEL) #really pin
```

後は、`mycar/myconfig,py` で設定するだけです。最低限必要な設定項目は以下です。

```python
CAMERA_TYPE = "CSIC"
DRIVE_TRAIN_TYPE = "DC_TWO_WHEEL_AF"
ADAFRUIT_MOTOR_NUM_LEFT = 1
ADAFRUIT_MOTOR_NUM_RIGHT = 2
```

# おわりに

以上で通常のDonkey Carと同様に利用できます。`~/mycar/myconfig.py` の BATCH_SIZE をデフォルトの半分程度にすれば Jetson Nano の GPU を使った学習もできます（遅いですが）。