ルンバをDonkey Carのベース車両にする

#はじめに

先日、[ルンバをラジコンのプロポから操作する](https://qiita.com/rukihena/items/e7214fc6ab1c35f07c02) という記事の中で、ルンバを [Donkey Car](https://www.donkeycar.com/) のベース車両にできるのではないかという提案をしました。

今回は実際に実装してみたのでその紹介です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">RoombaにDonkey Carを載せて、AI自動運転させてみました。<br>テーブルの脚のまわりを8の字走行します。<a href="https://twitter.com/hashtag/RoombaHack?src=hash&amp;ref_src=twsrc%5Etfw">#RoombaHack</a><a href="https://twitter.com/hashtag/DonkeyCar?src=hash&amp;ref_src=twsrc%5Etfw">#DonkeyCar</a> <a href="https://t.co/xoOiX0n6Pr">pic.twitter.com/xoOiX0n6Pr</a></p>&mdash; るきへな (@rukihena) <a href="https://twitter.com/rukihena/status/1226520050414174212?ref_src=twsrc%5Etfw">February 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


![P1040440.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104360/055bc98b-450e-c370-ed5a-b41401b639a0.jpeg)

なお、先日の記事の回路は使わず、ラズパイのシリアルポートから直接ルンバに接続してます。

#必要なもの

- ルンバ（ROIコネクタがある機種）
- Raspberry Pi（Donkey Carインストール済み）
- 広角カメラ
- DonkeyCar用ロールケージ（カメラ固定台として）
- ゲームパッド（ロジクールF710など。操作用として）
- モバイルバッテリー
- メスーオスジャンプワイヤ2本

Donkey Car とルンバを持っている方なら、新たに入手するものはジャンプワイヤぐらいなんじゃないかと思います。（モバイルバッテリーぐらいは持ってますよね？）

「ルンバとラズパイならある」という方については、カメラの固定だけ何とかなれば、容易に準備できると思います。

#配線

ルンバのコネクタは Mini-DIN 7pin ですが、とりあえず接続したい場合はブレッドボードなどで使うジャンパピンを挿すことで利用できます。GNDと信号線だけつなげばいいので、ラズパイとの接続はメスーオスジャンプワイヤ2本でつなぐだけです。

![roomba-raspi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104360/4f6eb2dd-9f76-0fd1-cdc1-83f2142c434a.png)

カメラの接続や、ラズパイの電源は言うまでもないでしょう。

#シリアルポート設定

ラズパイのシリアルポートの設定はいろいろ制約があって正直わけわかんないのですが、手元の環境では下記の設定でうまくいきました。

① ```/boot/config.txt``` ファイルに下記の行を追記してください。これは、GPIO 8,10ピンに繋がってる miniUARTというクソハードウェア（GPUクロックに依存するダメな子）をPL011のちゃんとしたやつに切り替える設定です。（bluetooth側からみたら、できる子がダメな子に入れ替わっちゃいます）

```sh:/boot/config.txt
dtoverlay=miniuart-bt
```

なお、古いraspbianでは```dtoverlay=pi3-miniuart-bt```です。いまでも ```pi3-``` でいいんですが、非推奨なので。

② シリアルポートをコンソールに見立ててログインする機能を殺します。
```/boot/config.txt``` から ```console=serial0,115200``` の記述を削除してください。

これらの設定をしても、bluetooth自体は使えます。（PS3コントローラーでDonkey Carを動かせることを確認しております。）

#ソフトウェア

##pySerial インストール

pythonからシリアルポートを使うので、pySerialをインストールします。

```
pip install pyserial
```

なお、ルンバ用のライブラリは使用せず、ROIのコマンドを直接送信してます。

##Roomba_ROIクラス

本来は ```actuator.py``` に追加するものと思いますが、面倒なので ```manager.py``` に追加します。追記する場所は ```import```群の下あたりでいいでしょう。

```py
class Roomba_ROI():

    def __init__(self, ttyName):
        import serial
        import time

        # open tty
        self.ser = serial.Serial(ttyName, 115200, timeout=1)

        # init ROI
        self.ser.write([128])  # start
        self.ser.write([131])  # safe mode
        time.sleep(0.1)
        self.ser.write([164])  # Digit LEDs ASCII
        self.ser.write(b"4649") # greeting message :-)
        time.sleep(0.1)

    def __del__(self):
        self.set_velocity(0, 0)
        self.ser.write([164])  # Digit LEDs ASCII
        self.ser.write(b"----")
        self.ser.close()

    def run(self, left_motor_speed, right_motor_speed):
        self.set_velocity(left_motor_speed, right_motor_speed)

    def set_velocity(self, left_motor_speed, right_motor_speed):
        roomba_left = int(left_motor_speed * 500)
        roomba_right = int(right_motor_speed * 500)

        self.ser.write([145]) # Drive Direct
        self.ser.write(roomba_right.to_bytes(2, 'big', signed=True))
        self.ser.write(roomba_left.to_bytes(2, 'big', signed=True))
```

（LED表示でちょっと遊んでますが、モード表示などマシな使い方をした方がいいかもしれません。）


##Roomba_ROIクラスを使えるようにする

```manager.py``` の ```elif cfg.DRIVE_TRAIN_TYPE == "~~~":```が並んでいるところの最後に、下記コードを追加します。

```python
    elif cfg.DRIVE_TRAIN_TYPE == "ROOMBA_ROI":
        from donkeycar.parts.actuator import TwoWheelSteeringThrottle

        roi = Roomba_ROI(cfg.ROOMBA_TTY)
        two_wheel_control = TwoWheelSteeringThrottle()

        V.add(two_wheel_control,
                inputs=['throttle', 'angle'],
                outputs=['left_motor_speed', 'right_motor_speed'])

        V.add(roi, inputs=['left_motor_speed', 'right_motor_speed'])
```

```TwoWheelSteeringThrottle``` クラスを利用しているところがミソ（？）です

##myconfig.py設定

```
DRIVE_TRAIN_TYPE = "SERVO_ESC"
```

を消して

```
DRIVE_TRAIN_TYPE = "ROOMBA_ROI"
ROOMBA_TTY = "/dev/ttyAMA0"
```

に書き換えます。

あとはいつものように走行するだけです！

```
cd ~/mycar
python manage.py drive --js
```

#おわりに

いかがでしたか？

ルンバは走行速度が遅いので、狭いご家庭でも走行しやすいと思います。

遅いので、```myconfig.py``` の ```DRIVE_LOOP_HZ = 20``` を小さい値にしてもうまくいくのではないか？ そうしたら Raspberry Pi Zero でも動くのではないか？ ということを考えています。