How to send data between Unity and Arduino
Using the Serial Port in Unity Game Engine
Sending data back and forth between Unity and your Arduino is relatively straightforward!
You can hook up sensors and buttons as input for your Unity project - or vice versa: control LEDs, motors or other physical things from right inside Unity!
There are Unity plugins for serial communication, but you don't necessarily need them.
Unity uses the C# programming language, which has built-in support for serial communication. It all works very similarly to other languages like P5, Processing or Python.
This article will show you how to connect and send data back and forth between your computer and Arduino.
Step 1: Open the serial port connection
Important Setup in Unity
Before you start, you must enable serial ports in Unity:
- Go to Edit > Project Settings > Player.
- Under Other Settings, find Api Compatibility Level.
- Change it from .NET Standard 2.1 to .NET Framework.
When your Arduino is plugged into your computer using the USB cable, you can open the serial port connection like this:
Arduino code:
Just put this code somewhere in your setup() function. It will run once and initialize the connection.
// Initialize serial communication
Serial.begin(9600); // 9600 is the requested speed in bytes per second.
// You can also choose 19200, 38400, 57600, and 115200 bps for faster data transfer.
// Wait for serial port to connect.
while (!Serial) {
; // do nothing; just keep looping until we have a connection!
}
Unity C# code:
On the computer side there might be more than one serial port available, as there might be multiple devices connected.
Therefore, to connect to your Arduino, you will first need to find out which of the serial ports it is plugged into.
// Put this at the very top of your C# script, to enable use of Serial Ports:
using System.IO.Ports;
// Put this inside your class; e.g. just above the Start() function
// so you will be able to access it from anywhere in your script:
private SerialPort serial;
// To get a list of available ports, put this, for example, inside your Start() function:
string[] portNames = SerialPort.GetPortNames();
// you can list the available port names in Unity's console like this:
foreach (string portName in portNames)
{
Debug.Log(portName);
}
// Once you know which port you want to connect to, add this code to start the connection:
// create a new instance of SerialPort and store it in the 'serial' variable.
serial = new SerialPort(portName, 9600); // change 'portName' to the port your Arduino is connected to.
// make sure to choose the same speed as in your Arduino code.
// some settings to make it all work reliably:
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.RtsEnable = true; // needed for two-way communication
serial.DtrEnable = true; // needed for two-way communication
serial.Open(); // open up the connection!
You should now ready to send data back and forth!!
Obviously, it will be helpful to create a simple UI in Unity for choosing and connecting to the right port, as they can sometimes change.
You could consider using a 'Dropdown' and 'Button' for this, and put them on your UI canvas.
Step 2: Send and receive data:
Method 1: The Easy Way™ - sending all data as text (strings)
Serial communication sends one byte at a time, at a pretty decent speed.
A byte can be one character (e.g. one letter), one Boolean value (true/false) or a one byte number (0-255).
Integers and floating point numbers consist of multiple bytes, so sending those is slightly more involved. You would need to break them up into multiple bytes and recombine them after receiving.
Thankfully - to keep things simple, we can just send any type of data as text instead!
We can then convert the messages back into numbers or booleans after receiving them. Both Arduino and C#/Unity have built-in functions to do this.
We will need to know when each separate message ends - especially when you are sending data continuously.
The simplest way to do that is to send each value as one line of text, and read them one line at a time on the other side.
In C#, you can use SerialPort.WriteLine(string text) to send, or SerialPort.ReadLine() to receive one line of text.
WriteLine adds the end-of-line character ('\n') to indicate the end of the message / line.
ReadLine will read from the serial connection until it encounters that character, so it knows that is the end of the line.
On the Arduino side, there are similar functions:
Serial.println(string text) - sends one line of text
Serial.readStringUntil('\n') - reads incoming text until the end of the line.
Below is some example code for sending / receiving different types of data.
Arduino code:
Method 2: The Efficient Way - sending any data as bytes
In some rare cases, you might need the data transfer to be as fast as possible. You can gain a bit of efficiency by sending your floats or integers directly as bytes, instead of as text.
Take the floating point number 123.45678, for example. To send it as a string, things that can go wrong:
- timeout
- not reading until end of message
- port busy
- wrong port
Sending multiple values at a time (e.g. sensor value + button value + game state, etc.)
Sending arrays
// example of one way to send/receive arrays
// assumes the first line sent is the size of the array (the number of integers) as a string,
// with each number of the array as a subsequent line of text.
int[] receiveIntArray()
{
String arraySizeAsString = Serial.readStringUntil('\n');
int arraySize = arraySizeAsString.toInt();
int intArray[arraySize]; // create an empty integer array of the correct size to hold the incoming numbers.
// read each incoming number as text, convert it to an integer, and store it in the array.
for(int i = 0; i < arraySize; i++){
String nextNumberString = Serial.readStringUntil('\n');
int nextNumber = nextNumberString.toInt();
intArray[i] = nextNumber;
}
return intArray; // done!
}
A note about threading
-
set backend to .NET instead of Mono (or IL2CPP)
-
Initialize, configure and open the serial port
-
Send and receive data
-
converting strings / bytes / ints / floats
-
write vs. writeLine/println vs. read / readLine
print("Hello, world!")
for i in range(10):
print(i)
References
- Arduino Serial Reference
- C# SerialPort Reference
Some great resources with more extensive information:
- https://sirwilliam.hashnode.dev/serial-communication-between-arduino-and-unity-3d
- https://www.xanthium.in/serial-port-communication-programming-arduino-raspberry-pi-using-csharp-on-windows#rts
Libraries / packages / scripts
- https://dyadica.co.uk/blog/unity3d-serialport-script/
- https://github.com/dwilches/Ardity
