Датчик Android: getRotationMatrix() возвращает неправильные значения, почему?
Прошло несколько дней с тех пор, как я начал использовать эту функцию и пока не смог получить действительные результаты.
Что я хочу, так это в основном преобразовать вектор ускорения из системы координат устройства в координаты реального мира. Я знаю, что это возможно, потому что у меня есть ускорение в относительных координатах, и я знаю ориентацию устройства в реальной системе.
Читая Android разработчики, кажется, что используя getRotationMatrix() я получаю R = матрицу вращения.
Поэтому, если я хочу A (вектор ускорения в мировой системе) из A' (вектор ускорения в телефонной системе), я должен сделать просто:
A=R*A'
Но я не могу понять, почему у вектора А ВСЕГДА первый и второй компоненты равны нулю (пример: +0,00;-0,00;+6,43)
Мой текущий код похож на это:
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
switch(event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
accelerometervalues = event.values.clone();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
geomagneticmatrix =event.values.clone();
break;
}
if (geomagneticmatrix != null && accelerometervalues != null) {
float[] Rs = new float[16];
float[] I = new float[16];
SensorManager.getRotationMatrix(Rs, I, accelerometervalues, geomagneticmatrix);
float resultVec[] = new float[4];
float relativacc[]=new float [4];
relativacc[0]=accelerationvalues[0];
relativacc[1]=accelerationvalues[1];
relativacc[2]=accelerationvalues[2];
relativacc[3]=0;
Matrix.multiplyMV(resultVec, 0, Rs, 0, relativacc, 0);
//resultVec[] is the vector acceleration relative to world coordinates system..but doesn't WORK!!!!!
}
}
}
Этот вопрос очень похож на этот. Преобразование данных акселерометра из координат устройства в координаты реального мира, но там я не могу найти решение... Я перепробовал все способы...
Пожалуйста, помогите мне, мне нужна помощь!!!
ОБНОВИТЬ:
Теперь мой код приведен ниже, я пытался объяснить матричный продукт, но ничего не изменилось:
float[] Rs = new float[9];
float[] I = new float[9];
SensorManager.getRotationMatrix(Rs, I, accelerationvalues, geomagneticmatrix);
float resultVec[] = new float[4];
resultVec[0]=Rs[0]*accelerationvalues[0]+Rs[1]*accelerationvalues[1]+Rs[2]*accelerationvalues[2];
resultVec[1]=Rs[3]*accelerationvalues[0]+Rs[4]*accelerationvalues[1]+Rs[5]*accelerationvalues[2];
resultVec[2]=Rs[6]*accelerationvalues[0]+Rs[7]*accelerationvalues[1]+Rs[8]*accelerationvalues[2];
Вот несколько примеров чтения данных и результата:
Rs separated by " " Rs[0] Rs[1]....Rs[8]
Av separated by " " accelerationvalues[0] ...accelerationvalues[2]
rV separated by " " resultVec[0] ...resultVec[2]
Как вы можете заметить, компоненты на осях x и y в реальном мире равны нулю (вокруг), даже если вы перемещаете телефон. Вместо этого относительный вектор ускорения правильно определяет каждое движение!!!
РЕШЕНИЕ Ошибки в нумераторах относятся к умножению чисел с плавающей запятой, которое отличается от двойного умножения. Это сводится к тому, что матрица вращения не стоит, если телефон, даже если с той же ориентацией, ускоряется. Поэтому невозможно перевести вектор ускорения в абсолютные координаты во время движения... Это сложно, но это реальность.
4 ответа
Finnaly я нашел ответ:
Ошибки в числах относятся к умножению чисел с плавающей запятой, которое не совпадает с двойным умножением. Здесь есть решение. Это сводится к тому, что матрица вращения не стоит, если телефон, даже если с той же ориентацией, ускоряется. Поэтому невозможно перевести вектор ускорения в абсолютные координаты во время движения... Это сложно, но это реальность.
К вашему сведению, вектор ориентации сделан из данных магнитометра И вектора силы тяжести. Это приводит к серьезной проблеме: преобразование относительного соотношения нуждается в ориентации, требует магнитного поля и гравитации, но мы знаем гравитацию только в том случае, если телефон остановлен относительно, поэтому мы возвращаемся, чтобы начать.
Это подтверждается разработчиками Android, где объясняется, что матрица вращения дает истинный результат только тогда, когда телефон не ускоряется (например, они говорят о свободном падении, потому что не должно быть гравитационного измерения) или когда он не находится в нерегулируемом положении. магнитное поле.
Матрицы, возвращаемые этой функцией, имеют смысл только тогда, когда устройство не свободно падает и не находится близко к магнитному северу. Если устройство ускоряется или находится в сильном магнитном поле, возвращаемые матрицы могут быть неточными.
В чужом мире это совершенно бесполезно... Вы можете доверять этой вещи, выполняя простой эксперимент на столе с Android Senor или что-то вроде этого..
Вы должны отследить эту арифметическую ошибку, прежде чем беспокоиться о вращении, ускорении или чем-либо еще.
Вы подтвердили, что
resultVec[0]=Rs[0]*accelerationvalues[0];
дает тебе
Rs[0]: 0.24105562
accelerationValues[0]: 6.891896
resultVec[0]: 1.1920929E-7
Итак, еще раз, упростите. Попробуй это:
Rs[0] = 0.2;
resultVec[0] = Rs[0] * 6.8
РЕДАКТИРОВАТЬ:
Последний дал resultVec[0]=1.36
Итак, давайте попробуем это:
Rs[0] = 0.2;
accelerationValues[0] = 6.8
resultVec[0] = Rs[0] * accelerationValues[0];
Если вы делаете суммы, используя напечатанные значения, которые вы добавили, я получаю
`(0.00112, -0.0004, 10)`
что не так мало, как то, что у вас есть. Поэтому возникает арифметическая ошибка!
Может быть проблема в том, что вы используете accelerationvalues[]
в последнем блоке и accelerometervalues[]
потом?
Я разработал несколько приложений, в которых используются датчики Android, поэтому я отвечаю на один из ваших вопросов в соответствии с моим опытом:
Но я не могу понять, почему у вектора А ВСЕГДА первый и второй компоненты равны нулю (пример: +0,00;-0,00;+6,43)
Я также наблюдал эту проблему с датчиком ускорения и датчиком магнитного поля. Показания равны нулю для некоторой оси (два, как вы указали, или только один в других случаях). Эта проблема возникает, когда вы только что включили датчики (registerListener ()), и я предполагаю, что это связано с некоторой инициализацией датчика. В случае с датчиком ускорения я заметил, что лишь небольшое встряхивание устройства заставляет его начать давать правильные показания датчика.
Правильным решением будет метод onAccuracyChanged(), предоставляющий правильную информацию о состоянии датчика. Он должен возвращать состояние SensorManager.SENSOR_STATUS_UNRELIABLE, но вместо этого он постоянно возвращает SensorManager.SENSOR_STATUS_ACCURACY_HIGH на всех физических устройствах, которые я тестировал до сих пор. При правильно реализованном методе onAccuracyChanged() вы можете игнорировать плохие показания или попросить пользователя подождать, пока инициализируется датчик.