Ускорение из системы координат устройства в абсолютную систему координат

С моего устройства Android я могу прочитать массив значений линейного ускорения (в системе координат устройства) и массив значений абсолютной ориентации (в системе координат Земли). Мне нужно получить значения линейного ускорения в последней координате. система.

Как я могу преобразовать их?

EDIT после ответа Али в комментарии:

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

Но я только что провел тест, в котором клал телефон в разные положения и получал ускорение по разным осям. Есть 3 пары картинок - на первых показано, как я ставлю прибор (извините за мой "мастерский скилл" в Paint), а на вторых - показания по данным, предоставленным линейным соотв. датчик:

  1. устройство положить на левую сторону

первое положениепервое чтение

  1. устройство лежит на спине

вторая позицияВторые чтения

  1. устройство стоя

введите здесь описание изображениявведите здесь описание изображения

А теперь - почему в третьем случае ускорение происходит по оси Z (а не по Y), ведь положение устройства не имеет значения?


comment
Был ли телефон неподвижен (совершенно неподвижен) во время измерений? Что находится на вертикальной оси? Что значит, например -14?   -  person Ali    schedule 20.07.2012
comment
во время измерений я очень быстро перемещал телефон по оси запад-восток (точно так, как показано на этих рисунках в Paint), чтобы получить показания ускорения (-14 — ускорение в м/с*с). И, как показано здесь, ссылка система координат измерения - та же, что и у телефона.   -  person alex    schedule 20.07.2012
comment
Хорошо, теперь я понимаю ваш эксперимент. Я исправлю свой ответ.   -  person Ali    schedule 20.07.2012
comment
Хорошо, это была моя ошибка, я ужасно извиняюсь. Я исправил свой ответ. Кроме того, я проголосовал за ваш вопрос.   -  person Ali    schedule 20.07.2012
comment
какой графический инструмент вы используете?   -  person Muhammad Babar    schedule 05.11.2014
comment
@MuhammadBabar, это просто MS Excel   -  person alex    schedule 05.11.2014
comment
как вам удалось его создать? Используете ли вы какое-либо программное обеспечение, которое считывает показания датчика и создает эти диаграммы?   -  person Muhammad Babar    schedule 05.11.2014
comment
@MuhammadBabar запрограммировал сохранение показаний в файл на устройстве и просто вручную импортировал их в Excel. ничего фантастического   -  person alex    schedule 05.11.2014
comment
@alex Ах да! Спасибо, в любом случае :)   -  person Muhammad Babar    schedule 06.11.2014
comment
Было бы лучше использовать Sensor.TYPE_GAME_ROTATION, если требуется только абсолютная система координат, пренебрегая истинным геомагнитным севером?   -  person SOFe    schedule 27.03.2017


Ответы (4)


Наконец-то мне удалось ее решить! Таким образом, чтобы получить вектор ускорения в земной системе координат, вам необходимо:

  1. получить матрицу вращения (float[16], чтобы позже ее мог использовать класс android.opengl.Matrix) из SensorManager.getRotationMatrix() (используя значения датчиков SENSOR.TYPE_GRAVITY и SENSOR.TYPE_MAGNETIC_FIELD в качестве параметров),
  2. используйте android.opengl.Matrix.invertM() в матрице вращения, чтобы инвертировать ее (не транспонировать!),
  3. используйте датчик Sensor.TYPE_LINEAR_ACCELERATION, чтобы получить вектор линейного ускорения (в системе координат устройства),
  4. используйте android.opengl.Matrix.multiplyMV(), чтобы умножить матрицу вращения на вектор линейного ускорения.

И вот оно! Надеюсь, я сэкономлю драгоценное время для других.

Спасибо Эдварду Фальку и Али за подсказки!!

person alex    schedule 23.07.2012
comment
Хм, странно. Я думал, что обратная матрица, полностью состоящая из вращений, является транспонированной. Думаю, мне нужно немного поиграть с этим. - person Edward Falk; 24.07.2012
comment
На шаге 4 вы не можете использовать данные датчика напрямую, так как их длина равна 3, а вам нужна длина 4. Вы добавляете 0 или 1 в конце или в начале? - person Nino van Hooff; 14.09.2012
comment
@NinovanHooff на 4-й позиции (массив [3]) должно быть значение 0 - person alex; 14.09.2012
comment
Какая именно у вас земная система координат? Вы ссылаетесь на это в документах Sensor.TYPE_ROTATION_VECTOR здесь developer.android .com/reference/android/hardware/? - person htz; 20.02.2013
comment
@htz Я, очевидно, имею в виду наиболее распространенную систему, которую все используют, например, при чтении карты. Один единичный вектор указывает на север, второй указывает на восток и последний направлен к центру Земли. Порядок и направление (например, запад/восток) векторов могут различаться, но суть одна и та же — использовать эту фиксированную систему в качестве ориентира для изменения положения других систем, например мобильный телефон. - person alex; 20.02.2013
comment
Ваше решение кажется сложным. См. мое простое решение по адресу stackoverflow.com/questions/14963190/ - person Hoan Nguyen; 20.02.2013
comment
За исключением обращения RotationMatrix, решения одинаковы. Почему эта инверсия сделана в вашем решении @alex? Я плохо знаком с этой арифметикой... - person htz; 22.02.2013
comment
Инверсия сделана, вероятно, потому, что матрица вращения вычисляется по мировой оси, а не по оси телефона, как было упомянуто здесь (gentlenav.googlecode.com/files/DCMDraft2.pdf). Вот научная статья, описывающая тот же подход в разделе III.A (ece. nus.edu.sg/stfpage/elesohws/PerCom_Pedestrian_Tracking.pdf) - person ravemir; 16.04.2013
comment
Не хватает шага? В статье о пешеходах говорится, что вам нужно сделать больше, чем просто инвертировать. В нем упоминается что-то об обратном порядке: чтобы получить значения ускорения в мировой системе координат, мы умножаем инверсию соответствующих матриц вращения в обратном порядке (обратный шаг, обратный крен и обратный азимут) на вектор ускорения, указанный в местная система координат. - person gregm; 13.09.2013
comment
@alex, не могли бы вы опубликовать код, в котором вы исправляете linear_acceleration в мировых координатах? Мой слушатель датчика создает матрицу вращения с помощью Sensor.TYPE_ROTATION_VECTOR, и он отлично работает, но я не могу исправить linear_acceleration так, как вы описываете. Пример кода был бы потрясающим - person erik; 25.06.2014
comment
@alex есть идеи, как это сделать на IPHONE? - person sau; 21.10.2014
comment
@sau это должно быть чем-то похоже, но iPhone API совершенно другой, так что ... я думаю, вам придется взломать его самостоятельно - person alex; 21.10.2014
comment
Не могли бы вы добавить пример кода, чтобы можно было увидеть фактические расчеты? Включая объявление всех переменных. Спасибо! - person helmesjo; 22.04.2015
comment
@Alex Насколько я понимаю, это изменяет ссылку, чтобы выровнять ее по магнитному северу и силе тяжести. Чтобы совместить его с истинным севером, вы должны повернуть вокруг оси Z по склонению. Чтобы получить склонение, используйте GeomagneticField.getDeclination() - person Kristian Benoit; 04.05.2015
comment
Привет Алекс, Можете ли вы добавить код для этого расчета? спасибо, Эяль. - person eyal; 10.05.2015
comment
почему вы использовали SENSOR.TYPE_GRAVITY в SensorManager.getRotationMatrix() ? Документация (developer.android.com/reference/android /hardware/, float[], float[], float[])) говорит использовать значения TYPE_ACCELEROMETER - person orak; 07.04.2016
comment
можно ли его рассчитать, если в устройстве нет датчика линейного ускорения и силы тяжести? - person Androider; 27.07.2016
comment
@alex Я пытался выполнить шаги здесь, но, похоже, я не получаю координаты Земли. Можешь взглянуть? stackoverflow.com/questions/46146602/ - person user1361529; 11.09.2017

Основываясь на ответе @alex, вот фрагмент кода:

private float[] gravityValues = null;
private float[] magneticValues = null;

 @Override
    public void onSensorChanged(SensorEvent event) {
        if ((gravityValues != null) && (magneticValues != null) 
            && (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {

            float[] deviceRelativeAcceleration = new float[4];
            deviceRelativeAcceleration[0] = event.values[0];
            deviceRelativeAcceleration[1] = event.values[1];
            deviceRelativeAcceleration[2] = event.values[2];
            deviceRelativeAcceleration[3] = 0;

            // Change the device relative acceleration values to earth relative values
            // X axis -> East
            // Y axis -> North Pole
            // Z axis -> Sky

            float[] R = new float[16], I = new float[16], earthAcc = new float[16];

            SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);

            float[] inv = new float[16];

            android.opengl.Matrix.invertM(inv, 0, R, 0);
            android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);
           Log.d("Acceleration", "Values: (" + earthAcc[0] + ", " + earthAcc[1] + ", " + earthAcc[2] + ")");                

        } else if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
            gravityValues = event.values;
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magneticValues = event.values;
        } 
   }
person orak    schedule 07.04.2016
comment
Это сработало! Спасибо @orak! У меня нет датчика силы тяжести, поэтому я просто использовал фильтр нижних частот, чтобы получить его. - person Kanat; 26.08.2016
comment
Извините, @orak, но что такое start переменная? Чтобы контролировать поток? я не уверен в этом. - person Saeger; 07.12.2016
comment
@Saeger, ты прав, это не нужно, я, вероятно, написал это для управления потоком, который мне позже не понадобился. - person orak; 01.01.2017
comment
@orak, не могли бы вы объяснить, что, если я должен сделать, если я хочу, чтобы ось X указывала на истинный север, а вертикаль Z? - person pixie; 25.01.2017
comment
@pixie просто поменять местами значения x и y? - person orak; 09.10.2017

Согласно документации вы получаете линейное ускорение в система координат телефона.

Вы можете преобразовать любой вектор из системы координат телефона в систему координат Земли, умножив его на матрицу вращения. Вы можете получить матрицу вращения из getRotationMatrix().

(Возможно, для вас уже есть функция, выполняющая это умножение, но я не занимаюсь программированием для Android и не знаком с ее API.)

Хорошим учебным пособием по матрице вращения является рукопись Direction Cosine Matrix IMU: Theory. Удачи!

person Ali    schedule 20.07.2012
comment
Спасибо за Ваш ответ! Кажется, что это должно работать правильно, но я понятия не имею, почему это не так. Пожалуйста, посмотрите мой комментарий к ответу Эдварда Фалька, я объяснил там, что все еще не так. - person alex; 23.07.2012

Хорошо, во-первых, если вы пытаетесь сделать реальную инерциальную навигацию на Android, у вас есть работа. Дешевый маленький датчик, используемый в смартфонах, просто недостаточно точен. Хотя была проделана интересная работа по внутренней навигации на небольших расстояниях, например, внутри здания. Наверняка есть статьи на эту тему, которые можно раскопать. Поищите в Google «Motion Interface Developers Conference» и вы найдете что-нибудь полезное — это конференция, которую Invensense организовала пару месяцев назад.

Во-вторых, нет, линейное ускорение находится в координатах устройства, а не в мировых координатах. Вам придется конвертировать себя, что означает знание трехмерной ориентации устройства.

Что вам нужно сделать, так это использовать версию Android, которая поддерживает виртуальные датчики TYPE_GRAVITY и TYPE_LINEAR_ACCELERATION. Вам понадобится устройство с гироскопами, чтобы получить достаточно точные и точные показания.

Внутри система объединяет гироскопы, акселерометры и магнитометры, чтобы получить истинные значения для ориентации устройства. Это эффективно разделяет устройство акселерометра на компоненты гравитации и ускорения.

Итак, что вам нужно сделать, так это настроить прослушиватели датчиков для TYPE_GRAVITY, TYPE_LINEAR_ACCELERATION и TYPE_MAGNETOMETER. Используйте данные гравитации и магнитометра в качестве входных данных для SensorManager. getRotationMatrix(), чтобы получить матрицу вращения, которая преобразует мировые координаты в координаты устройства или наоборот. В этом случае вам понадобится «обратная» часть. То есть преобразуйте ввод линейного ускорения в мировые координаты, умножив их на транспонирование матрицы ориентации.

person Edward Falk    schedule 21.07.2012
comment
Я сделал, как вы сказали, - я получил вектор ускорения A (в системе координат Земли) путем умножения матрицы вращения R (из getRotationMatrix(), предоставленной данными о силе тяжести и магнитном поле) и вектора линейного ускорения V (из линейного датчика в устройстве). coord. sys.) вот так: A=RV. Но я не получил хороших результатов. Я поставил телефон в положение стоя (осью Y вверх) и подвигал его вверх-вниз. Лин. соотв. датчик должен показывать движение по оси Y, а преобразованный вектор - по оси Z. Но я получил вектор V и вектор A. Так..? - person alex; 23.07.2012