I'm developing an app similar to a camera app, with a line in the center of the camera preview that shows the device tilt in regard to the horizon.
I'm using only the accelerometer, since my use case is a semi-stationary device (the user may move and tilt it and the line will update, but they should only expect a fair reading if the device is somewhat still).
This is what I've got so far:
public void onSensorChanged(SensorEvent event) {
switch( event.sensor.getType() ){
case Sensor.TYPE_ACCELEROMETER:
float[] acc = event.values.clone(); // [accX, accY, accZ]
double gravityNormalized = Math.sqrt(acc[0]*acc[0] + acc[1]*acc[1] + acc[2]*acc[2]);
double[] accNormalized = new double[3];
accNormalized[0] = acc[0]/gravityNormalized;
accNormalized[1] = acc[1]/gravityNormalized;
accNormalized[2] = acc[2]/gravityNormalized;
double[] tiltDegrees = new double[3];
tiltDegrees[0] = Math.toDegrees(Math.asin(accNormalized[0]));
tiltDegrees[1] = Math.toDegrees(Math.asin(accNormalized[1]));
tiltDegrees[2] = Math.toDegrees(Math.asin(accNormalized[2]));
Log.d(TAG, "tiltDegrees: " + Arrays.toString(tiltDegrees) + ", accNormalized: " + Arrays.toString(accNormalized) + ", acc: " + Arrays.toString(acc) );
((ImageView) findViewById(R.id.levelLine)).setRotation((int)tiltDegrees[0]);
break;
}
}
It seems to be working fairly well, as long as the rotation is moderate. When I start nearing 90 degrees rotation of the device (portrait orientation vs horizon), the line stops rotating and is thus no longer in line with the horizon, but slightly tilted (I'd say about 5-10 degrees). Also, if I continue to rotate the device further than 90 degrees, the line becomes more and more tilted away from the horizon and becomes vertical when the device is rotated 135/-135 degrees.
Am I doing something wrong here? Is there a better way of getting the device tilt?
Further along in development I have the need to accurately get the tilt "forwards/backwards" (i.e. how many degrees the phone is tilted forwards/backwards while in portrait orientation). I'm thinking I could use the same approach I'm doing now but on tiltDegrees[1]
instead of tiltDegrees[0]
?
I somehow find it a bit strange that there is a TYPE_ROTATION_VECTOR
that relates to the world-frame (north/south/east/west) but no device-frame TYPE_DEVICE_VECTOR
or something similar to easily get the rotation of the device along its X, Y and Z axis (e.g. in relation to a perfect portrait mode).