• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by qtoompuu · Dec 14, 2017 at 12:36 PM · rotationrotatelagarduinolaggy

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
     }
 }
 
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image KittenSnipes · Dec 14, 2017 at 12:47 PM 1
Share

I’m not a hundred percent sure as I am currently researching this a bit as well but I think the fact you change the value of rot in update and then use it later on in FixedUpdate without multiplying it by Time.deltaTime could be a factor if it’s oddness. Because when you don’t multiply it by that it does it every frame rather than every second.

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by Bunny83 · Dec 14, 2017 at 02:22 PM

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.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image qtoompuu · Dec 14, 2017 at 03:42 PM 0
Share

Thank you very much, I've been trying to get this to work for like 3 days now and this works perfectly.

avatar image
0

Answer by KittenSnipes · Dec 14, 2017 at 12:54 PM

@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.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image qtoompuu · Dec 14, 2017 at 01:23 PM 0
Share

the issue is that I am not rotating by a certain amount each x amount of time, I am rotating to a specific point deter$$anonymous$$ed by a number between -50 and 50(imagine you have a knob that you can turn either way and you want the game object to mimic that knob) the .Rotate() method causes the object to keep rotating past the mark.

avatar image KittenSnipes · Dec 14, 2017 at 01:37 PM 1
Share

Ok I understand a bit more. Can that not be solved by a simple if statement then. If the object goes past that point then set a Boolean like:

 if (rot >= currentRotation) {
     allowedToRotate = false;
 }
 
 if (allowedToRotate == true) {
     Rotate that thing.
 }
 
 else {
     return;
 }
 
avatar image qtoompuu KittenSnipes · Dec 14, 2017 at 02:09 PM 0
Share

I appreciate the help, but after some careful debugging, i've realized that my issue has to due with too many of my "try catches"(lines 28 - 40) failing and thus not running the necessary code. I need to figure out what is causing this error:

TimeoutException: The operation has timed-out, System.IO.Ports.WinSerialStream.Read(System.Byte[] buffer, Int32 offset, Int32count)

avatar image KittenSnipes · Dec 14, 2017 at 01:38 PM 0
Share

Oops that first statement I meant to switch that around because rot is a constant which is the max currentRotation can reach. Sorry about that.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

103 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to write : Rotate and Reset 0 Answers

How to get all gameObjects with a script on them 1 Answer

Trouble rotating a prefab while it's moving up,Rotating an object with an animation while it moves up 0 Answers

After rotate with joystick, rotate resetting,joystick rotate correction 0 Answers

Smoothly rotating an object to a specific rotation. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges