Reading Serial Data in Unity from Android Application

I am using Android SensoDuino ( Official site ) to send sensory data like Accelerometer, gyroscope, etc. using Bluetooth serial communication with Unity on a PC. I am using the following code in Unity to get data -

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);
    }
}

      

But I can't get any data. DataReceiveHandler

does not fire at all. I also tried to use ReadLine()

but it freezes Unity.

The format by which SensoDuino sends accelerometer data is

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

This is a continuous flow and may cause freezing in use ReadLine()

.

Please help me to read the data.

+4


source to share


3 answers


I found a solution. ReadLine()

is a blocking call, so I had to use it ReadByte()

to continuously read bytes and then convert the data. To reduce latency, the function ReadByte()

was called on a thread.

 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="";
            }
        }
    }
}

      



I did a pretty detailed tutorial here

+1


source


Problem: As answered here . This issue is due to the fact that Unity Mono does not have a complete implementation of the SerialPort class.

Simple solution: A simple solution could be to use this C # library which implements the MessageReceived event. I tested this on Windows and it worked without issue.

The library is available in NuGet. Then you can install some Unity plugin as "Nuget For Unity" from the resource store, and then install and use the library in your game.

Another solution: Another solution might be to implement yourself a class that reads data continuously on the serial port on another thread and then raises an event to notify when new data has arrived.



You can read this method from the previously mentioned library for inspiration.

Here is a copy of the library sequential reading 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();

      

Note: I know this question was posted a long time ago, but I am posting this answer here for future reference.

+1


source


Regarding why serial events are not handled in Unity, this can be answered here: fooobar.com/questions/2220566 / ...

0


source







All Articles