Processing:Библиотеки/Processing for Android/Руководства/Использование датчиков
Содержание | Среда разработки Processing | Справочник языка Processing | Библиотеки | Примеры | Режимы программирования |
Использование датчиков [1]
Описание
Это руководство дает базовое понимание того, как считывать данные с датчиков в Processing.
API для датчиков в SDK Android
Смартфоны и планшеты оснащены множеством различных датчиков – к примеру, акселерометрами, гироскопами, магнетометрами и термометрами. Эти датчики позволяют нам получать информацию о движениях, окружении и местоположении устройства. Хотя в языке Processing нет специальных функций для считывания данных этих датчиков, вы можете импортировать в Android SDK ПО-пакеты, отправляющие данные датчиков в ваш скетч.
Создание менеджера датчиков
В первом примере мы создадим скетч, реагирующий на изменения в ускорении, и нам понадобятся для этого данные акселерометра. Первый шаг в использовании API датчика – это получение контекста активности, в которой будет выполняться этот скетч, а затем получение менеджера датчиков из этого контекста. Затем мы можем инициализировать датчик, который понадобится в нашем скетче, и в данном случае это акселерометр. Делаем все это в блоке setup().
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
Context context;
SensorManager manager;
Sensor sensor;
void setup() {
fullScreen();
context = getActivity();
manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
void draw() {
}
Добавление «прослушки» датчика
Теперь нам нужно добавить класс для «прослушки», который будет уведомлять скетч о том, что у датчика доступы новые данные. «Слушатель» для каждого датчика наследует у базового класса SensorEventListener из SDK Android. Создав в скетче экземпляр «класса-слушателя», мы можем зарегистрировать слушателя при помощи менеджера:
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
Context context;
SensorManager manager;
Sensor sensor;
AccelerometerListener listener;
void setup() {
fullScreen();
context = getActivity();
manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener = new AccelerometerListener();
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
void draw() {
}
class AccelerometerListener implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Вы, возможно, заметили, что при регистрации «слушателя» используется аргумент SensorManager.SENSOR_DELAY_GAME. Этот аргумент задает скорость, с которой датчик будет считывать новые данные. Чем выше эта скорость, тем выше чувствительность датчика, но и тем быстрее расходуется заряд батареи. Помимо SENSOR_DELAY_GAME есть и другие предопределенные константы для установления скорости считывания данных – SENSOR_DELAY_FASTEST, SENSOR_DELAY_NORMAL и SENSOR_DELAY_UI.
Считывание данных датчика
Слушатель событий имеет два метода – onSensorChanged() и onAccuracyChanged(). Для считывания данных датчика нам понадобится только onSensorChanged(). Если речь об акселерометре, то данные от этого датчика представляют собой три значения с плавающей точкой, отвечающие за ускорение устройства по осям X, Y и Z. На устройстве эти оси выглядят следующим образом:
Для первого теста мы можем просто напечатать эти значения на экране, а также проверить, что если мы положим телефон на стол горизонтально и экраном вверх, то ускорение по оси Z составит 9.81 м/с2, что соответствует силе притяжения.
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
Context context;
SensorManager manager;
Sensor sensor;
AccelerometerListener listener;
float ax, ay, az;
void setup() {
fullScreen();
context = getActivity();
manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener = new AccelerometerListener();
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
textFont(createFont("SansSerif", 30 * displayDensity));
}
void draw() {
background(0);
text("X: " + ax + "\nY: " + ay + "\nZ: " + az, 0, 0, width, height);
}
class AccelerometerListener implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
ax = event.values[0];
ay = event.values[1];
az = event.values[2];
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Примечание: Обратите внимание на аргумент displayDensity, который используется для масштабирования размера текста. Это значение берется из поля DisplayMetrics.density в SDK Android. На экране с 160 dpi (например, с разрешением 240 х 320 и размером 1.5 на 2 дюйма) это значение будет «1». Это поле позволяет настроить размер графических элементов в скетче (вроде текста) пропорционально dpi.
При использовании датчиков рекомендуется отменить регистрацию слушателя, когда активность скетча поставлена на паузу, чтобы сэкономить заряд батареи, а затем, когда активность возобновится, снова зарегистрировать его. Это можно сделать, добавив в скетч такой фрагмент:
public void onResume() {
super.onResume();
if (manager != null) {
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
}
public void onPause() {
super.onPause();
if (manager != null) {
manager.unregisterListener(listener);
}
}
В конце выполняется проверка экземпляра класса менеджера на null, потому что функции onPause() и onResume() могут быть вызваны в вашем скетче до блока setup().
Более сложный пример с использованием Box2D
Один из вариантов использования данных от датчиков – это управление движением графических элементов в вашем скетче. Значения акселерометра, по сути, информируют о силах, которые действуют на ваше устройство, поэтому если мы воспользуемся ими для управления поведения, скажем, системы твердых тел, то сможем соединить поведение, заданное в коде, с поведением, задаваемым при помощи движений в реальности.
Чтобы реализовать это, мы воспользуемся библиотекой Box2D for Processing, разработанной Дэниэлом Шиффманом. Хотя эта библиотека создавалась не для Android, мы все равно сможем использовать ее в скетчах в режиме программирования Android, т.к. он написан на Java!
Мы объединим базовый код из предыдущего примера, чтобы прочесть данные акселерометра, с простой симуляцией Box2D, где границы экрана задают границы симуляции, и в ней также будет несколько коробок, болтающихся согласно силам ускорения, задаваемым перемещением устройства. Полный код этого скетча-примера можно найти тут.
Без данных от акселерометра код Box2D выглядит следующим образом (скетчи-примеры с использованием классов Box и Wall смотрите на GitHub – тут и тут):
import shiffman.box2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
Box2DProcessing box2d;
ArrayList<Box> boxes;
ArrayList<Wall> walls;
void setup() {
fullScreen(P2D);
orientation(PORTRAIT);
box2d = new Box2DProcessing(this);
box2d.createWorld();
box2d.setGravity(0, -10);
// группа коробок:
boxes = new ArrayList<Box>();
for (int i = 0; i < 20; i++) {
Box p = new Box(random(200, width-200), random(200, height-200));
boxes.add(p);
}
// невидимые стены:
walls = new ArrayList<Wall>();
walls.add(new Wall(width/2, -25, width, 50));
walls.add(new Wall(width/2, height+25, width, 50));
walls.add(new Wall(-25, height/2, 50, height));
walls.add(new Wall(width+25, height/2, 50, height));
}
void draw() {
background(255);
box2d.step();
for (Box b: boxes) {
b.display();
}
}
void mousePressed() {
for (Box b: boxes) {
b.shake();
}
}
В этом коде мы используем постоянное ускорение по оси Y в виде (0, 10), но мы также можем привязать силу притяжения в Box2D к значениям ускорения от акселерометра:
box2d.setGravity(-ax, -ay);
Таким образом, в результате скетч, в котором Box2D будет работать вместе с акселерометром, будет выглядеть следующим образом:
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import shiffman.box2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
Context context;
SensorManager manager;
Sensor sensor;
AccelerometerListener listener;
float ax, ay, az;
Box2DProcessing box2d;
ArrayList<Box> boxes;
ArrayList<Wall> walls;
void setup() {
fullScreen(P2D);
orientation(PORTRAIT);
context = getActivity();
manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
listener = new AccelerometerListener();
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
box2d = new Box2DProcessing(this);
box2d.createWorld();
// группа коробок:
boxes = new ArrayList<Box>();
for (int i = 0; i < 20; i++) {
Box p = new Box(random(200, width-200), random(200, height-200));
boxes.add(p);
}
// невидимые стены:
walls = new ArrayList<Wall>();
walls.add(new Wall(width/2, -25, width, 50));
walls.add(new Wall(width/2, height+25, width, 50));
walls.add(new Wall(-25, height/2, 50, height));
walls.add(new Wall(width+25, height/2, 50, height));
}
void draw() {
background(255);
// обновляем гравитационную информацию данными от акселерометра:
box2d.setGravity(-ax, -ay);
box2d.step();
for (Box b: boxes) {
b.display();
}
}
void mousePressed() {
for (Box b: boxes) {
b.shake();
}
}
public void onResume() {
super.onResume();
if (manager != null) {
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
}
public void onPause() {
super.onPause();
if (manager != null) {
manager.unregisterListener(listener);
}
}
class AccelerometerListener implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
ax = event.values[0];
ay = event.values[1];
az = event.values[2];
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Использование других датчиков
В документации Google для разработчиков есть подробная информация о том, как считывать данные с других датчиков движения. В качестве альтернативы можно воспользоваться библиотекой Ketai, разработанной Дэниэлом Сотером и Иисусом Дюраном. Она обертывает весь управляющий код и серьезно упрощает считывание данных от разных датчиков. Библиотеку Ketai можно установить из меню Contribution Manager.
См.также
Внешние ссылки
Примеры на Processing | |
---|---|
Основы |
|
Продвинутые графические эффекты |
|
Примеры из сторонних библиотек |