Remapping coordinate system in Android app

3.5k Views Asked by At

I'm implementing a simple Android app, in which I need to identify the north.

So I've implemented SensorEventListener and I used something like this:

@Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
    {
        SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
        SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, orientationVals);
        SensorManager.getOrientation(mRotationMatrix, orientationVals);

        orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
        orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
        orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);

        tv.setText(" Yaw: "+ orientationVals[0] +"\n Pitch: "+ orientationVals[1]+"\n Roll: "+ orientationVals[2]);
    }

}

The problem is that the code line

SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, orientationVals);

seems to not work, since in both case (with or without this code line) the value of Yaw (azimuth) depends on the orientation of the head of the phone (letting it layied on the back side)

what I expected, using my remapping, was that the Yaw changed based on the orientation of the back of the phone (the rear camera).

Why my remapping does not work?

2

There are 2 best solutions below

0
On

I used this:

/* Compensate device orientation */
            float[] remappedRotationMatrix = new float[9];
            switch (getWindowManager().getDefaultDisplay()
                    .getRotation()) {
            case Surface.ROTATION_0:
                SensorManager.remapCoordinateSystem(rotationMatrix,
                        SensorManager.AXIS_X, SensorManager.AXIS_Y,
                        remappedRotationMatrix);
                break;
            case Surface.ROTATION_90:
                SensorManager.remapCoordinateSystem(rotationMatrix,
                        SensorManager.AXIS_Y,
                        SensorManager.AXIS_MINUS_X,
                        remappedRotationMatrix);
                break;
            case Surface.ROTATION_180:
                SensorManager.remapCoordinateSystem(rotationMatrix,
                        SensorManager.AXIS_MINUS_X,
                        SensorManager.AXIS_MINUS_Y,
                        remappedRotationMatrix);
                break;
            case Surface.ROTATION_270:
                SensorManager.remapCoordinateSystem(rotationMatrix,
                        SensorManager.AXIS_MINUS_Y,
                        SensorManager.AXIS_X, remappedRotationMatrix);
                break;
            }

            /* Calculate Orientation */
            float results[] = new float[3];
            SensorManager.getOrientation(remappedRotationMatrix,
                    results);

Please tell me if it works because I still have Problems with that solution. It's my own code from here. I wrote it based on this official post.

0
On

Not sure if you solved this, but your line:

SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, orientationVals);

remaps the values in mRotationMatrix, and puts the result in orientationVals. This is correct (besides a confusing variable name for the remapped coordinate array).

However, you then overwrite this remapping directly after by calling:

SensorManager.getOrientation(mRotationMatrix, orientationVals);

This takes the values in mRotationMatrix and computes the orientation based on those (old, non-remapped) values, and stores it in orientationVals.

Thus your code above is simply getting the orientation of mRotationMatrix, whose axis have not been remapped, which probably explains your issue.

Something like the following may fix your problem:

float[] remapCoords = new float[16];
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapCoords);
SensorManager.getOrientation(remapCoords, orientationVals);

assuming your axis remap is what you actually want/correct, but that is another issue.

I should note that the article cited, while most excellent, does not explicitly mention that remap coordinate system has to be called every time your rotation matrix is computed, not just when the display changes (i.e., onCreate, onSurfaceChanged, etc.) which might be obvious to some, but not to others.