从Android应用程序读取Unity中的串行数据

时间:2015-08-05 07:59:20

标签: c# android unity3d bluetooth serial-port

我正在使用Android的SensoDuinoOfficial website)应用程序,使用蓝牙串行通信向PC中的Unity发送感应数据,如Accelerometer,gyro等。我在Unity中使用以下代码来接收数据 -

using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;

public class COM : MonoBehaviour {

    public SerialPort sp;
    public float data;

    void Start () {
        sp = new SerialPort("COM3", 9600,Parity.None, 8, StopBits.One);
        Debug.Log ("Connection started");

        if (sp != null) 
        {
            if (sp.IsOpen) 
            {
                sp.Close();
                Debug.Log ("Closing port, because it was already open!");
            }
            else 
            {
                sp.Open();  // opens the connection
                // sets the timeout value before reporting error
                sp.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
                Debug.Log("Port Opened!");
            }
        }
        else 
        {
            if (sp.IsOpen)
            {
                print("Port is already open");
            }
            else 
            {
                print("Port == null");
            }
        }

        Debug.Log ("Open Connection finished running");
    }

    void Update () { 
        data = float.Parse( sp.ReadTo ("\r") ) ;
        print ("data = " + data);
    }

    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPort spl = (SerialPort)sender;
        data = float.Parse( spl.ReadTo ("\r") ) ;
        Debug.Log(data.ToString());
        print ("data = " + data);
    }
}

但我无法收到任何数据。 DataReceiveHandler根本没有开火。我也尝试使用ReadLine(),但它冻结了Unity。

SensoDuino发送Accelerometer数据的格式是

  

1,104,0.54437256,-0.2632141,9.826126

     

1,105,0.56111145,-0.279953,9.8524475

     

1,106,0.54556274,-0.2632141,9.833298

     

1,107,0.5515442,-0.26081848,9.841675

     

1,108,0.5312042,-0.2644043,9.867996

这是一个连续的流,可能是使用ReadLine()时冻结的原因。

请帮我阅读数据。

3 个答案:

答案 0 :(得分:1)

我找到了解决方案。 ReadLine()是一个阻塞调用,所以我不得不使用ReadByte()来连续读取字节并稍后转换数据。为了减少延迟,在一个线程中调用ReadByte()函数。

 void recData() {
    if ((sp != null) && (sp.IsOpen)) {
        byte tmp;
        string data = "";
        string avalues="";
        tmp = (byte) sp.ReadByte();
        while(tmp !=255) {
            data+=((char)tmp);
            tmp = (byte) sp.ReadByte();
            if((tmp=='>') && (data.Length > 30)){
                avalues = data;
                parseValues(avalues);
                data="";
            }
        }
    }
}

我制作了一个非常详细的教程here

答案 1 :(得分:1)

问题:answered here。这个问题是因为Unity的Mono没有完全实现SerialPort类。

简单的解决方案: 一个简单的解决方案是使用this C# library来实现MessageReceived事件。我已经在Windows上对其进行了测试,并且可以正常工作。

该库在 NuGet 中可用。然后,您可以从资产商店中安装一些Unity插件,作为“ Nuget For Unity ”,然后在游戏中安装和使用该库。

另一种解决方案: 另一个解决方案是自己实现一个类,该类从另一个线程中的串行端口中永久读取数据,然后调用一个事件以通知何时有新数据可用。

您可以read this method从前面提到的库中获得启发。

以下是该库的串行读取方法的副本:

public delegate void MessageReceivedHandler(byte[] message);
public event MessageReceivedHandler MessageReceived;
void ReaderTask ()
{
    // Will ask for data while connected to the serial port
    while (IsConnected)
    {
        int messageLength = serialPort.BytesToRead;
        if (msglen > 0)
        {
            byte[] message = new byte[messageLength];
            int offset = 0;
            int count = messageLength - offset;
            // Ask data for ever if there is no data yet in the serial port
            while (serialPort.Read(message, offset, count) <= 0)
                ; // noop

            // Check if there are subscribed listeners
            if (MessageReceived != null)
            {
                MessageReceived(message);
            }
        }
        else
        {
            Thread.Sleep(100);
        }
    }
}

// In the main thread
// Start the Reader task
reader = new Thread(ReaderTask);
reader.Start();

注意:我知道这个问题是很久以前发布的,但是我在这里发布了这个答案以供将来参考。

答案 2 :(得分:0)

关于为什么在Unity中没有处理串行事件的问题,这可以在这里得到解答:https://stackoverflow.com/a/35413397/5386234