Search Unity

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

Discussion in 'Scripting' started by patricioaljndro, Jun 26, 2015.

  1. patricioaljndro

    patricioaljndro

    Joined:
    Mar 6, 2014
    Posts:
    12
    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: http://www.activexperts.com/download/
    (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: https://www.assetstore.unity3d.com/en/#!/content/15717

    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)


    Code (CSharp):
    1. using UnityEngine;
    2.     using System.Collections;
    3.     using AxSerial;//Import the DLL external class
    4.     using System;
    5.     using System.IO;
    6.     using System.Threading;
    7.     using CielaSpike;//Import the custom thread for unity
    8.  
    9.  
    10. public SerialController : MonoBehaviour {
    11.  
    12.             ComPort objComport;//Serial port object
    13.  
    14.             //string of data received for the serial port
    15.             string datareceived="";
    16.  
    17.             /*
    18.             *method that initializes the serial port
    19.             */
    20.             void initComponents()
    21.             {
    22.                     try
    23.                     {
    24.                         objComport = new ComPort();
    25.                         objComport.Device="COM7";//this specifies own port
    26.                         objComport.BaudRate = 9600;
    27.                         objComport.Open();//Open the port
    28.                     }
    29.                     catch(Exception ex)
    30.                     {
    31.                         Debug.Log(ex.GetBaseException());
    32.                     }
    33.             }
    34.  
    35.             void Start()
    36.             {
    37.                     initComponents();
    38.                     if (objComport.IsOpened)
    39.                     {
    40.                         StartCoroutine("manage_data");//Start coroutine for manage the data
    41.                         Debug.Log("Port opened");
    42.                     }
    43.                     else
    44.                     {
    45.                         Debug.Log("Could not  to open the port");
    46.  
    47.                     }
    48.             }
    49.  
    50.             void OnDestroy
    51.             {
    52.               try
    53.               {
    54.                         objComport.Close();
    55.               }
    56.               catch(Exception ex)
    57.               {
    58.                     Debug.Log(ex.GetBaseException());
    59.               }
    60.  
    61.             }
    62.             /*
    63.             *  asynchronous coroutine,
    64.             *  the idea is that the method of getting data is executing every so often, for example each one second.,
    65.             *  not for each frame like the Update method because this would down the performance
    66.             *
    67.             */
    68.             IEnumerator manage_data()
    69.             {
    70.                     this.StartCoroutineAsync(Blocking(), out task);
    71.                     yield return StartCoroutine(task.Wait());
    72.             }
    73.  
    74.             IEnumerator Blocking()
    75.             {
    76.                     int sleep = int.MaxValue;
    77.      
    78.                     //test cycle, I tried with the while cicle but it crashes Unity,
    79.                     // when this "for" cicle is executing , it reads data and prints them almost in sync when the serial device sends data
    80.                     //If you have a best idea, please share !!!
    81.                     for (int i = 0; i <= int.MaxValue; i++)
    82.                     {
    83.                         read_data();
    84.                         //wait 0.5 seconds and read again
    85.                         yield return new WaitForSeconds(0.5F);
    86.          
    87.                     }
    88.                     Thread.Sleep(sleep);
    89.             }
    90.  
    91.             /*
    92.             *Read the data from the serial port
    93.             */
    94.             void read_data()
    95.             {
    96.                     if (objComport.LastError == 0)
    97.                     {
    98.                             datareceived=objComport.ReadString();
    99.                             //Print data on Console
    100.                             print( "Data Received: " +datareceived)
    101.                     }
    102.                     else
    103.                     {
    104.                             Debug.Log("No data");
    105.                     }
    106.  
    107.             }
    108.  
    109.  
    110. }
    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
    http://www.activexperts.com/files/serial-port-component/manual.htm

    How To Work With C # Serial Port Communication
    http://codesamplez.com/programming/serial-port-communication-c-sharp

    Serial Communications: The Way .NET
    http://www.codeproject.com/Articles/5568/Serial-Communications-The-NET-Way

    Serial Communications in Win32
    https://msdn.microsoft.com/en-us/library/ms810467.aspx

    Coroutines vs Update
    http://forum.unity3d.com/threads/coroutines-vs-update.67856/

    Serial library for C ++
    http://www.codeproject.com/Articles/992/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
     
    Last edited: Jun 26, 2015
    ZJP and janoonk like this.
  2. chubbspet

    chubbspet

    Joined:
    Feb 18, 2010
    Posts:
    1,220
    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!
     
    patricioaljndro likes this.
  3. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    and few error occurs with above script, so I revised a little,

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using AxSerial;//Import the DLL external class
    4. using System;
    5. using System.IO;
    6. using System.Threading;
    7. using CielaSpike;//Import the custom thread for unity
    8. public class SerialManager : MonoBehaviour {
    9.      ComPort objComport;//Serial port object
    10.  
    11. //string of data received for the serial port
    12.      string datareceived = "";
    13. /*
    14. *method that initializes the serial port
    15. */
    16.     void initComponents() {
    17.         try {
    18.             objComport = new ComPort();
    19.             objComport.Device = "COM4";//this specifies own port
    20.             objComport.BaudRate = 9600;
    21.             objComport.Open();//Open the port
    22.         }
    23.         catch (Exception ex) {
    24.             Debug.Log(ex.GetBaseException());
    25.         }
    26.     }
    27.  
    28.     void Start() {
    29.         initComponents();
    30.         if (objComport.IsOpened) {
    31.             StartCoroutine("manage_data");//Start coroutine for manage the data
    32.             Debug.Log("Port opened");
    33.         }
    34.         else {
    35.             Debug.Log("Could not  to open the port");
    36.  
    37.         }
    38.     }
    39.  
    40.     void OnDestroy(){
    41.         try
    42.         {
    43.           objComport.Close();
    44.         }
    45.         catch(Exception ex)
    46.         {
    47.             Debug.Log(ex.GetBaseException());
    48.         }
    49.     }
    50. /*
    51. *  asynchronous coroutine,
    52. *  the idea is that the method of getting data is executing every so often, for example each one second.,
    53. *  not for each frame like the Update method because this would down the performance
    54. *
    55. */
    56.     IEnumerator manage_data() {
    57.         Task task;
    58.         this.StartCoroutineAsync(Blocking(), out task);
    59.         yield return StartCoroutine(task.Wait());
    60.     }
    61.  
    62.     IEnumerator Blocking() {
    63.         int sleep = int.MaxValue;
    64.  
    65.         //test cycle, I tried with the while cicle but it crashes Unity,
    66.         // when this "for" cicle is executing , it reads data and prints them almost in sync when the serial device sends data
    67.         //If you have a best idea, please share !!!
    68.         for (int i = 0; i <= int.MaxValue; i++) {
    69.             read_data();
    70.             //wait 0.5 seconds and read again
    71.             yield return new WaitForSeconds(0.5F);
    72.  
    73.         }
    74.         Thread.Sleep(sleep);
    75.     }
    76.  
    77. /*
    78. *Read the data from the serial port
    79. */
    80.     void read_data() {
    81.         if (objComport.LastError == 0) {
    82.             datareceived = objComport.ReadString();
    83.             //Print data on Console
    84.             Debug.Log("Data Received: " + datareceived);
    85.         }
    86.         else {
    87.             Debug.Log("No data");
    88.         }
    89.     }
    90. }
     
    Last edited: Nov 17, 2015
  4. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    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> <unknown method>
    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,

    http://www.activexperts.com/download/

    ActiveXperts Serial Port Component 3.2 (any cpu)

    after install, works well, no error like above.
     
    Last edited: Nov 21, 2015
  5. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    But what if 30 free trial days passed? Will not work? Any alternative way of not using this software?
     
  6. patricioaljndro

    patricioaljndro

    Joined:
    Mar 6, 2014
    Posts:
    12
    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 :(.
     
  7. djfitz

    djfitz

    Joined:
    Oct 9, 2016
    Posts:
    1
    @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.