Get device angle by using getOrientation() function - android

I was using Sensor.TYPE_ORIENTATION to determine current angle of device but TYPE_ORIENTATION is deprecated on API version 8. In SensorManager manual it refers to getOrientation() function in order to use TYPE_ORIENTATION.
Here is the manual
Here is my old code :
public void onSensorChanged(SensorEvent event) {
Log.d("debug","Sensor Changed");
if (event.sensor.getType()==Sensor.TYPE_ORIENTATION) {
Log.d("debug",Float.toString(event.values[0]));
float mAzimuth = event.values[0];
float mPitch = event.values[1];
float mRoll = event.values[2];
Log.d("debug","mAzimuth :"+Float.toString(mAzimuth));
Log.d("debug","mPitch :"+Float.toString(mPitch));
Log.d("debug","mRoll :"+Float.toString(mRoll));
}
}
I'm really confused about using getOrientation() function, can anyone please show me an example how to get the angles?

You now use two sensors (ACCELEROMETER and MAGNETIC_FIELD) to get that information. See blog post for more detail.
public class CompassActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
Sensor accelerometer;
Sensor magnetometer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mCustomDrawableView); // Register the sensor listeners
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
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;
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);
azimut = orientation[0]; // orientation contains: azimut, pitch and roll
}
}
}
}
Permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Regarding your second question. When you are registering your sensor listeners, change your code to read:
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
}

Google has a great demo app for orientation in their google-developer-training series called TiltSpot. Because it has an Apache license, I've taken the liberty of turning it into a small library called johnnylambada-orientation that makes getting orientation as simple adding this to your activity:
getLifecycle().addObserver(new OrientationReporter(this, (a, p, r) -> {
Log.i("orientation","a="+a+" p="+p+" r="+r);
}));

My Answer is for those who getting jumping values of heading. For further instruction let me know in the comment.
Sensor accelerometer;
Sensor magnetometer;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float[] Rv = new float[9];
private float[] I = new float[9];
class MapsActivity
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, SensorEventListener{
onSensorChanged(SensorEvent event)
#Override
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
float INITIAL_ALPHA = 0.97f;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = INITIAL_ALPHA * mGravity[0] + (1 - INITIAL_ALPHA)
* event.values[0];
mGravity[1] = INITIAL_ALPHA * mGravity[1] + (1 - INITIAL_ALPHA)
* event.values[1];
mGravity[2] = INITIAL_ALPHA * mGravity[2] + (1 - INITIAL_ALPHA)
* event.values[2];
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mGeomagnetic[0] = INITIAL_ALPHA * mGeomagnetic[0] + (1 - INITIAL_ALPHA)
* event.values[0];
mGeomagnetic[1] = INITIAL_ALPHA * mGeomagnetic[1] + (1 - INITIAL_ALPHA)
* event.values[1];
mGeomagnetic[2] = INITIAL_ALPHA * mGeomagnetic[2] + (1 - INITIAL_ALPHA)
* event.values[2];
if (Math.abs(mGeomagnetic[2]) > Math.abs(mGeomagnetic[1])) {
magStrength = Math.round(Math.abs(mGeomagnetic[2]));
} else {
magStrength = Math.round(Math.abs(mGeomagnetic[1]));
}
}
boolean success = SensorManager.getRotationMatrix(Rv, I, mGravity, mGeomagnetic);
if (success) {
float[] orientation = new float[3];
SensorManager.getOrientation(Rv, orientation);
azimuth = (float) Math.toDegrees(orientation[0]);
azimuth = (azimuth + 360) % 360;
// Log.d(TAG, "azimuth (deg): " + azimuth);
float degree = Math.round(azimuth);
// create a rotation animation (reverse turn degree degrees)
RotateAnimation ra = new RotateAnimation(
currentDegree,
-degree,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
ra.setDuration(500);
ra.setFillAfter(true);
ra.setRepeatCount(0);
binding.compassImage.startAnimation(ra);
showDirection(degree);
currentDegree = -degree;
}
}
}
onAccuracyChanged
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
onResume()
#Override
protected void onResume() {
super.onResume();
if (mSensorManager == null) {
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
onPause()
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(MapsActivity.this);
}

Related

FusedLocationProviderClient doesn't have bearing data

I'm using FusedLocationProviderClient class in android to get user's last location. Everything is fine and I can get latitude and longitude but task.getResult().getBearing() returns 0.0 and task.getResult().hasBearing() returns false. How can I get user's bearing information?
I'm getting ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions both in AndroidManifest file and at runtime.
This is the piece of code related to user location I'm using:
#SuppressLint("MissingPermission")
private void getLastLocation() {
fusedLocationClient
.getLastLocation()
.addOnCompleteListener(this, new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
if (task.isSuccessful() && task.getResult() != null) {
onLocationChange(task.getResult());
Log.i(TAG, "lat " + task.getResult().getLatitude() + " lng " + task.getResult().getLongitude());
Log.i(TAG, "bearing? " + task.getResult().hasBearing());
} else {
Toast.makeText(MainActivity.this, "Location Not Found!", Toast.LENGTH_SHORT).show();
}
}
});
}
private void onLocationChange(Location location) {
//do something
}
According to documentation
If this location does not have a bearing then 0.0 is returned.
I solved my problem using accelerometer and magnetic field sensors. This is the Compass class I use to get bearing of my cell phone:
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class Compass implements SensorEventListener {
private static final String TAG = "Compass";
public interface CompassListener {
void onNewAzimuth(float azimuth);
}
private CompassListener listener;
private SensorManager sensorManager;
private Sensor gsensor;
private Sensor msensor;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float[] R = new float[9];
private float[] I = new float[9];
private float azimuth;
private float azimuthFix;
public Compass(Context context) {
sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
public void start() {
sensorManager.registerListener(this, gsensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this, msensor,
SensorManager.SENSOR_DELAY_GAME);
}
public void stop() {
sensorManager.unregisterListener(this);
}
public void setAzimuthFix(float fix) {
azimuthFix = fix;
}
public void resetAzimuthFix() {
setAzimuthFix(0);
}
public void setListener(CompassListener l) {
listener = l;
}
#Override
public void onSensorChanged(SensorEvent event) {
final float alpha = 0.97f;
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = alpha * mGravity[0] + (1 - alpha)
* event.values[0];
mGravity[1] = alpha * mGravity[1] + (1 - alpha)
* event.values[1];
mGravity[2] = alpha * mGravity[2] + (1 - alpha)
* event.values[2];
// mGravity = event.values;
// Log.e(TAG, Float.toString(mGravity[0]));
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// mGeomagnetic = event.values;
mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
* event.values[0];
mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
* event.values[1];
mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
* event.values[2];
// Log.e(TAG, Float.toString(event.values[0]));
}
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
// Log.d(TAG, "azimuth (rad): " + azimuth);
azimuth = (float) Math.toDegrees(orientation[0]); // orientation
azimuth = (azimuth + azimuthFix + 360) % 360;
// Log.d(TAG, "azimuth (deg): " + azimuth);
if (listener != null) {
listener.onNewAzimuth(azimuth);
}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
I calibrated the value by adding 352 to bearing received by onNewAzimuth method of this class and used it in my code:
Compass compass = new Compass(this);
Compass.CompassListener cl = new Compass.CompassListener() {
#Override
public void onNewAzimuth(float azimuth) {
// using (360 - (azimuth) + 8) value
}
};
compass.setListener(cl);

How to get only west direction from the Compass Sensor in Android?

I want to show the west direction in my app using compass. No matter where my user are my compass will always navigate to west direction. I am confused about it that how can i achieve and rotate my image in only one direction . Below is my code -
public class Compass implements SensorEventListener {
private static final String TAG = "Compass";
private SensorManager sensorManager;
private Sensor gsensor;
private Sensor msensor;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float azimuth = 0f;
private float currectAzimuth = 0;
private Context context ;
PackageManager packageManager ;
// compass arrow to rotate
public ImageView arrowView = null;
public Compass(Context context) {
this.context = context;
sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
packageManager = context.getPackageManager();
}
public void start() {
if(packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)){
sensorManager.registerListener(this, gsensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this, msensor,
SensorManager.SENSOR_DELAY_GAME);
}
else{
Toast.makeText(context,"No Compass Sensor !", Toast.LENGTH_SHORT).show();
}
}
public void stop() {
sensorManager.unregisterListener(this);
}
private void adjustArrow() {
if (arrowView == null) {
Log.i(TAG, "arrow view is not set");
return;
}
Log.i(TAG, "will set rotation from " + currectAzimuth + " to "
+ azimuth);
Animation an = new RotateAnimation(-currectAzimuth, -azimuth,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
currectAzimuth = azimuth;
an.setDuration(500);
an.setRepeatCount(0);
an.setFillAfter(true);
arrowView.startAnimation(an);
}
#Override
public void onSensorChanged(SensorEvent event) {
final float alpha = 0.97f;
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = alpha * mGravity[0] + (1 - alpha)
* event.values[0];
mGravity[1] = alpha * mGravity[1] + (1 - alpha)
* event.values[1];
mGravity[2] = alpha * mGravity[2] + (1 - alpha)
* event.values[2];
// mGravity = event.values;
// Log.e(TAG, Float.toString(mGravity[0]));
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// mGeomagnetic = event.values;
mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
* event.values[0];
mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
* event.values[1];
mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
* event.values[2];
// Log.e(TAG, Float.toString(event.values[0]));
}
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);
Log.d(TAG, "azimuth (rad): " + azimuth);
azimuth = (float) Math.toDegrees(orientation[0]); // orientation
azimuth = (azimuth + 360) % 360;
Log.d(TAG, "azimuth (deg): " + azimuth);
adjustArrow();
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Why don't you use trigonometry to calculate the correct angle for the image based on north being at 0 degrees.
If north is 0 degrees, west would be -90 degrees or 270 degrees in comparison. So simply set the rotation of the image to north + 270 degrees?

Accelerometer values to degrees

I wrote the following code,where the values of the accelerometer are shown in x,y,z during rotation.
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private TextView xText,yText,zText;
private Sensor mySensor;
private SensorManager SM;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Creating the Sensor Manager
SM = (SensorManager)getSystemService(SENSOR_SERVICE);
// Accelerometer Sensor
mySensor = SM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// Register sensor Listener
SM.registerListener(this, mySensor, SensorManager.SENSOR_DELAY_NORMAL);
// Assign TextView
xText = (TextView)findViewById(R.id.xText);
yText = (TextView)findViewById(R.id.yText);
zText = (TextView)findViewById(R.id.zText);
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
xText.setText("X: " + sensorEvent.values[0]);
yText.setText("Y: " + sensorEvent.values[1]);
zText.setText("Z: " + sensorEvent.values[2]);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
}
Now I want to convert the values I get from the SensorEvents to degrees. I looked at various questions here,but I got confused.
double x = sensorEvent.values[0];
double y = sensorEvent.values[1];
double z = sensorEvent.values[2];
There should be a formula that takes the above values and convert them in degrees.
Any ideas?
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
//xText.setText("X: " + sensorEvent.values[0]);
//yText.setText("Y: " + sensorEvent.values[1]);
//zText.setText("Z: " + sensorEvent.values[2]);
double x = sensorEvent.values[0];
double y = sensorEvent.values[1];
double z = sensorEvent.values[2];
double pitch = Math.atan(x/Math.sqrt(Math.pow(y,2) + Math.pow(z,2)));
double roll = Math.atan(y/Math.sqrt(Math.pow(x,2) + Math.pow(z,2)));
//convert radians into degrees
pitch = pitch * (180.0/3.14);
roll = roll * (180.0/3.14) ;
yText.setText(String.valueOf(pitch));
zText.setText(String.valueOf(roll));
}
Now I want to convert the values I get from the SensorEvents to degrees
The unit of the value you get from TYPE_ACCELEROMETER is m/s^2, thus trying to convert to degree does not make sense.
Your pitch and roll calculations do not seem right. For the correct calculation see the method processSensorData(DProcessedSensorEvent.DProcessedSensorEventBuilder builder) in the DSensorEventProcessor class at https://github.com/hoananguyen/dsensor/blob/master/dsensor/src/main/java/com/hoan/dsensor_master/DSensorEventProcessor.java
To convert pitch and roll to degrees use Math.toDegrees(valueToConvert)
Youll need to register for the TYPE_ACCELEROMETER, but also for TYPE_MAGNETIC_FIELD and than you can leverage SensorManager built-in method for your help:
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geomagnetic = event.values;
if (mGravity != null && geomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity, geomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
myAzimut = orientation[0]; // myAzimut is The geomagnetic inclination angle in radians.
}
}
}
You can learn all additional information by reading SensorManagersource code comments.
your code seem right. use Math.PI in (180.0/3.14) to get more accurate results.

Android trouble getting compass direction

I am trying to get the users magnetic heading using the SensorEventListener. Sadly on Android this seams to be a bit of a hassle.
On my HTC, my readings seam to be fairly accurate. On my Samsung Galaxy S3, the readings are totally random. I know there must be something wrong with my class though since the compass apps from the Play store seam to work just fine.
My code is:
public class HeadingSensor implements SensorEventListener {
private static final String LOG_TAG = "sw_HeadingSensor";
private SensorManager mSensorManager;
private long mLastHeadingUpdate;
private int mMinUpdateFrequency = 500;//milliseconds
private HeadingListener mCallback;
private float[] mGravity;
private float[] mGeomagnetic;
public interface HeadingListener {
public void headingChanged(int heading);
}
public HeadingSensor(Context context, HeadingListener headingListener) {
mCallback = headingListener;
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
}
public void registerListener() {
Log.d(LOG_TAG, "listener registered");
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
}
public void unregisterListener() {
Log.d(LOG_TAG, "listener unregistered");
mSensorManager.unregisterListener(this);
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = sensorEvent.values;
}
if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mGeomagnetic = sensorEvent.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) {
long currentTime = System.currentTimeMillis();
if ((currentTime - mLastHeadingUpdate) > mMinUpdateFrequency) {
mLastHeadingUpdate = currentTime;
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azimuthInRadians = orientation[0];
int azimuthInDegress = (int)(Math.toDegrees(azimuthInRadians) + 360) % 360;
if (null != mCallback) {
mCallback.headingChanged(azimuthInDegress);
}
}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}
I have read as many tutorials, references, etc as possible but I can't find a good way to get the compass heading. Can someone show me what is wrong with this class?
You should use TYPE_GRAVITY instead of TYPE_ACCELEROMETER else you should low pass filter TYPE_ACCELEROMETER. Your problem lies mainly in
mGravity = sensorEvent.values;
and
mGeomagnetic = sensorEvent.values;
Since sensorEvent is a local variable and either mGravity or mGeomagnetic points to this value, either of these can be anything by the next time onSensorChanged is called. It should be
mGravity = sensorEvent.values.clone();
and
mGeomagnetic = sensorEvent.values.clone();
You can look at my answer at Android getOrientation Azimuth gets polluted when phone is tilted

how can we measure distance between object and android phone camera

I want to calculate the distance between the camera and the recognized object.For this I tried a lot of methods, I tried to find the angle between the object and the camera using accelerometer and then use
d = h * tan a
h is height of from from the base generally which is 1.4
and i tried to calculate the angle by using get orientation method. Kindly let me know where am I doing wrong. Its been more than 2 days I have been struggling with this requirement. We have looked into various Camera applications which are available on Android Store and have tried to understand the functionality of the same but nothing has been fruitful.
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetSensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values;
if (gravity != null && geoMagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity,
geoMagnetic);
if (success) {
/* Orientation has azimuth, pitch and roll */
float orientation[] = new float[3];
//SensorManager.remapCoordinateSystem(R, 1, 3, orientation);
SensorManager.getOrientation(R, orientation);
azimut = 57.29578F * orientation[0];
pitch = 57.29578F * orientation[1];
roll = 57.29578F * orientation[2];
}
}
}
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
double d = (Math.tan(Math.toRadians(Math.abs(pitch))) * sensorHeight);
Toast.makeText(
getApplicationContext(),
"Distance = "
+ String.valueOf(d)
+ "m Angle = "
+ String.valueOf(Math.toRadians(Math.abs(pitch))),
Toast.LENGTH_LONG).show();
}
});
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accSensor,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
Your getRotationMatrix is probably returning false! You should copy the values to your own vectors so they don't get mixed up! Use the clone() method to do so!
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values.clone();
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values.clone();
Using your code plus this change I was able to get the azimuth/pitch/roll values, without this change the success flag returns false:
Log.d("a", "orientation values: " + azimut + " / " + pitch + " / " + roll);
05-21 16:07:55.743: D/a(29429): orientation values: 77.71578 / 43.352722 / -152.39603
05-21 16:07:55.883: D/a(29429): orientation values: 175.26134 / 23.031355 / -148.72844
05-21 16:07:56.793: D/a(29429): orientation values: -146.3089 / 4.1098075 / -14.46417
You should use the PITCH value if you are holding the phone in portrait mode, if you are holding the phone in landscape mode you should use the ROLL value.
If you are holding the phone at a 1.4 height then you will have:
float dist = Math.abs((float) (1.4f * Math.tan(pitch * Math.PI / 180)));
Please note that you should use RADIANS and not DEGREES on the Math.tan function.
I tested here and the values seem to be valid!
The final code is
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetSensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values;
if (gravity != null && geoMagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity,
geoMagnetic);
if (success) {
/* Orientation has azimuth, pitch and roll */
float orientation[] = new float[3];
//SensorManager.remapCoordinateSystem(R, 1, 3, orientation);
SensorManager.getOrientation(R, orientation);
azimut = 57.29578F * orientation[0];
pitch = 57.29578F * orientation[1];
roll = 57.29578F * orientation[2];
}
}
}
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
float d = Math.abs((float) (1.4f * Math.tan(pitch * Math.PI / 180)));
Toast.makeText(
getApplicationContext(),
"Distance = "
+ String.valueOf(d)
+ "m Angle = "
+ String.valueOf(Math.toRadians(Math.abs(pitch))),
Toast.LENGTH_LONG).show();
}
});
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accSensor,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}

Categories

Resources