gilberto
gilberto

Reputation: 157

How can i get device tilt in xamarin forms?

I´d like to get the tilt of the device, so i can use this to mesure the tilt os some surface, laying down the device over the surface.

Right now i am using Device Motion Plugin for xamarin forms from here https://github.com/rdelrosario/xamarin-plugins

and the code below:

CrossDeviceMotion.Current.Start(MotionSensorType.Accelerometer);

    CrossDeviceMotion.Current.SensorValueChanged += (s, a) =>
    {

        switch (a.SensorType)
        {
            case MotionSensorType.Accelerometer:
                {
                    Debug.WriteLine("A: {0},{1},{2}", ((MotionVector)a.Value).X, ((MotionVector)a.Value).Y,
                     ((MotionVector)a.Value).Z);
                    Exposicao.Inclinacao = ((MotionVector)a.Value).Z;
                    break;
                }
            case MotionSensorType.Compass:
                {
                    // Debug.WriteLine("H: {0}", a.Value);
                    Exposicao.Bussola = (double)a.Value.Value;
                    break;
                }
        }
    };

The compass part is ok, the accelerometer part is working but there are some but´s.

If i am not wrong, i get the tilt in Z axis, so z.Value.Value.

This value is diferent for android and ios, lets focus in android.

z values are from 10 when device is laying down on flat surface, to 0 if device is stand up, lets focus only in just one quadrant.

I am doing something wrong to achieve what i explained?

How can i convert those values to a Angle between 0 and 90? It seems not linear, so the 5 does not seem 45 degrees.

Thanks

Upvotes: 4

Views: 1636

Answers (1)

Timo Salomäki
Timo Salomäki

Reputation: 7189

I'd probably roll out my own platform implementation for the feature you're looking for. The DeviceMotion library looks a bit simple for your purposes, as can be seen from the answer below. I'm pretty sure you can use it as a good starting point but it needs to be extended a little.

Android

On Android, you should use the Rotation Vector Sensor which uses a Kalman filter (with accelerometer, magnetometer and gyroscope) to get accurate measurements of the device's rotation:

The rotation vector represents the orientation of the device as a combination of an angle and an axis, in which the device has rotated through an angle θ around an axis (x, y, or z). enter image description here

Image from the official Android documentation

iOS:

For iOS, you have to do a bit more work yourself. The key is to make use of CMAttitude, which describes the attitude of the device relative to an initial attitude. I found a snippet I've saved to my collection from an unknown source (can't credit the original author) here:

public void CalculateLeanAngle ()
{           
    motionManager = new CMMotionManager ();
    motionManager.DeviceMotionUpdateInterval = 0.02; 

    if (motionManager.DeviceMotionAvailable) {
        motionManager.StartDeviceMotionUpdates(CMAttitudeReferenceFrame.XArbitraryZVertical, NSOperationQueue.CurrentQueue, (data, error) => { 
            CMQuaternion quat = motionManager.DeviceMotion.Attitude.Quaternion;
            double x = quat.x;
            double y = quat.y;
            double w = quat.w;
            double z = quat.z;
            double degrees = 0.0;

            //Roll
            double roll = Math.Atan2 (2 * y * w - 2 * x * z, 1 - 2 * y * y - 2 * z * z);                        
            degrees = Math.Round (-applyKalmanFiltering (roll) * 180.0 / Constants.M_PI);
    });
}

public double applyKalmanFiltering (double yaw)
{
    if (motionLastYaw == 0)
        motionLastYaw = yaw;

    float q = 0.1f;   // process noise
    float r = 0.1f;   // sensor noise
    float p = 0.1f;   // estimated error
    float k = 0.5f;   // kalman filter gain

    double x = motionLastYaw;
    p = p + q;
    k = p / (p + r);
    x = x + k * (yaw - x);
    p = (1 - k) * p;
    motionLastYaw = x;

    return motionLastYaw;
}

enter image description here

Image from the official Xamarin documentation

I'll try to look for the original source when I have more time but I'm pretty sure this will work out of the box for your purposes.

Upvotes: 2

Related Questions