Использование Cardboard SDK для определения ориентации устройства
Invite pending
Получения текущих углов наклона устройстве с помощью сенсоров — интересная задача. Но проблема заключается не в том, как получить значения, а как их отфильтровать. Дело все в том, что показания акселерометра очень неточные, гироскоп имеет проблему «дрифта», то есть его значения постоянно уменьшаются при неподвижном состоянии, а магнитный сенсор зависит от окружающего его магнитного поля.
Решением этой проблемы является совмещение показаний гироскопа и акселерометра и их фильтрация с помощью алгоритма Калмана, как это делают здесь.
В поисках найти код на Java для всего этого наткнулся на статью «Android sensor fusion tutorial». Их программа показала себя не лучшим образом при измерении с помощью акселерометра + магнитного сенсора + гироскопа: значения сильно колебались и зависели от магнитного поля (при поднесении магнита).
Лучшим вариантом стало решение от Google для Cardboard. Этот API дает показания высокой точности почти без колебаний и значения не зависят от магнитного поля, так как для измерений используются только гироскоп и акселерометр.
Здесь рассказано о том, как использовать лишь часть API для отслеживания поворота головы (проект пишу в Android Studio):
1. Скачать библиотеки cardboard.jar и libprotobuf-java-2.6-nano.jar отсюда или отсюда;
2. Поместить их в папку lib проекта;
3. Связать проект с этими библиотеками: File > Project Structure > Dependencies > (+) > Выбрать нужные файлы. Должно получиться вот так:
4. Класс HeadTransform скачиваем и кладем вместе со своими классами. (API не позволяет пользоваться некоторыми методами этого класса, поэтому мы положим его копию в свой пакет. HeadTransform отвечает только за некоторые математические преобразования, поэтому может использоваться отдельно);
5. В нужной Activity объявляем:
6. В onCreate:
7. В onResume:
8. В onStop:
9. Для получения текущих углов пишем:
10. Теперь в массиве angles будут углы:
• Pitch (X axis): [-pi/2, pi/2]
• Yaw (Y axis): [-pi, pi]
• Roll (Z axis): [-pi, pi]
Подробнее:https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/HeadTransform#getEulerAngles
11. Получать эти значения можно в каком-либо Thread с небольшой задержкой;
12. Значения углов очень точные, так как используются и акселерометр и гироскоп. Благодаря коррекции отклонений гироскопа, решена проблема «дрифта» показаний;
13. Для графических игр лучше использовать матрицу переноса как сказано здесь. Пример: https://github.com/googlesamples/cardboard-java;
14. Подробнее про Cardboard API:https://developers.google.com/cardboard/;
15. Почитать исходный код cardboard.jar можно здесь или здесь (декомпилированые старые версии 0.5.1);
16. Мой пример;
17. Готово!
Решением этой проблемы является совмещение показаний гироскопа и акселерометра и их фильтрация с помощью алгоритма Калмана, как это делают здесь.
В поисках найти код на Java для всего этого наткнулся на статью «Android sensor fusion tutorial». Их программа показала себя не лучшим образом при измерении с помощью акселерометра + магнитного сенсора + гироскопа: значения сильно колебались и зависели от магнитного поля (при поднесении магнита).
Лучшим вариантом стало решение от Google для Cardboard. Этот API дает показания высокой точности почти без колебаний и значения не зависят от магнитного поля, так как для измерений используются только гироскоп и акселерометр.
Здесь рассказано о том, как использовать лишь часть API для отслеживания поворота головы (проект пишу в Android Studio):
1. Скачать библиотеки cardboard.jar и libprotobuf-java-2.6-nano.jar отсюда или отсюда;
2. Поместить их в папку lib проекта;
3. Связать проект с этими библиотеками: File > Project Structure > Dependencies > (+) > Выбрать нужные файлы. Должно получиться вот так:
4. Класс HeadTransform скачиваем и кладем вместе со своими классами. (API не позволяет пользоваться некоторыми методами этого класса, поэтому мы положим его копию в свой пакет. HeadTransform отвечает только за некоторые математические преобразования, поэтому может использоваться отдельно);
5. В нужной Activity объявляем:
HeadTracker track;
float [] angles = new float[3];
6. В onCreate:
track = HeadTracker.createFromContext(this);
7. В onResume:
track.startTracking();
8. В onStop:
track.stopTracking();
9. Для получения текущих углов пишем:
HeadTransform trans = new HeadTransform();
track.getLastHeadView(trans.getHeadView(), 0);
trans.getEulerAngles(angles, 0);
10. Теперь в массиве angles будут углы:
• Pitch (X axis): [-pi/2, pi/2]
• Yaw (Y axis): [-pi, pi]
• Roll (Z axis): [-pi, pi]
Подробнее:https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/HeadTransform#getEulerAngles
11. Получать эти значения можно в каком-либо Thread с небольшой задержкой;
12. Значения углов очень точные, так как используются и акселерометр и гироскоп. Благодаря коррекции отклонений гироскопа, решена проблема «дрифта» показаний;
13. Для графических игр лучше использовать матрицу переноса как сказано здесь. Пример: https://github.com/googlesamples/cardboard-java;
14. Подробнее про Cardboard API:https://developers.google.com/cardboard/;
15. Почитать исходный код cardboard.jar можно здесь или здесь (декомпилированые старые версии 0.5.1);
16. Мой пример;
17. Готово!