2017-03-01 1 views
2

파일럿 네트워크를위한 간단한 시뮬레이션 환경을 신경 네트워크 기반의 파이썬 컨트롤러와 연결하려고합니다. 시뮬레이션 된 Unity 환경의 주인공은 자신의 경험에 기반한 행동을 배워야합니다.파일럿 시뮬레이션을 위해 파이썬 컨트롤러와 파이썬 컨트롤러를 연결하는

  1. 주인공은 환경을 스캔하여 데이터 구조에 저장합니다.
  2. 이 데이터 구조는 TCP를 통해 파이썬에서 실행중인 서버로 전송됩니다.
  3. 파이썬에서 복잡한 계산 (Unity에서받은 데이터를 기반으로)이 수행되고 결과 (작업)가 생성됩니다.
  4. 결과 (조치)가 TCP를 통해 Unity로 되돌려 보내집니다. 캐릭터는 결과에 해당하는 동작을 수행합니다.
  5. 단계 1-4는 무한대로 반복됩니다 (클라이언트 또는 서버가 중지하지 않는 한).

이 프로세스는 Unity가 "Ping"을 전송하는 TCP를 통해 보내는 핑퐁 (Ping-Pong) 메시지로 추상화 될 수 있습니다. 파이썬은 계산을 수행하고 시뮬레이션을 업데이트하는 유니티로 되돌아 오는 "Pong"을 생성합니다 그리고 다시 "Ping"을 만들어 파이썬으로 보냅니다 ...

저는 현재 장난감 프로젝트에서이 과정을 테스트하고 있습니다. 내가 실행 한 다음 서버를 시작하면

import socket 
import json 

host = 'localhost' 
port = 50000 
backlog = 5 
size = 1024 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind((host,port)) 
s.listen(backlog) 

while 1: 
    client, address = s.accept() 
    print "Client connected." 
    while 1: 
     data = client.recv(size) 
     if data == "ping": 
      print ("Unity Sent: " + str(data)) 
      client.send("pong") 
     else: 
      client.send("Bye!") 
      print ("Unity Sent Something Else: " + str(data)) 
      client.close() 
      break 

:

using UnityEngine; 
using System.Collections; 
using System; 
using System.IO; 
using System.Net.Sockets; 
using Newtonsoft.Json; 
using System.Threading; 



public class networkSocketSO : MonoBehaviour 
{ 
    public String host = "localhost"; 
    public Int32 port = 50000; 

    internal Boolean socket_ready = false; 
    internal String input_buffer = ""; 

    TcpClient tcp_socket; 
    NetworkStream net_stream; 

    StreamWriter socket_writer; 
    StreamReader socket_reader; 

    private void Start() 
    { 
     setupSocket(); 
    } 


    void Update() 
    { 
     string received_data = readSocket(); 
     switch (received_data) 
      { 
       case "pong": 
        Debug.Log("Python controller sent: " + (string)received_data); 
        writeSocket("ping"); 
        break; 
       default: 
        Debug.Log("Nothing received"); 
        break; 
     } 
    } 

    void OnApplicationQuit() 
    { 
     closeSocket(); 
    } 

    // Helper methods for: 
    //...setting up the communication 
    public void setupSocket() 
    { 
     try 
     { 
      tcp_socket = new TcpClient(host, port); 
      net_stream = tcp_socket.GetStream(); 
      socket_writer = new StreamWriter(net_stream); 
      socket_reader = new StreamReader(net_stream); 
      socket_ready = true; 
     } 
     catch (Exception e) 
     { 
      // Something went wrong 
      Debug.Log("Socket error: " + e); 
     } 
    } 

    //... writing to a socket... 
    public void writeSocket(string line) 
    { 
     if (!socket_ready) 
      return; 

     line = line + "\r\n"; 
     socket_writer.Write(line); 
     socket_writer.Flush(); 
    } 

    //... reading from a socket... 
    public String readSocket() 
    { 
     if (!socket_ready) 
      return ""; 

     if (net_stream.DataAvailable) 
      return socket_reader.ReadLine(); 

     return ""; 
    } 

    //... closing a socket... 
    public void closeSocket() 
    { 
     if (!socket_ready) 
      return; 

     socket_writer.Close(); 
     socket_reader.Close(); 
     tcp_socket.Close(); 
     socket_ready = false; 
    } 
} 

그리고 다음 코드를 파이썬 서버 : I는 다음과 같습니다 유니티 장면에서 메인 카메라에 장착 스크립트가 Unity 프로젝트 나는 이상한 일이 일어나게합니다. 즉, 파이썬 서버는 Unity 클라이언트가 보낸 "ping"문자열을 이해하지 못하는 것 같습니다. 또한, 파이썬 서버에서 "Pong"메시지를 받기 전에 유니티 시뮬레이션의 프레임을 업데이트하지 않기를 바랍니다.

나는 coroutines 또는 쓰레드를 사용하는 것과 비슷한 문제에 대한 해결책을 읽었지만 실제 "ping-pong-updateframe-ping-pong-updateframe ..."프로세스없이 다른 "clock"과 결과를 얻을 것을 두려워합니다.

아이디어가 있으십니까?

미리 감사드립니다.

P. 실제 메시지는 "핑 (Ping)"과 "퐁 (Pong)"이 아니라 적절한 Json 객체가 될 것이라는 점을 명심하십시오. 이것은 단지 단순화입니다.

EDIT : 먼저 파이썬 서버를 시작한 다음 유니티 시뮬레이션 (편집기에서)을 시작하십시오. 파이썬 콘솔에서 내가 얻을 :

는 "파이썬 유니티 (C 번호)를 통해 전송 된 문자열을 이해하지 못하는"나의 주장을 정당화
Client connected. 
Unity Sent Something Else: ping 

이 ... 유니티 콘솔에서

내가 얻을 :

enter image description here

+0

. 첫 번째 경우 : 파이썬 서버가 아무 것도받지 못합니까? 당신의 프로그램은 무엇을 인쇄합니까? – Dschoni

+0

현재 코드가 어떻게되는지 알려줄 수 있습니까? – Programmer

+0

방금 ​​파이썬 프린트와 Unity 콘솔 로그로 원래의 질문을 편집했습니다. 그리고 ... 응답 녀석을위한 감사합니다. – thecritter

답변

0

"파이썬은 Unity에서 보낸 문자열을 이해하지 못했습니다."라는 질문에 대한 해결책을 찾았습니다. 개행 시퀀스가 ​​문제를 일으킨 것 같습니다.원래 코드에서

line = line + "\r\n"; 

라인 :

은 그냥 제거. 이렇게하면 추가 이스케이프 문자가 문자열에 추가되지 않습니다. \r\n을 추가하면 파이썬 socket.recv()pingping\r\n을 비교하게되어 switch 문에서 항상 기본 대소 문자가 트리거됩니다.

다른 방법으로 주위에 (파이썬에서) 내가 streamWriter.ReadLine()pong 명확받을 수 있도록 (이스케이프 문자주의) 위해 유니티의 (C#을)에서 pong\n을 보낼 수 있습니다.

이제 상호 메시지 이해가 작동합니다. 그러나, 그것은 내 두 번째 문제를 해결하지 않습니다 - 탁구 업데이트 프레임 프로세스에 도달.

0

응답을 비동기로 설정해야합니다. 콜백을 사용할 수 있습니다. 귀하의 오류는 당신이 지속적으로 폴링을하고 있으며 소켓 사용 가능 호출이 항상 거짓 일 것입니다.

유니티에서이 코드를보십시오 :이 하나 개 이상의 질문은

using UnityEngine; 
using System.Collections; 
using System; 
using System.Net; 
using System.Net.Sockets; 

public class Client : MonoBehaviour { 

private Socket _clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 
private byte[] _recieveBuffer = new byte[8142]; 

void Start() { 
    SetupServer(); 
} 

void Update() { 

} 

void OnApplicationQuit() 
{ 
    _clientSocket.Close(); 
} 

private void SetupServer() 
{ 
    try 
    { 
     _clientSocket.Connect(new IPEndPoint(IPAddress.Loopback,50003)); 
    } 
    catch(SocketException ex) 
    { 
     Debug.Log(ex.Message); 
    } 

    _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null); 

} 


private void ReceiveCallback(IAsyncResult AR) 
{ 
    //Check how much bytes are recieved and call EndRecieve to finalize handshake 
    int recieved = _clientSocket.EndReceive(AR); 

    if(recieved <= 0) 
     return; 

    //Copy the recieved data into new buffer , to avoid null bytes 
    byte[] recData = new byte[recieved]; 
    Buffer.BlockCopy(_recieveBuffer,0,recData,0,recieved); 

    //Process data here the way you want , all your bytes will be stored in recData 
    Debug.Log(System.Text.Encoding.Default.GetString(_recieveBuffer)); 
    SendData (System.Text.Encoding.Default.GetBytes ("ping")); 

    //Start receiving again 
    _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null); 
} 

private void SendData(byte[] data) 
{ 
    SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs(); 
    socketAsyncData.SetBuffer(data,0,data.Length); 
    _clientSocket.SendAsync(socketAsyncData); 
} 

}

관련 문제