シリアル通信してみた。（ラズパイ＆M5StickCPlus）

# 目的
今回は`RaspberryPi`と`M5StickCPlus`でシリアル通信（`M5StickCPlus`→`ラズパイ`）を有線で行いたいと思います。

# 仕様したハード・ソフト
・MacBookPro(2016)
・RaspberryPi 4B
・M5 StickC Plus
・VSCode
・PlatformIO(VSCode拡張機能)

※PlatformIOの導入には以下の記事を参考にさせていただきました。

https://qiita.com/ume-bar/items/234014927ae0857baf51

# アジェンダ
1. `M5StickCPlus`のコード
1. `RaspberryPi`のコード
1. シリアル通信

※以下に記載するコードは全て`VSCode`内拡張機能`PlatformIO`にて開発しています。

# M5StickCPlusのコード
今回`M5StickCPlus`で行いたいのはシリアル通信にて送信するデータの取得とデータの送信になります。
送信するデータは`M5StickCPlus`に標準搭載されている`IMU`(複合センサ)`MPU6886`の値(Acceleration,Gyro,Pitch,Roll,Yaw)を仕様したいと思います。

### 使用するライブラリ
```c++
#include <M5StickCPlus.h>
```
今回はM5StickCPlusライブラリのみになります。
こちらのライブラリでは`M5StickCPlus`のセンサやLCD等を利用するためのライブラリです。

### 変数宣言
```c++
//  加速度センサ、角速度センサの値
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

float pitch = 0.0F;
float roll  = 0.0F;
float yaw   = 0.0F;
//


bool isSend = false; // データ送信フラグ
```
送信するデータ（取得するデータ）は３軸加速度、３軸角速度、三次元ベクトルの回転の計九つになります。

`isSend`に関しては送信を行う際のフラグになるので`false`を入れておきます。

### セットアップ
```c++
void setup() {
  M5.begin();
  M5.IMU.Init();

  Serial.begin(9600);
  
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0,0,4);
  M5.Lcd.println("Not Send");
}
```
大まかに
- `M5StickCPlus`を使うための設定
- `IMU`を使うための設定
- シリアル通信速度の設定
- `LCD`の設定
 
になります。

### ループ
```c++
void loop() {
  M5.update();
  if(M5.BtnA.wasPressed()){
    isSend = !isSend;
    if(isSend){
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0,0,4);
      M5.Lcd.println("Send");
    }
    else{
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0,0,4);
      M5.Lcd.println("Not Send");
    }
  }

  if(isSend){
    // 加速度データ取得
    M5.IMU.getAccelData(&accX, &accY, &accZ);
    //　ジャイロデータ
    M5.IMU.getGyroData(&gyroX, &gyroY, &gyroZ);
    //角度データ
    M5.IMU.getAhrsData(&pitch, &roll, &yaw);
    
    // 加速度データを送信
    Serial.printf("%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f\n", accX,accY,accZ,gyroX,gyroY,gyroZ,pitch,roll,yaw);
  }
  delay(200);
}
```
行っていることは
- ボタンが押されたら処理を実行（`LCD`niNot Send or Sendを表示）
- `isSend`が`True`になったらデータを取得しシリアル通信を行う

のみになっています。

### コード全体
```c++
#include <M5StickCPlus.h>


//  加速度センサ、角速度センサの値
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

float pitch = 0.0F;
float roll  = 0.0F;
float yaw   = 0.0F;
//

bool isSend = false; // データ送信フラグ

void setup() {
  M5.begin();
  M5.IMU.Init();

  Serial.begin(9600);
  
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0,0,4);
  M5.Lcd.println("Not Send");
}

void loop() {
  M5.update();
  if(M5.BtnA.wasPressed()){
    isSend = !isSend;
    if(isSend){
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0,0,4);
      M5.Lcd.println("Send");
    }
    else{
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0,0,4);
      M5.Lcd.println("Not Send");
    }
  }

  if(isSend){
    // 加速度データ取得
    M5.IMU.getAccelData(&accX, &accY, &accZ);
    //　ジャイロデータ
    M5.IMU.getGyroData(&gyroX, &gyroY, &gyroZ);
    //角度データ
    M5.IMU.getAhrsData(&pitch, &roll, &yaw);
    
    // 加速度データを送信
    Serial.printf("%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f\n", accX,accY,accZ,gyroX,gyroY,gyroZ,pitch,roll,yaw);
  }
  delay(200);
}
```

以上が`M5StickCPlus`のコードになります。

# RaspberryPiのコード
### 使用するライブラリ
```python
import serial
import time
```
`serial`とは`pySerial`ライブラリのことであり、`pip3`でインストールする必要があります。
今回はこのライブラリを用いてシリアル通信を行なっていきます。

## 注意
`serial`でインポートできるライブラリとして`pySerial`ライブラリの他に`serial`ライブラリも存在しています。
私はpipインストールの際に間違えて両方入れてしまいコードが動作しなかったため、`uninstall`しました。

### デバイスのポート指定
```python
ser = serial.Serial("/dev/ttyUSB0", 9600, timeout=0.1)
```
USBによるシリアル通信を行うためにどのポートで送受信を行うのかを指定する必要があります。
`9600`という数字は`M5StickCPlusu`の方でも指定したものと同じ通信速度にしてください。
"/dev/ttyUSB0"という箇所はご自分の機器にて接続した状態で以下のような`ls`コマンドを入力して検出できたものにしてください。

```
ls /dev/ttyUSB*
```
![スクリーンショット 2023-06-04 9.57.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3403549/10b0bbac-51de-a74f-d259-f68330a09644.png)

このような表記が出ます。

### コード全体
```python
import serial
import time

ser = serial.Serial("/dev/ttyUSB0", 9600, timeout=0.1)

time.sleep(2) 
       
try:
    while True: 
        # print("test")    
        if ser.in_waiting > 0: # シリアル通信 受信待ち
            bytes = ser.readline()
            result, buf = bytes.decode('utf-8').split('\n')
            data = list(map(float, result.split(',')))
            print("AccX: {0}, AccY: {1}, AccZ: {2},GyroX: {3}, GyroY: {4}, GyroZ: {5},Pitch: {6}, Roll: {7}, Yaw: {8}".format(data[0], data[1], data[2], data[3],data[4],data[5],data[6],data[7],data[8]))
            
        time.sleep(0.2)

except KeyboardInterrupt:
    pass

print('program end')
ser.close()
```
短いので全体を載せてしまいます。
行なっていることは単純でシリアル通信にて受信したデータを`list`型に格納しそれらをプリントしているのみです。

# 実行
`ラズパイ`と`M5StickCPlus`をUSBケーブルにて接続しボタンを押すと...
![スクリーンショット 2023-06-04 9.49.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3403549/c8435939-a7ee-9564-5be6-45bf850580d7.png)

値を取得することができました。
以上で目標達成です。