Donkey Carのセットアップ

Page content

Donkeycar(http://www.donkeycar.com/) を、5年以上前に組み立てた作動モーター式ロボットに搭載してみようと思います。 しかし、DonkeycarはPCA9685を経由してラジコンのサーボモーターを制御していますので、 自前の作動モーター回路(2個のモーターに個別のPWM信号を与えてステアリングと駆動制御を同時に行う)にはそのまま適用できません。 そこで stm32 nucleoとmbedを使い I2C slave、作動モーター制御のシステムブロックを用意し、raspberry pi上のDonkeycarに手を加えず使えるようにしようと思います。

ここではまずDonkeycarのセットアップのだいたいの流れを説明しています。

設定

  • ここに従ってRaspberry Piにdonkeycarをセットアップします(Get the Raspberry Pi working. から Create your car app.まで)。
  • 既存donkeycarシステム(以下の接続)をセットアップします(配線に注意)
  • Raspberry Piを起動し、raspi-confiで I2Cインタフェイスを有効にします。
  • コード編集:コーディング環境としてVisual Studio Codeを使います。(SSHで直接ファイル編集でき、とても楽)
  • コマンド実行:Putty(SSH)などを使います。

標準donkeycarシステム

標準システムとしては、このようなハードウェア構成です。

  • Rpi3B+ —(I2C,3.3V,GND)— PCA9685(PWM module) —(PWM,GND)— Therbo motor(1:Throttle,2:Angle)
  • Rpi3B+ —Flexible cable— Raspi Camera

改造donkeycarシステム

これにPCA9685変換機能をmbedで実装し、置き換えます。 追加: mbed on stm32 nucleo : PCA9638 emulation and differential DC motor drive converter

削除: PCA9685(PWM module)

このようなハードウェア構成となります。

  • Rpi3B+ —(I2C,GND)— mbed on stm32 nucleo —(PWM,GND)— differential motors
  • Rpi3B+ —Flexible cable— Raspi Camera

Flowchart

  • raspberry pi(I2C master)から送信されるPCA985への送信データを mbed(I2C slave)で受信する
  • 受信データ(PWMパラメータ)から作動モータの制御パラメータへ加工
  • mbedの PWM設定

制御パラメータ加工ポイントとしては、サーボモーター用のPWM設定値(PCA9685)と作動モーター制御パラメータを等価なものにすることです。 例えば、PCA9685で前進出力50% とするPWM設定値の場合、mbed出力としてはモーターA、Bに前進出力としてそれぞれ50%を与えることです(左右バランス補正常にゼロ)。 また、直進する上での左右バランスや、右左折する場合はPCA9685のステアリング情報を使って、モーターA,Bに与える推進力の割合だけを決めるようにします。

外部リンク: PCA9685 datasheet

詳細は別の記事で。

開発環境

  • Raspberry pi 3B+ : donkeycar.comからパッケージされたイメージファイルをそのまま利用。
  • Visual Studio Code (SSH FS, Python) : PCからRaspberry pi上のpythonソースコードを編集
  • Adafruit Servo/PWM Pi HAT! : 試運転用に接続(今後これがstm32 mbedに置き換えられる)
  • Nucleo L432KC : 小型mbed対応 smt32 nucleo board
  • ロボット本体 : 作動モーター駆動型自作機
  • バッテリー : RAV POWER, Model RP-PB052 (22000mAh/83.6Wh), 5V/5.8A in total

テスト実行

まずは標準システムでセットアップしたRaspberry piがエラーなく動作することを確認します。 このコマンドを使ってシステムを起動します。

> python manage.py drive

実行結果: 正常終了すると以下のメッセージで待機状態になります。Ctrl+Cなどで強制終了できます。

(env) pi@carbot1:~/mycar $ python manage.py drive
using donkey version: 2.5.8 ...
/usr/lib/python3/dist-packages/h5py/__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
loading config file: /home/pi/mycar/config.py
config loaded
PiCamera loaded.. .warming camera
Starting Donkey Server...
You can now go to http://mydonkey.local:8887 to drive your car.
/home/pi/env/lib/python3.5/site-packages/picamera/encoders.py:544: PiCameraResolutionRounded: frame size rounded up from 160x120 to 160x128
  width, height, fwidth, fheight)))

つづく。。

トラブルシューティング

ところで、以下のようなIOエラーがでる場合は接続を見直してみましょう(I2Cデバイスから応答が無い場合のエラースローです)。 PCA9685(NXP)駆動には3.3V必要ですが、ボード上の外部電源(サーボ用電源)からは供給されません。 Raspberry PIから与える必要があります。これを忘れているとデバイスが応答できずにこのようなエラーとなる場合があります。 アクセス先のI2Cアドレスを意図的に変更している場合は、PythonディレクトリのSitePackagesにあるdonkeycarクラスにAdafruite_PC9685の呼び出し文があるので、そちらを変更してください。

AdafruitのページでI2C slave addressがどれなのか確認します。(標準は 0x40)

外部リンク: Adafruit 16-Channel PWM / Servo HAT for Raspberry Pi - Mini Kit

外部リンク: Python usage

外部リンク: Technical Usage

外部リンク: sunfounder.cc

Traceback (most recent call last):
  File "/home/pi/env/lib/python3.5/site-packages/adafruit_bus_device/i2c_device.py", line 74, in __init__
    i2c.readfrom_into(device_address, result)
  File "/home/pi/env/lib/python3.5/site-packages/busio.py", line 55, in readfrom_into
    return self._i2c.readfrom_into(address, buffer, stop=stop)
  File "/home/pi/env/lib/python3.5/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 44, in readfrom_into
    readin = self._i2c_bus.read_bytes(address, end-start)
  File "/home/pi/env/lib/python3.5/site-packages/Adafruit_PureIO/smbus.py", line 155, in read_bytes
    return self._device.read(number)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pi/env/lib/python3.5/site-packages/adafruit_pca9685.py", line 131, in __init__
    self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
  File "/home/pi/env/lib/python3.5/site-packages/adafruit_bus_device/i2c_device.py", line 76, in __init__
    raise ValueError("No I2C device at address: %x" % device_address)
ValueError: No I2C device at address: 40