Android Rotation Vector sensor and Rotation Matrix - android

I'm new in the rotation matrices field and I'm trying to understand the behave of the Rotation Vector Sensor. I can't understand the relation between yaw, pith and roll with the values returned by the Rotation Vector Sensor.
I checked the source code of the SensorManager.getRotationMatrixFromVector() here and the Android documentation. The Rotation vector sensor returns the following values:
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)
From the documentation: "the device has rotated through an angle θ around an axis (x, y, z)". So my dubt now is, what is θ? And what are x,y and z?
Following this tutorial from the OpenGL documentation, to rotate a vector V I need the pith, roll and yaw values with which I build the rotation matrix. At the end I have to multiply this matrix by V to rotate the vector. If I'm right, this matrix is different from the one related to the values vector obtained using SensorManager.getRotationMatrixFromVector(). Am I right? So what represents that matrix?

Related

Rotate a rotation matrix about what would be the pitch Euler angle

I've got my 3D scene's camera rotating as desired, but to do it I converted to Euler angles using SensorManager.getOrientation(rotationMatrixIn, eulerAnglesOut); so I could add 90 to the pitch before recalculating a rotation matrix from the modified Euler angles. I'm adding 90 to the pitch so my rotation can be used for a cubemap where Y is up when the phone is held perpendicular to the ground.
I'm using Euler angles because this made it intuitive to rotate the pitch by 90 degrees. But I'm suffering from gimbal lock now when the phone is held near vertical and the pitch approaches -90 or 90 degrees. The view rapidly rotates 180 degrees (in the roll and azimuth axes) when it gets close to these angles. This does not occur when I use the unmodified rotation matrix, but then I don't have the orientation corrections I need.
I'm having trouble wrapping my head around the math needed to skip the Euler angles conversion and directly rotate the rotation matrix by 90 degrees about what would be the X axis in Euler angles and invert the roll. I have access to various math classes from a library (Matrix and Quaternion) which can be multiplied by each other and convert to and from Eulers.
I want to rotate about what would be the X axis. Is there a way to do this without introducing gimbal lock?
To clarify: the Euler angles I'm talking about are in -Z, X, Y order, where X is the pitch.
As #meowgoesthedog stated in a deleted comment, the rotation matrix should be pre-multiplied by a matrix that holds a 90 degree rotation about the X axis.
The rotation matrix from Android's sensors converts device orientation to world orientation, so pre-multiplying it by some other matrix is like applying a rotation to the device first before converting the coordinate system.
I was also tripped up by Android's row-major matrix ordering. The matrix must be inverted to get it into OpenGL's column-major ordering. My Euler angles worked OK because they were hiding this inconsistency.

List of rotation matrix for object projection on screen in android

I have vector X and Y which I get from GPS latitude and longitude of my device position and the target object. Now to draw a marker on the target object on my screen I need to do some transformation to the vector. To transform I need to use rotation matrices. I have created a list of rotation matrices. But my point is not being drawn on the correct position. I think I m missing some rotation matrices. Below is the list
Rotation for being landscape about X axis -90 degree
Remap coordinate by after getting rotation by getrotation() method
My point is being shown to left of the main object. So its about Y axis I guess. My projection is correct as that's taken from opengl. So I think I am missing some rotation about Y axis. Please help.
Yes you are missing a rotation about Y-axis. It is the error for the magnetic north not being same to true north. The magnetic north is moving to NW at a speed of 40km/year from true north. As a result you need to calculate the deflection of your magnetic sensor north at you position from true north.
Problem is this deflection is different at different position and different time. Android gives a method to calculate the deflection at any position given your latitude,longitude and current time. The method is getDeclination () and use it like below to get angle
gmf = new GeomagneticField((float)Latitude,(float)Longitude,(float)Altitude,
System.currentTimeMillis());
angleY = Math.toRadians(-gmf.getDeclination());
For reference take a look at GeomagneticField

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.

Find heading for a device

I need to find the heading(in terms of degrees east or west of north) for an Android device that is being held vertically(like this: Heading) . I accessed the sensor.event[2] values returned from the geomagnetic sensor and found that they vary from 1 to 35 as I rotate the device completely about vertical axis. How can I convert this value to a heading? A very brief explanation or a link would be appreciated.
Look at SensorManager.getOrientation It returns 3 angles, around the 3 axes.
Computes the device's orientation based on the rotation matrix.
When it returns, the array values is filled with the result:
values[0]: azimuth, rotation around the Z axis.
values[1]: pitch, rotation around the X axis.
values[2]: roll, rotation around the Y axis.
The reference coordinate-system used is different from the world coordinate-system defined for the rotation matrix:
X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points West).
Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.
Z points towards the center of the Earth and is perpendicular to the ground.
You'll need to use the geomagnetic and accelerometer sensors to feed in the data to get the rotation matrix. Look at SensorManager for more info

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