I am currently trying to understand the sensor values I get from code similar to this.
The yaw/azimuth value seems to be okay. The problem is the pitch value, because I get -90° when the device is upright and tilting back and forward lead to the same values.
Lets say i tilt by 45° forward - the value is -45°, so its the same like tilting the device 45° backward.
Like this I cannot determine the device pitch in 360°.
Can somebody help me with that?
Taken from http://developer.android.com/reference/android/hardware/SensorListener.html:
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).
So Pitch -180° - 180° instead of 0° - 360°. The difference is forward shows -45° and backward should show 45°, right?
Related
I am trying to implement a business logic layer that tells me on what degree from 180 to -180 is the device currently is in the x axis. It will be used for a camera screen that requires the user to hold the phone vertically.
So in order to do so, I listens to both the TYPE_ACCELEROMETER and to the TYPE_MAGNETIC_FIELD sensors types as suggested in the official docs -
https://developer.android.com/guide/topics/sensors/sensors_position#sensors-pos-prox
And I ended up with the following code -
override fun onSensorChanged(event: SensorEvent?) {
val value = event?.values ?: return#onSensorChanged
var accelerometerReading = floatArrayOf()
var magnetometerReading = floatArrayOf()
when(event.sensor.type) {
TYPE_ACCELEROMETER -> {
accelerometerReading = floatArrayOf(value[0], value[1], value[2])
}
TYPE_MAGNETIC_FIELD -> {
magnetometerReading = floatArrayOf(value[0], value[1], value[2])
}
}
val rotationMatrix = FloatArray(9)
if (magnetometerReading.isEmpty() || accelerometerReading.isEmpty()) return#setOnSensorValuesChangedListener
SensorManager.getRotationMatrix(rotationMatrix, FloatArray(9), accelerometerReading, magnetometerReading)
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles) //always returns the same values that are provided to it. why?
As you can see, I implemented the exact same code as said to do in the official docs but the values I get have nothing to do in the range of 180 to -180 in both 3 of the elements in the orientationAngles array. I get values that are very similar to the input I give it, something like [-0.051408034, -0.007878973, 0.04735359] which is some random irrelevant data for me.
Any idea why would this happen and how to indeed get what I want which is the x axis angle of the device?
Edit:
I'll try to simplify what I want.
Imagine holding a device in portrait mode locked in with it facing you. In a perfect portrait stance I want to get a 90 degree value from the sensor. When the user tilts the device either left or right the values would either go down to 0 or up to 180 (which side it is doesn't matter). All I need is these 2 dimensional x axis values.
It gives the angles in radians, not degrees. Almost nothing in math uses degrees beyond grade school math, radians is the norm. Radians generally go from 0 to 2*pi, equaling 0 to 360 degrees. The formula to convert is degrees= radians/pi * 180
According to docs, the angles returned by getOrientation returns radians in the range -PI to PI, where 0 is defined by the individual angles. From the docs:
values[0]: Azimuth, angle of rotation about the -z axis. This value represents the angle between the device's y axis and the magnetic north pole. When facing north, this angle is 0, when facing south, this angle is π. Likewise, when facing east, this angle is π/2, and when facing west, this angle is -π/2. The range of values is -π to π.
values[1]: Pitch, angle of rotation about the x axis. This value represents the angle between a plane parallel to the device's screen and a plane parallel to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the top edge of the device toward the ground creates a positive pitch angle. The range of values is -π/2 to π/2.
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 -π to π.
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.
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.
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
Assumption: the phone is held flat (parallel with the ground).
I am using getRotationMatrix() and getOrientation (float[] R, float[] values) to get the azimuth. Under this assumption, the azimuth is simply values[0].
The documentation says:
All three angles above are in radians and positive in the
counter-clockwise direction.
Then I checked, when my phone's y axis points to the North, the azimuth is indeed 0.
However, here comes the problem: when my phone's y axis points to West, i.e. I rotated my phone counter-clockwise to make it point from North to West, the azimuth is negative!
Shouldn't the angle be positive when it is rotated counter-clockwise from North?
Where goes wrong?
No, if the positive direction of Z points to the sky then when y axis points to West then the angle is positive. But the coordinate used in getOrientation the positive direction of Z points down to the earth, thus now what seems counter-clockwise becomes clockwise, so West is negative.