I know this has been asked before, but I haven't found the answer I am looking for.
All I want to do is hold my phone up at the sky, and know the angle at which I am holding it with respect to the horizon. So if I am holding it directly above me (screen facing ground) then it should read 90 degrees, and if I hold it in front of me (screen facing me), it should read 0 degrees.
I have fumbled through some basics of getting data from the accelerometer and I believe I have the X, Y and Y values from it. How can I take those points and find my angle? Below is my OnSensorChanged event that I gather the coordinate from.
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
playerAngle = (float) Math.toDegrees(Math.atan2(orientation[1], orientation[0]));
}
Related
This is my code so far and is changing the rotation of the marker regarding the position of the tablet.
float[] mGravity;
float[] mGeomagnetic;
Float azimut;
Marker Mymarker;
MarkerOptions MyMarkerOption = new MarkerOptions();
public void onSensorChanged(SensorEvent event) {
if(GotLocation){
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
MyLocation = new LatLng(currentLatitude, currentLongitude);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0];
float azimuthInRadians = orientation[0];
float azimuthInDegress = (float)(Math.toDegrees(azimuthInRadians)+360)%360;
if(location_marker == 0){
MyMarkerOption.position(MyLocation);
Mymarker = map.addMarker(MyMarkerOption);
location_marker++;
}
Mymarker.setPosition(MyLocation);
Mymarker.setRotation(azimuthInDegress);
Mymarker.setFlat(true);
}
}
}
}
I would like that the rotation of the marker changes regarding a given lat-long position. So I guess that now the algorithm is calculating the azimuthInDegress regarding the tablet. I would like that it calculates it regarding a given point.
I found this thread where someone was asking the same thing, but I do not know how to implement this solution for my code..The thread is also 5 years old so maybe there is another solution right now.
Which is the inclination of the moving angle to an angle 0 which corresponds to mobile laid flat.
I want exactly measure angle on the corner walls (between 2 walls)
I already use this code, and the results obtained:
public void onAccuracyChanged(Sensor sensor, int accuracy) {
float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event){
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = event.values.clone();
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values.clone();
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0];
mAzimuthView.setText(String.format("%.2f",Math.toDegrees(azimut)) + '°');
tv.setText(String.format("%.2f", Math.toDegrees(azimut-angle_reset)) + '°');
}
}
}
1 - GSM is a flat vertical -> azimuth = 37 ° .
2 - Turn GSM Horizontally 90 ° -> = -111 ° azimuth .
So the difference ( 111-37 ) is 74 ° !!!! ( But normally I have to get 90 °)
Fast and simple. How to get the quaternion data from the sensors?
basically I need:
float quaternion_x = ?
float quaternion_y = ?
float quaternion_z = ?
float quaternion_w = ?
I have something like this:
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
{
float[] values = event.values;
float quaternion_x = values[0];
float quaternion_y = values[1];
float quaternion_z = values[2];
float quaternion_w = values[3]; <----- ERROR HERE
}
I get an index out of bound exception because values has only 3 values inside. According to this page:
http://developer.android.com/guide/topics/sensors/sensors_motion.html
There should be 4 values or am I understanding something wrong?
The SensorManager class offers a helper function to convert for you:
SensorManager.getQuaternionFromVector(Q, values);
float[] quaternion_w = Q[0];
float[] quaternion_x = Q[1];
float[] quaternion_y = Q[2];
float[] quaternion_z = Q[3];
The android implementation of getOrientation returns the same values of getQuaterionFromVector.
So, you can take those values and construct the Quaternion if you want;
float[] quaternion = new float[4];
quaternion[0] = 0; //w
quaternion[1] = orientation[0]; //x
quaternion[2] = orientation[1]; //y
quaternion[3] = orientation[2]; //z
I checked it out with this code.
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mMagneticField = event.values;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if ((mGravity == null) || (mMagneticField == null))
return;
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mMagneticField);
if (success) {
mOrientation = new float[3];
mQuaternion = new float[4];
SensorManager.getOrientation(R, mOrientation);
mAzimut = mOrientation[0]; // orientation contains: azimut, pitch and roll
mPitch = mOrientation[1];
mRoll = mOrientation[2];
SensorManager.getQuaternionFromVector(mQuaternion, mOrientation);
if(mAzimut - mQuaternion[1] == 0 && mPitch - mQuaternion[2] == 0 && mRoll - mQuaternion[3] == 0){
Log.d("ORIENTATION", "QUATERNION IS THE SAME");
}
notifyObservers();
}
}
I want to compute the compass' direction, so I use the following code:
SensorManager mManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
Sensor accelerometer = mManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magnetometer = mManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
private float mR[] = new float[9];
private float mI[] = new float[9];
float mOrientation[] = new float[3];
....
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
boolean success = SensorManager.getRotationMatrix(mR, mI, mGravity, mGeomagnetic);
if (success) {
SensorManager.getOrientation(mR, mOrientation);
int azimut = (int) (mOrientation[0]*180/3.14159f); // This is the data
}
}
}
It usually works fine. It does not work when there is an interference with the magnetic field - for example under my car radio. In that case - I get a wrong constant reading.
how can I detect magnetic interference?
I am trying to get the compass bearing in degrees (i.e. 0-360) using the following method:
float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azimut = orientation[0];
bearing.setText("Bearing: "+ azimut);
}
}
}
The azimuth value (i.e. orientation[0]) should be 0<=azimuth<360 but I am getting only values from -3 to 3 as I rotate my device. Can someone please tell me what the problem might be please?
The values are in radian, you have to convert to degree of arc
int azimut = (int) Math.round(Math.toDegrees(orientation[0]));
It is true that it is in Radians. Thanks Hoan. I added some logic to get that bearing in degrees from 0 to 360 becuase if I only converted it to degrees, I was getting values from -180 to 180.
float azimuthInRadians = orientation[0];
float azimuthInDegress = (float)Math.toDegrees(azimuthInRadians)+360)%360;
// This answer applies to Google Maps api v2.
// It is possible by registering your application with Sensor Listener for Orientation and get the
// angle relative to true north inside onSensorChanged and update camera accordingly.
// Angle can be used for bearing. Following code can be used:
// Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION
// has been deprecated.
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (sensorManager != null)
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
public void onSensorChanged(SensorEvent event) {
float compassBearingRelativeToTrueNorth = Math.round(event.values[0]);
Log.d(TAG, "Degree ---------- " + degree);
updateCamera(compassBearingRelativeToTrueNorth);
}
private void updateCamera(float bearing) {
CameraPosition oldPos = googleMap.getCameraPosition();
CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing)
.build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
}