Статьи

Датчики Android в глубине: приближение и гироскоп

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

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

Вы можете получить обзор аппаратных датчиков Android, прочитав следующий учебник:

  • Android SDK
    Android с нуля: аппаратные датчики
    Пол Требилкокс-Руис

Чтобы следовать, вам понадобится следующее:

  • Android-устройство с датчиком приближения и гироскопом
  • Последняя версия Android Studio

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

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

1
2
3
4
5
6
<uses-feature
    android:name=»android.hardware.sensor.proximity»
    android:required=»true» />
<uses-feature
    android:name=»android.hardware.sensor.gyroscope»
    android:required=»true» />

Тем не менее, обратите внимание, что, поскольку <uses-feature> не помогает, если пользователь устанавливает ваше приложение вручную, используя его файл APK, вы все равно должны программно проверить, доступен ли датчик перед его использованием.

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

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

Чтобы получить доступ к любому аппаратному датчику, вам нужен объект SensorManager . Чтобы создать его, используйте метод getSystemService() вашего класса Activity и передайте SENSOR_SERVICE константу SENSOR_SERVICE .

1
2
SensorManager sensorManager =
       (SensorManager) getSystemService(SENSOR_SERVICE);

Теперь вы можете создать объект Sensor для датчика приближения, вызвав метод getDefaultSensor() и передав TYPE_PROXIMITY константу TYPE_PROXIMITY .

1
2
Sensor proximitySensor =
       sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

Прежде чем продолжить, всегда проверяйте, чтобы объект « Sensor не был null . Если это так, это означает, что датчик приближения недоступен.

1
2
3
4
if(proximitySensor == null) {
    Log.e(TAG, «Proximity sensor not available.»);
    finish();
}

Чтобы иметь возможность считывать необработанные данные, сгенерированные датчиком, необходимо связать с ним SensorEventListener , вызвав метод registerListener() объекта SensorManager . При этом вы также должны указать, как часто данные должны считываться с датчика.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
// Create listener
SensorEventListener proximitySensorListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        // More code goes here
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }
};
 
// Register it, specifying the polling interval in
// microseconds
sensorManager.registerListener(proximitySensorListener,
                proximitySensor, 2 * 1000 * 1000);

Я предлагаю вам всегда регистрировать прослушиватель в onResume() вашей активности и onPause() его регистрацию в onPause() . Вот как вы можете отменить регистрацию слушателя:

1
sensorManager.unregisterListener(proximitySensorListener);

Объект SensorEvent , который доступен внутри onSensorChanged() , имеет массив values содержащий все необработанные данные, сгенерированные связанным датчиком. В случае датчика приближения массив содержит единственное значение, определяющее расстояние между датчиком и близлежащим объектом в сантиметрах.

Если значение равно максимальному диапазону датчика, можно предположить, что поблизости ничего нет. И наоборот, если он меньше максимального диапазона, это означает, что рядом есть что-то. Вы можете определить максимальный диапазон любого аппаратного датчика, используя метод getMaximumRange() связанного объекта Sensor .

Чтобы фактически изменить цвет фона действия на основе данных датчика приближения, вы можете использовать метод setBackgroundColor() представления декора окна верхнего уровня.

Соответственно, добавьте следующий код в метод onSensorChanged() который вы создали на предыдущем шаге:

1
2
3
4
5
6
7
if(sensorEvent.values[0] < proximitySensor.getMaximumRange()) {
    // Detected something nearby
    getWindow().getDecorView().setBackgroundColor(Color.RED);
} else {
    // Nothing is nearby
    getWindow().getDecorView().setBackgroundColor(Color.GREEN);
}

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

Цвет фона меняется при обнаружении объекта поблизости

Гироскоп позволяет определять угловую скорость устройства Android в любой момент времени. Проще говоря, он говорит вам, как быстро устройство вращается вокруг своих осей X, Y и Z. В последнее время даже бюджетные телефоны производятся со встроенным гироскопом, что делает приложения дополненной реальности и виртуальной реальности столь популярными.

Используя гироскоп, вы можете разрабатывать приложения, которые могут реагировать на незначительные изменения в ориентации устройства. Чтобы увидеть, как, давайте теперь создадим действие, цвет фона которого меняется на синий каждый раз, когда вы поворачиваете телефон в направлении против часовой стрелки вдоль оси Z, и на желтый в противном случае.

Чтобы создать объект Sensor для гироскопа, все, что вам нужно сделать, это передать константу TYPE_GYROSCOPE в метод getDefaultSensor() объекта SensorManager .

1
2
gyroscopeSensor =
       sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// Create a listener
gyroscopeSensorListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        // More code goes here
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }
};
 
// Register the listener
sensorManager.registerListener(gyroscopeSensorListener,
        gyroscopeSensor, SensorManager.SENSOR_DELAY_NORMAL);

Исходные данные датчика гироскопа состоят из трех значений с float , определяющих угловую скорость устройства по осям X, Y и Z. Единицей каждого значения является радиан в секунду. В случае вращения против часовой стрелки вдоль любой оси значение, связанное с этой осью, будет положительным. В случае вращения по часовой стрелке оно будет отрицательным.

Поскольку в настоящее время нас интересует только вращение вдоль оси Z, мы будем работать только с третьим элементом в массиве SensorEvent объекта SensorEvent . Если оно больше 0.5f , мы можем в значительной степени убедиться, что вращение происходит против часовой стрелки, и установить цвет фона на синий. Точно так же, если оно меньше -0.5f , мы можем установить цвет фона на желтый.

1
2
3
4
5
if(sensorEvent.values[2] > 0.5f) { // anticlockwise
    getWindow().getDecorView().setBackgroundColor(Color.BLUE);
} else if(sensorEvent.values[2] < -0.5f) { // clockwise
    getWindow().getDecorView().setBackgroundColor(Color.YELLOW);
}

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

Изменение цвета фона в зависимости от угловой скорости

Однако, если вы включите телефон слишком сильно, ориентация его экрана изменится на альбомную, и ваша активность возобновится. Чтобы избежать этого условия, я предлагаю вам установить screenOrientation действия в screenOrientation в файле манифеста.

1
2
3
4
<activity
    android:name=».GyroscopeActivity»
    android:screenOrientation=»portrait»>
</activity>

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

В примере предыдущего шага мы меняли цвет фона деятельности каждый раз, когда угловая скорость вдоль оси Z превышала 0,5 рад / с в направлении по часовой стрелке или против часовой стрелки. Работа с угловыми скоростями, однако, не является интуитивно понятной. Кроме того, мы понятия не имели, каким был реальный угол устройства до или после поворота.

Используя датчик вектора вращения, давайте теперь создадим действие, цвет фона которого изменяется только при повороте на определенный угол. Например, мы могли бы поворачивать его желтым каждый раз, когда его вращение — вдоль оси Z — больше 45 °, белым, когда его вращение составляет от -10 ° до 10 °, и синим, когда его вращение меньше -45 °.

Чтобы получить датчик вектора вращения, необходимо передать константу TYPE_ROTATION_VECTOR в метод getDefaultSensor() объекта SensorManager .

1
2
rotationVectorSensor =
       sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// Create a listener
rvListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        // More code goes here
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }
};
 
// Register it
sensorManager.registerListener(rvListener,
            rotationVectorSensor, SensorManager.SENSOR_DELAY_NORMAL);

Датчик вектора вращения объединяет необработанные данные, генерируемые гироскопом, акселерометром и магнитометром, для создания кватерниона . Следовательно, массив values его объекта SensorEvent имеет следующие пять элементов:

  • X, Y, Z и W компоненты кватерниона
  • Точность курса

Вы можете преобразовать кватернион в матрицу вращения, матрицу 4×4, используя метод getRotationMatrixFromVector() класса SensorManager .

1
2
3
float[] rotationMatrix = new float[16];
SensorManager.getRotationMatrixFromVector(
        rotationMatrix, sensorEvent.values);

Если вы разрабатываете приложение OpenGL, вы можете использовать матрицу вращения непосредственно для преобразования объектов в 3D-сцене. На данный момент, однако, давайте преобразуем матрицу вращения в массив ориентаций, задав вращение устройства вдоль осей Z, X и Y. Для этого мы можем использовать метод getOrientation() класса SensorManager .

Перед вызовом getOrientation() необходимо переназначить систему координат матрицы вращения. Точнее, вы должны повернуть матрицу вращения так, чтобы ось Z новой системы координат совпадала с осью Y исходной системы координат.

01
02
03
04
05
06
07
08
09
10
// Remap coordinate system
float[] remappedRotationMatrix = new float[16];
SensorManager.remapCoordinateSystem(rotationMatrix,
        SensorManager.AXIS_X,
        SensorManager.AXIS_Z,
        remappedRotationMatrix);
 
// Convert to orientations
float[] orientations = new float[3];
SensorManager.getOrientation(remappedRotationMatrix, orientations);

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

1
2
3
for(int i = 0; i < 3; i++) {
    orientations[i] = (float)(Math.toDegrees(orientations[i]));
}

Теперь вы можете изменить цвет фона действия на основе третьего элемента массива orientations .

1
2
3
4
5
6
7
if(orientations[2] > 45) {
    getWindow().getDecorView().setBackgroundColor(Color.YELLOW);
} else if(orientations[2] < -45) {
    getWindow().getDecorView().setBackgroundColor(Color.BLUE);
} else if(Math.abs(orientations[2]) < 10) {
    getWindow().getDecorView().setBackgroundColor(Color.WHITE);
}

Если вы запустите приложение сейчас, держите телефон в портретном режиме и наклоните его более чем на 45 ° по часовой или против часовой стрелки, вы должны увидеть изменение цвета фона.

Цвет фона меняется в зависимости от угла

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

Чтобы узнать больше об оборудовании датчиков и данных, которые они генерируют, вы можете обратиться к официальному руководству API датчиков . И посмотрите некоторые другие наши аппаратные и сенсорные материалы здесь на Envato Tuts +!

  • Android SDK
    Android с нуля: аппаратные датчики
    Пол Требилкокс-Руис
  • Android
    Введение в Android вещи
    Пол Требилкокс-Руис
  • Android
    Google Fit для Android: чтение данных датчика
    Пол Требилкокс-Руис
  • Android SDK
    Делайте фотографии с помощью приложения для Android