How can I get horizontal rotation angle whatever device orientation? - android

I can get horizontal rotation angle by calculating the roll value (according to the definition of iOS Device Motion) when the device is portrait.
The x, y, z-axis of the mobile device:
But when the device is in landscape, y-axis is horizontal and x-axis is vertical. How can I get the angle? The pitch value is not correct. I have tried to exchange x and y in quaternion but not worked.
And more, how can I get the angle when the device is in the middle of portrait and landscape, for example, you tilt the device 30 degrees about z-axis?
Is there a unified quaternion or rotational matrix to calculate the angle whatever device orientation?

Probably you want to get angle of some device "direction". For example if you want to get angle of Z axis projected on ground, do it exactly.
Transform the Z(0,0,1) vector into current device rotation.
You have direction of "ZinWorld" vector in some world frame.
According to world frame orientation , project "ZinWorld" into ground plane. For example , if in default world frame Z is pointing to UP , then just take X Y components of "ZinWorld".
Take atan2(X, Y) to get proper angle.

Related

rephrase definition for android orientation angle "roll"

The definition of 'roll' in android is:
angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground
See here.
Maybe I'm missing something, but there seem to be many planes perpendicular to the ground giving many different angles.
Could someone please rephrase this definition using e.g planes parallel to ground or screen, north direction, gravity direction?
NB! I am asking for a rephrasing using different words. I know the official definition as I have stated. Please don't repost the official definition.
From the mentioned docs:
Roll, angle of rotation about the y axis. This value represents the
angle between a plane perpendicular to the device's screen and a plane
perpendicular to the ground.
From another doc:
Roll (degrees of rotation about the y axis). This is the angle between
a plane perpendicular to the device's screen and a plane perpendicular
to the ground. If you hold the device parallel to the ground with the
bottom edge closest to you and tilt the left edge of the device toward
the ground, the roll angle becomes positive. Tilting in the opposite
direction—moving the right edge of the device toward the ground—
causes the roll angle to become negative. The range of values is -90
degrees to 90 degrees.
You may also have a look at that picture
The important point is about the y-axis. The y-axis is the one that goes positive from the bottom edge to the upper edge of the screen.
----EDIT----
A may be much more explicit picture here.
values[2]: Roll, angle of rotation about the y axis. This value represents the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the left edge of the device toward the ground creates a positive roll angle. The range of values is -π/2 to π/2.
The plane "perpendicular to the ground" here is just a reference for how "tilted" (rolled) the device is. Imagine the device flat on a table next to a wall. If you lift the edge of the device so it is tilted to the side, the angle of roll is the angle between the plane of the device and the plane of the wall. This is because we have constrained the x axis (pitch) so that you are looking at roll. Now, if you lift the top of the device towards you, the roll stays the same while the pitch changes, because the device is still at the same angle towards the wall along it's y axis.

Rotate 3d vector value into a single axis using a rotation quaternion

I want to rotate the whole value of a 3d vector into one axis using quaternion rotations.
The reason behind is that I want to align the X and Y Axis of my smartphone with the X and Y Axis of my vehicle in order to detect lateral and longitudinal acceleration separated on these two axis. Therefore I want to detect the first straight acceleration of the car and rotate the whole acceleration value into the heading axis (X-Axis) of the phone assuming a straight forward motion.
How do I achieve this?
I got it myself while this Link helped me a lot.
In the end I just needed to define the destination axis as a Vector V(Magnitude_Source, 0, 0), calculate the angle between V and the source vector and rotate the source vector.

Android device orientation , pitch calculation not consistent

I have developing an android application , which requires device inclination for real time processing. the device is inclined on a surface
i wanted to calculate the angle, for this i have used the project in github to calculate the pitch value. but the pitch values returned by this method is not accurate over multiple tests.. in the pitch value there is some margin of error most of the times .
And the same program tested over another phone it shows different pitch value in same position (laying the phones on the table) .
is there any way i can get the accurate pitch values across multiple devices.
i had used s6 and one plus 2 devices.
The Rotation Matrix is defined by applying roll first, then the pitch, and finally the yaw rotation. You can get the phone in the same position if you apply pitch first, then roll and again finally yaw. This is why you expect a certain pitch, but you get inaccurate values.
To prove to yourself this, play with the phone by bringing it in a certain random position by applying angle rotations in an certain order and then try to get to the same position by different order of rotations (a good position to try is phone in vertical position like keeping it in front of your face and tilted a bit to the side).
Most of the times you would use code like this
int rotation = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
if(rotation == 0) // Default display rotation is portrait
SensorManager.remapCoordinateSystem(Rmat, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_Y, R2);
else // Default display rotation is landscape
SensorManager.remapCoordinateSystem(Rmat, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, R2);
to make it more intuitive. This is how by you virtually would change the order, since you still have the Rotation Matrix defined by applying roll first, then the pitch, and finally the yaw rotation, but however this rotations are defined against an new XYZ coordinate system.
public abstract void onSensorChanged (int sensor, float[] values)
Added in API level 1
Called when sensor values have changed. The length and contents of the values array vary depending on which sensor is being monitored. See SensorManager for details on possible sensor types.
Definition of the coordinate system used below.
The X axis refers to the screen's horizontal axis (the small edge in portrait mode, the long edge in landscape mode) and points to the right.
The Y axis refers to the screen's vertical axis and points towards the top of the screen (the origin is in the lower-left corner).
The Z axis points toward the sky when the device is lying on its back on a table.
IMPORTANT NOTE: The axis are swapped when the device's screen orientation changes. To access the unswapped values, use indices 3, 4 and 5 in values[].
SENSOR_ORIENTATION, SENSOR_ORIENTATION_RAW:
All values are angles in degrees.
values[0]: Azimuth, rotation around the Z axis (0<=azimuth<360). 0 = North, 90 = East, 180 = South, 270 = West
values[1]: Pitch, rotation around X axis (-180<=pitch<=180), with positive values when the z-axis moves toward the y-axis.
values[2]: Roll, rotation around Y axis (-90<=roll<=90), with positive values when the z-axis moves toward the x-axis.
Note that this definition of yaw, pitch and roll is different from the traditional definition used in aviation where the X axis is along the long side of the plane (tail to nose).
And the difference between phones it is expected.

Set sprite rotation based on heading

I want to set a 2D sprite's rotation so it faces the direction it's moving in. Currently I hooked the accelerometer to the sprite's linear velocity and when I tilt my device it doesn't rotate, only moves. I am running AndEngine on Android.
I want to calculate x+/x-/y+/y- to receive a value in rotation degrees.
atan2(y,x) should do the trick.
So if angle=0 is in positive x direction,
angle = Math.atan2(y_velocity, x_velocity);
gives you the angle you have to rotate.
Figured it out eventually, to achieve this I did the following:
float radians=(float)Math.atan2(-acceleration.x, acceleration.y); //No Idea why I had to invert x axiz but it wouldn't work without it being done
float degrees=(float)Math.toDegrees(radians)+90; //Had to rotate my sprite by 90 degrees
radians=(float)Math.toRadians(degrees);
sprite.setTransform(sprite.getWorldCenter(), radians);

gimbal lock, can't solve by quaternion

When device is rotated by some amount, a simple cube has to rotate by the same amount but in the opposite direction. For example, the cube has to rotate to 45 degrees to the left if the device is rotated 45 degrees to the right. Or when pitch is 30 degrees, the cube has to rotate -30 degrees around X axis. When the yaw is 10 degrees, the cube has to rotate -10 degrees around Z axis. I've used .getRotationMatrixFromVector followed by getOrientation like so:
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(
mRotationMatrix , event.values);
SensorManager.getOrientation(mRotationMatrix, orientationVals);
azimuthVal = (Math.round((Math.toDegrees(orientationVals[0]))*100.0)/100.0);
pitchVal= (Math.round((Math.toDegrees(orientationVals[1]))*100.0)/100.0);
rollVal = (Math.round((Math.toDegrees(orientationVals[2]))*100.0)/100.0);}
But the problem with it change in pitch affects roll and vice versa and as a result when device is rotated around X axis, the pinch value changes->roll changes -> the cube rotates not only around X but also around Y, when I don't need that.
I've looked around the internet and many refer to Quaternions as a solution but how can I apply quaternions to my specific application, as I need to know amount of degrees device is rotated by along an axes.
Gimbal lock happens when you want to extract (Euler) rotation angles from the rotation matrix, basically at some specific rotation we loose a degree of freedom in the equation between rotation matrix components and rotation angles and the actual rotation angles are not recoverable,
So in your code it may happen at :
SensorManager.getOrientation(mRotationMatrix, orientationVals);
You should somehow solve the issue before extracting the rotation angles,
this could be done by modifying the quaternion's components as is explained here:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/

Categories

Resources