はじめに
先日、ルンバをラジコンのプロポから操作する という記事の中で、ルンバを Donkey Car のベース車両にできるのではないかという提案をしました。
今回は実際に実装してみたのでその紹介です。
RoombaにDonkey Carを載せて、AI自動運転させてみました。
— るきへな (@rukihena) February 9, 2020
テーブルの脚のまわりを8の字走行します。#RoombaHack#DonkeyCar pic.twitter.com/xoOiX0n6Pr
なお、先日の記事の回路は使わず、ラズパイのシリアルポートから直接ルンバに接続してます。
必要なもの
- ルンバ(ROIコネクタがある機種)
- Raspberry Pi(Donkey Carインストール済み)
- 広角カメラ
- DonkeyCar用ロールケージ(カメラ固定台として)
- ゲームパッド(ロジクールF710など。操作用として)
- モバイルバッテリー
- メスーオスジャンプワイヤ2本
Donkey Car とルンバを持っている方なら、新たに入手するものはジャンプワイヤぐらいなんじゃないかと思います。(モバイルバッテリーぐらいは持ってますよね?)
「ルンバとラズパイならある」という方については、カメラの固定だけ何とかなれば、容易に準備できると思います。
配線
ルンバのコネクタは Mini-DIN 7pin ですが、とりあえず接続したい場合はブレッドボードなどで使うジャンパピンを挿すことで利用できます。GNDと信号線だけつなげばいいので、ラズパイとの接続はメスーオスジャンプワイヤ2本でつなぐだけです。
カメラの接続や、ラズパイの電源は言うまでもないでしょう。
シリアルポート設定
ラズパイのシリアルポートの設定はいろいろ制約があって正直わけわかんないのですが、手元の環境では下記の設定でうまくいきました。
① /boot/config.txt
ファイルに下記の行を追記してください。これは、GPIO 8,10ピンに繋がってる miniUARTというクソハードウェア(GPUクロックに依存するダメな子)をPL011のちゃんとしたやつに切り替える設定です。(bluetooth側からみたら、できる子がダメな子に入れ替わっちゃいます)
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
群の下あたりでいいでしょう。
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 == "~~~":
が並んでいるところの最後に、下記コードを追加します。
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 でも動くのではないか? ということを考えています。