【Unity】ESP32マイコンでBluetoothでUnityと接続するコントローラを作る

はじめに

この記事はカヤックUnity アドベントカレンダー2018の5日目の記事になります。

こんにちは!デバイスエンジニアの宮野です。

今日はBluetooth内蔵のマイコンボードESP32とUnityを接続してシンプルなコントローラを作成します。 Bluetooth Serial通信でUnityにボタン情報を送り、Unity側でその情報をもとに画面上のオブジェクトを操作します。

f:id:miyano-yuji:20181204010254g:plain

環境と用意するもの

Arduino IDEとESP32のセットアップ

1.Arduino IDEでESP32が使えるようにする

Arduino IDEを立ち上げ、ファイル > 環境設定を開きます。 追加のボードマネージャのURL:https://dl.espressif.com/dl/package_esp32_index.jsonを入力してOKを押します。

f:id:miyano-yuji:20181204005619p:plain

ツール > ボード > ボードマネージャを開きます。 検索窓にesp32と入力し、esp32 by Espressif Systemsをインストールします。

f:id:miyano-yuji:20181204005637p:plain

2. テストプログラムの書き込み

arduino-esp32/SerialToSerialBT.ino at master · espressif/arduino-esp32ESP32でserial bluetooth接続 - Qiitaを参考に以下のプログラムを打ち込みます。

ファイル > スケッチ例 > BluetoothSerial > SerialToSerialBTからもサンプルプログラムを参照できます。

f:id:miyano-yuji:20181204011354p:plain

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

void setup() {
  SerialBT.begin("ESP32"); //Bluetooth device name
}

void loop() {
  SerialBT.println("Hello");
  delay(1000);
}

ESP32をUSBポートに接続して、ツール > ボード:ESP32 Dev Moduleを選択し、シリアルポートでESP32が接続されているポートを選びます。 その他の設定は変更していません。

f:id:miyano-yuji:20181204005708p:plain

スケッチ > マイコンボードに書き込むを押し、プログラムを書き込みます。 書き込みが完了すると、IDEの下のほうにボードへの書き込みが完了しました。というメッセージが表示されます。

3. テストプログラムの確認

Windowsメニューの設定からデバイスを選択しBluetoothまたはその他のデバイスを追加するを押します。

f:id:miyano-yuji:20181204005728p:plain

デバイスを追加するBluetoothを選択します。

f:id:miyano-yuji:20181204005743p:plain

先ほど書き込んだプログラムで指定したデバイス名(今回は)ESP32を選択してペアリングします。

f:id:miyano-yuji:20181204010010p:plainf:id:miyano-yuji:20181204010031p:plain

デバイスマネージャーを開くとCOM4COM5が増えています。

f:id:miyano-yuji:20181204010059p:plain

Arduino IDEに戻りツール > シリアルポートCOM4を選択し、シリアルモニタを開きます。 左下のbaudrate115200bpsにすると、1秒おきにHelloの文字が表示されます。

f:id:miyano-yuji:20181204010121p:plain

うまく表示されない場合は別のポートを選択して再度試してください。

Unityで受信する

新しいプロジェクトを作成し、SerialPort または Uniduino を使った Unity と Arduino を連携させる方法調べてみた - 凹みTipsを元にシリアル通信を行うプログラムを作成します。

SerialHanderはSerialHandler.csをそのまま利用します。オブジェクトにアタッチしてInspectorで上で指定したポート名を入力してください。

シリアル通信で受け取った情報をConsoleに表示するプログラムは上記サイトのRotateByAccelerometer.csを元に作成しました。こちらもオブジェクトにアタッチして、上のSerialHandlerがアタッチされたオブジェクトをInspectorで紐づけてください。 実行するとConsoleにHelloの文字が表示されます。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ConsoleOutput : MonoBehaviour
{
    public SerialHandler serialHandler;

    void Start()
    {
        serialHandler.OnDataReceived += OnDataReceived;
    }

    void OnDataReceived(string message)
    {
        var data = message.Split(
            new string[]{"\n"}, System.StringSplitOptions.None);
        if (data.Length != 1) return;
        Debug.Log(data[0]);
    }
}

ESP32にボタンを接続する

ユニバーサル基板にタクトスイッチを配置して、タクトスイッチを押すとGNDに接続されるように配置します。 今回は以下のようにピンを割り当てました。

ボタン名 ピン番号
左ボタン 33
上ボタン 25
下ボタン 26
右ボタン 27
Aボタン 14
Bボタン 12

回路図は割愛しますが、こんな感じになりました(配線を間違えたのでピンソケットがはみ出てます)。

f:id:miyano-yuji:20181204010215j:plainf:id:miyano-yuji:20181204010154j:plain

ESP32にボタン用のプログラムを書き込む

先ほどのHelloの代わりに、押されたボタンに応じてUpDownRightLeftABの文字を送るプログラムを書きます。

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Pin Assingment
const int buttonLeft = 33; 
const int buttonUp = 25; 
const int buttonDown = 26; 
const int buttonRight = 27; 
const int buttonA = 14; 
const int buttonB = 12; 

BluetoothSerial SerialBT;

void setup() {
  SerialBT.begin("ESP32"); //Bluetooth device name
  
  pinMode(buttonLeft, INPUT_PULLUP);
  pinMode(buttonUp, INPUT_PULLUP);
  pinMode(buttonDown, INPUT_PULLUP);
  pinMode(buttonRight, INPUT_PULLUP);
  pinMode(buttonA, INPUT_PULLUP);
  pinMode(buttonB, INPUT_PULLUP);
}

void loop() {
  if(digitalRead(buttonLeft) == LOW){
    SerialBT.println("Left");
  }
  else if(digitalRead(buttonUp) == LOW){
    SerialBT.println("Up");
  }
  else if(digitalRead(buttonDown) == LOW){
    SerialBT.println("Down");
  }
  else if(digitalRead(buttonRight) == LOW){
    SerialBT.println("Right");
  }
  else if(digitalRead(buttonA) == LOW){
    SerialBT.println("A");
  }
  else if(digitalRead(buttonB) == LOW){
    SerialBT.println("B");
  }
  else {
    SerialBT.println();
  }
  delay(100);
}

ボタン情報に応じたUnityプログラムを作成する

ESP32から送られてくる文字をもとに、画面上のオブジェクトを動かすプログラムを書いてCubeにアタッチします。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObjectController : MonoBehaviour
{
    public SerialHandler serialHandler;
    public float delta = 0.01f;
    private float deltaPos;
    private    Vector3 pos;

    void Start()
    {
        serialHandler.OnDataReceived += OnDataReceived;
    }

    void OnDataReceived(string message)
    {
        Vector3 pos = transform.localPosition;
        var data = message.Split(
            new string[]{"\n"}, System.StringSplitOptions.None);
        Debug.Log(message);
        
        switch (data[0]){
            case "Up":
                deltaPos = delta * 1;
                pos.y += deltaPos;
                break;
            case "Down":
                deltaPos = delta * -1;
                pos.y += deltaPos;
                break;
            case "Left":
                deltaPos = delta * -1;
                pos.x += deltaPos;
                break;
            case "Right":
                deltaPos = delta * 1;
                pos.x += deltaPos;
                break;
            default:
                break;
        }
        transform.localPosition = pos;
    }  
}

動かしてみるとこんな感じです。

f:id:miyano-yuji:20181204010254g:plain

ESP32につながっているUSBをPCから抜いてモバイルバッテリーにすると、より無線感が味わえます。 今回A、Bボタンは使いませんでしたが、色を変えるなりジャンプさせるなり、好きに使ってください。

ユニバーサル基板ではなく基板を設計して切削や外注で作ったり、外装を3Dプリンタで作ったりすれば、より実用的になると思います。ボタンも用途に応じて増やしたり減らしたり、ボタンではなく別のセンサを使ったりと必要に応じてカスタマイズしてください!

最後に

カヤックではゲームだけでなくインタラクティブサイネージやAR/VR案件でもUnityをよく使っています。私のようなデバイスエンジニアもUnityを使うことは多いです。 興味のある人は採用ページをのぞいてみてください。

明日は、中山大輔による「動的に枠を描く話」です。