Огляд орієнтації телефону на Android, включаючи компас


107

Я деякий час намагався обвести голову навколо датчиків орієнтації на 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]: Крок, обертання навколо осі х (це телефон Нахилившись вперед або назад)
значення [2]: котиться, обертається навколо осі y (телефон перекидається на його ліву чи праву сторону)

Тому я думаю (тобто я не знаю), чому причина Android дає азимут (підшипник компаса), а не читання третього акселерометра - це те, що підшипник компаса просто корисніший. Я не впевнений, чому вони втратили датчик такого типу, оскільки тепер, здається, вам потрібно зареєструвати слухача в системі для SensorEvents типу TYPE_MAGNETIC_FIELD. value[]Масив події потрібно перенести в SensorManger.getRotationMatrix(..)метод, щоб отримати матрицю обертання (див. Нижче), яка потім передається в SensorManager.getOrientation(..)метод. Хтось знає, чому застаріла команда Android Sensor.TYPE_ORIENTATION? Це річ ефективності? Це те, що мається на увазі в одному з коментарів до подібного питання, але вам все одно потрібно зареєструвати іншого типу слухача врозробка / зразки / Compass / src / com / example / android / compass / CompassActivity.java приклад.

Зараз я хотів би поговорити про матрицю обертання. (Це я там, де я не впевнений) Отже, вище, ми маємо три фігури з документації на Android, ми їх назвемо A, B і C.

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

B = Координатна система, що використовується API SensorEvent.

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

Отже, я розумію, що А являє собою "систему координат у світі", яка, як я вважаю, відноситься до того, як місця на планеті даються як пара (широта, довгота) з необов'язковою (висотою). X - координата "схід" , Y - координата "північного" . Z вказує на небо і представляє висоту.

Система координат телефонів показана на малюнку В. Його вісь Y завжди вказує на верх. Матриця обертання постійно обчислюється телефоном і дозволяє проводити картування між ними. Тож я маю рацію, думаючи, що матриця обертання перетворює систему координат від B до C? Отже, коли ви викликаєте SensorManager.getOrientation(..)метод, ви використовуєте values[]масив зі значеннями, які відповідають фігурі C. Коли телефон вказується на небо, матриця обертання - це матриця ідентичності (матричний математичний еквівалент 1), що означає, що не потрібно відображати карти, оскільки пристрій вирівнюється зі світовою системою координат.

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


25
Мені дуже подобається це питання. Я не можу відповісти на це, але мені це подобається.
Октавіан А. Дам’ян

4
Тіме, ти коли-небудь отримував відповідь? Я при цьому чухав голову. Це один із найбільш слабо задокументованих API, який я коли-небудь бачив.
П’єр-Люк Паур

Не дуже боюся. Мені довелося рухатись далі. Колись я повернусь до цього питання.
Тім

1
Тут у мене таке ж питання, майже? І Відповідь, рішення теж. Оприлюднив мій код у Github.

те саме, що мені цікаво, я здійснив компас на пристрої Android і працює належним чином, якщо я взяв допомогу з Інтернету, він працює добре, але те, що бентежить, це ... Припустимо, мій пристрій знаходиться на обличчі землі назустріч мені та його вказівці на північ, зараз я берусь за мобільний телефон і ставлю його вертикально над головою, а обличчя все ще спрямоване на мене. По-перше, голка повинна змінити свій напрямок і чому. На мій погляд я не повинен так, як я не змінив напрямок, але це змінюється в моєму додатку та в усіх інших завантажених мною програмах. Хтось може пояснити, чому?
Syed Raza Mehdi

Відповіді:


26

Можливо, ви хочете перевірити статтю на одному екрані, заслуговує на іншу статтю. Це пояснює, для чого вам потрібна матриця обертання.

У двох словах, датчики телефону завжди використовують ту саму систему координат, навіть коли пристрій повертається.

У додатках, які не зафіксовані в одній орієнтації, система координат екрана змінюється при повороті пристрою. Таким чином, коли пристрій повертається з режиму перегляду за замовчуванням, система координат датчика вже не є такою, як екранна система координат. Матриця обертання в цьому випадку використовується для перетворення 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]);
        }
    }
}

4
лише зауважте, що азимут, крок та котик НЕ є тим самим, що виходять із застарілого 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])); }нормалізує висоту
Рафаель T

@RafaelT і нормалізувати рулон? Або це не має сенсу?
Маттіас

@RafaelT: Здається, ваша нормалізація азимуту впливає: значення переходять від [-180,180] до [0, 360]. Але отримані вами значення висоти значень вже знаходяться в [-90,90], тому нормалізація, яку ви пропонуєте, не впливає.
Маттіас

Що означає, якщо після перевірки (гравітація! = Null && geomag! = Null) значення geomag завжди дорівнює 0, незалежно від того, як я переміщу планшет? Може бути планшет без датчика геомагу?
Розширений

3

Рулон - це функція сили тяжіння, рулон 90 градусів ставить всю гравітацію в регістр х.

Крок такий же, як нахил на 90 градусів вгору вносить всю складову сили тяжіння в регістр y.

Знизування / заголовок / азимут не впливає на гравітацію, це ЗАВЖДИ під прямим кутом до сили тяжіння, отже, незалежно від того, яким способом ви зіткнетесь із гравітацією, не можна змінити.

Ось чому вам потрібен компас для оцінки, можливо, це має сенс?



0

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

Все ще в пейзажі, але з пристроєм, що лежить на спині, мій датчик дає 0-360. а в портретному режимі він працює 0-360 як лежачи на спині, так і стоячи в портреті.

Сподіваюся, що хтось допомагає

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.