本日は Unity と HoloLens の技術調査枠です。
UWPアプリでUDP受信を行う方法をまとめます。
いつも通り、まずは UnityEditor 上での確認からです。
UnityEditorでのUDP受信
UnityEditor上でのUDP受信には UdpClient クラスを利用します。
docs.microsoft.com
プロジェクトとシーンの準備
以下の記事を元にHoloLens(WindowsMR)プロジェクトを作成します。
bluebirdofoz.hatenablog.com
2019/3/11現在、MRTK 2017 の最新バージョンは 2017.4.3.0 です。
UdpClientを用いたサンプルコード
以下の処理を行うサンプルコードを作成しました。
1.ポート 4602 に受信する全てのUDPメッセージの非同期受信を開始する
2.UDPメッセージを受信すると、UnityEventで指定された関数に受信したバイト列を渡します。
・UDPMessageReceiver.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; // UnityEvent を利用するため Events を追加 using UnityEngine.Events; // 引数にByte列を受け取る UnityEvent<T0> の継承クラスを作成する // UDP受信したバイト列を引数として渡す // Inspector ビューに表示させるため、Serializable を設定する [System.Serializable] public class MyIntEvent : UnityEvent<byte[]> { } public class UDPMessageReceiver : MonoBehaviour { /// <summary> /// UDPメッセージ受信時実行処理 /// </summary> [SerializeField, Tooltip("UDPメッセージ受信時実行処理")] private MyIntEvent UDPReceiveEventUnityEvent; /// <summary> /// UDP受信ポート /// </summary> [SerializeField, Tooltip("UDP受信ポート")] private int UDPReceivePort = 4602; /// <summary> /// UDP受信データ /// </summary> private byte[] p_UDPReceivedData; /// <summary> /// UDP受信イベント検出フラグ /// </summary> private bool p_UDPReceivedFlg; /// <summary> /// 起動時処理 /// </summary> void Start() { // 検出フラグOFF p_UDPReceivedFlg = false; // 初期化処理 UDPClientReceiver_Init(); } /// <summary> /// 定期実行 /// </summary> void Update() { if (p_UDPReceivedFlg) { // UDP受信を検出すればUnityEvent実行 // 受信データを引数として渡す UDPReceiveEventUnityEvent.Invoke(p_UDPReceivedData); // 検出フラグをOFF p_UDPReceivedFlg = false; } } /// <summary> /// UDP受信時処理 /// </summary> private void UDPReceiveEvent(byte[] receiveData) { // 検出フラグONに変更する // UnityEventの実行はMainThreadで行う p_UDPReceivedFlg = true; // 受信データを記録する p_UDPReceivedData = receiveData; } /// <summary> /// UDP受信初期化 /// </summary> private void UDPClientReceiver_Init() { // UDP受信ポートに受信する全てのメッセージを取得する System.Net.IPEndPoint endPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Any, UDPReceivePort); // UDPクライアントインスタンスを初期化 System.Net.Sockets.UdpClient udpClient = new System.Net.Sockets.UdpClient(endPoint); // 非同期のデータ受信を開始する udpClient.BeginReceive(OnReceived, udpClient); } /// <summary> /// UDP受信時コールバック関数 /// </summary> private void OnReceived(System.IAsyncResult a_result) { // ステータスからUdpClientのインスタンスを取得する System.Net.Sockets.UdpClient udpClient = (System.Net.Sockets.UdpClient)a_result.AsyncState; // 受信データをバイト列として取得する System.Net.IPEndPoint endPoint = null; byte[] receiveBytes = udpClient.EndReceive(a_result, ref endPoint); // 受信データを受信時処理に引き渡す UDPReceiveEvent(receiveBytes); // 非同期受信を再開する udpClient.BeginReceive(OnReceived, udpClient); } }
UnityEvent で呼び出す処理として、バイト列を文字列に変換してテキスト表示する関数を作成します。
・ChangeText.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ChangeText : MonoBehaviour { /// <summary> /// 文字列を反映するテキストフィールド /// </summary> [SerializeField, Tooltip("文字列を反映するテキストフィールド")] private Text TargetTextField; /// <summary> /// byte列を文字列に変換してテキストフィールドに反映する /// </summary> /// <param name="message"></param> public void SetASCIIBytes(byte[] bytes) { // データを文字列に変換 string getMessage = System.Text.Encoding.ASCII.GetString(bytes); TargetTextField.text = getMessage; } }
作成した2つのスクリプトを Text オブジェクトにアタッチします。
UDPMessageReceiver.cs の UnityEvent に Text オブジェクト自身を指定します。
呼び出し関数として、テキスト表示の関数を設定します。
ChangeText.cs の TargetTextField にも Text オブジェクト自身を指定します。
動作確認用Pythonスクリプトの作成
動作確認用にUDPメッセージを送信するpythonスクリプトを作成します。
・UDPSend.py
# UDP用import import socket # UDP接続のための設定項目 holoaddress = '192.168.10.100' holoport = 4602 # 受信関数 def sendudp_message(msg): client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client.sendto(msg.encode(), (holoaddress, holoport)) print(msg) # 実行指定で呼び出されているかチェック if __name__ == "__main__": sendudp_message('UDPTestMessage')
UnityEditorでの動作確認
[再生]ボタンをクリックしてプロジェクトを動作確認します。
先ほど作成したpythonスクリプトを実行すると、送信したメッセージがテキストに表示されました。
次は UWP 向けコードを追加して HoloLens 上での動作確認を行います。
bluebirdofoz.hatenablog.com