Arduino with Unity: Bad Framerate!

So im trying to send the data from my Arduino which is using a HC-SR04 Ultrasonic Distance sensor. It is clearly sending it but the problem is that im averaging roughly 2.0 frames per second… I have no idea why. Im at 9600 Baud, on Com 3. Heres the code for Unity:

using UnityEngine;
using System.Collections;
using System.IO.Ports;

public class ArduinoConnect : MonoBehaviour {
	SerialPort stream= new SerialPort("COM3", 19200);
	string distance;
	
	// Use this for initialization
	void Start () {
	
		stream.Open();
		
	}
	
	// Update is called once per frame
	void Update () {
	
		distance= stream.ReadLine();
		Debug.Log(distance);
		
	}

}

Heres the code I uploaded to my arduino:

#include <NewPing.h>

#define TRIGGER_PIN  12
#define ECHO_PIN     11
#define MAX_DISTANCE 200

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

void setup() {
  Serial.begin(19200);
}

void loop() {
  delay(50);
  int uS = sonar.ping_median(10);
  Serial.println(uS / US_ROUNDTRIP_CM); //prints the distance in cm
  delay(30);
}

The issue is you are trying to read the serial port too often and Readline is a blocking read (synchronous and it doesn’t return until it either gets characters or times out in which case it throws a TimeOutException).

There are a few ways to solve this. Personally I’d use the event DataReceived so you don’t have to deal with timeout exceptions.

Something like

using UnityEngine;
using System.Collections;
using System.IO.Ports;
 
public class ArduinoConnect : MonoBehaviour {
    SerialPort stream= new SerialPort("COM3", 19200);
    string distance;
 
    // Use this for initialization
    void Start () {
       try{
           stream.Open();
           stream.DataReceived += DataReceivedHandler;
       }
       catch(Exception e){
           Debug.Log("Could not open serial port: " + e.Message);

       }
 
    }
 
    private void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        string distance = sp.ReadLine();
        Debug.Log(distance);
    }
 
}

You are still blocking until you get the newline character, but you aren’t doing it once per frame (and you know that the newline char is coming soon since you have data).

Another way is to use ReadExisting and read it into a buffer then parse the buffer (basically look for the newline in your case).

I’ve also seen a separate thread used that attempts to read a single character in a loop (which handles the timeout exception and uses code in the catch to mark when last data was received etc). That’s basically the only way to do it if you have a protocol that has to react to individual characters quickly. Letting it throw exceptions is ugly though (there’s a bit of overhead to an exception being thrown).

Anyhow, that should get you going. If you have any questions to clarify things don’t hesitate to ask.

Oh, also make sure you have parity, stopbits data bits and handshake set correctly (sounds like the defaults are working for you though).

For completeness you should also handle the ErrorReceived event. Its delegate is a little different from the data one, so you’ll need something like this:

stream.ErrorReceived += DataErrorReceivedHandler;


    private void DataErrorReceivedHandler(object sender, 
                                          SerialErrorReceivedEventArgs e)
    {
        Debug.Log("Serial port error:" e.EventType.ToString ("G"));            
    }

Also,

You can create a thread that deals with TimeException errors with Arduino. This works perfect, and any delay occured in run time.

Thread myThread;

void Start(){
 myThread = new Thread(new ThreadStart(GetArduino));
 myThread.Start();
}

private void GetArduino(){
 while(myThread.IsAlive())
 {
     string value = stream.ReadLine();
 }
}

Hi, you can chek this code as it worked for me .- YouTube this tutorial _h-n-rTg
Hope this help.
Regards nidhalkratos