LEGO SPIKEプライムとRaspberryPiをUARTで連携する

今回はLEGO SPIKEPrimeとRaspberryPiを連携して使用していく前段階としてUARTを用いて信号をやり取りする仕組みを作ってみた。
今後はこれを応用してRaspberryPi側でカメラなどを用いて機械学習をしその結果に応じてSPIKEのモーターなどを駆動させる連携をさせていくう予定。


## 使うもの
* [LEGO SPIKE PRIME](https://spike.afrel.co.jp/#sec-brics)
* RaspberryPi4(3ではURATの設定が変わる可能性がある)
* [Breadboard Connector Kit for SPIKE Prime Ultrasonic sensor cable](http://www.mindsensors.com/spike-prime/218-breadboard-connector-kit-for-spike-prime-ultrasonic-sensor-cable)(要はんだ付け)
* [T6　トルクスドライバー](https://www.amazon.co.jp/%E3%83%88%E3%83%AB%E3%82%AF%E3%82%B9%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC-%E3%83%98%E3%82%AF%E3%82%B9%E3%83%AD%E3%83%BC%E3%83%96%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC-%E3%81%84%E3%81%98%E3%82%8A%E9%98%B2%E6%AD%A2-%E5%85%AD%E8%A7%92%E6%98%9F%E5%9E%8B%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC-%E7%A3%81%E7%9F%B3%E4%BB%98%E3%81%8DMacBook/dp/B077XT8YCW)
(超音波センサーを分解するのに必要)
* RaspberryPiを環境構築するためのネットワーク環境  
(RaspberrypiOSを用いるため別途SDHCカードも必要)  


## RaspberryPiの環境構築
OS:[RaspberryPi OS](https://www.raspberrypi.org/software/operating-systems/#raspberry-pi-os-32-bit)を利用する
PCからリモートアクセスする場合は[VNCviewer](https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-vnc/)を使うと便利である。  

RaspberryPiOSの準備が完了したら必要なものをインストールしていく。

* 今回はPythonエディタ[Mu](https://codewith.mu/)を利用する。  
MuはPython3を簡単に実行できるエディタな他、SPIKEをUSB接続することでSPIKE内にあるMicroPythonを直接実行することができる。  
RaspberryPi上でターミナルを起動してコマンドを入力してMuをインストールしていく。

~~~
1.Raspberrypi OSのリポジトリから必要なものをインストールする。

sudo apt-get install python3-pyqt5 python3-pyqt5.qsci python3-pyqt5.qtserialport
python3-pyqt5.qtsvg python3-dev python3-gpiozero python3-pgzero libxmlsec1-dev libxml2
libxml2-dev
~~~
~~~
2.virtualenvの環境を作成する。

sudo pip3 install virtualenv

virtualenv -p /usr/bin/python3 --system-site-packages ~/mu-venv
~~~
~~~
3.作成したvirtualenvの環境をアクティブにする。
source ~/mu-venv/bin/activate
~~~
~~~
4.Muをgitからクローンする。
git clone https://github.com/mu-editor/mu.git ~/mu-source
~~~
~~~
5.virtualenvを有効にした状態で、pipでRaspberry Pi用のPythonパッケージをインストールする。

cd ~/mu-source

pip install -e ".[dev]"
~~~
~~~
6.Muのエディタを起動する。

mu-editor
~~~

これでMuの導入は完了。
次回以降Muを起動するときは
`source ~/mu-venv/bin/activate`
`mu-editor`
の順でターミナルでコマンドを実行すれば起動できる。(複数のターミナルで複数のMuを起動することもできる)  


## RaspberryPiのGPIOを有効にする(UART5を利用する)
SPIKEとの信号のやりとりに利用するGPIOを利用できるようにRaspberryPiの設定を行っていく。  
1. RaspberryPi内の「/boot/config.txt」を編集する。 

ファイル内の末尾に「dtoverlay=uart5」を追加で入力し保存する。
ファイルの編集はnanoエディターやviエディターを利用する。
以下はnanoエディターを利用して編集する際のコマンド。  

~~~
sudo nano /boot/config.txt
↓
ファイル内編集、保存
~~~

2.新しいポートが開いてるかコマンドで確認する。

~~~
ls /dev/ttyA*
↓
表示されるリストの中にttyAMA1があればOK
~~~

3.RaspberrypiとBreadboard Connector Kitを用いてSPIKEと接続する。
<img width="600" alt="00-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440646/1e77e1b6-01c2-4cef-7e2c-33d30c2dbd6d.png">

4.SPIKEをRaspberryPiのUSBポートに接続する。

これで通信を行う準備は完了。


## 通信のやり取りを行ってみる。
以下の手順でプログラムを作成し実行することで通信を行ってみた。
1.RaspberryPiでMuエディタを2つ立ち上げる。
RaspberryPi上でターミナルを2つ立ち上げ、それぞれで
`source ~/mu-venv/bin/activate`
`mu-editor`
を実行することでMuのウィンドウが2つ立ち上がる。

2.2つ立ち上げたMuエディタのモードを変更する。
一方はPython3モード、一方はSPIKE MicroPythonモードに変更する。



3.RaspberryPi側、SPIKE側のPythonプログラムをそれぞれMuエディタにて作成する。
それぞれのPythonプログラムは以下

Raspberrypi側(Python3モード側)

~~~ Test.py
import time
import serial,time


ser = serial.Serial('/dev/ttyAMA1',115200)

while True:
    if ser.in_waiting: #if data, read until \n
        x=ser.readline()
        print(x)
        ser.write(b’read: %s\n’ % x)
~~~

SPIKE側(SPIKE MicroPythonモード側)

~~~ Main.py
import hub, time

serial = hub.port.C
serial.mode(hub.port.MODE_FULL_DUPLEX)
time.sleep(1)
serial.baud(115200)

serial.read(1000)
serial.write("\n testing \n\n")
serial.read(1000)
~~~

4.RaspberryPiとSPIKEの接続を行い、2つのMuエディタにてそれぞれのPythonプログラムを実行する。
接続は以下の画像をのようにしている。(Aポートのモーターは次の項目で使用する。)  
<img width="600" alt="00-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440646/8ecdaf91-d749-8333-8beb-c22c41aceb3e.png">

プログラム内の`write`の記述部分が送信されている。
実行するとPython3側Muエディタのコンソール部分に受信したデータが出力される。(`testing`)


## 受信をフラグにしてSPIKEを制御する
信号のやり取りはできたので、それをSPIKEの制御に当てる。

同じようにそれぞれのMuエディタでプログラムを作成する。

Raspberrypi側(Python3モード側)

~~~ Test2.py
import time
import serial

# serial ini
ser = serial.Serial('/dev/ttyAMA1', 115200)

# start send
print('start')
while True:
    time.sleep(5.0)
    ser.write(b't')
    print('send test')
~~~

SPIKE側(SPIKE MicroPythonモード側)

~~~ Main2.py
import hub, time
from spike import Motor

# serial ini
serial = hub.port.C
serial.mode(hub.port.MODE_FULL_DUPLEX)
time.sleep(1)
serial.baud(115200)

# motor ini
motor = Motor('A')

# start recive
print('start')
while True:
    reply = serial.read(1000)
    if reply:
        response = reply.decode('utf-8')
        print(response)
        if response == 't':
            motor.run_for_degrees(360,speed=50)
            time.sleep(1.0)
~~~

プログラムを作成できたらSPIKEのAポートにMモーターを接続する。
プログラムを実行して動作を確認するが、今回は受信待機状態になるSPIKE側から先に実行し、
その後Raspberrypi側を実行する。

正常に動作していればRaspberrypi側から5秒おきにバイト型の`t`が送信され、
受け取ったSPIKE側がutf-8にデコードし、`t`を受け取っていることを判定できたらモーターを360度回すという処理が行われる。