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

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

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

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

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

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

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

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

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

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

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

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

C = Рисунок метода SensorManager.getOrientation (..)

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

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

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


person Tim    schedule 27.01.2011    source источник
comment
Мне очень нравится этот вопрос. Я не могу ответить, но мне это нравится.   -  person Octavian A. Damiean    schedule 29.01.2011
comment
Тим, ты когда-нибудь получал ответ? Я при этом чесал в затылке. Это один из самых плохо документированных API, которые я когда-либо видел.   -  person Pierre-Luc Paour    schedule 23.06.2011
comment
Не очень боюсь. Пришлось двигаться дальше. Когда-нибудь я вернусь к этому вопросу.   -  person Tim    schedule 24.06.2011
comment
Здесь у меня почти такой же вопрос? И Response, решение тоже. Сделал мой код общедоступным на Github.   -  person    schedule 14.09.2013
comment
то же самое, что меня интересует, я реализовал компас на устройстве Android и работает нормально, если мне нужна помощь из Интернета, он работает нормально, но сбивает с толку ... Предположим, мое устройство находится на земле лицом ко мне, и он указывает на север, теперь я беру свой мобильный телефон и кладу его вертикально над головой, но лицо все еще обращено ко мне. Во-первых, должна ли игла изменить свое направление и почему. По моему мнению, этого не должно быть, поскольку я не изменил своего направления, но он меняется в моем приложении и во всех других приложениях, которые я загрузил. Кто-нибудь может объяснить почему?   -  person Syed Raza Mehdi    schedule 11.03.2014


Ответы (4)


Возможно, вы захотите ознакомиться с One Screen Turn Turn Заслуживает Еще одна статья. Это объясняет, зачем вам нужна матрица вращения.

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

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

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

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]);
        }
    }
}
person Community    schedule 24.07.2011
comment
просто отметьте, что азимут, тангаж и крен НЕ совпадают с исходящими от устаревшего OrientationSensor. 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])); } нормализует угол наклона - person Rafael T; 30.04.2012
comment
@RafaelT а рулон нормализовать? Или в этом нет смысла? - person Matthias; 17.03.2013
comment
@RafaelT: Ваша нормализация азимута, кажется, влияет: значения меняются от [-180,180] до [0, 360]. Но значения высоты тона, которые я получаю, уже находятся в диапазоне [-90,90], поэтому предлагаемая нормализация не имеет никакого эффекта. - person Matthias; 17.03.2013
comment
Что это значит, если после проверки (gravity! = Null && geomag! = Null) значение geomag всегда равно 0, независимо от того, как я перемещаю планшет? Может быть планшет без сенсора геомаг? - person Advanced; 18.06.2013

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

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

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

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

person Craig    schedule 25.11.2011

Взгляните на это: Stackoverflow.com: Q.5202147

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

person TheCodeArtist    schedule 05.03.2011

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

По-прежнему в альбомной ориентации, но когда устройство лежит на спине, мой датчик показывает 0-360. а в портретном режиме он работает 0–360 как лежа на спине, так и стоя в портретном режиме.

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

person hopeless bob    schedule 27.06.2014