- Home /
High drawcall make delay when read variable from serial port
I have game that connected with arduino, my game have 500 drawcalls, when I try read variable from serial port, there's delay about 1-5 sec. But when the drwacalls less than 300 there's no delay when read the serial port. Is that the large amount of drawcalls make delay when read variable from serial port? Here's my code :
using UnityEngine;
using System.Collections;
using System.IO;
using System.IO.Ports;
using System.Threading;
public class Micro : MonoBehaviour
{
string strIn;
string FileName;
StreamReader reader;
string COM;
int EnableMicro;
public static int a1 = 0;
public static int a2 = 0;
public static int d1 = 0;
public static int d2 = 0;
public static int d3 = 0;
SerialPort serial;
private string[] data;
string[] fungsi;
string[] nilai;
float TimerMicro;
string value;
void Start()
{
LoadConfig();
if (EnableMicro == 1)
{
serial = new SerialPort(COM, 9600, Parity.None, 8, StopBits.One);
//serial.Open();
OpenConnection();
}
//serial.ReadTimeout = 1;
}
void Update()
{
//Debug.Log(value);
if (EnableMicro == 1)
{
//TimerMicro += Time.deltaTime;
try
{
value = serial.ReadLine();
}
//if (TimerMicro > 1.0f)
//{
catch
{
value = ("a1=0 a2=0 d1=0 d2=0");
}
if (value != null)
{
fungsi = value.Split('=');
try
{
nilai = fungsi[1].Split(' ');
a1 = int.Parse(nilai[0]);
}
catch
{
a1 = 0;
}
//fungsi = value.Split('=');
try
{
nilai = fungsi[2].Split(' ');
a2 = int.Parse(nilai[0]);
}
catch
{
a2 = 0;
}
//fungsi = value.Split('=');
try
{
nilai = fungsi[3].Split(' ');
d1 = int.Parse(nilai[0]);
}
catch
{
d1 = 0;
}
//fungsi = value.Split('=');
try
{
nilai = fungsi[4].Split(' ');
d2 = int.Parse(nilai[0]);
}
catch
{
d2 = 0;
}
}
//Debug.Log(value);
//Debug.Log("Fungsi 1:" + fungsi[0] + " Fungsi2:" + fungsi[1] + " Fungsi3:" + fungsi[2] + " Fungsi4:" + fungsi[3]);
//fungsi = value.Split('=');
//nilai = fungsi[5].Split(' ');
//d3 = int.Parse(nilai[0]);
//Debug.Log("L=" + L + " R=" + R + " U=" + U + " D=" + D + " RUN=" + RUN);
Debug.Log("a1=" + a1 + " a2=" + a2 + " d1=" + d1 + " d2=" + d2);
////if (L == 1)
//// Debug.Log("Kiri");
////if (R == 1)
//// Debug.Log("Kanan");
////if (U == 1)
//// Debug.Log("Atas");
////if (D == 1)
//// Debug.Log("Bawah");
//strIn=("L="+L+" R="+R+" U="+U+" D="+D+" RUN="+RUN);
//Debug.Log(strIn);
//return strIn;
//}
}
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width - 100, (Screen.height) - 20, 120, 30), "a1: " + a1);
GUI.Label(new Rect(Screen.width - 200, (Screen.height) - 20, 120, 30), "a2: " + a2);
GUI.Label(new Rect(Screen.width - 300, (Screen.height) - 20, 120, 30), "d1: " + d1);
GUI.Label(new Rect(Screen.width - 400, (Screen.height) - 20, 120, 30), "d2: " + d2);
}
public void LoadConfig()
{
FileName = "Config.txt";
if (!File.Exists(FileName))
{
return;
}
else
{
reader = File.OpenText(FileName);
string buffer;
buffer = reader.ReadLine();
string[] token = buffer.Split(':');
COM = (token[1]);
buffer = reader.ReadLine();
token = buffer.Split(':');
EnableMicro = int.Parse(token[1]);
reader.Close();
}
}
void OpenConnection()
{
if (serial != null)
{
if (serial.IsOpen)
{
serial.Close();
Debug.Log("Closing port, because it was already open!");
}
else
{
try
{
serial.Open(); // opens the connection
serial.ReadTimeout = 10; // sets the timeout value before reporting error
Debug.Log("Port Opened!");
}
catch
{
Debug.Log("com False");
}
}
}
else
{
if (serial.IsOpen)
{
// print("Port is already open");
Debug.Log("Port is already open");
}
else
{
//print("Port == null");
Debug.Log("Port == null");
}
}
}
void OnApplicationQuit()
{
if (serial != null)
serial.Close();
}
}
and this the pictures :
Anyone can solve my problem? Thank you :)
Answer by Bunny83 · May 10, 2013 at 10:47 AM
You use a readtimeout of 10 ms, so each call to serial.ReadLine(); will block your whole game for 10ms (except when a line is available). You should handle hardware IO stuff in a seperate thread.
Something like that:
//SerialPortLineReader.cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.IO.Ports;
public class SerialPortLineReader
{
private SerialPort m_SerialPort = null;
private Thread m_ReadLoop = null;
private object m_LockHandle = new object();
private List<string> m_Lines = new List<string>();
public bool IsDataAvailable
{
get
{
lock (m_LockHandle)
{
return m_Lines.Count > 0;
}
}
}
public string ReadLine()
{
string tmp = null;
lock (m_LockHandle)
{
if (m_Lines.Count > 0)
{
tmp = m_Lines[0];
m_Lines.RemoveAt(0);
}
}
return tmp;
}
public SerialPortLineReader(SerialPort aSerialPort)
{
m_SerialPort = aSerialPort;
m_ReadLoop = new Thread(_ThreadFunc);
m_ReadLoop.IsBackground = true;
m_ReadLoop.Start();
}
private void _ThreadFunc()
{
while (m_ReadLoop.ThreadState != ThreadState.StopRequested)
{
string tmp = m_SerialPort.ReadLine();
lock (m_LockHandle)
{
m_Lines.Add(tmp);
}
}
}
}
Use this class like that:
SerialPort port = new SerialPort( .... );
SerialPortLineReader reader = new SerialPortLineReader( port );
// ...
string line = reader.ReadLine();
if (line != null)
{
//...
This will seperate the io reading from your gameloop and only sync when you want to access data.
Btw: I just thrown this class together without testing it, but it should work ;)
Note: the class lacks of proper port closing. Usually the OS will close any open ports of a program when it ends. However closing the port manually could cause an exception in the background thread. You might want to implement some checks for that ;)
Btw: in your OpenConnection function the else block of if (serial != null) will cause a null-ref-exception when serial is really null since you check serial.IsOpen on a known null reference.
thank for your answer Bunny83, I will try later, but now I got fever :(
You have a FEVER ? $$anonymous$$y God, that's horrible. Eat more meat. If you can read German I strongly recommend Leben ohne Brot, Dr. Wolfgang Lutz ISBN:3887601009
Thank you, this saved me some serious headache.
I had a relatively old PC reading serial port and changing images according to the received data, but the serial data came in extremely slow/lagging behind. After delegating serial port reading to another thread, it seemed to fix that, but then introduced an ever-increasing lag between what sensor saw and what Unity read from serial port. What did the trick was to flush serial port buffer after reading it - port.DiscardOutBuffer() and port.DiscardInBuffer().
Your answer
Follow this Question
Related Questions
Long delay sending data to Arduino via Serial Communication 0 Answers
Why do await Task.Delay(10); stops execution in unity Web-GL? 1 Answer
How to read two separate values from the same SerialPort? 1 Answer
How do i Smooth ingame movement with flickering sensor input? 0 Answers
Map some Values taken from Serial Port 0 Answers