#やること
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側の受信処理はスレッドを立てて実行
#参考
https://github.com/devemin/UDPesp32unity
今回の記事はほぼこちらのトレースであります。ありがたく勉強させていただきます。
#ESP32用スクリプト
#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用スクリプト
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送受信で連携する
→逆方向の送受信にも対応しました。