transform.rotation = ... reacts slow

I’m trying to integrate Arduino and unity for fun, and my current project involves using a potentiometer(variable resistor) to rotate an object in unity. I do this by measuring the output voltage from the potentiometer and translating it into a rotation(the value comes out as a number between 0 and 1023). I’ve had no issues getting the bytes into unity with the system.IO.Ports stuff, nor have I had trouble translating it into a Euler angle, but when I try to use that angle to set the objects rotation, it is slow and laggy(jumps to the rotation after several seconds). initially I was using transform.Rotate(…), which worked significantly better, but I want the rotation to be set to a specific spot, not to be continually rotated. I’m not sure if there is a more efficient way of setting the rotation(or for that matter, if I’m coming at this from the complete wrong direction), and any help would be appreciated.

Here is the code I’m working with:

using UnityEngine;
using System.Collections;
using System.IO.Ports;
public class ArduinoInput : MonoBehaviour {

    public SerialPort p = new SerialPort("COM4", 9600);
    float speed;
    string temp;
    public float speedMod = 10;
    public float turnMod;
    Rigidbody rb;
    float rot;

    public GameObject obj;

    void Start () 
    {
        rb = transform.GetComponent<Rigidbody> ();
	    if (!p.IsOpen) 
	    {
		    p.Open ();
	    }
	    p.ReadTimeout = 1;
    }
    void Update () {
	    if (p.IsOpen)
	    {
		    try
		    {
			    temp = p.ReadLine(); //grabs data
			    string[] data = temp.Split(','); // splits the string to separate 2 vars
			    float rotData = float.Parse(data[1]); // translates 1st var to float
			    float speedData = float.Parse(data[0]); // translates 2nd var to float
                rot = ((rotData/10.23f) - 50); //changes value from between (0 - 1023) to ((-50) - 50)
		    	speed = (speedData)/speedMod; //modifies speed
		    }
		    catch(System.Exception)
		    {
			    throw;
		    }
	    }
    }
    void FixedUpdate()
    {
        obj.transform.localRotation = Quaternion.Euler(0, rot, 0); //sets local rotation
        rb.velocity = transform.forward * speed; //moves object forward
    }
}

I see several issues here. First of all you should never do lowlevel hardware communication on the main thread. ReadLine is a blocking call which waits until data arrives (or the timeout is hit if one is set).

Next thing is you have set your timeout to “1ms”. So it will most likely run into the timeout all the time.

Low-level hardware communication should always be done on a seperate thread. Note that i said “thread”, not coroutine. A coroutine won’t help at all. Of course you have to synchronise your threads in order to transfer information from one thread to another.

You can decide if you want to do the parsing inside the reading-thread or in main thread. In your case it would be the easiest solution to parse it in the main thread as you only need to transfer single string between your threads. Of course the reading happens asynchronously and from your observation most likely much less often than your visual framerate. However you have to keep in mind that in theory if your framerate drops dramatically for some reason the reading thread might read two or more lines per update. Though since the information you’re processing are just state information you could simply "drop"older information and just keep the newest one.

Here’s an example:

public float speedMod = 10;
public GameObject obj;

Thread readingThread;
bool threadRunning = true;

bool newData = false;
string threadData;

Rigidbody rb;
float speed;
float rot;

void Start()
{
    rb = transform.GetComponent<Rigidbody>();
}

void OnEnable()
{
    readingThread = new Thread(ReadingThreadFunc);
    readingThread.Start();
}

void OnDisable()
{
    threadRunning = false; // signal the thread to terminate itself
    if (!readingThread.Join(400)) // wait for the thread to finish
    { // if it doesn't finish in the given time, force terminate the thread
        readingThread.Abort();
    }
    readingThread = null;
}

void Update ()
{
    if (newData)
    {
        lock(readingThread)
        {
            newData = false;
            string[] data = threadData.Split(',');
            float rotData = float.Parse(data[1]);
            float speedData = float.Parse(data[0]);
            rot = ((rotData / 10.23f) - 50);
            speed = (speedData) / speedMod;
        }
        obj.transform.localRotation = Quaternion.Euler(0, rot, 0);
        rb.velocity = transform.forward * speed;
    }
}

void ReadingThreadFunc()
{
    SerialPort p = new SerialPort("COM4", 9600);
    p.Open();
    p.ReadTimeout = 200; // wait 0.2 sec max
    while (threadRunning)
    {
        try
        {
            string data = p.ReadLine();
            lock (readingThread)
            {
                threadData = data;
                newData = true;
            }
        }
        catch (System.TimeoutException)
        {}
    }
    p.Close();
}

Keep in mind that the rate in which your arduino sends out information might be too slow. By default a serial port uses a baud rate of 9600 bits/sec. It takes about9 to 10 bits to transfer one byte. Since you send out strings they have quite a bit of overhead as your string could be 4 bytes + comma + 4bytes + newline character–> around 10 bytes per line. That’s just the limit of the serial port which gives you at max a rate of about 100 updates / lines per sec.

@qtoompuu
This code works for me but tell me how it works for you. Here it is:

float rotation=rotationspeed*Time.deltaTime;
 if (rot > rotation)
 {
     rot -= rotation;
 }
 else
 {
     rotation = rot;
     rot = 0;
 }
 transform.Rotate(0, 0, rotation);

I put this in my update method as it performs the rotation once per my instructions. Maybe you can fit it to your needs.