HoloLensからmicro:bitをBLE連携するメモ

HoloLensからmicro:bitをBLE連携するメモです。

やりたいこと

この知見をもとにHoloLensからmicro:bitを連携してみます。

HoloLens側の準備

micro:bitとHoloLensをBluetoothで接続できたメモ – 1ft-seabass.jp.MEMO

この記事をもとにHoloLensとmicro:bitペアリングを済ませている状態にしておきます。

ソースコード

Bluetooth SensorTagとHoloLens連携してジャイロセンサー取得するメモ – 1ft-seabass.jp.MEMO

こちらの記事を元に、micro:bitのボタンサービスとLEDサービスへのソースコードを書いていきました。

できたのがこちらです。

using UnityEngine;
using System;

#if UNITY_UWP
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Storage.Streams;
#endif

public class MicroBitConnectCube : MonoBehaviour {

#if UNITY_UWP
    public DeviceInformationCollection gattServices;
    public GattDeviceService gattService;
    public GattCharacteristic charData;
    public GattCharacteristic charDataLED;
    public GattCharacteristic charConfig;
#endif

    private string LED_SERVICE_UUID = "e95dd91d251d470aa062fa1922dfa9a8";
    private string LED_MATRIX_STATE_CHARACTERISTIC_UUID = "e95d7b77251d470aa062fa1922dfa9a8";
    private string LED_TEXT_CHARACTERISTIC_UUID = "e95d93ee251d470aa062fa1922dfa9a8";
    private string LED_SCROLLING_DELAY_CHARACTERISTIC_UUID = "e95d0d2d251d470aa062fa1922dfa9a8";

    private string BUTTON_SERVICE_UUID = "e95d9882251d470aa062fa1922dfa9a8";
    private string BUTTON_A_CHARACTERISTIC_UUID = "e95dda90251d470aa062fa1922dfa9a8";
    private string BUTTON_B_CHARACTERISTIC_UUID = "e95dda91251d470aa062fa1922dfa9a8";

    // Use this for initialization
    void Start () {
       ConnectMicroBit();
    }
	
	// Update is called once per frame
	void Update () {
		
	}

    /*
     * 接続および準備(今回は1台だけの動作想定)
     * 
     * */
    public void ConnectMicroBit()
    {
#if UNITY_UWP
        Task.Run(async () =>
        {
            var selectorButton = GattDeviceService.GetDeviceSelectorFromUuid(new System.Guid(BUTTON_SERVICE_UUID));
            var collectionButton = await DeviceInformation.FindAllAsync(selectorButton);
            foreach (DeviceInformation infoButton in collectionButton)
            {
                Debug.Log(string.Format("Name={0} IsEnabled={1}", infoButton.Name, infoButton.IsEnabled));

                // ボタンサービスへの接続
                var serviceButton = await GattDeviceService.FromIdAsync(infoButton.Id);
                var characteristicsA = serviceButton.GetCharacteristics(new Guid(BUTTON_A_CHARACTERISTIC_UUID))[0];
                var characteristicsB = serviceButton.GetCharacteristics(new Guid(BUTTON_B_CHARACTERISTIC_UUID))[0];
                Debug.Log(characteristicsA.Uuid);
                Debug.Log(characteristicsB.Uuid);
                characteristicsA.ValueChanged += (sender, eventArgs) =>
                {
                    var data = eventArgs.CharacteristicValue.ToArray();
                    // ボタンのON/OFFはBooleanで取得
                    // 押したとき:True 離したとき:False で取得できた。
                    var buttonState = BitConverter.ToBoolean(data, 0);
                    Debug.Log(string.Format("A_BUTTON buttonState : {0}", buttonState));
                };
                await characteristicsA.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);

                characteristicsB.ValueChanged += (sender, eventArgs) =>
                {
                    var data = eventArgs.CharacteristicValue.ToArray();
                    // ボタンのON/OFFはBooleanで取得
                    // 押したとき:True 離したとき:False で取得できた。
                    var buttonState = BitConverter.ToBoolean(data, 0);
                    Debug.Log(string.Format("B_BUTTON buttonState : {0}", buttonState));
                };
                await characteristicsB.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);

                // LEDサービスへの接続
                var selectorLED = GattDeviceService.GetDeviceSelectorFromUuid(new Guid(LED_SERVICE_UUID));
                var collectionLED = await DeviceInformation.FindAllAsync(selectorLED);
                foreach (DeviceInformation infoLED in collectionLED)
                {
                    Debug.Log(string.Format("Name={0} IsEnabled={1}", infoLED.Name, infoLED.IsEnabled));
                    var serviceLED = await GattDeviceService.FromIdAsync(infoLED.Id);
                    var characteristicsLED = serviceLED.GetCharacteristics(new Guid(LED_TEXT_CHARACTERISTIC_UUID))[0];
                    Debug.Log(characteristicsLED.Uuid);
                    charDataLED = characteristicsLED;
                    // 接続できたら「CONNECT OK!」と文字を送る
                    WriteDataMicroBit("CONNECT OK!");

                }

                Debug.Log("connect");

            }
        }
        );
#endif
    }

    /*
     * データの送信
     * 
     * */
    public void WriteDataMicroBit(string message)
    {
#if UNITY_UWP
        Task.Run(async () =>
        {
            Debug.Log("message : " + message);

            var dataWriter = new DataWriter();
            dataWriter.WriteString(message);
            var buffer = dataWriter.DetachBuffer();

            var status = await charDataLED.WriteValueAsync(buffer);
            if (status == GattCommunicationStatus.Unreachable)
            {
                // 接続失敗
                Debug.Log("Write failed");
                await Task.Delay(100);
            }
            else
            {
                // 接続成功
                Debug.Log("Write Success!!");
            }
        });
#endif
    }
    
}

少々苦労はしたのですが、特筆すべきは、やはり固有のデータをほどくところでしょう。今回で言うと、ボタンサービスのON/OFFについてはBuffer値が降りてくるのですが、Booleanで取得するために、

var buttonState = BitConverter.ToBoolean(data, 0);

で取得できました。

このあたりは、micro:bitのBLE情報ページ(Bluetooth Developer Studio – Profile Report)で、にらめっこしながら地道にやるしかないのですが、うまくデータがつながったときの喜びは格別です。

おかげさまで、以下のように押したとき:True 離したとき:False で取得できました。(HoloLensデバック中のコンソールキャプチャ)

image

実際に動かしてみます

HoloLensを起動してみます。

無事にCONNECT OK!という文字が表示されます。

まとめ

ようやく、HoloLensからmicro:bitを連携することができました。

実は、HoloLensからBLE操作する上で、ある程度、プログラミングによるカスタマイズができて、BLE通信も手軽に行えるデバイスを探していたのですが、いい感じにつながって良かったです。

ここからまた発展させていきます。

それでは、よき HoloLens & micro:bit Life を!