Направление компаса зависит от ориентации телефона - PullRequest
6 голосов
/ 24 декабря 2011

Моему приложению дополненной реальности нужен компасный вид с камеры, и есть множество примеров получения направления от менеджера сенсоров.

Однако я нахожу результирующее значение разным в зависимости от ориентации телефона -Пейзаж, повернутый вправо, примерно на 10 градусов отличается от пейзажа, повернутого влево (разница между ROTATION_0 и ROTATION_180 меньше, но все же отличается).Этой разницы достаточно, чтобы испортить любой эффект AR.

Это как-то связано с калибровкой?(Я не уверен, что делаю цифру 8 правильно - я пробовал разные способы, которые я нашел на YouTube).

Есть идеи, почему есть разница?Я что-то напутал на матрице вращения?У меня есть возможность ограничить приложение одной ориентацией, но меня все равно беспокоит, что показания компаса все еще не очень точны (даже если после фильтрации они довольно стабильны)

public void onSensorChanged(SensorEvent event) {
        if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
            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[] rotationMatrixA = mRotationMatrixA;
            if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {

                float[] rotationMatrixB = mRotationMatrixB;

                Display display = getWindowManager().getDefaultDisplay(); 
                int deviceRot = display.getRotation();

                switch (deviceRot)
                {
                // portrait - normal
                case Surface.ROTATION_0: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        rotationMatrixB);
                break;
                // rotated left (landscape - keys to bottom)
                case Surface.ROTATION_90: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_Z, SensorManager.AXIS_MINUS_X,
                        rotationMatrixB); 
                break;
                // upside down
                case Surface.ROTATION_180: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        rotationMatrixB); 
                break;
                // rotated right
                case Surface.ROTATION_270: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_MINUS_Z, SensorManager.AXIS_X,
                        rotationMatrixB); 
                break;

                default:  break;
                }

                float[] dv = new float[3]; 
                SensorManager.getOrientation(rotationMatrixB, dv);
                // add to smoothing filter
                fd.AddLatest((double)dv[0]); 
            }
            mDraw.invalidate();     
        }
    }

Ответы [ 2 ]

10 голосов
/ 21 мая 2012

Попробуйте это

public void onSensorChanged(SensorEvent event) {
    if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
        return;
    }

    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[] rotationMatrixA = mRotationMatrixA;
        if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {

            float[] rotationMatrixB = mRotationMatrixB;
            SensorManager.remapCoordinateSystem(rotationMatrixA,
                    SensorManager.AXIS_X, SensorManager.AXIS_Z,
                    rotationMatrixB);
            float[] dv = new float[3]; 
            SensorManager.getOrientation(rotationMatrixB, dv);
            // add to smoothing filter
            fd.AddLatest((double)dv[0]); 
        }
        mDraw.invalidate();     
    }
}

Вы не нуждаетесь в операторе switch, похоже, существует много путаницы в отношении getRotationMatrix, remapCoordinateSystem и getOrientation из вопросов stackoverflow.
Я, вероятно, напишу подробное объяснение этого в ближайшем будущем.

1 голос
/ 15 апреля 2014

Ответ Хоан на самом деле неверен, поскольку он не учитывает поворот дисплея. Это правильный ответ.

...