Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity: Input.gyro.attitude Accuracy

In my app, I need to be aware of the device rotation. I am trying to pull the y-axis value from the gyroscope using the following:

var y = Input.gyro.attitude.eulerAngles.y;

If I simply output that to the screen and turn in a circle (holding my phone straight up and down...as if you were looking at the screen), I get the following:

270, 270, 270, 270, etc...270, 290, 310, 20, 40, 60, 80 (very quickly)...90, 90, 90, 90, etc...blah...

Is there any way to account for this jump in numbers?

like image 404
user472292 Avatar asked Mar 20 '17 03:03

user472292


3 Answers

Gimbal Lock

What you're seeing is something called the gimbal lock more info here. It happens with Euler angles cross the 360 plane or more specifically (two of the three axis's are driven into a parallel configuration), and that is why people use Quaternions.

Quaternions

You shouldn't be pulling the euler angles directly. I would recommend something like this:

Quaternion q = Input.gyro.attitude.rotation;

By using the Quaternion rather than the euler angles we will avoid the gimbal lock and therefore avoid the 360, 0 issue.

If you simply want to show the angle they are facing in the y direction I might recommend something like this, this wraps the y angle to 0 to 180 degrees:

/// <summary>
/// This method normalizes the y euler angle between 0 and 180. When the y euler
/// angle crosses the 180 degree threshold if then starts to count back down to zero
/// </summary>
/// <param name="q">Some Quaternion</param>
/// <returns>normalized Y euler angle</returns>
private float normalizedYAngle(Quaternion q)
{
    Vector3 eulers = q.eulerAngles;
    float yAngle = eulers.y;
    if(yAngle >= 180f)
    {
        //ex: 182 = 182 - 360 = -178
        yAngle -= 360;
    }
    return Mathf.Abs(yAngle);
}
like image 54
Dan Flanagan Avatar answered Oct 23 '22 15:10

Dan Flanagan


You could set a maximum rotation to prevent fast jumps.

y_diff = new_y - last_y;
y = y + Mathf.Clamp(y_diff, -limit, limit);
like image 38
FLX Avatar answered Oct 23 '22 15:10

FLX


You could use linear interpolation to achieve this effect. The only thing you need to consider is how fast you will do it, since the phone will be constantly rotating and you don't want your values to be lagging.
An example using Mathf.Lerp:

    // Your values
    var y = 0;       

    // speed for the Lerp
    static float t = 1.0f;

    void Update()
    {
        float old = y
        float new = Input.gyro.attitude.eulerAngles.y;
        // Interpolate
        y = Mathf.Lerp(old, new, t * Time.deltaTime);    
    }

Referenced from here

like image 1
Hristo Avatar answered Oct 23 '22 13:10

Hristo