user472292
user472292

Reputation: 329

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?

Upvotes: 6

Views: 4798

Answers (3)

FLX
FLX

Reputation: 2679

You could set a maximum rotation to prevent fast jumps.

y_diff = new_y - last_y;
y = y + Mathf.Clamp(y_diff, -limit, limit);

Upvotes: 2

Dan Flanagan
Dan Flanagan

Reputation: 504

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);
}

Upvotes: 4

Hristo
Hristo

Reputation: 1815

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

Upvotes: 1

Related Questions