• 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
6
Question by codingChris · Apr 08, 2013 at 02:07 PM · rotationquaterniongyroscope

How to obtain roll / tilt angle from gyroscope?

Imagine that the user is holding the device with both hands in landscape mode. I need to determine the roll / tilt angle. The picture below show three different angles.

z rotation

This is the only kind of rotation I am interested in. So I tried using Input.gyro.attitude.eulerAngles.z. That works if the forward vector of the gyroscope is pointing at the horizon like the top image below. But if the forward vector is pointing downwards (3rd image) it fails.

x rotation

So I was wondering if anyone has an idea of how to determine the angles (z rotation) shown in the first image regadles of x rotation. I know that this a typical case of gimbal lock, but there must be a work-around. How do racing games tackle this problem when using the gyro for steering??

Note: I do not want to use Input.gyro.rotationRate and apply it as a delta to some kind of starting orientation, because that will become more and more inaccurate over time. Input.gyro.attitude (which is a quaternion) is the way to go. I just don't know how to get roll / tilt if the device is facing down (or up).

phone.jpg (43.4 kB)
iphone-rotation.gif (23.2 kB)
Comment
Add comment
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

3 Replies

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

Answer by codingChris · Apr 16, 2013 at 06:03 PM

As it turns out, the solution is pretty easy. After having spent way too much time with manual calculation I came up with this few lines instead:

 Quaternion referenceRotation = Quaternion.identity;
 Quaternion deviceRotation = DeviceRotation.Get();
 Quaternion eliminationOfXY = Quaternion.Inverse(
     Quaternion.FromToRotation(referenceRotation * Vector3.forward, 
                               deviceRotation * Vector3.forward)
 );
 Quaternion rotationZ = eliminationOfXY * deviceRotation;
 float roll = rotationZ.eulerAngles.z;

Rotating the quaternion so that its forward vector points to referenceRotation * Vector3.forward eliminates x and y rotation while maintaining z.

Still, the resulting roll angle will get a little bit unstable if you turn yourself 180° around real worlds y axis while playing (e.g. if you're sitting in a moving vehicle). That's what referenceRotation is for, which could either be reset manually by the user or even better via compass. That's what's next on my to do list :)

PS:

DeviceRotation.Get() is a wrapper for gyro input which adjusts the forward axis and takes different device orientations into account. Read more about it here.

Comment
Add comment · Show 8 · 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 gasparuff · Nov 27, 2014 at 06:25 PM 0
Share

Where can I find information about the DeviceRotation.Get()? The content on the website you have posted the link to seems to have changed. Thanks!

avatar image codingChris · Nov 28, 2014 at 09:39 AM 2
Share

DeviceRotation.Get() is a self written wrapper for Input.gyro.attitude. The article of that website explains what rotations have to be applied to Input.gyro.attitude and why. Here is the relevant code of my DeviceRotation class.

 public static class DeviceRotation {
     private static bool gyroInitialized = false;
 
     public static bool HasGyroscope {
         get {
             return SystemInfo.supportsGyroscope;
         }
     }
     
     public static Quaternion Get() {
         if (!gyroInitialized) {
             InitGyro();
         }
 
         return HasGyroscope
             ? ReadGyroscopeRotation()
             : Quaternion.identity;
     }
 
     private static void InitGyro() {
         if (HasGyroscope) {
             Input.gyro.enabled = true;                // enable the gyroscope
             Input.gyro.updateInterval = 0.0167f;    // set the update interval to it's highest value (60 Hz)
         }
         gyroInitialized = true;
     }
 
     private static Quaternion ReadGyroscopeRotation() {
         return new Quaternion(0.5f, 0.5f, -0.5f, 0.5f) * Input.gyro.attitude * new Quaternion(0, 0, 1, 0);
     }
 }
avatar image gasparuff · Nov 28, 2014 at 06:08 PM 0
Share

Oh thanks for that! Do you know how I could modify this to get only the values of the z axis?

avatar image codingChris · Nov 29, 2014 at 10:32 AM 0
Share

That's what the code in the original answer is for :)

avatar image bluewhite · May 12, 2015 at 03:35 PM 0
Share

How can I calculate pitch ins$$anonymous$$d? Sorry, but I dont understand quaternions at all

avatar image codingChris bluewhite · Jul 09, 2016 at 07:36 PM 0
Share

Look at my comment below. Using that code you can get the pitch by calling GetAngleByDeviceAxis(Vector3.right).

Show more comments
avatar image
1

Answer by Big Bang Studio · Jun 26, 2016 at 08:14 AM

@codingChris we are dealing with a similar situation right now where we need the X and Y axis. You describe this working for the Z axis, do you mean the "heading" rotation as used in regular aeronautics?

much appreciated, and sorry for the gravereply!

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 codingChris · Jul 09, 2016 at 07:30 PM 1
Share

You can pretty much use the same approach as above. I generalized the code, so that it looks like this:

     /// <summary>
     /// Returns the rotation angle of given device axis. Use Vector3.right to obtain pitch, Vector3.up for yaw and Vector3.forward for roll.
     /// This is for landscape mode. Up vector is the wide side of the phone and forward vector is where the back camera points to.
     /// </summary>
     /// <returns>A scalar value, representing the rotation amount around specified axis.</returns>
     /// <param name="axis">Should be either Vector3.right, Vector3.up or Vector3.forward. Won't work for anything else.</param>
     float GetAngleByDeviceAxis(Vector3 axis) {
         Quaternion deviceRotation = DeviceRotation.GetRotation();
         Quaternion eli$$anonymous$$ationOfOthers = Quaternion.Inverse(
             Quaternion.FromToRotation(axis, deviceRotation * axis)
         );
         Vector3 filteredEuler = (eli$$anonymous$$ationOfOthers * deviceRotation).eulerAngles;

         float result = filteredEuler.z;
         if (axis == Vector3.up) {
             result = filteredEuler.y;
         }
         if (axis == Vector3.right) {
             // incorporate different euler representations.
             result = (filteredEuler.y > 90 && filteredEuler.y < 270) ? 180 - filteredEuler.x : filteredEuler.x;
         }
         return result;
     }

So you'd call it with float xAngle = GetAngleByDeviceAxis(Vector3.right) and float yAngle = GetAngleByDeviceAxis(Vector3.up).

avatar image cg_augmentaio codingChris · Nov 30, 2016 at 05:44 PM 0
Share

@codingChris is GetRotation() the same as Get() ?

avatar image Cato11 cg_augmentaio · Apr 24 at 01:46 PM 0
Share

Unfortunately I do not think it is the same. He said that Get() adjusts for the forward-axis. When I try to use Get() for the y-axis (up), the readings go crazy. What's worse is that the link he posted is dead!

avatar image radiodario codingChris · Jan 17, 2017 at 10:20 AM 0
Share

hi @codingChris,

I'm using your solution but i'm seeing some strange results trying to get the xAngle (using Vector3.right)

At certain orientations, the returned angle spikes wildly (which is why i think you 're doing the "incorporate different euler representations" line in your code). I find that just subtracting 180 degrees from filteredEuler.x doesn't work. Say, i hold the phone so that i get about 70 degrees of pitch. However, as i turn the phone around the Y axis, it eventually spikes up to 360 degrees and then down to zero, and back to 70. Is this some kind of issue with the quaternion math? could you point me to somewhere i can read about this?

thanks a lot for your code anyway!

avatar image
0

Answer by Cato11 · Apr 24 at 01:09 PM

When I use Chris' code for the z-axis (the most upvoted post), I am able to change the referenceRotation to my own value (using DeviceRotation.Get), and measure the difference from that. It works perfectly, as I set my referenceRotation to the player's resting hand position on startup. And I use that as my reference point.

But as soon as I try to do the same with the y-axis (using Vector3.up), it does not work and the reading goes completely crazy. This axis only seems to work with a referenceRotation of Quaternion.identity, nothing else. Can anyone please advise why this might be? I really need to do the same thing as the z-axis and I do not understand why it won't work.

@codingChris any ideas?


EDIT: I suspect it has something to do with when he says "DeviceRotation.Get() is a wrapper for gyro input which adjusts the forward axis and takes different device orientations into account". I suspect I need to do the same for the up axis, but unfortunately the tutorial he posted no longer works!! Does anyone know how to do this?

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 andygeersdt · May 25 at 04:24 PM 0
Share

The linked article is available via the WayBack Machine here: https://web.archive.org/web/20180904151819/http://blog.heyworks.com/how-to-write-gyroscope-controller-with-unity3d/

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.

Follow this Question

Answers Answers and Comments

16 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

Related Questions

How to implement a mounted but movable headlight using the gyroscope? 1 Answer

quaternion - rotate camera based on original facing at scene start? 0 Answers

Gyroscope in Landscape mode snaps object to random rotation 0 Answers

Rotate with raw gyro data. 0 Answers

3rd player orientation using gyro with offset 0 Answers


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