質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
UDP

UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1726閲覧

unity UDP受信の値が更新されなくて困っています(pythonでは更新されます)

meJ15

総合スコア55

UDP

UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/07/04 01:54

前提・実現したいこと

unityでUDP受信をしたいのですが、
一回一回unityの再生ボタンを押さないと値が更新されません(再生ボタンを押したら値が更新される)
下の画像で1,2,3とあるところが、三角の再生ボタンを押して出力された値です
イメージ説明

python側ではデータの変化を受信できているのですが、unityでそれができません。

UDP通信に使うもとになるものはUDP通信を使っています。
これをfloat配列をおくるようにパケットを書き直しました。

その結果下のpythonプログラムでは常に正しい値が出力されていました

python

1import socket #通信用 2import struct 3address = ('', 40002) #通信を受け付けるIPアドレスと受信に使うポート番号の設定.127.0.0.1とするとPC内通信. 4 5udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #udpという名前のUDPソケット生成 6udp.bind(address) #udpというソケットにaddressを紐づける 7 8while True: #受信ループ 9 try: 10 rcv_byte = bytes() #バイトデータ受信用変数 11 rcv_byte, addr = udp.recvfrom(1024) #括弧内は最大バイト数設定 12 #msg = rcv_byte.decode() #バイトデータを文字列に変換 13 14 # bytes -> double(8byte浮動少数) x 3 15 res = struct.unpack('<fffffffffffffffff', rcv_byte) 16 print(res) 17 18 except KeyboardInterrupt:#強制終了を検知したらUDPソケットを閉じて終了 19 udp.close()

しかしunityのほうだと一回一回再生ボタンを押さなければ出力が更新されません(pythonとC#のUDP通信に違いがある?

該当のソースコード

受信用プログラム

C#

1using forudp; 2public class udp_rec : MonoBehaviour 3{ 4 private UDP commUDP = new UDP(); 5 //commUDP.init(int型の送信用ポート番号, int型の送信先ポート番号, int型の受信用ポート番号); 6 7 // Start is called before the first frame update 8 void Start() 9 { 10 commUDP.init(40005, 40002, 40002); 11 } 12 void Update() 13 { 14 15 commUDP.start_receive(); 16 var b = commUDP.rcv_float_arr; 17 for (int i = 0; i < 5; i++) 18 { 19 Debug.Log("[" + b[i * 3].ToString() + "," + b[i * 3 + 1] + "," + b[i * 3 + 2] + "]"); 20 } 21 }

下がUDP通信のもととなるものです。

using System.Text; using System.Net;//for UDP using System.Net.Sockets; //for UDP using System.Collections.Generic; using System; namespace forudp //namespaceは本体に合わせて要修正 { public class UDP { private UdpClient udpForSend; //送信用クライアント private string remoteHost = "localhost";//送信先のIPアドレス private int remotePort;//送信先のポート private UdpClient udpForReceive; //受信用クライアント public string rcvMsg = "ini";//受信メッセージ格納用 public float rcvMsg_xyz = 0; private System.Threading.Thread rcvThread; //受信用スレッド public List<float> rcv_float_arr = new List<float>(); //List<float> rcv_float_arr = IEnumerable.ToList(); public UDP() { } public bool init(int port_snd, int port_to, int port_rcv) //UDP設定(送受信用ポートを開きつつ受信用スレッドを生成) { try { udpForSend = new UdpClient(port_snd); //送信用ポート remotePort = port_to; //送信先ポート udpForReceive = new UdpClient(port_rcv); //受信用ポート rcvThread = new System.Threading.Thread(new System.Threading.ThreadStart(receive_xyz)); //受信スレッド生成 //rcvThread = new System.Threading.Thread(new System.Threading.ThreadStart(receive)); //受信スレッド生成 return true; } catch { return false; } } public void send(string sendMsg) //文字列を送信用ポートから送信先ポートに送信 { try { byte[] sendBytes = Encoding.ASCII.GetBytes(sendMsg); udpForSend.Send(sendBytes, sendBytes.Length, remoteHost, remotePort); } catch { } } public void send_xyz_arr(float[] sendMsg) //float配列を送信用ポートから送信先ポートに送信 { try { byte[] sendBytes = new byte[sendMsg.Length]; byte[] rv = new byte[4*sendBytes.Length]; for (int i = 0; i < sendMsg.Length; i++) { sendBytes = BitConverter.GetBytes(sendMsg[i]); System.Buffer.BlockCopy(sendBytes, 0, rv, i*4, sendBytes.Length); } udpForSend.Send(rv, rv.Length, remoteHost, remotePort); } catch { } } public void receive_xyz() //受信スレッドで実行される関数 { IPEndPoint remoteEP = null;//任意の送信元からのデータを受信 while (true) { try { byte[] rcvBytes = udpForReceive.Receive(ref remoteEP); for (int i = 0; i < rcvBytes.Length; i++) { var a = BitConverter.ToSingle(rcvBytes, i * 4); rcv_float_arr.Add(a); } } catch { } } } public void start_receive() //受信スレッド開始 { try { rcvThread.Start(); } catch { } } public void stop_receive() //受信スレッドを停止 { try { rcvThread.Interrupt(); } catch { } } public void end() //送受信用ポートを閉じつつ受信用スレッドも廃止 { try { udpForReceive.Close(); udpForSend.Close(); rcvThread.Abort(); } catch { } } } }

試したこと

最初unityで受け取ろうとしていたのですが、毎回再生ボタンを押さないといけないことから正しい値は届いていることがわかったのですが、念の為pythonで受信用プログラムを動かしました。
その結果正しい値が届いていました。

おそらくunityのUDP通信に問題があると思っているのですが何がおかしいのでしょうか
udp_recのほうのupdate関数で毎フレームごと
変化するUDPの値を受け取ることができると考えているのですが、それが更新されていない理由が検討もつきません
いろいろ試したのですが結局解決できませんでした
よろしくお願いします

補足情報(FW/ツールのバージョンなど)

unity 2018 3.14
windows10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

rcv_float_arrに受信データを逐次入れていると思うのですが、
今のコードだとそのListの先頭5個(正しくは5*3=15個)を毎フレーム表示しているだけになっています。
最新の結果が欲しいなら「Listの最後尾」を表示する形にしないといけないのでは思います。
(そもそもforは必要なんでしょうか?)

あと、毎フレームcommUDP.start_receive();してていいんでしょうか。
スレッド開始というコメントから見るに最初に1回やればいいように思うのですが。
(UDP通信について詳しくないので見当違いなら申し訳無いです、無視してください)

投稿2019/07/04 02:18

sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meJ15

2019/07/04 02:30

回答ありがとうございます!! どんどんデータ追加されていってることを忘れていました ``` public void receive_xyz() //受信スレッドで実行される関数 { IPEndPoint remoteEP = null;//任意の送信元からのデータを受信 while (true) { try { byte[] rcvBytes = udpForReceive.Receive(ref remoteEP); rcv_float_arr = new List<float>(); //Interlocked.Exchange(ref rcvMsg_xyz, BitConverter.ToSingle(rcvBytes, 4)); for (int i = 0; i < rcvBytes.Length; i++) { var a = BitConverter.ToSingle(rcvBytes, i * 4); rcv_float_arr.Add(a); } } catch { } } } ``` Listを受信するごとに初期化して追加するようにしました。 あとcommUDP.start_receive();はstart関数にいれるようにしました。ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問