Unity と M5StickC で BLE通信(iOS/macOSエディタ
- Unity の iOSアプリや、mac エディタで、M5StcikC や M5Stack などと Bluetooth Low Energy で通信する事ができました
- M5StickC から Unity に通知したり、Unity から M5StickC に書き込む事で、相互にデータを送受信する事が可能です
- 下の動画↓では、M5StickC のボタンを押すと Unity 内の数字が増え、Unity 内のボタンを押すと M5StickC の数値が増える事を確認できます
unityとm5stickでBLE通信できた! pic.twitter.com/wMqooDpYM5
— ふじき (@fzkqi) August 2, 2021
サンプル
- リポジトリはこちらです↓
- Unity には BLE の機能がないので、Swift で Native Plugin を作って実装しています
- Examples/UnityExample/Assets/Plugins/UnityCoreBluetooth をプロジェクトにコピーする事で、導入する事が可能です
M5StickC の実装
- 基本的に、BLE周りの処理は M5StcikC は M5Stack と同じです
- スケッチはこちら
設定
- M5StickC や M5Stack は Peripheral として動かします
- Server 名は "M5StickC" や "M5Stack" などわかりやすい名前であれば何でも良いです
- SERVICE_UUID と CHARACTERISTIC_UUID は適当に決めます
- 今回は、1つの Characteristic で送受信します
#define SERVICE_UUID "FE55"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define SERVER_NAME "M5StickC"
Write のコールバック
- BLECharacteristic の getValue で書き込まれた値を取得します
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
M5.Lcd.setCursor(0, 160);
M5.Lcd.setTextSize(5);
M5.Lcd.println(value.c_str());
}
};
setup ble
- MyCallbacks をコールバックとして登録した Characteristic が追加された Service を作成し、Advertising を開始して、Unity から接続できるようにします
void setup() {
BLEDevice::init(SERVER_NAME);
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_WRITE_NR |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
}
値の通知
- ボタンが押されたら、Characteristic に値を設定し、通知します
void loop() {
if(M5.BtnB.wasPressed()) {
pCharacteristic->setValue(counter);
pCharacteristic->notify();
counter += 1;
}
M5.update();
}
Unity の実装
スキャンの開始
- CoreBluetoothManager のシングルトンのインスタンスを取得します
- poweredOn になることを確認して、スキャンを開始します
manager = CoreBluetoothManager.Shared;
manager.OnUpdateState((string state) =>
{
Debug.Log("state: " + state);
if (state != "poweredOn") return;
manager.StartScan();
});
接続したいデバイス名のデバイスを見つけたら接続する
manager.OnDiscoverPeripheral((CoreBluetoothPeripheral peripheral) =>
{
if (peripheral.name != "")
Debug.Log("discover peripheral name: " + peripheral.name);
if (peripheral.name != "M5StickC") return;
manager.StopScan();
manager.ConnectToPeripheral(peripheral);
});
デバイスに接続したらサービスを探す
manager.OnConnectPeripheral((CoreBluetoothPeripheral peripheral) =>
{
Debug.Log("connected peripheral name: " + peripheral.name);
peripheral.discoverServices();
});
対象の uuidの サービスが見つかったら characteristic を探す
manager.OnDiscoverService((CoreBluetoothService service) =>
{
Debug.Log("discover service uuid: " + service.uuid);
if (service.uuid != "FE55") return;
service.discoverCharacteristics();
});
usage が notify の characteristic が見つかったら通知を有効にする
- 通知を有効にすることで、M5StickC からデータを受け取ることが可能になります
manager.OnDiscoverCharacteristic((CoreBluetoothCharacteristic characteristic) =>
{
string uuid = characteristic.uuid;
string usage = characteristic.propertis[0];
Debug.Log("discover characteristic uuid: " + uuid + ", usage: " + usage);
if (usage != "notify") return;
characteristic.setNotifyValue(true);
});
characteristic から通知があったら、データを受け取る
- リアルタイムで受け取れるのですが、メインスレッド保証ではないです
- そこで、一度変数に格納して、Update関数などでUIに反映させます
manager.OnUpdateValue((CoreBluetoothCharacteristic characteristic, byte[] data) =>
{
this.value = data;
this.flag = true;
});
Manager の動作開始
- コールバックの設定が終わった後に、Start関数を呼ぶことで、Bluetooth機能を起動します
manager.Start();
書き込み
- 書き込み先の characteristic に書き込みます
- System.Text.Encoding.UTF8.GetBytes を使って、文字列からバイト配列を取得します
private int counter = 0;
public void Write()
{
characteristic.Write(System.Text.Encoding.UTF8.GetBytes($"{counter}"));
counter++;
}
おわりに
- M5StickC や M5Stack と Unity が外部機器無しで通信できるようになる BLE はとても便利です
- Swift で実装しているので、iOS実機、macエディタ向けの Native Plugin を同時に開発できました
- エディタでも動くので、動作検証が容易になります