ESP32からUnityへWiFiでデータ送信したい


理解のためのメモ

やること

ESP32からUnityへ、WiFiのアクセスポイント経由でデータを送信します。
UDPパケットを使います。
今回はESP32が送信、Unityが受信に一方向のみの通信です。

送信するデータ形式は符号あり2バイトのShort型が配列で10個並んだものです。
これを1バイトずつ送り、Unity側で受信後に2バイト数値に戻します。

Unity側ではインスペクターに受信データを表示します。

記事アップデート

https://qiita.com/Ninagawa_Izumi/items/59b56bcf7a9d13961a4f
送受信に対応したバージョンはこちらになります。

ポイント

  • ESP32側では2バイトを1バイトに変換するために共用体を利用
  • Unity側では近い処理をBitConverterで実施
  • Unity側の受信処理はスレッドを立てて実行

参考

今回の記事はほぼこちらのトレースであります。ありがたく勉強させていただきます。

ESP32用スクリプト

Arduino
#include <WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "SSID";//WiFiアクセスポイントのSSID
const char* password = "password";//WiFiアクセスポイントのパスワード
const char* client_address = "PCのIPを調べて入力";//送信相手のPCのIP
const int client_port = 22222;  //送り先のポート番号
const int server_port = 22224;  //ESP32のポート番号

WiFiUDP udp;

//送るデータのサイズ。データはショート型の符号付き2バイト、送信時は1バイトに変換。
static const int MSG_SIZE = 10;//送信データの数
static const int MSG_BUFF = MSG_SIZE * 2;//送信データのバイト数

//共用体の設定。共用体はたとえばデータをショートで格納し、バイト型として取り出せる
typedef union {
  short sval[MSG_SIZE];//ショート型
  uint8_t bval[MSG_BUFF];//符号なしバイト型
} UDPData;
UDPData s_upd_message_buf; //共用体のインスタンスを宣言

int count = 0;//送信変数用のカウント

void setup() {
  Serial.begin(115200);
  delay(500);//シリアル準備待ち用ディレイ
  //WiFi 初期化
  WiFi.disconnect(true, true);//WiFi接続をリセット
  Serial.println("Connecting to WiFi to : " + String(ssid));//接続先を表示
  delay(100);
  WiFi.begin(ssid, password);//Wifiに接続
  while ( WiFi.status() != WL_CONNECTED) {//https://www.arduino.cc/en/Reference/WiFiStatus 返り値一覧
    delay(100);//接続が完了するまでループで待つ
  }
  Serial.println("WiFi connected.");//WiFi接続完了通知
  Serial.print("WiFi connected. ESP32's IP address is : ");
  Serial.println(WiFi.localIP());//デバイスのIPアドレスの表示

  //UDP 開始
  udp.begin(server_port);
  delay(500);
}

//送信用の関数
void sendUDP() {
  String test = "";//表示用の変数

  udp.beginPacket(client_address, client_port);//UDPパケットの開始

  for (int i = 0; i < MSG_BUFF; i++) {
    udp.write(s_upd_message_buf.bval[i]);//1バイトずつ送信
    if (i % 2 == 0) {//表示用に送信データを共用体から2バイトずつ取得
      test += String(s_upd_message_buf.sval[i / 2]) + ", ";
    }
  }
  Serial.println("[SEND] " + test );//送信データ(short型)を表示

  udp.endPacket();//UDPパケットの終了
}


void loop() {

  //送信するデータを作成
  for (int i = 0; i < MSG_SIZE; i++) {
    s_upd_message_buf.sval[i] = (short)( i + count);
  }

  sendUDP();//UDPで送信

  count += 10;//データ作成用のカウントを追加
  if (count > 10000) {
    count = 0;
  }

  delay(500);
}

まずこちらのスケッチをESP32に書き込みます。
実行直後(リセット直後)に、シリアルモニタにESP32のIPアドレスを表示し、
その後は送信データを表示し続けます。

Unity用スクリプト

udp_receive_test.cs
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System;

public class udp_receive_test : MonoBehaviour
{
    int LOCAL_PORT = 22222;//受信に使うポートの番号
    static UdpClient udp;//UDPを使う準備
    Thread thread;//スレッドを使う準備

    const int datanum = 10;//受信するshort型データの個数
    static char[] c_buf = new char[datanum * 2];//データ受信用のchar型変数(1バイト)
    static short[] s_buf = new short[datanum];//データ格納用のshort型変数(2バイト)
    public int[] showdata = new int[10];//インスペクタ表示用


    void Start()
    {
        udp = new UdpClient(LOCAL_PORT);
        udp.Client.ReceiveTimeout = 1000;//UDP通信のタイムアウト設定
        thread = new Thread(new ThreadStart(ThreadMethod));//受信用スレッドを準備
        thread.Start();//受信用スレッドを開始
    }


    void Update()
    {
        //受信データをインスペクターに反映
        for (int i = 0; i < datanum; i++)
        {
            showdata[i] = s_buf[i];//受信データをpublic配列に転記
        }
    }


    void OnApplicationQuit()//アプリ終了時の処理
    {
        thread.Abort();
    }


    private static void ThreadMethod()//受信スレッド用の関数
    {
        while (true)
        {
            IPEndPoint remoteEP = null;
            byte[] data = udp.Receive(ref remoteEP);

            //パケットサイズをチェックし、受信データをUnityに反映
            if (data.Length == datanum * 2) // 
            {
                for (int i = 0; i < datanum; i++)
                {
                    s_buf[i] = BitConverter.ToInt16(data, i * 2);
                }
            }
        }
    }
}

使い方と実行

・Unityの新規プロジェクトを立ち上げます。
・アセットに新規スクリプトを作成してファイル名を「udp_receive_test」とし、上記のスクリプトをコピペします。
・ヒエラルキーウィンドウに空のオブジェクトを作成し、スクリプトをアタッチします。
・空のオブジェクトを選択し、インスペクターを表示します。
・スケッチが書き込まれたESP32を起動します。
・インスペクターにカウントアップする数値が表示されます。

おわりに

次回記事:ESP32とUnityをWiFi送受信で連携する
→逆方向の送受信にも対応しました。