M5StickCを使った空中操作可能な無線マウス

## 目的
家でだらっとしている時に楽な姿勢で操作できるマウスを作る！
そのために無線(BLE)で操作できるマウスを作成する

## 環境
M5StickC(6軸IMU：MPU6886[^1])
[^1]: センサーが変わるとマウスの挙動が大きく変わると予想されるので注意

## 作業メモ
<b>参考サイト</b>
https://github.com/T-vK/ESP32-BLE-Mouse
https://programresource.net/2020/04/11/3253.html

### 仕様

| マウス操作 | M5StickC操作 |
|:----------|:------------|
| 左クリック | Homeボタン単押し |
| 右クリック | Homeボタン長押し |
| マウスホイール | 右側ボタン押下したまま本体を↑↓ |
| マウスカーソル移動 | 本体を傾ける[^2] (以下の図参照) |

[^2]: 3次元ベクトルのpitch/roll/yawを使って実現しているが、M5StickCはyawの値が怪しい(何もしていないのに値が動き続ける)ため、今回は使用していない。yawも使いたい場合は[この辺](https://qiita.com/foka22ok/items/53d5271a21313e9ddcbd)で補正が必要と思われる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248487/dccea807-d43f-57e6-9eba-6d6407b8bdc6.png)


### ライブラリ準備
[参考サイト](https://github.com/T-vK/ESP32-BLE-Mouse) からライブラリをダウンロード
ダウンロードしたライブラリ内に`examples`というフォルダがあり、サンプルコードの動作確認

### ソースコード[^3]

[^3]: [参考サイト](https://programresource.net/2020/04/11/3253.html) のコードをM5StickC用にちょい変しただけ

`M5 GyroMouse` という名称でPCなどからBluetooth検索可能

```C
#include <M5StickC.h>
#include <BleMouse.h>
 
#define GYRO_CHECK_INTERVAL     10
#define GYRO_CHECK_INTERVAL_WHEEL   30
 
BleMouse bleMouse("M5 GyroMouse");
bool blestate = false;
bool wheelmode = false;
bool mouserightstate = false;
int gyrointerval = GYRO_CHECK_INTERVAL;
signed char mousex, mousey, mwheel;
int ipitch, iroll, iyaw;
float pitch, roll, yaw;
char chbuff[32];
unsigned long current_millis, last_millis = 0;
 
void showstate(char *txt) {
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.printf(txt);
}
 
void showgyro(char *txt) {
    M5.Lcd.setCursor(0, 20);
    M5.Lcd.printf(txt);
}
 
void setup() {
    M5.begin();
    bleMouse.begin();

    // メニュー表示
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setRotation(1);
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextFont(2);
    M5.Lcd.println("Gyro Mouse");
    M5.Lcd.println("B: Wheel(Hold)");
    M5.Lcd.println("A: Left(shortpress)");
    M5.Lcd.println("A: Right(1[s]longpress)");
    showstate("Disconnected");
 
    M5.IMU.Init();
}
 
void loop() {
  
  M5.update();
  
  current_millis = millis();
  
  if (bleMouse.isConnected()) {
    if (!blestate) {
      blestate = true;
      showstate("Connected");
    }
    
    if (current_millis - last_millis > gyrointerval) {
      // 3次元ベクトル取得
      M5.IMU.getAhrsData(&pitch, &roll, &yaw);
      ipitch = (int)pitch;
      iroll = (int)roll;
      iyaw = (int)yaw;

      if (wheelmode) {
      // マウスホイール操作
        mousex = 0;
        mousey = 0;
        if (abs(iroll) >= 10) {
          mwheel = (signed char)(iroll / 10);

// for debug
#if 0
          sprintf(chbuff, "%d           ", mwheel);
          showgyro(chbuff);
#endif
        }
      } 
      else {
      // マウスカーソル操作
        mousex = (signed char)((ipitch < 0 ? min(0, ipitch + 10) : max(0, ipitch - 10)) / 10);
        mousey = -1 * (signed char)((iroll < 0 ? min(0, iroll + 10) : max(0, iroll - 10)) / 10);
        mwheel = 0;

// for debug
#if 0
        sprintf(chbuff, "%d %d %d           ", mousex, mousey, mwheel);
        showgyro(chbuff);
#endif
      }
      bleMouse.move(mousex, mousey, mwheel);
      last_millis = current_millis;
    }
    
    // BtnA:BUTTON_A_PIN Homeボタン
    // BtnB:BUTTON_B_PIN 側面ボタン
    if (M5.BtnA.pressedFor(1000)) {
      // Homeボタン長押しで右クリック
      bleMouse.press(MOUSE_RIGHT);
      mouserightstate = true;
    } 
    else if (M5.BtnA.wasPressed()) {
      bleMouse.press(MOUSE_LEFT);
      mouserightstate = false;
    } 
    else if (M5.BtnA.wasReleased()) {
      if( mouserightstate == true ){
        bleMouse.release(MOUSE_RIGHT);
      }
      else{
        bleMouse.release(MOUSE_LEFT);
      }
    } 
    else if (M5.BtnB.wasPressed()) {
      wheelmode = true;
      gyrointerval = GYRO_CHECK_INTERVAL_WHEEL;
    } 
    else if (M5.BtnB.wasReleased()) {
      wheelmode = false;
      gyrointerval = GYRO_CHECK_INTERVAL;
    } 
  } 
  else {
    if (blestate) {
      blestate = false;
      showstate("Disconnected");
    }
  }
}
```

こんな形で操作メニュー表示がされるようになっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248487/3e843363-9104-6290-4e85-59052e9f8d33.png)

## まとめ
>家でだらっとしている時に楽な姿勢で操作できるマウスを作る！
そのために無線(BLE)で操作できるマウスを作成する

一応目標は達成
ただし、精度を求められる操作はできないため、利用シーンは限られそう