dreamdrive が 2022年09月25日12時55分24秒 に編集
初版
タイトルの変更
SPRESENSE Wi-Fi Add-onボード iS110BでUnityとTCP通信テスト
タグの変更
SPRESENSE
Unity
TCP
メイン画像の変更
記事種類の変更
セットアップや使用方法
ライセンスの変更
(MIT) The MIT License
本文の変更
Spresenseのマルチコアを活かして、非同期でコアごとに制御を分けたシステムを作りたいのですが、この記事は、その要素技術として、SPRESENSE Wi-Fi Add-onボード iS110Bを使用して、UnityとTCPで通信する忘備録です。 ## 用意するもの - Spresense - 1個 - Spresense拡張ボード - 1個 - SPRESENSE Wi-Fi Add-onボード iS110B - 1個 - Unity 2020.3.XXf1 とそれが動くPC - WiFi環境 ## Spresense 側のプログラム https://github.com/jittermaster/GS2200-WiFi のサンプル「TCPClient」のApp_TCPClient_Test関数を下記の通り書き換えます。 config.hは、適宜WiFi環境に合わせて設定してください ``` /*---------------------------------------------------------------------------* App_TCPClient_Test --------------------------------------------------------------------------- Description: Connect TCP server, send data on and on Show the received data from the TCP server ---------------------------------------------------------------------------*/ void App_TCPClient_Test(void) { ATCMD_RESP_E resp; char server_cid = 0; bool served = false; ATCMD_NetworkStatus networkStatus; uint32_t timer = 0; bool transmit_allow = true; // このフラグが立っている時だけ送って良いよ AtCmd_Init(); App_InitModule(); App_ConnectAP(); while (1) { if (!served) { resp = ATCMD_RESP_UNMATCH; // Start a TCP client ConsoleLog( "Start TCP Client"); resp = AtCmd_NCTCP( (char *)TCPSRVR_IP, (char *)TCPSRVR_PORT, &server_cid); if (resp != ATCMD_RESP_OK) { ConsoleLog( "No Connect!" ); delay(2000); continue; } if (server_cid == ATCMD_INVALID_CID) { ConsoleLog( "No CID!" ); delay(2000); continue; } do { resp = AtCmd_NSTAT(&networkStatus); } while (ATCMD_RESP_OK != resp); ConsoleLog( "Connected" ); ConsolePrintf("IP: %d.%d.%d.%d\r\n", networkStatus.addr.ipv4[0], networkStatus.addr.ipv4[1], networkStatus.addr.ipv4[2], networkStatus.addr.ipv4[3]); served = true; } else { ConsoleLog( "Start to send TCP Data"); // Prepare for the next chunck of incoming data WiFi_InitESCBuffer(); // Start the infinite loop to send the data while ( 1 ) { // 送信許可フラグが立っていない時は送信しない if (transmit_allow) { transmit_allow = false; // 送信したら送信許可フラグを倒す if ( ATCMD_RESP_OK != AtCmd_SendBulkData( server_cid, TCP_Data, strlen(TCP_Data) ) ) { // Data is not sent, we need to re-send the data delay(10); transmit_allow = true; // ただし、送信失敗した際は、次回再度送信するように送信許可フラグを戻す } } while ( Get_GPIO37Status() ) { resp = AtCmd_RecvResponse(); if ( ATCMD_RESP_BULK_DATA_RX == resp ) { if ( Check_CID( server_cid ) ) { ConsolePrintf( "Receive %d byte:%s \r\n", ESCBufferCnt - 1, ESCBuffer + 1 ); // 受信した際に送信許可フラグを立てる transmit_allow = true; } WiFi_InitESCBuffer(); } } if ( msDelta( timer ) > 100 ) { timer = millis(); led_effect(); } } } } } ``` ## Unityのサーバー側プログラム 下記のソースコードを適当なゲームオブジェクトにアタッチします。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; public class tcp : MonoBehaviour { //================================================================================ // 変数 //================================================================================ // この IP アドレスとポート番号はクライアント側と統一すること public string m_ipAddress = "127.0.0.1"; public int m_port = 10001; private TcpListener m_tcpListener; private TcpClient m_tcpClient; private NetworkStream m_networkStream; private string m_message = string.Empty; // クライアントから受信した文字列 //================================================================================ // 関数 //================================================================================ /// <summary> /// 初期化する時に呼び出されます /// </summary> private void Awake() { // クライアントから文字列を受信する処理を非同期で実行します // 非同期で実行しないと接続が終了するまで受信した文字列を UI に表示できません Task.Run(() => OnProcess()); } /// <summary> /// クライアント側から通信を監視し続けます /// </summary> private void OnProcess() { byte[] TCP_Data = System.Text.Encoding.ASCII.GetBytes("Unity to SPRESENSE"); var ipAddress = IPAddress.Parse(m_ipAddress); m_tcpListener = new TcpListener(ipAddress, m_port); m_tcpListener.Start(); Debug.Log("待機中"); // クライアントからの接続を待機します m_tcpClient = m_tcpListener.AcceptTcpClient(); Debug.Log("接続完了"); // クライアントからの接続が完了したので // クライアントから文字列が送信されるのを待機します m_networkStream = m_tcpClient.GetStream(); while (true) { var buffer = new byte[256]; var count = m_networkStream.Read(buffer, 0, buffer.Length); // クライアントからの接続が切断された場合は if (count == 0) { Debug.Log("切断"); // 通信に使用したインスタンスを破棄して OnDestroy(); // 再度クライアントからの接続を待機します Task.Run(() => OnProcess()); break; } else { // クライアントから文字列を受信した場合はログに出力します var message = Encoding.UTF8.GetString(buffer, 0, count); Debug.LogFormat("受信成功:{0}", message); // データ送信(応答) m_networkStream.Write(TCP_Data, 0, TCP_Data.Length); } } } /// <summary> /// 破棄する時に呼び出されます /// </summary> private void OnDestroy() { // 通信に使用したインスタンスを破棄します m_networkStream?.Dispose(); m_tcpClient?.Dispose(); m_tcpListener?.Stop(); } } ``` ## 実行結果 SPRESENSEからのデータに対して、Unityが応答していることが確認できます。 ![SPRESENSEからのデータを受け付けたら応答を返す様子](https://camo.elchika.com/6c493dcb2fce5a03b55432a98be2ca94382b4687/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f65663139313932372d333632372d346437632d623934342d6334393661306531343437312f64643830623062322d633666652d346232332d383235332d393065373362633437613066/) ## 謝辞 UnityでのTCPサーバーはこちらの記事を参考にさせていただきました。 > 【Unity】Unity 同士で TCP 通信を行う > https://baba-s.hatenablog.com/entry/2020/09/08/090000