Как я должен рассчитать Азимут, шаг, ориентацию, когда мое устройство Android не плоское?

Я использую датчики гравитации и магнитного поля Android для вычисления ориентации через SensorManager.getRotationMatrix и SensorManager.getOrientation. Это дает мне Азимут, высоту и ориентацию. Результаты выглядят разумными, когда устройство лежит на столе.

однако я отключил переключатели между портретом и пейзажем в манифесте, так что getWindowManager().getDefaultDisplay().getRotation() всегда равен нулю. Когда я поверните устройство на 90 Градусы так, что он стоит вертикально, я сталкиваюсь с проблемами. Иногда цифры кажутся совершенно неправильными, и я понял, что это относится к блокировка вращения. Однако, другие приложения не имеют этой проблемы. Например, я сравнил свое приложение с двумя бесплатными приложениями для тестирования датчиков (Тестер Датчиков (Dicotomica) и контроль датчика (программное обеспечение R)). Мое приложение согласуется с этими приложениями, когда устройство плоское, но когда я поворачиваю устройство по вертикали позиция может быть существенной. Два приложения, похоже, согласны друг с другом, так как они обходят эту проблему?

2 ответов


Я думаю, что лучший способ определить ваши углы ориентации, когда устройство не плоское, - использовать более подходящую угловую систему координат, которую вы получаете от стандартных углов Эйлера SensorManager.getOrientation(...). Я предлагаю тот, который я описываю здесь на math.stackexchange.com. Я также поместил некоторый код, который реализует его в ответ тут. Помимо хорошего определения азимута, он также имеет определение угла тангажа, который является точно заданным углом by Math.acos(rotationMatrix[8]) это упоминается в другом ответе здесь.

Вы можете получить полную информацию из двух ссылок, которые я дал в первом абзаце. Однако, в общем, ваша матрица вращения R из SensorManager.getRotationMatrix(...) is

equation with definition of R matrix

где (Ex, Ey, Ez), (Nx, Ny, Nz) и (Gx, Gy, Gz) - векторы, указывающие на Восток, Север и в направлении силы тяжести. Тогда азимутальный угол, который вы хотите, задается

equation defining the azimuth angle


когда устройство не плоское, вы должны позвонить remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR); перед вызовом getOrientation.

на azimuth возвращает getOrientation получается ортогонально проектировать блок устройства Y axis в мире East-North plane а затем вычислить угол между результирующим вектором проекции и Северной осью.

теперь мы обычно думаем о направлении как направлении, куда указывает задняя камера. Это направление -Z здесь Z - это устройство оси указывая на экран. Когда устройство плоское, мы не думаем о направлении и принимаем то, что когда-либо дано. Но когда он не плоский, мы ожидаем, что это направление -Z. Но!--2-- > вычислить направление Y axis, таким образом, нам нужно поменять Y and Z axes перед вызовом getOrientation. Это именно то, что remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR) делает, он держит X axis в целости и карте Z to Y.

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

float inclination = (float) Math.acos(rotationMatrix[8]);
if (result.inclination < TWENTY_FIVE_DEGREE_IN_RADIAN 
            || result.inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
{
    // device is flat just call getOrientation
}
else
{
    // call remap
}

наклон выше-это угол между экраном устройства и плоскостью Восток-Север. Он показывает, насколько устройство наклоняется.