1
votes

I am trying to convert the 5 values returned when using the Rotation Vector Sensor Type to roll, azimuth, and pitch.

The code I am using to do so is the following.

@Override
public void onSensorChanged(SensorEvent event) {
    double[] g = convertFloatsToDoubles(event.values.clone());

    double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]);

    g[0] /= norm;
    g[1] /= norm;
    g[2] /= norm;
    g[3] /= norm;

    double xAng = (2 * Math.acos(g[0])) * (180 / Math.PI);
    double yAng = (2 * Math.acos(g[1])) * (180 / Math.PI);
    double zAng = (2 * Math.acos(g[2])) * (180 / Math.PI);
}

private double[] convertFloatsToDoubles(float[] input)
{
    if (input == null)
        return null;
        
    double[] output = new double[input.length];
    
    for (int i = 0; i < input.length; i++)
        output[i] = input[i];
        
    return output;
}

The issue is the values that are returned by variables xAng and yAng seem to be restricted to 80 - 280.

As for zAng (which I think is the azimuth), it is working like a compass but when it returns 0 it appears to be about 12 degrees off magnetic South.

I assume I have done something wrong with the maths used but I am unsure of what exactly.


The values for Sensor.TYPE_ROTATION_VECTOR are defined here as:

values[0]: x*sin(θ/2)

values[1]: y*sin(θ/2)

values[2]: z*sin(θ/2)

values[3]: cos(θ/2)

values[4]: estimated heading Accuracy (in radians) (-1 if unavailable)

1

1 Answers

3
votes

In case it helps anyone looking to accomplish the same task. The maths was being handled completely incorrectly.

Below onSensorChanged has been updated so it returns the correct values in degrees.

@Override
public void onSensorChanged(SensorEvent event) {
    //Get Rotation Vector Sensor Values
    double[] g = convertFloatsToDoubles(event.values.clone());

    //Normalise
    double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]);
    g[0] /= norm;
    g[1] /= norm;
    g[2] /= norm;
    g[3] /= norm;

    //Set values to commonly known quaternion letter representatives
    double x = g[0];
    double y = g[1];
    double z = g[2];
    double w = g[3];

    //Calculate Pitch in degrees (-180 to 180)
    double sinP = 2.0 * (w * x + y * z);
    double cosP = 1.0 - 2.0 * (x * x + y * y);
    double pitch = Math.atan2(sinP, cosP) * (180 / Math.PI);

    //Calculate Tilt in degrees (-90 to 90)
    double tilt;
    double sinT = 2.0 * (w * y - z * x);
    if (Math.abs(sinT) >= 1)
        tilt = Math.copySign(Math.PI / 2, sinT) * (180 / Math.PI);
    else
        tilt = Math.asin(sinT) * (180 / Math.PI);

    //Calculate Azimuth in degrees (0 to 360; 0 = North, 90 = East, 180 = South, 270 = West)
    double sinA = 2.0 * (w * z + x * y);
    double cosA = 1.0 - 2.0 * (y * y + z * z);
    double azimuth = Math.atan2(sinA, cosA) * (180 / Math.PI);
}