Sensor.TYPE_ORIENTATION is working fine on mobile but its not working on tablet.
List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if(mySensors.size() > 0)
{
Toast.makeText(this, "Start ORIENTATION Sensor", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(this, "No ORIENTATION Sensor", Toast.LENGTH_LONG).show();
}
can anyone help me.
Looks like Sensor.TYPE_ORIENTATION constant is deprecated. Use SensorManager.getOrientation() instead.
I used SensorManager.getOrientation() its also working in phone but not in tablet.
float[] mGravity;
float[] mGeomagnetic;
float RR[] = new float[9];
float I[] = new float[9];
float orientation[] = new float[3];
SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor mMageneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this,mAccelerometer,SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this,mMageneticField,SensorManager.SENSOR_DELAY_NORMAL);
// Inside onSensorChanged
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
mGravity = event.values.clone();
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
mGeomagnetic = event.values.clone();
}
SensorManager.getRotationMatrix(RR, I, mGravity, mGeomagnetic);
SensorManager.getOrientation(RR, orientation);
azimuth = orientation[0];
pitch = orientation[1];
roll = orientation[2];
System.out.println("Pitch " + pitch);
Related
I am trying to implement the logic for finding the qibla direction.
I used Sensor.TYPE_ORIENTATION and copied the code from here
mSensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
but I found that the Sensor.TYPE_ORIENTATION is deprecated and instead, I used accelerometer and magnetic field sensors from here
here is my code now
private void registerSensor() {
mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
accelerometer = mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mySensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mySensorManager.registerListener(mySensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_UI);
mySensorManager.registerListener(mySensorEventListener, magnetometer, SensorManager.SENSOR_DELAY_UI);
}
private SensorEventListener mySensorEventListener = new SensorEventListener() {
float degree;
float head;
#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 (lastKnownLocation == null || image == null || arrow == null) {
return;
}
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);
degree = orientation[2]; // orientation contains: azimut, pitch and roll
head = orientation[0];
}
}
I am trying to get the degree and head. what am I doing wrong here?
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 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);
}
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);
}
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));
}