スタンプ型デバイス(4) ~今度こそHoloLens2とBluetoothで通信~

####まえがき
[前回](https://qiita.com/T170521/items/408cf8a5132ea181b7c5)はシリアル通信がうまくいかずに失敗した．
かなり悩んだ末に，新たな手法を試すことにした．

####本題
HoloLens2のBluetooth接続はワイヤレスマウス，ワイヤレスキーボードを主にサポートしている．
前回のまとめから，デバイスを一種のキーボードとして認識させてはどうだろうかという考えに至った．
現在位置の取得はいったん保留として入力デバイスとして機能させることを優先する．
![シャチハタデバイス5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/87c248ea-550c-359b-556d-0c86a1463747.jpeg)


#####機器概要
・Windows10 Laptop
・Unity 2019.3.2f1
・HoloLens2
・Arduino IDE
・Visual Stadio 2019
・スタンプ型デバイス(M5StickC)

####手順
#####1.デバイス側のプログラム作成
ワイヤレスキーボードとして機能させるためのライプラリを作成してくださっている方がいるので，利用させていただく
この[リンク](https://github.com/T-vK/ESP32-BLE-Keyboard)からライプラリをZIP形式でDLする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/573ba5dc-1993-e56a-55ae-271e90e37a31.png)

Arduino IDEを開き，`スケッチ/ライプラリをインクルード/.zip形式のライプラリをインストール...` からDLしたファイルをインストールする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/a4f7829d-7069-05a4-682b-a48ef54aee1b.png)
ワイヤレスキーボードとしてのプログラムを作成する
ON/OFFスイッチをCtrlキーとして割り当てる

```C++:BleKeyboard.ino
#include <M5StickC.h>
#include <BleKeyboard.h>

BleKeyboard bleKeyboard;
const int buttonA = 26; //pinの番号
String chipname = "Stamp";
char Key = KEY_LEFT_CTRL; //Ctrlキー

void set(){
  M5.begin();
  Serial.begin(115200);
  //画面表示
  M5.Lcd.setCursor(0*0, 0*0);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.printf("Bluetooth: %s\n", chipname);
  M5.Lcd.printf("Ver: %s %s\n", __DATE__, __TIME__);
  M5.Lcd.println();
  M5.Lcd.printf("State:");
  //pinの設定
  pinMode(buttonA,INPUT_PULLUP);  //指定のpinを入力に設定
  bleKeyboard.begin(); //Bluetooth接続を開始
}

void setup() {
  set();
}

void loop() {
   if( M5.Axp.GetBtnPress() == 2 ){  // 電源ボタンクリック
   bleKeyboard.end(); //Bluetooth接続を終了
   M5.Axp.DeepSleep(1000000); // 1秒スリープ(リセット)
   set();
  } 
  if (bleKeyboard.isConnected()) { //Bluetoothで接続できたら
    if(digitalRead(buttonA) == LOW){ //スイッチが押されたとき
      //Serial.println("ON "); //USBのポートに「ON」送信
      M5.Lcd.setCursor(8*5, 8*3); //本体画面のカーソルを調整
      M5.Lcd.printf("ON "); //本体画面に「ON」表示
      bleKeyboard.press(Key);  //Ctrlキーを押す
    }else{
      //Serial.println("OFF"); //USBのポートに「OFF」送信
      M5.Lcd.setCursor(8*5, 8*3); //本体画面のカーソルを調整
      M5.Lcd.printf("OFF"); //本体画面に「OFF」表示
      bleKeyboard.releaseAll(); //すべてのキーを離す
    }
    
   delay(100); //0.1s時間を空ける
   }
}
```
このプログラムでは前回と異なり，PCとデバイスで1対1の接続が確立される

#####2.Unity側のプログラム作成
今度は受信するためのプログラムを作成する
前回のscriptより簡潔で分かりやすい

```C#:ColorSwitch.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ColorSwitch : MonoBehaviour
{
    int num = 0;
    public Material[] array = new Material[5]; //変化させる色の配列
    public GameObject obj; //色を変更するobject

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftControl))  //Ctrlキーを押した瞬間に実行
        {
            //オブジェクトの色を用意したMaterialの色に変更する
            obj.GetComponent<Renderer>().material.color = array[num].color;
                num++;
                if(num > 4) num = 0;
        }
    }
}
```

空のGameObjectを作成し，Eventとして先ほどのscriptをアタッチする
適当にマテリアルを割り当てる
対象のobjectとしてCubeをアタッチ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/81a837ff-697c-b8a2-fe81-35d42aa2ec3a.png)

#####3.PCで実行確認
PCとデバイスをBluetoothで接続する
`設定/Bluetoothとその他のデバイス`で接続を確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/4fa6a5d2-594c-8537-9228-17b47bf9df0d.png)
UnityでDemoを実行して動作確認する
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">入力の仕方を変えてみた<br>(動作は変わらん) <a href="https://t.co/evJZxJCd0E">pic.twitter.com/evJZxJCd0E</a></p>&mdash; ゆーま (@sagirin262) <a href="https://twitter.com/sagirin262/status/1298938361051099137?ref_src=twsrc%5Etfw">August 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#####4.HoloLens2にビルド
まずHoloLens2とデバイスをBluetoothで接続する(ここが本命)
接続を確認！！
![HoloLens2_Bluetooth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563922/54c678a4-bcfd-ba28-c0fe-429fc9d33b15.jpeg)
あとはアプリケーションをビルドして完了！！
####実行例
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">こいつ，HoloLens2でも使えるぞ😋😋😋<a href="https://twitter.com/hashtag/HoloLens2?src=hash&amp;ref_src=twsrc%5Etfw">#HoloLens2</a> <a href="https://twitter.com/hashtag/M5StickC?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickC</a> <a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://twitter.com/hashtag/ArduinoIDE?src=hash&amp;ref_src=twsrc%5Etfw">#ArduinoIDE</a> <a href="https://t.co/OjEc5wD6Cw">pic.twitter.com/OjEc5wD6Cw</a></p>&mdash; ゆーま (@sagirin262) <a href="https://twitter.com/sagirin262/status/1298939171122212864?ref_src=twsrc%5Etfw">August 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

####あとがき
念願のHoloLens2と連携することが出来た😆😆😆
使えるとなったら後はいろいろ活用していくだけです！！
もしアイデアとかあったらいただけるとありがたいです．

今後の方針🤔
位置の取得が課題となっている
・デバイス自体をマーカーとして認識させる(Vuforia)
・ワイヤレスキーボードではなくワイヤレスマウスとして実装する(相対位置になるが)
・特定範囲内で赤外認識(あんまり意味ない)

####参考
・M5StickC
[ESP32をBluetoothキーボードやマウスにする](https://neocat.hatenablog.com/entry/2019/09/28/151947)
[Keyboard (Arduino用のコード使い方)](https://www.arduino.cc/reference/en/language/functions/usb/keyboard/)
[1から自作キーボードを作ってみた](https://qiita.com/kamaboko123/items/c32ad91434ffc7f4ff8d)
[KeyboardModifiers](https://www.arduino.cc/en/Reference/KeyboardModifiers)
・Input
[UnityのInputで入力を扱う](https://qiita.com/yando/items/c406690c9ad87ecfc8e5)