Android не может определить направление по компасу

Я пытаюсь получить магнитный курс пользователей, используя SensorEventListener. К сожалению, на Android это может быть немного хлопотно.

На моем HTC мои показания довольно точны. На моем Samsung Galaxy S3 показания абсолютно случайные. Я знаю, что с моим классом должно быть что-то не так, поскольку приложения компаса из магазина Play работают нормально.

Мой код:

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) { }
}

Я прочитал как можно больше руководств, справочников и т. д., но не могу найти хороший способ получить направление по компасу. Может кто-нибудь показать мне, что не так с этим классом?


person shiznatix    schedule 19.12.2014    source источник
comment
Вы вынесли свой S3 на улицу? Компас моего Moto G чрезвычайно чувствителен к помехам.   -  person Kevin Krumwiede    schedule 19.12.2014
comment
Да, и в то же время, если я оставлю телефон в том же положении на своем столе, приложение компаса все покажет правильно, в то время как мой код дает очень случайные показания.   -  person shiznatix    schedule 19.12.2014


Ответы (1)


Вы должны использовать TYPE_GRAVITY вместо TYPE_ACCELEROMETER, иначе вы должны использовать фильтр нижних частот TYPE_ACCELEROMETER. Ваша проблема заключается в основном в

mGravity = sensorEvent.values;

и

mGeomagnetic = sensorEvent.values;

Поскольку sensorEvent является локальной переменной и либо mGravity, либо mGeomagnetic указывают на это значение, любое из них может быть любым при следующем вызове onSensorChanged. Должен быть

mGravity = sensorEvent.values.clone();

и

mGeomagnetic = sensorEvent.values.clone();

Вы можете посмотреть мой ответ на Android getOrientation Azimuth загрязняется, когда телефон наклонен

person Hoan Nguyen    schedule 20.12.2014