EV3モーターLをRaspberry Pi 4から制御する

# LEGO Mindstome EV3のEV3 インタラクティブサーボモーターLをRaspberry Pi 4から制御する
## 概要
ネットワークを介し倒立振子を制御する実験を行うため、計算アーキテクチャを含むハードウェア構成の検討を実施した。
当初、[インテリジェントブロック EV3](https://education.lego.com/ja-jp/product-resources/mindstorms-ev3/%E5%85%88%E7%94%9F%E5%90%91%E3%81%91%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%EF%BC%8F%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E9%81%B8%E6%8A%9E/)とwifiを介し、接続されたエッジ計算デバイスからパラメータ読み取り/書き込みを実行する構成を検討。
EV3は計算資源が貧弱かつ通信速度も極めて低速であるため、200ミリ秒から500ミリ秒程度の制御周期しか実現できず、倒立振子の制御手段としては不適と判断し使用を断念。

次に[Raspberry Pi Build HAT](https://www.raspberrypi.com/products/build-hat/)を介して[ SPIKE™ Lアンギュラーモーター](https://education.lego.com/ja-jp/products/-spike-l-/45602/)を制御する構成を検討した。
Build HATは[公式ドキュメント](https://buildhat.readthedocs.io/en/latest/hub_index.html)を参照する事で、Python 3スクリプトから簡便にSpikeモータ制御並びにセンサ読み取りを実行できる。
他方で[公式ドキュメントの実装例](https://buildhat.readthedocs.io/en/latest/buildhat/motor.html#example)で確認できる様に、継続的にモータを回転させ続けるためにtime.sleepを用いる必要がある。
Spike Lアンギュラーモーターは[モータ内部](https://www.eurobricks.com/forum/index.php?/forums/topic/175559-spike-primeessentialc-angular-motor-disassemble/)に実装されたマイコンを介してモータを制御する構造となっており、例えばモータにデューティー比を与える事で、回転状態を維持しつつ連続的に回転速度を制御するような運用は困難であり、用途との見合いで使用を断念した。

最後に、Raspberry Pi 4から[Wave Share Motor Driver HAT](https://www.waveshare.com/wiki/Motor_Driver_HAT)を介してンタラクティブサーボモーターL(※以後「Lモータ」)を制御する方法を検討した。
Wave ShareはMotor Driver HAT向けのライブラリをを公開しており、加えてPython実装例を提供している。
加えて、Pythonモジュール[pigpio](https://pypi.org/project/pigpio/)、[gpiozero](https://gpiozero.readthedocs.io/en/latest/)を利用し、Lモータのロータリーエンコーダから回転角度を読み取る事が可能である。

## 目的
Raspberry PI 4からEV3 Lモータを制御する。

## インタラクティブサーボモーターLの詳細
### インタラクティブサーボモーターLの概要
LEGO Mindstome EV3基本セットに2個同梱されているモータである。
Lモータの筐体にはロータリーエンコーダが内蔵されており、Raspberry Piのピンと結線することでPythonスクリプトから簡易に回転角度が取得できる。

また、Lモータは[出力端子の仕様](https://depfields.com/dcmotor-pwmcontrol/)が解析されており、コネクタを介してLモータと接続できる配線を作成する事で、容易にRaspberry Piと接続する事ができる。

### インタラクティブサーボモーターLのインターフェース
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627111/161b9f95-1855-2414-edbc-36318fa5843f.png" width= "300px" >

|pin配置|機能|
| ---- | ---- |
|1. モータ1|Motor Driver HATのMA1またはMB1に接続|
|2. モータ2|Motor Driver HATのMA2またはMB2に接続|
|3. GND  | Raspberry PiのGNDに接続|
|4. +3.3VDC| Raspberry Piの3.3Vに接続|
|5. エンコーダA|Raspberry PiのGPIO_GEN[N]に接続|
|5. エンコーダB|Raspberry PiのGPIO_GEN[N]に接続|

### Pythonスクリプトの実装例

https://github.com/nekonabesan/connectionScript/blob/main/ev3lmotor_local.py

以下にgithubにアップロードしたスクリプトから、本投稿に関連する箇所を抜き出し解説する。

#### モータ制御
PCA9685モジュールをインストール
https://github.com/adafruit/Adafruit_Python_PCA9685

```
sudo pip install adafruit-pca9685
```

PCA9685モジュールをimportする
```
from modules.PCA9685 import PCA9685
```

PWMインスタンスを初期化
```
pwm = PCA9685(0x40, debug=False)
pwm.setPWMFreq(50)
motor_driver = MotorDriver()
pwm.setPWMFreq(50000000.0)
```

モータとのインターフェースはクラスへ切り出し

https://github.com/nekonabesan/connectionScript/blob/main/MotorDriver.py

本実装例では回転方向を文字列として配列に定義した
```
direction = [
    'forward',
    'backward',
]
```

クラスに定義したメソッドを介してデューティ比を印加
```
motor_driver.MotorRun(pwm, 0, direction[direction_a], ua)
motor_driver.MotorRun(pwm, 1, direction[direction_d], ua)
```
MotorRunメソッド内で文字列forward/backwardを0/1に読み替え

#### ロータリーエンコーダ読み取り
gpio Zeroをimport
```
from gpiozero import RotaryEncoder
from gpiozero.pins.pigpio import PiGPIOFactory
```
エンコーダを初期化
```
factory = PiGPIOFactory()
rotary_encoder_a = RotaryEncoder(
    PIN_ROTAR_A1, PIN_ROTAR_A2, wrap=True, max_steps=180, pin_factory=factory
)
rotary_encoder_a.steps = 0
rotary_encoder_a.when_rotated_clockwise = rotated_clockwise_a
rotary_encoder_a.when_rotated_counter_clockwise = rotated_counter_clockwise_a
```
エンコーダから相対角度を読み取り
```
rt_a_counter = rotary_encoder_a.steps
```
																																									
## 検証
オシロスコープで出力波形を確認
※キャプチャは事後投稿

## 最後に
インテリジェントブロック EV3の計算アーキテクチャは陳腐化しており、加えてev3devではPython 3.x系を利用する事は困難である。

過去事例として[ev3devからROSを利用する試み](https://www.youtalk.jp/2017/09/11/suspend-ev3-ros.html)もあったが引用記事の通り、様々な障害があり中断されている。

他方でEV3Lモータは内部にロータリーエンコーダを内蔵しており、市販のモータ、ロータリーエンコーダを組み合わせて同等の仕様を実現する手間を考えると、プロトタイピング等に際して簡単に高機能なモータを利用できるメリットがある。

以上の利点を考慮し倒立振子のハードウェア構成として、Raspberry Piならびに安価な市販のHATとLモータを組み合わせを選択した。