KeiganMotor を HoloLens2 から Bluetooth でつないで LED の色を操作するメモ

KeiganMotor を HoloLens2 から Bluetooth でつないで LED の色を操作するメモです。

この記事は 2022年 ゆるくすすめる ( ワンフットシーバス ) | GWアドベントカレンダー の 5/8 10日目の記事でもあります。

こちらで登壇したネタのナレッジです

XRミーティング 20220316 に登壇してきました

2022/03 でXRミーティングに登壇してきたときの KeiganMotor を HoloLens2 から Bluetooth でつないで LED の色を操作するナレッジです。

KeiganMotor と HoloLens2 の接続

image

KeiganMotor に電源を入れておきます。

image

設定 > デバイス から、

image

Bluetooth とその他のデバイス > デバイスの追加 > Bluetooth とその他のデバイスを追加する を選択し、

image

しばらく待っていると KM-1U ではじまるデバイスが出てくるので、

image

クリックして接続をしてペアリングを完了しておきます。

実際に動したソースコード

image

HoloLens 2 側では Bluetooth を Package.appxmanifest の Capabilities で ON にしておきましょう。(よく忘れてハマる)

ソースコードはこちらです。

using UnityEngine;
using System;

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


public class KeiganBLEOnlyLED : MonoBehaviour
{
    // KeiganMotor の Service UUID
    private string KEIGAN_MOTOR_SERVICE_UUID = "f140ea35-8936-4d35-a0ed-dfcd795baa8c";

    // LED の Characteristic UUID
    private string CHARCTERISTIC_LED_UUID = "f1400003-8936-4d35-a0ed-dfcd795baa8c";

#if WINDOWS_UWP
    // HoloLens 専用の C# 処理
    // BLE 系の準備
    GattCharacteristicsResult characteristicsLED;

    GattCharacteristicsResult characteristicsMotorControl;

    DeviceWatcher deviceWatcher;
#endif

    void Start()
    {
        Invoke("Launch", 0.5f);
    }

    void Update()
    {
        
    }

    void Launch()
    {
        Debug.LogFormat("KeiganBLE Launched!");

        // 接続開始
        ConnectKeiganMotor();
    }

    void ConnectKeiganMotor()
    {
        // Debug.LogFormat("ConnectKeiganMotor KEIGAN_MOTOR_SERVICE_UUID:{0}", KEIGAN_MOTOR_SERVICE_UUID);

#if WINDOWS_UWP
        Debug.LogFormat("ConnectKeiganMotor connecting... 1.0.3");

        // WatchStart();

        Task.Run(async () =>
        {
            // GattDeviceService で KeiganMotor の Service UUID に狙いを定める
            var selectorKeigan = GattDeviceService.GetDeviceSelectorFromUuid(new Guid(KEIGAN_MOTOR_SERVICE_UUID));

            // DeviceInformation で BLE でつながっているデバイスの全捜索をかける
            var collectionKeigan = await DeviceInformation.FindAllAsync(selectorKeigan);

            UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                Debug.LogFormat("deviceWatcher wait!");
            }, true);

            // KeiganMotor の Service UUIDと一致したものからループでつなげる
            foreach (DeviceInformation infoKeigan in collectionKeigan)
            {
                UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                    Debug.LogFormat("infoKeigan Name={0} IsEnabled={1} id={2}", infoKeigan.Name, infoKeigan.IsEnabled, infoKeigan.Id);
                    Debug.LogFormat("infoKeigan Kind={0} Pairing={1}", infoKeigan.Kind, infoKeigan.Pairing);
                }, true);

                // Keigan への接続
                GattDeviceService serviceKeigan = await GattDeviceService.FromIdAsync(infoKeigan.Id);

                UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                    // serviceKeigan に関するメッセージを出力
                    Debug.LogFormat("serviceKeigan {0}", serviceKeigan);
                }, true);

                // LED Characteristic 取得
                characteristicsLED = await serviceKeigan.GetCharacteristicsForUuidAsync(new Guid(CHARCTERISTIC_LED_UUID));

                // LED Characteristic 取得成功時
                if (characteristicsLED.Status == GattCommunicationStatus.Success)
                {
                    // OK
                    UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                        Debug.LogFormat("characteristicsLED Success!");
                        // Debug.LogFormat("characteristicsLED.Characteristics.Count {0}", characteristicsLED.Characteristics.Count);
                    }, true);

                    // 初回は青く光る
                    WriteDataKeiganMotorLED(1, 0, 0, 255);
                }
            }
        });


#endif


    }

    // LED を実際に光らせる処理
    // RGB で指定できる
    public void WriteDataKeiganMotorLED(int mode, int r, int g, int b)
    {
#if WINDOWS_UWP
        Task.Run(async () =>
        {
            UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                Debug.LogFormat("WriteDataKeiganMotorLED mode {0} red {1} green {2} blue {3}", mode, r, g, b);
            }, true);

            byte[] comPress = { Convert.ToByte(mode), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b) };
            GattCommunicationStatus status = await characteristicsLED.Characteristics[0].WriteValueAsync(comPress.AsBuffer());

            UnityEngine.WSA.Application.InvokeOnAppThread(() => {
                Debug.LogFormat("GattCommunicationStatus {0}", status.ToString());
            }, true);
        });
#endif
    }
}

このコードで KeiganBLEOnlyLED という GameObject に以下の KeiganBLEOnlyLED.cs を割り当てていると、接続成功後に LED が青く光ります。

image

とくにデータを送る部分は UWP(C#)でSwitchBot(BLEデバイス)を操作する 記事の WriteValueAsync あたりを参考にさせていただきました。