Serial Ports - Alternative for reading data from serial ports into Unity

Hello, I am here to present an alternative to using serial ports on Unity, this is only an approximation to the final resolution of this problem. I hope to be helpful.

First apologize for my bad English.

Background:

Some time ago I faced with the problem of handling serial ports within unity, fails to read the data properly but I can send them. Researching I realized that the problem arises with an event data management, this enables notify the system when data is received, if we try to read otherwise errors can occur because our algorithm can not be synchronized with the data sent from the device serial port, for example the famous “the Operation has timeout”. this event is called “SerialDataReceivedEventHandler” ( Represents the method that will handle the data received event of a Serial Port object.)

This method does not seem to be implemented in unity by what I have seen in many forums

NOTE: I’m using a PIC serial board but I guess this works also with Arduino both use the standard UART (universal asynchronous receiver/transmitter) for serial communications.

ALTERNATIVES

Well now I want to share a good solution I found, below I submit a temporary alternative solution as a developer I want to create my own.

One day I read about a plugin for unity ,particularly one external DLL. I used the shortest route and downloaded a commercial serial component called “Component Activexperts Serial Port”, you can try it for 30 days.

The component made me realize I can make a correct handling of serial ports through of dynamic link libraries (DLL) and is probably the best way.

that’s why I want to create my own DLL to handle serial ports, I have been researching and apparently I have to learn c ++ and Win32.

Well, I would like to show you an example of how to use this component serial port if anyone can get the paid version.

First we download the serial component of this link: ActiveXperts Software - download page
(We installed it as a typical program)

Once installed we go to the installation folder C: \ Program Files \ ActiveXperts \ Serial Port Component \ Samples

In this location will find examples, we go to the “Visual CSharp.NET” folder and look for into any project the dll file “Interop.AxSerial” Visual inside the folder “Any CPU” and copy this file.

Paste the file in your project and after at the following location: “C: \ Program Files \ Unity \ Editor”.

NOTE: Currently I’m using Unity 5 free version (Last Update)

Now we need to install a free package that allows you to use coroutines as asynchronous thread named Thread Ninja - Multithread Coroutine
Link: The Best Assets for Game Making | Unity Asset Store

The idea is not to use the update method as this will down the performance so it is best to use a method that act as an update method that runs every so often (seconds), not every frame so it is very fast. So we update data received from the port ,for example, every 1 second .

And when we have the package installed and pasting dll file in its respective location, create a class (in the same location Interop.AxSerial) location such as:

(This is an algorithm that requires a lot of improvement)

using UnityEngine;
    using System.Collections;
    using AxSerial;//Import the DLL external class
    using System;
    using System.IO;
    using System.Threading;
    using CielaSpike;//Import the custom thread for unity


public SerialController : MonoBehaviour {

            ComPort objComport;//Serial port object

            //string of data received for the serial port
            string datareceived="";

            /*
            *method that initializes the serial port
            */
            void initComponents()
            {
                    try
                    {
                        objComport = new ComPort();
                        objComport.Device="COM7";//this specifies own port
                        objComport.BaudRate = 9600;
                        objComport.Open();//Open the port
                    }
                    catch(Exception ex)
                    {
                        Debug.Log(ex.GetBaseException());
                    }
            }

            void Start()
            {
                    initComponents();
                    if (objComport.IsOpened)
                    {
                        StartCoroutine("manage_data");//Start coroutine for manage the data
                        Debug.Log("Port opened");
                    }
                    else
                    {
                        Debug.Log("Could not  to open the port");

                    }
            }

            void OnDestroy
            {
              try
              {
                        objComport.Close();
              }
              catch(Exception ex)
              {
                    Debug.Log(ex.GetBaseException());
              }

            }
            /*
            *  asynchronous coroutine,
            *  the idea is that the method of getting data is executing every so often, for example each one second.,
            *  not for each frame like the Update method because this would down the performance
            *
            */
            IEnumerator manage_data()
            {
                    this.StartCoroutineAsync(Blocking(), out task);
                    yield return StartCoroutine(task.Wait());
            }

            IEnumerator Blocking()
            {
                    int sleep = int.MaxValue;
     
                    //test cycle, I tried with the while cicle but it crashes Unity,
                    // when this "for" cicle is executing , it reads data and prints them almost in sync when the serial device sends data
                    //If you have a best idea, please share !!!
                    for (int i = 0; i <= int.MaxValue; i++)
                    {
                        read_data();
                        //wait 0.5 seconds and read again
                        yield return new WaitForSeconds(0.5F);
         
                    }
                    Thread.Sleep(sleep);
            }

            /*
            *Read the data from the serial port
            */
            void read_data()
            {
                    if (objComport.LastError == 0)
                    {
                            datareceived=objComport.ReadString();
                            //Print data on Console
                            print( "Data Received: " +datareceived)
                    }
                    else
                    {
                            Debug.Log("No data");
                    }

            }


}

This algorithm is not perfect, it’s just a suggestion for handling serial ports. Any suggestions, better idea, please sharing.

As I said the idea is to create your own free dll component.

bibliography:

I hope ti helps:

ActiveXperts Serial Port Component Manual

How To Work With C # Serial Port Communication

Serial Communications: The Way .NET

Serial Communications in Win32

Coroutines vs Update

Serial library for C ++

DLL Tutorial For Beginners
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/DLL-Tutorial-For-Beginners.htm

2 Likes

I will definitely be trying this out since I do a lot of arduino work with Unity and I have also been having issues with serial management. I ended up getting some Bluetooth modules and now I am handling the comms in a java class I wrote for android. Thanks so much for sharing!

1 Like

and few error occurs with above script, so I revised a little,

using UnityEngine;
using System.Collections;
using AxSerial;//Import the DLL external class
using System;
using System.IO;
using System.Threading;
using CielaSpike;//Import the custom thread for unity
public class SerialManager : MonoBehaviour {
     ComPort objComport;//Serial port object

//string of data received for the serial port
     string datareceived = "";
/*
*method that initializes the serial port
*/
    void initComponents() {
        try {
            objComport = new ComPort();
            objComport.Device = "COM4";//this specifies own port
            objComport.BaudRate = 9600;
            objComport.Open();//Open the port
        }
        catch (Exception ex) {
            Debug.Log(ex.GetBaseException());
        }
    }

    void Start() {
        initComponents();
        if (objComport.IsOpened) {
            StartCoroutine("manage_data");//Start coroutine for manage the data
            Debug.Log("Port opened");
        }
        else {
            Debug.Log("Could not  to open the port");

        }
    }

    void OnDestroy(){
        try
        {
          objComport.Close();
        }
        catch(Exception ex)
        {
            Debug.Log(ex.GetBaseException());
        }
    }
/*
*  asynchronous coroutine,
*  the idea is that the method of getting data is executing every so often, for example each one second.,
*  not for each frame like the Update method because this would down the performance
*
*/
    IEnumerator manage_data() {
        Task task;
        this.StartCoroutineAsync(Blocking(), out task);
        yield return StartCoroutine(task.Wait());
    }

    IEnumerator Blocking() {
        int sleep = int.MaxValue;

        //test cycle, I tried with the while cicle but it crashes Unity,
        // when this "for" cicle is executing , it reads data and prints them almost in sync when the serial device sends data
        //If you have a best idea, please share !!!
        for (int i = 0; i <= int.MaxValue; i++) {
            read_data();
            //wait 0.5 seconds and read again
            yield return new WaitForSeconds(0.5F);

        }
        Thread.Sleep(sleep);
    }

/*
*Read the data from the serial port
*/
    void read_data() {
        if (objComport.LastError == 0) {
            datareceived = objComport.ReadString();
            //Print data on Console
            Debug.Log("Data Received: " + datareceived);
        }
        else {
            Debug.Log("No data");
        }
    }
}

I got the following error when try to open the port.

I met this error at some computer which I installed some ft232 usb driver for serial, but I don’t know why this occur.


System.Runtime.InteropServices.COMException (0x80040154):
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR (Int32 errorCode) [0x0000d] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs:1031
at System.__ComObject.Initialize (System.Type t) [0x0007d] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/__ComObject.cs:103
at (wrapper remoting-invoke-with-check) System.__ComObject:Initialize (System.Type)
at Mono.Interop.ComInteropProxy.CreateProxy (System.Type t) [0x00007] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/Mono.Interop/ComInteropProxy.cs:108
at System.Runtime.Remoting.RemotingServices.CreateClientProxyForComInterop (System.Type type) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:588
at System.Runtime.Remoting.Activation.ActivationServices.CreateProxyForType (System.Type type) [0x00047] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Remoting.Activation/ActivationServices.cs:234
at <0x00000>
at SerialTest.initComponents () [0x00000] in H:\project\SerialTest\Assets\SerialTest.cs:35
UnityEngine.Debug:Log(Object)
SerialTest:initComponents() (at Assets/SerialTest.cs:43)
SerialTest:Start() (at Assets/SerialTest.cs:20)

→ (solved)
so this seems maybe because not installing of this program,

ActiveXperts Serial Port Component 3.2 (any cpu)

after install, works well, no error like above.

But what if 30 free trial days passed? Will not work? Any alternative way of not using this software?

The other solution is build your own dll component but you have to know C++ and Win32 in case you´re using Windows.
past 30 days the ActiveExpert plugin stops working :(.

@chubbspet , so are you using serial through USB or Bluetooth? Any chance you can make that Java Serial Class available?
Apparently, using a separate java jar or dll is one of the only ways to get Unity on Android to talk over serial.