【Unity】micro:bitとシリアル通信してみた
micro:bitを買ったので、Unityで遊んでみました。
参考ページ
分かりやすくまとまっていました。
ありがとうございます。
qiita.com
環境準備
私が試した環境はこちらです。
項目 | 内容 |
---|---|
OS | Windows10 |
Unity | 2018.4.14f1 (LTS) |
mbed Windows serial port driver のインストール
micro:bitをWindows10にUSBで接続して、下記のサイトからドライバをインストールします。
Windows10でmicro:bitとシリアル通信できるようになります。
Windows serial configuration - Handbook | Mbed
micro:bit のプログラミング
MakeCode で micro:bit のプログラム作成
micro:bitのサイトに行き、プログラミングしましょう。 makecode.microbit.org
今回は、micro:bitの傾きをシリアル通信で送るだけのシンプルなものになります。
micro:bit にプログラムのインストール
micro:bit のサイトから、作成したプログラミングの hexファイルをダウンロードします。
ダウンロードした hexファイルをエクスプローラのMICROBITにコピーしましょう。
これで作成したプログラムのインストールは完了です。
Tera Term で確認
Tera Term というソフトウェアを使って、micro:bit とシリアル通信ができているか試してみます。
インストールがまだの方はこちらから。
Tera Term のシリアルポートの設定
Tera Term でシリアルポート接続します。
下記のように設定しましょう。
後ほど使いますので、ポートのCOM番号は覚えておきましょう。
ポートのCOM番号は、環境によって変わります。
Tera Term で接続確認
シリアルポート接続すると、下記のように micro:bit から送られてきたメッセージが表示されます。
Unity のプログラミング
それでは、Unity でプログラミングしていきましょう。
Unity のプロジェクト作成
今回は、3Dのプロジェクトを作成します。
Build Settings で「Universal Windows Platform」に切り替える
Build Settings で Platform を「Universal Windows Platform」に切り替えます。
「Universal Windows Platform」が選択できない場合は、Unity Hub で「UWP Build Support (.NET)」モジュールを加えます。
MySerial.cs の作成
Assetsフォルダに、MySerial.cs スクリプトを新規作成します。
下記のようにプログラミングします。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using System.IO.Ports; using System.Threading; using System; public class MySerial : MonoBehaviour { public enum Baudrate { B_9600 = 9600, B_19200 = 19200, B_38400 = 38400, B_57600 = 57600, B_115200 = 115200, B_230400 = 230400, } public event ActionOnDataReceived; SerialPort _serialPort; Thread _thread; Queue _messages; string _data = ""; bool _isRunning; // Update is called once per frame void Update() { if (! _isRunning) { return; } lock(_messages) { while (_messages.Count > 0) { string msg = _messages.Dequeue(); if (OnDataReceived != null) { OnDataReceived(msg); } } } } public static string[] GetPortNames() { if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor) { return Directory.GetFiles(@"/dev/", "tty.usb*", SearchOption.AllDirectories); } else if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) { return SerialPort.GetPortNames(); } Debug.LogError("Unsupported platform"); return new string[0]; } public bool Open(string portName = null, Baudrate baudRate = Baudrate.B_9600) { if (string.IsNullOrEmpty(portName)) { var ports = GetPortNames(); if (Debug.isDebugBuild) { foreach (var port in ports) { Debug.LogFormat("port : {0}", port); } if (ports.Length == 0) { Debug.LogWarning("Serial port not found"); } } if (ports.Length == 0) { return false; } portName = ports[0]; } _messages = new Queue (); _serialPort = new SerialPort(portName, (int)baudRate, Parity.None, 8, StopBits.One); try { _serialPort.Open(); } catch (IOException e) { Debug.LogError(e); _serialPort.Dispose(); return false; } _isRunning = true; _thread = new Thread(Read); _thread.Start(); return true; } public void Close() { _isRunning = false; if (_thread != null && _thread.IsAlive) { _thread.Join(); } if (_serialPort != null && _serialPort.IsOpen) { _serialPort.Close(); _serialPort.Dispose(); } } void Read() { while (_isRunning && _serialPort != null && _serialPort.IsOpen) { try { byte b = (byte)_serialPort.ReadByte(); while (b != 255 && _isRunning) { char c = (char)b; if (c == '\n') { lock (_messages) { _messages.Enqueue(_data); _data = ""; } } else { _data += c; } b = (byte)_serialPort.ReadByte(); } } catch (Exception e) { Debug.LogWarning(e.Message); } Thread.Sleep(1); } } static MySerial _instance; public static MySerial Instance { get { if (_instance == null) { var go = new GameObject(typeof(MySerial).ToString()); DontDestroyOnLoad(go); _instance = go.AddComponent (); } return _instance; } } }
ObjRotation.cs の作成
Assetsフォルダに、ObjRotation.cs スクリプトを新規作成します。
下記のようにプログラミングします。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ObjRotation : MonoBehaviour { MySerial serial; float _pitch; float _roll; public string portNum; // Start is called before the first frame update void Start() { serial = MySerial.Instance; bool success = serial.Open(portNum, MySerial.Baudrate.B_115200); if (! success) { return; } serial.OnDataReceived += SerialCallBack; } private void OnDisable() { serial.Close(); serial.OnDataReceived -= SerialCallBack; } // Update is called once per frame void Update() { } void SerialCallBack(string m) { objRotation(m); } void objRotation(string message) { string[] a; a = message.Split("="[0]); if (a.Length != 2) { return; } int v = int.Parse(a[1]); switch (a[0]) { case "pitch": _pitch = v; break; case "roll": _roll = v; break; } Quaternion AddRot = Quaternion.identity; AddRot.eulerAngles = new Vector3(-_pitch, 0, -_roll); transform.rotation = AddRot; } }
テスト
シーンにキューブを配置し、ObjRotation.cs を AddComponent します。
Inspector ビューで、ObjRotationコンポーネントの Port Num にポートのCOM番号を設定します。
Playボタンを押して、動作確認しましょう。