I'm working on an app that uses the smartphone to control the pointer on a desktop. I saw many app of this type on the store so I know it isn't impossible! I'm doing this for university, I'm not looking for the perfect app but I can't figure which sensor should I use... I tried to use the rotation vector sensor and it's good for pitch (y values of pointer) but not the same for azimuth (for the x axis)... I didn't filter values. Do you think I have to change sensor or is it just a matter of filtering data? Any tips?
EDIT: Gyro mouse in Ali's video is really smooth and accurate and it says it's very simple to do but not for me! I take the rotation Matrix, get the angle change and then I map it to pixels but it's very inaccurate (the azimuth)! I'll post the code to show clearly what I'm doing:
//get values from Rotation Vector sensor
SensorManager.getRotationMatrixFromVector(rotationMatrix, sensorValues);
SensorManager.getAngleChange(orientationValues, rotationMatrix, prevMatrix);
prevMatrix = rotationMatrix;
azimuth += orientationValues[0];
pitch += orientationValues[1];
//getAngleChange returns radians so I multiply by 100
float dX = (azimuth - lastX)*100.f;
float dY = (pitch - lastY)*100.f;
pixel.x += dX;
pixel.y += dY;
// store values
lastX = azimuth;
lastY = pitch;
prevMatrix = rotationMatrix;
What you are looking for is most likely the gyro mouse. Basically, you just accumulate the change in angles along each axis. Code snippet is also given in the linked video.
UPDATE: Yes, you need sensor fusion. Unfortunately, I am not familiar with the Android API or with the Android sensors so I can only guess. I would try the SensorManager.getRotationMatrix() to get the rotation matrices, then determine the change of angle with SensorManager.getAngleChange(). Then you just accumulate the change along each axis.
Related
I am currently implementing an speedometer by receiving orientation data from my phone. I am using
SensorManager.getRotationMatrix(R, I, gravity, geomagnetic);
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azimuth = orientation[0];
double azimuthD = Math.toDegrees(azimuth);
if(azimuthD < 0) azimuthD = 360 + azimuthD;
With this i am able to receive the rotation data from my phone, such as azimuth etc..
Anyway, this works fine while the device is placed on a table or something. But when rotating around a certain point (in my case the device is fixed on a wheel and rotating at a certain speed) the values are far away from being accurate. I believe, since I am using gravity and the geomagnetic sensor, there could be an conflict with forces that influence these sensors, while rotating. As the wheel turns, the rotation changes relative to a point, but the local device rotation stays the same.
How can I access the orientation of the device while it's turning without running into a lot of noisy data?
I read some about the ´Sensor.TYPE_ROTATION_VECTOR´ property, but couldn't quite figure out how it works. Also I read about the possibility to remap the coordination system, but how is that supposed to help, since my phone is never not vertical to the floor more like with an angle of 5°-10°.
I would appreciate any help.
Cheers,
viehlieb
I guess i found my answer.
The solution was to throw away all the code i posted above and use the gyroscope, obviously.
The gyroscope values measure angular velocity of the device's rotation. The coordinate system used is the devices own coordinate system. In my case the relevant value was the rotation around the z-axis.
Values are in radiant per second, which can be mapped to m/s if you figure multiply the wheel's circumference. So the trick was in the OnSensorChanged method:
if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
gyroscope = sensorEvent.values;
double rotZ = gyroscope[2];
double degrees = Math.toDegrees(gyroscope[2]);
//calculate the speed with circumference = 2.23m
float speed = (float) degrees/ 360.0f * 2.23f * 3.6f;
}
If now you'd like to have accurate values, you could store them in an array and calculate the average. Remember to clear the array every 20th time (or so) the onSensorChanged method is called. With SENSOR_DELAY_GAME registered there's sufficient data over which you could build the average.
I want to detect if the user has taken a turn on the road while driving using the sensors on the android phone. How do I code this? I am collecting data live from all the sensors(accelerometer,location,rotation,geomagnetic) and storing them on the sd card. So now i just want to know whether the user has a taken a turn and in which direction he has turned.
I assume the registration of the sensor is done properly. You can detect the direction by using the orientation sensor (deprecated) as follows:
#Override
public void onSensorChanged(SensorEvent event) {
float azimuth_angle = event.values[0];
int precision = 2;
if (prevAzimuth - azimuth_angle < precision * -1)
Log.v("->", "RIGHT");
else if (prevAzimuth - azimuth_angle > precision)
Log.v("<-", "LEFT");
prevAzimuth = azimuth_angle;
}
Note: The variable of "prevAzimuth" is declared as global. You can change "precision" value to whatever you want. We need this value because we do not want to see output after each trivial change in azimuth angle. However, too large precision gives imprecise results. To me, "2" is optimum.
If you are tracking location coordinates, you can also track shifts between the angle from previous locations.
angle = arctan((Y2 - Y1) / (X2 - X1)) * 180 / PI
See this answer for calculating x and y.
Decision to use sensor values is based on an unrealistic assumption that the device is never rotated with respect to the vehicle.
A week ago i didn't know anything about Android Motion Sensors. After know the amazing thing called Virtual Reality I started to search about which sensors are used to get those results. Than I had a idea for a APP but I still don't know which sensors I should use for the situation below:
I have to get the phone orientation in reference to it self. I mean, I should be able to isolate each axis in degress. Something like it:
In this case, using gyroscope, I think that this variation is on the Z Axis.
Using ONLY gyroscope I had a good result for this situation, but after some repetions, I got a famous problem for the Gyro Sensor: Drift.
After this tutorial:
http://www.thousand-thoughts.com/articles/#articles
things became more clear in my head, but I still am having problems like latency between the real movement, and the output and wrong outputs when I change the device orientation (I think that the gravity is the guilty for that).
Is there some code example about how to get 0 - 360 degrees for each axis using ONLY the gyroscope and accelerometer sensors?
(I may had commited some english mistakes. Sorry for that)
The following code will give you correct lean angle, but only if your phone Z axis is 0. (like the way you illustrated it).
When starting to change the Z axis as well, it become problematic, i'm still working on that. (* Degrees has minus "-" sign when lean left and "+" sign to the right)
float[] mGravity;
float[] mGeomagnetic;
float[] temp = new float[9];
float[] RR = new float[9];
//Load rotation matrix into R
SensorManager.getRotationMatrix(temp, null,
mGravity, mGeomagnetic);
//Remap to camera's point-of-view
SensorManager.remapCoordinateSystem(temp,
SensorManager.AXIS_X,
SensorManager.AXIS_Z, RR);
//Return the orientation values
float[] values = new float[3];
SensorManager.getOrientation(RR, values);
Double degrees = (values[2] * 180) / Math.PI;
I am trying to have the tilt of the Z axis in an Android phone power the movement of a Libgdx Box2D car. I already know how to make the car move on my computer, but how do I implement that into an Android? The orientation is LANDSCAPE. Thanks so much!
I know something has to do with getRotation or something.... :)
you can get the Accelerometer Readings like this:
float accelX = Gdx.input.getAccelerometerX();
float accelY = Gdx.input.getAccelerometerY();
float accelZ = Gdx.input.getAccelerometerZ();
Wiki entry for more info:
https://github.com/libgdx/libgdx/wiki/Accelerometer
Then just apply a force to the body with it:
body.applyForceToCenter(<your_horizontal_accel_reading>, <vertical_if_needed_0_if_not>, true);
I have quite a simple requirement. Assuming a device is standing on its end, perpendicular to the ground, and it is tilted, all I need to determine is whether the phone is tilted forward or back (screen more toward the ground or more toward the ceiling).
I know how to read values from the various sensors and I figure that using sensor TYPE_ROTATION_VECTOR is the way forward. All I'm missing is the maths know-how to determine forward or back from the three values it returns.
I've read all related threads on SO without enlightenment, any help very much appreciated.
float[] rotationMatrix = new float[9];
float[] inclinationMatrix = new float[9];
float[] accelerometer; // values from sensor
float[] magnetic; // values from sensor
SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometer, magnetic)
int inclination = (int) Math.round(Math.toDegrees(Math.acos(rotationMatrix[8])));
if (inclination < 90)
{
// face up
}
if (inclination > 90)
{
// face down
}
The X axis is horizontal and points to the right, the Y axis is vertical and points up and the Z axis points towards the outside of the front face of the screen. In this system, coordinates behind the screen have negative Z values.
The reference coordinate system is defined as a direct orthonormal basis, where:
X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).
Y is tangential to the ground at the device's current location and points towards magnetic north.
Z points towards the sky and is perpendicular to the ground.
In your case try this,
if(Round(y,4) < 8.0){
Log.d("sensor", "=====UP====");
}
else if(Round(y,4) < -8.0){
Log.d("sensor", "=====DOWN====");
}
You can use the accelerometer and the magnetic field sensor to detect this.
I've found this helpful blog post which has the necessary code to show you how to do this.
http://www.ahotbrew.com/how-to-detect-forward-and-backward-tilt/