- Home /
Serial port on unity
Hi, I would like to use the serial port of unity but I can not make it work. First of all I do not understand why you can not find the serial port if I write
sp = new SerialPort ( "COM58", 115200) ;
but I have to write
sp = new SerialPort ( "\\\\.\\COM58", 115200) ;
Then, I wanted to use the event DataReceived but I can not make it work, every time gives me an error nullReferenceObject. I used the same method of visual studio without any problems. My question is: can you use the serial port of unity? If so, does anyone have any examples?
So, the serial port of instrument (not Arduino), I can not make work. I loaded settings .net 2.0 but keeps telling me that the COM port does not exist. This way I can not go on in my game. I downloaded a script that I found online:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
// System.IO.Ports requires a working Serial Port. On Mac, you will need to purcase the Uniduino plug-in on the Unity Store
// This adds a folder + a file into your local folder at ~/lib/libMonoPosixHelper.dylib
// This file will activate your serial port for C# / .NET
// The functions are the same as the standard C# SerialPort library
// cf. http://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx
public class Serial : MonoBehaviour
{
/// <summary>
/// Enable notification of data as it arrives
/// Sends OnSerialData(string data) message
/// </summary>
public bool NotifyData = false;
/// <summary>
/// Enable line detection and notification on received data.
/// Message OnSerialLine(string line) is sent for every received line
/// </summary>
public bool NotifyLines = false;
/// <summary>
/// Maximum number of lines to remember. Get them with GetLines() or GetLastLine()
/// </summary>
public int RememberLines = 0;
/// <summary>
/// Enable lines detection, values separation and notification.
/// Each line is split with the value separator (TAB by default)
/// Sends Message OnSerialValues(string [] values)
/// </summary>
public bool NotifyValues = false;
/// <summary>
/// The values separator.
/// </summary>
public char ValuesSeparator = '\t';
//string serialOut = "";
private List<string> linesIn = new List<string> ();
/// <summary>
/// Gets the received bytes count.
/// </summary>
/// <value>The received bytes count.</value>
public int ReceivedBytesCount { get { return BufferIn.Length; } }
/// <summary>
/// Gets the received bytes.
/// </summary>
/// <value>The received bytes.</value>
public string ReceivedBytes { get { return BufferIn; } }
/// <summary>
/// Clears the received bytes.
/// Warning: This prevents line detection and notification.
/// To be used when no \n is expected to avoid keeping unnecessary big amount of data in memory
/// You should normally not call this function if \n are expected.
/// </summary>
public void ClearReceivedBytes ()
{
BufferIn = "";
}
/// <summary>
/// Gets the lines count.
/// </summary>
/// <value>The lines count.</value>
public int linesCount { get { return linesIn.Count; } }
#region Private vars
// buffer data as they arrive, until a new line is received
private string BufferIn = "";
// flag to detect whether coroutine is still running to workaround coroutine being stopped after saving scripts while running in Unity
private int nCoroutineRunning = 0;
#endregion
#region Static vars
// Only one serial port shared among all instances and living after all instances have been destroyed
private static SerialPort s_serial;
//
private static List<Serial> s_instances = new List<Serial> ();
#endregion
void Start ()
{
// print ("Serial Start ");
}
void OnValidate ()
{
if (RememberLines < 0)
RememberLines = 0;
}
void OnEnable ()
{
// print("Serial OnEnable");
// if (s_serial != null)
// print ("serial IsOpen: " + s_serial.IsOpen);
// else
// print ("no serial: ");
s_instances.Add (this);
checkOpen (9600);
}
void OnDisable ()
{
//print("Serial OnDisable");
s_instances.Remove (this);
}
public void OnApplicationQuit ()
{
if (s_serial != null) {
if (s_serial.IsOpen) {
print ("closing serial port");
s_serial.Close ();
}
s_serial = null;
}
}
void Update ()
{
//print ("Serial Update");
if (s_serial != null && s_serial.IsOpen) {
if (nCoroutineRunning == 0) {
//print ("starting ReadSerialLoop coroutine");
// Each instance has its own coroutine but only one will be active a
StartCoroutine (ReadSerialLoop ());
} else {
if (nCoroutineRunning > 1)
print (nCoroutineRunning + " coroutines in " + name);
nCoroutineRunning = 0;
}
}
}
public IEnumerator ReadSerialLoop ()
{
while (true) {
if (!enabled) {
//print ("behaviour not enabled, stopping coroutine");
yield break;
}
//print("ReadSerialLoop ");
nCoroutineRunning++;
try {
while (s_serial.BytesToRead > 0) { // BytesToRead crashes on Windows -> use ReadLine in a Thread
string serialIn = s_serial.ReadExisting ();
// Dispatch new data to each instance
foreach (Serial inst in s_instances) {
inst.receivedData (serialIn);
}
}
} catch (System.Exception e) {
print ("System.Exception in serial.ReadLine: " + e.ToString ());
}
yield return null;
}
}
/// return all received lines and clear them
/// Useful if you need to process all the received lines, even if there are several since last call
public List<string> GetLines (bool keepLines = false)
{
List<string> lines = new List<string> (linesIn);
if (!keepLines)
linesIn.Clear ();
return lines;
}
/// return only the last received line and clear them all
/// Useful when you need only the last received values and can ignore older ones
public string GetLastLine (bool keepLines = false)
{
string line = "";
if (linesIn.Count > 0)
line = linesIn [linesIn.Count - 1];
if (!keepLines)
linesIn.Clear ();
return line;
}
public static void Write (string message)
{
if (checkOpen ())
s_serial.Write (message);
}
public static void WriteLn (string message = "")
{
if (s_serial != null && s_serial.IsOpen)
s_serial.Write (message);
}
/// <summary>
/// Verify if the serial port is opened and opens it if necessary
/// </summary>
/// <returns><c>true</c>, if port is opened, <c>false</c> otherwise.</returns>
/// <param name="portSpeed">Port speed.</param>
public static bool checkOpen (int portSpeed = 230400)
{
if (s_serial == null) {
string portName = "COM58";
if (portName == "") {
print ("Error: Couldn't find serial port.");
return false;
} else {
//print ("Opening serial port: " + portName);
}
s_serial = new SerialPort (portName, portSpeed);
s_serial.Open ();
//print ("default ReadTimeout: " + serial.ReadTimeout);
//serial.ReadTimeout = 10;
// cler input buffer from previous garbage
s_serial.DiscardInBuffer ();
}
return s_serial.IsOpen;
}
// Data has been received, do what this instance has to do with it
protected void receivedData (string data)
{
if (NotifyData) {
SendMessage ("OnSerialData", data);
}
// Detect lines
if (NotifyLines || NotifyValues) {
// prepend pending buffer to received data and split by line
string [] lines = (BufferIn + data).Split ('\n');
// If last line is not empty, it means the line is not complete (new line did not arrive yet),
// We keep it in buffer for next data.
int nLines = lines.Length;
BufferIn = lines [nLines - 1];
// Loop until the penultimate line (don't use the last one: either it is empty or it has already been saved for later)
for (int iLine = 0; iLine < nLines - 1; iLine++) {
string line = lines [iLine];
//print(line);
// Buffer line
if (RememberLines > 0) {
linesIn.Add (line);
// trim lines buffer
int overflow = linesIn.Count - RememberLines;
if (overflow > 0) {
print ("Serial removing " + overflow + " lines from lines buffer. Either consume lines before they are lost or set RememberLines to 0.");
linesIn.RemoveRange (0, overflow);
}
}
// notify new line
if (NotifyLines) {
SendMessage ("OnSerialLine", line);
}
// Notify values
if (NotifyValues) {
string [] values = line.Split (ValuesSeparator);
SendMessage ("OnSerialValues", values);
}
}
}
}
static string GetPortName ()
{
string[] portNames;
switch (Application.platform) {
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.OSXDashboardPlayer:
case RuntimePlatform.LinuxPlayer:
portNames = System.IO.Ports.SerialPort.GetPortNames ();
if (portNames.Length == 0) {
portNames = System.IO.Directory.GetFiles ("/dev/");
}
foreach (string portName in portNames) {
if (portName.StartsWith ("/dev/tty.usb") || portName.StartsWith ("/dev/ttyUSB"))
return portName;
}
return "";
default: // Windows
portNames = System.IO.Ports.SerialPort.GetPortNames ();
if (portNames.Length > 0)
return portNames [0];
else
return "COM3";
}
}
}
someone managed to use it? Thank you!
P.S. I'm sure the com port is correct
Answer by GabrielKevers · Apr 29, 2016 at 06:34 AM
use the .NET 2.0 (not subset) Config is into Edit>ProjectSettings>Player>ApiCompatibilityLevel.
Hey I'm using Ardity to communicate Serial port and It's works really good when I uses arduino. but It's not working with usb to rs485.
How can I fix this problem? I checked data comes to my computer using serial monitor program.
setting: portName : CO$$anonymous$$6 baudRate 57600
In Unity, Console Log appear "Connection established" but nothing comes up next..
Answer by Mondkin · Jul 03, 2016 at 04:39 AM
Hello,
A quick solution for using COM ports from Unity is this unitypackage I made, it does all the threading for you. It also comes with some samples to make it easy to use.
(If you have questions please go here: https://github.com/DWilches/SerialCommUnity/issues instead of adding a new comment in this page, as they are easier to track there)
Any chance you can revive that Unity package $$anonymous$$ondkin? Link doesn't work and i'm chasing down all options for my port sharing issue on OSX El Capitan.
Hi. Actually, the package is live in GitHub, I just moved it there. Hope you enjoy it! https://github.com/DWilches/SerialCommUnity
Hi @$$anonymous$$ondkin, thank you for the serial package, I've been using it. Perhaps a newbie question but there is a substantial lag that is caused by this now running in a separate thread: I measure something like 30-50 milliseconds from the time of enqueue message to then the serialthread noticing data and starting to writeline it out. The lag varies of course since the threads do not run simultaneously.
Is there any way to reduce this lag? Preferrably down to 0 or as close to it as possible, of course.
Hi @rainisto, I'm glad to know the package is being useful for you! About the delay, I can think of two main factors that you might be experiencing: (1) SerialCommUnity
reads from your device as often as the Update
function of your $$anonymous$$onoBehaviour
is being called. That Update
function runs once per frame, so if your program runs at 30 FPS, the library will try to read from your device every ~33ms (1 second/30 fps = 0.033s). I don't know how you are doing your delay measurement, but this is a big factor. (2) The default baudrate in my examples is the slowest "standard" value: 9600. Set it to something like 115200 to increase the communication speed. You will also need to change the baud-rate in your piece of hardware to match this. Why did I default to 9600? because though it is the slowest, it's the less error prone (there is less chance of bits being flipped because of network errors, and we are talking here at network protocols without error correction). So if you plan to increase your baudrate, increase it to the lowest value you can get off with! And use only the "standard" values. Here is a list of baudrates and further explanation, in case you are not familiar with the concept.
I hope this is useful!
(I copied your question here as well because it is a very useful question, and I want other people to find it quickly)
Thanks @mondkin. Yes, I tried to run it in 115200, and fiddled around with the Windows com port settings even ( http://digital.ni.com/public.nsf/allkb/D776A9D834B132AB86256ED2004E18EF for those that do not know). That can affect up to 15ms. Still the lag was pretty high.
Ultimately since our use case is very real-time critical, this time we ended up using https://roofman.wordpress.com/2012/09/13/fast-serial-communication-for-c-real-time-applications/ - for one reason or another, I didn't have time to fully explore why, we got this to work really quickly indeed.
Hi @$$anonymous$$ondkin. Thank you for the serial package. I'm currently trying to use it for my Final Year Project. However, after I imported the package, I noticed that the console returns quite weird error.
Assets/SerialComm/Scripts/SerialThread.cs(245,46): error CS1061: Type System.IO.Ports.SerialPort' does not contain a definition for
ReadLine' and no extension method ReadLine' of type
System.IO.Ports.SerialPort' could be found (are you missing a using directive or an assembly reference?)
The same error type also appears on the other ReadLine function (line 238) and WriteLine function (line 166). I try to check for this error on your code however I feel that its quite weird because WriteLine and ReadLine is included in the System.IO library and the implementation is correct based on $$anonymous$$SDN (and no other complain). I already changed the project settings to NET 2.0 based on your Github. Did I miss something?
Yes, that's weird. Which version of Unity are you using?
I'm currently using Unity Daydream Preview 5.4.2f2-GVR13 (64-bit).
@$$anonymous$$ondkin I tried to use SerialPort in Unity 5.6, including the unitypackage you made, but for some reason, no matter what I do, when I call serialPort.Open(), even if I check that the serialport is not open, Unity always throws an IOException that access is denied. I tried CO$$anonymous$$4 and CO$$anonymous$$5, but to no avail. Do you know if there is any solutions for this?
@Ben-BearFish Is it possible you have the same port already open in another application? That's one of the reasons that can produce that error. If it's not that, I can think of your Windows' user not having privileges to open the port (though it's just a guess)
Awesome package - will certainly use it.
About your second comment - Unity can open CO$$anonymous$$ ports with higher numbers, you just have to write them like a different path, in case of your library, write this in the Editor:
\\.\CO$$anonymous$$11
Thanks @Wout_BlinkBlink ! I wasn't aware of that different path, I'll update the readme of my repo.
Answer by RevoltingMuffin · Nov 04, 2016 at 07:09 PM
Please visit the following web site to view updates on this issue and comment letting the Unity staff know how important this functionality is to the COM Port and TTY reading community! VOICE YOU OPINION!
https://issuetracker.unity3d.com/issues/serialport-bytestoread-returns-null-reference
Your answer
Follow this Question
Related Questions
Serial port IOException: access is denied 0 Answers
Need Help Connecting Arduino to Unity 0 Answers
Reading Serial data in Unity from Android app 2 Answers
Unity 5 3D Space Movement Issues 0 Answers
Vertex transforms in custom shader don't work in Unity 5 0 Answers