Обзор ориентации телефона Android, включая компас

95

Я пытался на некоторое время окунуться в сенсоры ориентации Android. Я думал, что понял. Тогда я понял, что нет. Теперь я думаю (надеюсь), что у меня есть лучшее чувство для него снова, но я все еще не на 100%. Я попытаюсь объяснить свое неоднозначное понимание этого и, надеюсь, люди смогут исправить меня, если я ошибаюсь по частям или заполняю любые пробелы.

Я полагаю, что я стою на 0 градусов долготы (первичный меридиан) и 0 градусов широты (экватор). Это место действительно находится в море у берегов Африки, но несут меня. Я держу свой телефон перед моим лицом, так что нижняя часть телефона указывает на мои ноги; Я смотрю на Север (смотря на Гринвич), поэтому правая сторона телефона указывает на Восток в сторону Африки. В этой ориентации (со ссылкой на приведенную ниже диаграмму) у меня есть ось X, указывающая Восток, ось Z указывает на юг и точку оси Y на небо.

Изображение 9983

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

Прежде чем я доберусь до этого, представьте, что вы стоите на этом мнимом участке земли при 0 градусах широты и долготы, стоящих в указанном выше направлении. Представьте себе, что вы с завязанными глазами и ваши ботинки закреплены на кольцевой развязке на детской площадке. Если кто-то запишет вас спиной, вы упадете вперед (к северу) и положите обе руки, чтобы сломать свое падение. Точно так же, если кто-то швыряет вас влево, вы упадете на правую руку. Ваше внутреннее ухо имеет "гравитационные датчики" (клип youtube), которые позволяют вам обнаруживать, что вы падаете вперед/назад или падаете влево/вправо или падать (или вверх!). Поэтому люди могут обнаруживать выравнивание и вращение вокруг тех же осей X и Z, что и телефон.

Теперь представьте, что теперь кто-то поворачивает вас на 90 градусов по кольцевой развязке, чтобы теперь вы столкнулись с Востоком. Вы вращаетесь вокруг оси Y. Эта ось различна, потому что мы не можем ее обнаружить биологически. Мы знаем, что мы наклонены на определенную величину, но мы не знаем направления относительно магнитного магнитного полюса планеты. Вместо этого нам нужно использовать внешний инструмент... магнитный компас. Это позволяет нам определить, с каким направлением мы сталкиваемся. То же самое можно сказать и о нашем телефоне.

Теперь телефон также имеет 3-осный акселерометр. У меня есть идея НЕТ, как они на самом деле работают, но то, как я визуализирую это, - представить себе гравитацию как постоянный и однородный "дождь", падающий с неба, и представить себе оси на рисунке выше как трубки, которые могут обнаружить количество дождя. Когда телефон держится вертикально, весь дождь будет проходить через Y 'tube'. Если телефон постепенно поворачивается, поэтому его экран обращен к небу, количество дождя, протекающего через Y, будет уменьшаться до нуля, а громкость через Z будет постоянно увеличиваться до тех пор, пока не достигнет максимального количества дождя. Точно так же, если мы теперь опрокинем телефон на свою сторону, X-трубка в конечном итоге соберет максимальное количество дождя. Поэтому в зависимости от ориентации телефона, измеряя количество дождя, проходящего через 3 трубки, вы можете рассчитать ориентацию.

В телефоне также есть электронный компас, который ведет себя как обычный компас - его "виртуальная игла" указывает на магнитный север. Android объединяет информацию с этих двух датчиков, так что всякий раз, когда генерируется SensorEvent of TYPE_ORIENTATION, массив values[3] имеет значения [0]: азимут - (компас, расположенный к востоку от магнитного севера)
значения [1]: шаг, вращение вокруг оси x (это телефон, наклоняющийся вперед или назад)
значения [2]: рулон, вращение вокруг оси y (это телефон, наклоняющийся над его левой или правой стороной)

Итак, я думаю (т.е. я не знаю), причина, по которой Android дает азимут (компасный подшипник), а не чтение третьего акселерометра, заключается в том, что компасный подшипник является более полезным. Я не уверен, почему они устарели от такого типа датчиков, поскольку теперь вам нужно зарегистрировать слушателя с системой для SensorEvent типа TYPE_MAGNETIC_FIELD. Массив события value[] должен быть передан в метод SensorManger.getRotationMatrix(..) для получения матрицы вращения (см. Ниже), которая затем передается в метод SensorManager.getOrientation(..). Кто-нибудь знает, почему команда Android устарела Sensor.TYPE_ORIENTATION? Это эффективность? Это то, что подразумевается в одном из комментариев к аналогичному question, но вам все равно нужно зарегистрировать другой тип слушателя в development/samples/Compass/src/com/example/android/compass/CompassActivity.java.

Изображение 9984Изображение 9983Изображение 9985

Теперь я хотел бы поговорить о матрице вращения. (Вот где я не уверен) Итак, выше мы имеем три цифры из документации для Android, мы будем называть их A, B и C.

A = метод SensorManger.getRotationMatrix(..) и представляет собой систему координат мира

B = Система координат, используемая API SensorEvent.

C = SensorManager.getOrientation(..) method figure

Итак, я понимаю, что A представляет собой "мировую систему координат", которая, как я полагаю, относится к тому, как местоположения на планете даются как (широта, долгота) пара с опциональной (высота). X - координата "easting" , Y - "northing" . Z указывает на небо и представляет собой высоту.

Система координат телефонов показана на рисунке B. Его ось Y всегда указывает верхнюю. Матрица вращения постоянно вычисляется по телефону и позволяет отображать между ними. Я правильно понимаю, что матрица вращения преобразует систему координат B в C? Поэтому, когда вы вызываете метод SensorManager.getOrientation(..), вы используете массив values[] со значениями, соответствующими рисунку C. Когда телефон направлен на небо, матрица поворота является матрицей идентичности (матричный математический эквивалент 1), что означает, что отображение не требуется, поскольку устройство выровнено с мировой системой координат.

Ok. Кажется, мне лучше остановиться сейчас. Как я уже сказал, я надеюсь, что люди скажут мне, где я испортил или помог людям (или смутил людей еще дальше!)

  • 25
    Мне очень нравится этот вопрос. Я не могу ответить, но мне это нравится.
  • 4
    Тим, ты когда-нибудь получал ответ? Я почесал голову в то же время. Это один из самых плохо документированных API, которые я когда-либо видел.
Показать ещё 3 комментария
Теги:
orientation
compass-geolocation
device-orientation
bearing

4 ответа

23
Лучший ответ

Возможно, вы захотите проверить One Screen Turn Deseses Another. Это объясняет, почему вам нужна матрица вращения.

В двух словах телефонные датчики всегда используют одну и ту же систему координат, даже если устройство повернуто.

В приложениях, которые не заблокированы для одной ориентации, система координат экрана изменяется при повороте устройства. Таким образом, когда устройство повернуто из режима просмотра по умолчанию, система координат датчика больше не совпадает с системой координат экрана. В этом случае матрица вращения используется для преобразования A в C (всегда остается неподвижным).

Вот фрагмент кода, чтобы показать вам, как его можно использовать.

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}
  • 4
    просто отметьте, что азимут, высота тона и крена НЕ совпадают с выходом из устаревшего датчика ориентации. orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360; нормализует азимут и if (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); } нормализует высоту тона
  • 0
    @RafaelT а нормализовать крен? Или это не имеет смысла?
Показать ещё 2 комментария
3

Roll - это функция гравитации, 90-градусный бросок помещает всю тяжесть в регистр x.

Шаг одинаковый, шаг 90 градусов помещает весь компонент силы тяжести в регистр y.

Yaw/Heading/azimuth не влияет на гравитацию, он ВСЕГДА находится под прямым углом к ​​гравитации, следовательно, независимо от того, каким образом вы столкнетесь с гравитацией, будет непроницаемо.

Вот почему вам нужен компас для оценки, может быть, это имеет смысл?

0

У меня была эта проблема, поэтому я наметил, что происходит в разных направлениях. Если устройство монтируется в ландшафтном режиме, например, в автомобиле, то "градусы" от компаса, по-видимому, работают от 0-275 (по часовой стрелке) выше 269 (между западом и севером), он отсчитывает назад от -90 до 0, затем вперед от 0 до 269. 270 становится -90

В ландшафте, но с устройством, лежащим на спине, мой датчик дает 0-360. и в портретном режиме он работает 0-360, лежащих на спине и стоящих на портрете.

Надеюсь, что кто-то поможет

0

Посмотрите на это: https://stackoverflow.com/questions/4174389/different-values-between-sensors-type-accelerometer-type-magnetic-field-and-type

Вы, кажется, в основном правы до трех диаграмм A, B, C. После этого вы запутались.

  • 0
    Я взгляну. Спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню