Search code examples
androidopengl-es-2.0accelerometergyroscopelowpass-filter

Android : Rotating a 3D object based on sensors : TYPE_ROTATION_VECTOR vs TYPE_ACCELEROMETER


Coming from a iOS background, I am starting to see some of the more interesting parts of Android like device support for sensors and even OpenGL calls.

I have been using the Sensor.TYPE_ROTATION_VECTOR in Android to rotate a object in 3D space based on the device. Works great on a Nexus 7 (2012) with no issues. However, any other device (Nexus 5, HTC sensation, Terga Note) it jumps around like its on speed.

This was the same result I got when I just used the Sensor.TYPE_ACCELEROMETER

Does anyone have any advice, code or anything about getting a smooth (on majority of devices) sensor value.

Override
    public void onSensorChanged(SensorEvent event) {

        int type = event.sensor.getType();

        //Log.i("TAG", "Sensor " + type);

        // It is good practice to check that we received the proper sensor event
        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
            //lowPass( event.values.clone(), MagneticFieldValues_last );

            // Convert the rotation-vector to a 4x4 matrix.
            SensorManager.getRotationMatrixFromVector(mRotationMatrix,
                    event.values);

            SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mRotationMatrix);
            SensorManager.getOrientation(mRotationMatrix, orientationVals);

            Matrix.multiplyMV(orientationVector, 0, mRotationMatrix, 0, sZVector, 0);
            orientation = (float) (-Math.atan2(orientationVector[0], orientationVector[1]) * RADIANS_TO_DEGREES);

            Matrix.invertM(mRotationMatrix_inv, 0, mRotationMatrix, 0);
            Matrix.multiplyMV(azimuthVector, 0, mRotationMatrix_inv, 0, sZVector, 0);
            azimuth = (float) (180 + Math.atan2(azimuthVector[0], azimuthVector[1]) * RADIANS_TO_DEGREES);

            // Optionally convert the result from radians to degrees
            orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
            orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
            orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);

        }


        if (type == Sensor.TYPE_MAGNETIC_FIELD) {

            pitch = event.values[2] * axisSwapper;
        }
    }

I was using a low pass filter however it was not required on the Nexus 7 and did not seem to work well.

//    protected float[] lowPass( float[] input, float[] output ) {
//        if ( output == null ) return input;
//
//        for ( int i=0; i<input.length; i++ ) {
//            output[i] = output[i] + ALPHA * (input[i] - output[i]);
//        }
//        return output;
//    }

Solution

  • I found moving to Google Cardboard for head tracking made things just work! really easy to implement. Copied

    https://github.com/MasDennis/RajawaliVR