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?
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?
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 °)
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
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);
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]));
}