Accelerometer android что это

Accelerometer android что это

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

Взаимодействие с приложением на смартфоне не только через кнопки, но и с помощью жестов, поворотов дает как новые возможности и пользователи, и программисту, так и делает работу со смартфоном более «живой», интересной и необычной.

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

Начинаем работать. Создаем новый проект, названия либо оставьте по умолчанию, либо введите свои, но потом будете разбираться в них сами:). Наше будущее приложение будет поддерживать только портретную ориентацию. Поэтому сразу идем в файл манифеста приложения AndroidManifest.xml и настроим проекту только портретный вид:

В основном классе программы MainActivity.java нужно выполнить SensorEventListener интерфейс. Для этого, добавляем к строке объявления класса следующее:

Для успешного использования SensorEventListener нужно добавить к строкам импорта следующее:

При объявлении выполнения интерфейса SensorEventListener программа заругалась на нас ошибками. Ничего страшного, просто для реализации этого интерфейса необходимы два особых метода, с которыми мы сейчас разберемся. Ниже метода onCreate добавим следующие методы:

Взглянем на метод onSensorChanged. Этот метод используется для обнаружения жестов. Он вызывается всякий раз, когда в акселерометре устройства происходят какие то перемены. Он вызывается многократно, всякий раз, когда устройство приходит в движение. Для того, чтобы использовать классы Sensor и SensorEvent, необходимо добавить еще пару строк в импорт:

Перед тем, как использовать метод onSensorChanged, нам нужно задекларировать использование следующих переменных:

Если после этого у вас появились ошибки, проверьте, есть ли среди импорта это:

В методе onCreate мы инициализируем наши переменные и создаем слушателя событий:

Для инициализации SensorManager мы вызываем getSystemService, таким образом мы получаем доступ к акселерометру. Метод getSystemService вызывается для получения ссылки на необходимый нам сервис. Отсылка к акселерометру происходит благодаря команде getDefaultSensor. Далее, для регистрации сенсора, мы используем метод registerListener:

Теперь нам нужно описать еще два метода: onPause и onResume. Это будет использоваться для того, чтобы отключать работу с акселерометром, когда мы не работаем в приложении, и опять включать при продолжении работы, что будет способствовать быстродействия аппарата и уровню потребления батареи. Эти методы будут выглядеть примерно так:

Теперь нужно научить наше приложение распознавать жесты. Большинство работ по реализации этого будет происходить внутри метода onSensorChanged. Для начала задекларируем в классе MainActivity.java такие переменные:

Теперь перейдем в работе в методе onSensorChanged. Мы получаем ссылку на акселерометр и проверяем, не ошиблись ли мы с выбором адаптера (акселерометра):

Далее нужно определить положение устройства в трехмерном пространстве по x,y, и z осям. Чтобы лучше понять о чем речь, изучаем следующую картинку:

Для того, чтобы получить эти необходимые нам координаты, мы делаем так:

Сенсоры большинства смартфонов невероятно чувствительны. Неважно, насколько твердо ваша рука держит смартфон, сенсор все равно будет постоянно видеть изменение положения аппарата. Поэтому для мониторинга положения устройства метод onSensorChanged вызывается очень часто, по несколько раз в секунду. Правда нам не нужно так много информации для нашего приложения, поэтому мы сделаем так, что этот методу будет вызываться не чаще, чем раз в 100 миллисекунд:

Теперь усовершенствуем программу до состояния, когда она сможет подсчитывать скорость движения устройства, Для этого мы декларируем особенную переменную SHAKE_THRESHOLD, которая будет показывать, зарегистрировано ли движение устройства или нет. Изменение значения переменной SHAKE_THRESHOLD увеличивает или уменьшает чувствительность сенсора, поэтому здесь можете пофантазировать на свое усмотрение:

И так, у нас уже есть приложение, с помощью акселерометра способное определять жесты и движение. Теперь мы сделаем так, что при встряхивании устройством будет выбираться 6 случайных чисел, но об этом чуть позже. Сейчас нам нужно отредактировать файл activity_main.xml. В уроке в качестве фона используется изображение синего шара, вы можете выбрать на фон, что вам угодно:

Каждый FrameLayout содержит элемент TextView, в котором будет отображаться случайно сгенерированное число от 1 до 49. Удостоверьтесь, что все FrameLayout и TextView имеют свой id, чтобы можно было к ним потом обращаться.

Теперь давайте еще разок вернемся в класс MainActivity.java и добавим туда метод выбора случайного числа от 1 до 49:

Мы создаем объект ArrayList для хранения выбранных 6 чисел и в цикле for с помощью стандартного java класса Random выбираем случайные числа. Также выполняется проверка уже добавленных в ArrayList чисел, чтобы избежать повторов. Чтобы все заработало исправно, добавим еще пару строчек к импорту:

Последним шагом будет отображение выбранных 6 случайных чисел в пользовательском интерфейсе. Получаем ссылки на элементы TextView, созданные ранее, и привязываем к ним числа, а также добавим анимацию нашим FrameLayout:

Читайте также:  Хорошая жена для андроида

Добавим к строкам импорта еще такие:

Для настройки анимации нужно создать соответствующий файл, в котором мы ее зададим. Создайте в файлах проекта папку anim и в ней файл move_down_ball_first.xml и добавьте туда следующий код:

Все, что осталось сделать, это вызвать метод getRandomNumber в методе onSensorChanged класса MainActivity.java:

Все, наше приложение, работающее на акселерометре устройства готово! Запускаем на смартфоне программу, трясем как следует аппарат и видим примерно это:

Надеюсь, вам этот урок оказался полезен, удачи!

Источник

Полный список

— читаем данные с сенсоров

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

Android поддерживает несколько типов сенсоров. В данный момент хелп сообщает, что таких типов 13. Мы в этом уроке рассмотрим сенсоры света, ускорения, гравитации и магнитного поля.

Получать данные с сенсоров несложно. Для этого нам надо будет запросить у системы объект-сенсор и повесить на него своего слушателя. В метод слушателя будет приходить массив с данными.

Список сенсоров. Сенсор света.

Первое приложение будет выводить нам список доступных сенсоров и данные с сенсора света.

Project name: P1371_Sensors
Build Target: Android 2.3.3
Application name: Sensors
Package name: ru.startandroid.develop.p1371sensors
Create Activity: MainActivity

В strings.xml добавим строки:

Кнопки для получения списка сенсоров и данных по свету, и TextView для отображения данных.

В onCreate получаем SensorManager. У него запрашиваем полный список сенсоров, используя метод getSensorList и передавая туда тип сенсора TYPE_ALL.

Чтобы получить конкретный сенсор (Sensor), вызываем метод getDefaultSensor. Передаем тип TYPE_LIGHT и получаем сенсор света. Тут аккуратнее, т.к. если такого сенсора в девайсе нет – то метод вернет null.

В onClickSensList мы отписываем слушателя от сенсора. Об этом чуть позднее.

Далее берем список сенсоров и выводим по ним инфу на экран:
getName – имя
getType – тип
getVendor – создатель
getVersion – версия
getMaximumRange – максимальное значение, которое может вернуть сенсор
getResolution – насколько я понял, это минимальный шаг, с которым может изменяться значение

В методе onClickSensLight мы используем метод registerListener, чтобы на ранее полученный сенсор света (sensorLight) повесить своего слушателя listenerLight. Третий параметр метода – скорость получения новых данных. Т.е. насколько часто вам необходимо получать данные от сенсора. Есть 4 скорости в порядке убывания: SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, SENSOR_DELAY_FASTEST.

Правда хелп пишет, что система может проигнорить это значение и выдавать данные как ей удобно. А начиная с API Level 9 можно вместо константы скорости передавать свое значение в микросекундах. Не перепутайте с миллисекундами.

В onPause мы отписываем своего слушателя от сенсора света. Тут, как обычно, рекомендуется отписываться как только данные вам не нужны, чтобы не расходовать зря батарею.

listenerLight – слушатель, реализует интерфейс SensorEventListener. У него два метода:

onAccuracyChanged – вызывается, когда меняется точность данных сенсора и в начале получения данных. Дает нам объект-сенсор и уровень точности:

SENSOR_STATUS_ACCURACY_HIGH – максимально возможная точность
SENSOR_STATUS_ACCURACY_MEDIUM – средняя точность, калибровка могла бы улучшить результат
SENSOR_STATUS_ACCURACY_LOW – низкая точность, необходима калибровка
SENSOR_STATUS_UNRELIABLE – данные сенсора совсем ни о чем. Либо нужна калибровка, либо невозможно чтение данных.

onSensorChanged – здесь то мы и получаем данные от сенсора в объекте SensorEvent.

Все сохраняем и запускаем приложение. Жмем List и получаем список.

У меня он выглядит вот так:

На скрине видно, что в устройстве есть несколько сенсоров одного типа. Если вместо TYPE_ALL передать в метод getSensorList какой-либо конкретный типа сенсора, то получим список сенсоров только этого типа.

Теперь нажмем Light. Приложение покажет текущее значение освещенности. Попробуйте менять яркость освещения рядом с девайсом, должно меняться значение.

У меня в полутемной комнате показывает 0. Если взять фонарик и издалека начать подносить к датчику света покажет последовательно: 10, 100, 1000, 10000 и в конце 30000. При этом, на скрине со списком сенсоров видно, что максимум значения = 3000, а шаг (если я правильно понял параметр resolution) = 1. Почему такое несоответствие инфы с реальностью – я не знаю.

Ускорение

Далее рассмотрим сенсоры движения. Для этого нам надо будет понять, что в нашем трехмерном пространстве у устройства есть три оси. В хелпе гугла есть такая картинка.

Т.е. если держать устройство перед собой, то ось X проходит слева направо, ось Y проходит снизу вверх, ось Z проходит сквозь устройство в вашем направлении. Сенсор ускорения вернет нам массив из трех значений, каждое из которых соответствует определенной оси.

Project name: P1372_Acceleration
Build Target: Android 2.3.3
Application name: Acceleration
Package name: ru.startandroid.develop.p1372acceleration
Create Activity: MainActivity

В onCreate мы получаем три сенсора:

TYPE_ACCELEROMETER – ускорение, включая гравитацию (ту самую, которая 9.8, из физики)

В onResume регистрируем один слушатель listener на все три сенсора. И запускаем таймер, который будет каждые 400 мсек отображать данные в TextView.

Читайте также:  Fnaf андроид все части

В onPause отписываем слушателя от всех сенсоров, вызывая метод unregisterListener, но не указывая конкретный сенсор. И отключаем таймер.

Метод format просто отформатирует float значения до одного знака после запятой.

showInfo выведет в TextView данные. Данные у нас будут в пяти массивах.

В слушателе listener в методе onSensorChanged мы определяем тип сенсора и пишем данные в соответствующие массивы:

valuesAccel – данные с сенсора ускорения (включая гравитацию)

valuesAccelMotion и valuesAccelGravity – данные из valuesAccel, разделенные с помощью вычислительного фильтра на чистое ускорение (без гравитации) и гравитацию.

valuesLinAccel – данные с сенсора ускорения без гравитации

valuesGravity – данные с сенсора гравитации

Т.е. мы получаем данные по ускорению (valuesAccel) с сенсора TYPE_ACCELEROMETER и потом вычислительным фильтром сами разбиваем на чистое ускорение и гравитацию. Но можно так не заморачиваться, а использовать сенсоры TYPE_LINEAR_ACCELERATION и TYPE_GRAVITY, которые должны дать нам примерно тот же результат.

Кстати, обратите внимание, как я считываю данные в свой массив. Я читаю значения и пишу их себе. Почему просто не выполнить присваивание типа: valuesAccel = event.values? Если так сделать, то могут периодически проскакивать кривые данные, если вы несколько сенсоров читаете. Там, похоже, используется пул объектов, чтобы сборщик мусора не грузить таким диким кол-вом новых объектов на единицу времени. Соответственно, если вы возьмете объект по ссылке, то пока он дойдет у вас до обработки, система может снова взять его в оборот и записать в него уже новые значения, причем еще и от другого сенсора. Так что лучше читать значения, а не ссылку брать.

Запустим приложение. И положим девайс на стол экраном вверх.

Еще раз обсудим, что вывелось на экран

Accelerometer: данные по ускорению + гравитация. Видим, что третья ось (Z), которая в лежачем положении проходит вертикально вверх, показывает ускорение примерно равное гравитации. Т.е. даже в состоянии покоя сенсор показывает не чистое ускорение а еще и гравитацию, что не всегда нужно.

Мы использовали фильтр, чтобы отделить ускорение от гравитации.

Accel motion: чистое ускорение, вычисленное из ускорения с гравитацией. Здесь все нули, т.к. устройство лежит и не двигается.

Accel gravity: гравитация, вычисленная из ускорения с гравитацией. Здесь первые две оси = нулю, т.к. они проходят паралелльно земле и по этим осям гравитации нет. Зато она есть по третьей оси, которая проходит вертикально. Проще говоря планета не тянет нас влево-вправо-вперед-назад, она тянет нас вниз. Поэтому показывать ускорение в 9.8 будет та ось, которая находится вертикально к земле.

Lin accel: данные с сенсора чистого ускорения (без гравитации). Тут все нули, т.к. устройство в состоянии покоя. Эти значения примерно должны совпадать с теми, что мы посчитали в Accel motion.

Gravity: данные с сенсора гравитации. Третья ось показывает, что она находится вертикально, т.к. гравитация по ней близка к максимуму. Эти значения должны совпадать с теми, что мы посчитали в Accel gravity.

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

Теперь я возьму устройство в руки и подниму перед собой так, чтобы оно было на уровне глаз, а экран смотрел на меня. Т.е. так же, как выше в тексте, на картинке c осями.

Смотрим, как изменились данные.

Accelerometer: четко видно, что теперь вторая ось (Y) расположена почти вертикально, по ней идет гравитация 9.8. А оси X и Z близки к нулю. Они не равны точно нулю, т.к. я держу устройство не идеально ровно и небольшие перекосы дают гравитацию и на эти оси.

Т.е. вывод можно сделать следующий. Чем ближе значение оси к 9.8, тем вертикальнее ее положение в пространстве. А чем ближе к нулю, тем горизонтальнее.

Accel motion и Lin accel показывают нам чистое ускорение. Оно близко к нулю, т.к. я стараюсь не дергать устройство.

Accel gravity и Gravity показывают, что по второй оси имеем почти полную гравитацию, а значит ось расположена вертикально.

Попробуйте понаклонять устройство в разные стороны и наблюдайте как меняется гравитация. При переходе оси от горизонтального положения к вертикальному значение сенсора по этой оси будет меняться от 0 до 9.8.

Ориентация

Теперь попробуем использовать данные сенсора ускорения и добавим к ним данные сенсора магнитного поля. Эти два набора данных при определенных манипуляциях дадут нам углы наклона устройства. Угла будет три, по одному для каждой оси.

Project name: P1373_Orientation
Build Target: Android 2.3.3
Application name: Orientation
Package name: ru.startandroid.develop.p1373orientation
Create Activity: MainActivity

В onCreate мы получаем сенсоры ускорения (TYPE_ACCELEROMETER) и магнитного поля (TYPE_MAGNETIC_FIELD).

В onResume вешаем слушателя и запускаем таймер, который каждые 400 мсек будет определять ориентацию девайса в пространстве и выводить эту инфу на экран. В переменную rotation получаем значение текущей ориентации экрана. Это нам понадобиться для корректного определения ориентации девайса.

Читайте также:  Резервное копирование ватсап андроид где находится

В onPause отключаем слушателя и таймер.

Метод format просто отформатирует float значения до одного знака после запятой.

showInfo покажет данные массивов в TextView. Но сначала эти данные надо вычислить. Этим займутся следующие два метода.

Метод getDeviceOrientation определяет текущую ориентацию девайса в пространстве без учета поворота экрана. Для этого мы сначала вызваем метод getRotationMatrix, который берет данные ускорения и магнитного поля и формирует из них матрицу данных в переменную r. Далее метод getOrientation из этой матрицы позволяет получить массив значений (в радианах) поворота трех осей. Остается перевести радианы в градусы методом toDegrees и у нас есть готовый массив с углами наклона девайса.

Метод getActualDeviceOrientation аналогичен методу getDeviceOrientation, но он позволяет учесть ориентацию экрана. Для этого мы дополнительно вызываем метод remapCoordinateSystem, который пересчитает нам матрицу. С помощью переменных x_axis и y_axis мы передаем в этот метод данные о том, как оси поменялись местами при повороте экрана.

Слушатель listener получает данные ускорения и магнитного поля и пишет их в массивы valuesAccel и valuesMagnet.

Запускаем приложение. Кладем устройство на ровную поверхность.

Orientation: данные по ориентации в пространстве без учета ориентации экрана устройства.
Orientation 2: данные по ориентации в пространстве с учетом ориентации экрана устройства. Они равны данным Orientation если экран устройства находится в нормальной ориентации.

Здесь, в отличие от ускорения, оси немного в другом порядке показаны. Первая цифра – это угол по оси Z. В горизонтальном положении устройства, это число показывает градус отклонения от севера. Т.е. это компас. Поверните устройство, сохраняя горизонтально положение, так, чтобы первая цифра стала близка к нулю. Теперь ваш девайс должен смотреть строго на север.

Вторая цифра – угол по оси X. Т.е. если устройство слева направо проткнуть (воображаемой!) спицей, и попробовать потом на ней повращать, будет меняться именно эта, вторая, цифра. Протыкать мы ничего не будем. Просто возьмите устройство за его верхнюю (дальнюю от вас) сторону и поднимайте ее на себя, как будто хотите, что-то посмотреть на экране. Нижняя сторона при этом лежит на столе. Видно, как меняется вторая цифра. Когда устройство будет вертикально стоять на нижней стороне, это значение должно стать равным -90. Т.е. это прямой угол. Попробуйте также поднимать нижнюю сторону, оставляя верхнюю на столе. Угол будет идти к 90.

Третья цифра – угол по оси Y. Тут аналогично оси X. Если положить устройство на стол, и начать поднимать его правую сторону, оставляя левую на столе (как будто переворачиваем страницу), будет меняться третья цифра. Она покажет угол наклона по оси Y. Попробуйте также поднимать левую, оставляя правую на столе.

Тем самым мы получили полную картину положения девайса в пространстве.

Попробуйте поменять ориентацию экрана и заблокировать ее в настройках. И снова потестируйте наклоны. Вы увидите, что данные Orientation выводятся относительно стандартной ориентации экрана, а Orientation2 – относительно текущей ориентации экрана.

Данные по ориентации также можно получить без всяких манипуляций, используя сенсор TYPE_ORIENTATION . Но он объявлен устаревшим с API Level 8.

Прочее

Еще немного инфы по теме сенсоров.

Сенсоры бывают реальные (hardware) и виртуальные (virtual). Реальные – это датчики, которые дают нам значения. А виртуальные используют значения реальных и по ним вычисляют свои значения. В рассмотренных нами примерах мы использовали реальный сенсор ускорения (TYPE_ACCELEROMETER) и из него сами посчитали чистое ускорение и гравитацию. Используемые нами там же сенсоры чистого ускорения (TYPE_LINEAR_ACCELERATION) и гравитации (TYPE_GRAVITY) являются виртуальными и так же, как и мы вычисляют свой результат. Только, я думаю что механизм подсчета там отличен от нашего и позволяет получить более реальные результаты.

Сенсор-гироскоп (TYPE_GYROSCOPE) показывает скорость вращения по осям в радиан/сек.

У сенсора есть еще такая характеристика как power – потребляемая мощность (mA). Чем она ниже, тем, разумеется, лучше для батареи.

Если ваше приложение обязательно использует сенсор и не будет без него работать, вы можете указать это в манифесте с помощью тега uses-feature. В этом случае Google Play не должен дать поставить приложение на устройство, которое не имеет указанного сенсора.

Пример для сенсора ускорения.

Значения других сенсоров можно найти в хелпе в секции Sensors.

На следующем уроке:

— получаем данные о местоположении

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью