Serial Port reading with Unity 5

Using the Unity 5 game engine, something I have a lot of experience with, I thought I'd be able to create a quick way to read data from the serial port sent from an Uno board and a gyro.

I have started off with something quite basic, using 2 buttons that write a 1 or 2 to the serial port on COM4 with a bitrate of 9600 bps.

In Unity, I wrote a short script to detect these inputs and act depending on the value (1 or 2).

Both scripts are below, but errors in Unity keep throwing saying the operation on the SerialPort have timed out, it also seems incapable of finding the data/file name.

Does anyone know what I am doing wrong on either end?

Unity Error

System.TimeoutException: The operation has timed-out.
  at System.IO.Ports.WinSerialStream.Read (System.Byte[] buffer, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.Ports.SerialPort.read_byte () [0x00000] in <filename unknown>:0 
  at System.IO.Ports.SerialPort.ReadByte () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.IO.Ports.SerialPort:ReadByte ()
  at ArduinoInput.Update () [0x00022] in D:\Labyrith\Tabletop\Assets\ArduinoInput.cs:26 
UnityEngine.MonoBehaviour:print(Object)
ArduinoInput:Update() (at Assets/ArduinoInput.cs:34)

Arduino Script

const int buttonPin01 = 7;
const int buttonPin02 = 8;

void setup()
{
  Serial.begin(9600);

  pinMode(buttonPin01, INPUT);
  pinMode(buttonPin02, INPUT);

  digitalWrite(buttonPin01, HIGH);
  digitalWrite(buttonPin02, HIGH);
}

void loop()
{
  if(digitalRead(buttonPin01) == LOW)
 {
   Serial.println("LEFT");
   Serial.write(1);
   Serial.flush();
   delay(20);
 }
 
  if(digitalRead(buttonPin02) == LOW)
 {
   Serial.println("RIGHT");
   Serial.write(2);
   Serial.flush();
   delay(20);
 } 
}

Unity Script

using UnityEngine;
using System.IO.Ports;

public class ArduinoInput : MonoBehaviour {

	public float speed;
	private float amountToMove;

	SerialPort sp = new SerialPort("COM4", 9600);

	void Start () 
	{
		sp.Open();
		sp.ReadTimeout = 1;
	}
	
	void Update () 
	{
		amountToMove = speed * Time.deltaTime;

		if (sp.IsOpen)
		{
			try
			{
				//MoveObject(sp.ReadByte());
				if (sp.ReadByte() != 0)
				{
					print(sp.ReadByte());
				}
			}

			catch (System.Exception e)
			{
				print(e);
				throw;
			}
		}
	}

	void MoveObject(int direction)
	{
		if (direction == 1) 
		{
			transform.Translate(Vector3.left * amountToMove, Space.World);
		}

		if (direction == 2) 
		{
			transform.Translate(Vector3.right * amountToMove, Space.World);
		}
	}
}

You know that Serial.print() and Serial.println() statements send data the same place as Serial.write(), right?

You are not, in Unity, dealing with the Serial.print()ed data.

I don't know enough about Unity to make sense of your script.

There will be a problem if Unity opens the serial port (and causes the Arduino to reset) everytime it wants to receive data.

Ensure that it opens the serial port at the start of business and keeps it open until you are finished with the Arduino.

Also, when the serial port is opened your PC must allow time for the Arduino to complete its reset cycle.

...R

I keep getting "not responding" issues with Unity like it's crashing every time it tries to open/read the serial port.

I have tried this on 2 computers running different OS's and I still get the same issue, either Unity is somehow incapable of handling the input or the Arduino itself is sending something it doesn't like.

Has anyone else ever tried to receive Arduino data in Unity before (and succeeded)?

KyleBriggs:
I keep getting "not responding" issues with Unity like it's crashing every time it tries to open/read the serial port.

How often does it try to open the serial port ?

Every few seconds or just when the Unity program is started ?

...R

The serial port is opened in the start function, so only on the first frame of the app running.

What language does Unity use ?

This is not a Unity forum so I am only clutching at straws.

You don't seem to have any debug code to tell you where the problem arises. What about checking isOpen() in the Start function - or using try/catch.

Are you sure you are using the correct COM port ?

...R

When a port is opened then the Arduino is reset. Then the boot loader sends a request to see if code needs to be uploaded. It is likely that this code is upsetting your PC program.

You might like to try and disable the auto reset function with a large capacitor.

You don't have Serial Monitor open while you try to receive data in Unity, right? Cause that would cause an issue.

I'm not really sure what's wrong with your code, I was able to receive Serial data in Unity using C# in the past, which is what it looks like you are doing. However, instead of using ReadByte() I did ReadLine().

I highly suggest putting your serial processing in Unity on a separate thread. If it is continuously looking for data, that will stop other things in Unity from running well unless they are on separate threads, at least in my experience when I did something similar.

Also... if you do if(sp.ReadByte() != 0) and then print(sp.ReadByte()) wouldn't it proceed one extra byte afterwards and not actually read the intended byte? It's probably better to store your data in a temporary variable and then do checks on it.

Edit: actually, that seems to be where your error lies... It is a timeout exception, which means it was trying to read data but timed out when there wasn't any (I think?). In this case, I think you are trying to read more data than there actually is, by running sp.ReadByte() one extra time by accident after the if statement. Try only using sp.ReadByte() once and see if that fixes it