Используйте API универсального датчика, чтобы получить доступ к датчикам на устройстве, таким как акселерометры, гироскопы и магнитометры.
Сегодня данные датчиков используются во многих приложениях для конкретных платформ, чтобы обеспечить такие варианты использования, как захватывающие игры, отслеживание фитнеса, а также дополненная или виртуальная реальность. Разве не было бы здорово преодолеть разрыв между платформерными и веб-приложениями? Введите API универсального датчика для Интернета!
Что такое API универсального датчика?
API универсального датчика — это набор интерфейсов, которые предоставляют сенсорным устройствам доступ к веб-платформе. API состоит из базового интерфейса Sensor
и набора конкретных классов датчиков, построенных на его основе. Наличие базового интерфейса упрощает процесс реализации и спецификации конкретных классов датчиков. Например, взгляните на класс Gyroscope
. Он очень крошечный! Основная функциональность определяется базовым интерфейсом, �� Gyroscope
про��то расширяет его тремя атрибутами, представляющими угловую скорость.
Некоторые классы датчиков взаимодействуют с реальными аппаратными датчиками, такими как, например, классы акселерометра или гироскопа. Их называют датчиками низкого уровня. Другие датчики, называемые датчиками слияния , объединяют данные от нескольких датчиков низкого уровня, чтобы предоставить информацию, которую в противном случае пришлось бы вычислять сценарию. Например, датчик AbsoluteOrientation
предоставляет готовую к использованию матрицу вращения размером четыре на четыре на основе данных, полученных с акселерометра, гироскопа и магнитометра.
Вы можете подумать, что веб-платформа уже предоставляет данные датчиков, и вы абсолютно правы! Например, события DeviceMotion
и DeviceOrientation
предоставляют данные датчика движения. Так зачем нам новый API?
По сравнению с существующими интерфейсами Generic Sensor API предоставляет множество преимуществ:
- Generic Sensor API — это платформа датчиков, которую можно легко расширить за счет новых классов датчиков, и каждый из этих классов сохранит общий интерфейс. Клиентский код, написанный для одного типа датчиков, можно повторно использовать для другого с минимальными изменениями!
- Вы можете настроить датчик. Например, вы можете установить частоту дискретизации, подходящую для нужд вашего приложения.
- Вы можете определить, доступен ли датчик на платформе.
- Показания датчиков имеют высокоточные временные метки, что обеспечивает лучшую синхронизацию с другими действиями в вашем приложении.
- Модели данных датчиков и системы координат четко определены, что позволяет производителям браузеров реализ��вывать совместимые решения.
- Интерфейсы на основе Generic Sensor не привязаны к DOM (то есть они не являются ни
navigator
, ни объектамиwindow
), и это открывает будущие возможности для использования API внутри сервис-воркеров или реализации его в автономной среде выполнения JavaScript, например, во встроенных устройствах. - Аспекты безопасности и конфиденциальности являются главным приоритетом для API универсального датчика и обеспечивают гораздо лучшую безопасность по сравнению со старыми API датчиков. Имеется интеграция с Permissions API.
- Автоматическая синхронизация с координатами экрана доступна для
Accelerometer
,Gyroscope
,LinearAccelerationSensor
,AbsoluteOrientationSensor
,RelativeOrientationSensor
иMagnetometer
.
Доступные общие API датчиков
На момент написания статьи существует несколько датчиков, с которыми вы можете поэкспериментировать.
Датчики движения:
-
Accelerometer
-
Gyroscope
-
LinearAccelerationSensor
-
AbsoluteOrientationSensor
-
RelativeOrientationSensor
-
GravitySensor
Датчики окружающей среды:
-
AmbientLightSensor
(за флагом#enable-generic-sensor-extra-classes
в Chromium.) -
Magnetometer
(за флагом#enable-generic-sensor-extra-classes
в Chromium.)
Обнаружение функций
Обнаружение функций аппаратных API является сложной задачей, поскольку вам необходимо определить, поддерживает ли браузер рассматриваемый интерфейс, и имеет ли устройство соответствующий датчик. Проверить, поддерживает ли браузер интерфейс, несложно. (Замените Accelerometer
любым из других интерфейсов, упомянутых выше .)
if ('Accelerometer' in window) {
// The `Accelerometer` interface is supported by the browser.
// Does the device have an accelerometer, though?
}
Для действительно значимого результата обнаружения функции вам также необходимо попытаться подключиться к датчику. Этот пример иллюстрирует, как это сделать.
let accelerometer = null;
try {
accelerometer = new Accelerometer({ frequency: 10 });
accelerometer.onerror = (event) => {
// Handle runtime errors.
if (event.error.name === 'NotAllowedError') {
console.log('Permission to access sensor was denied.');
} else if (event.error.name === 'NotReadableError') {
console.log('Cannot connect to the sensor.');
}
};
accelerometer.onreading = (e) => {
console.log(e);
};
accelerometer.start();
} catch (error) {
// Handle construction errors.
if (error.name === 'SecurityError') {
console.log('Sensor construction was blocked by the Permissions Policy.');
} else if (error.name === 'ReferenceError') {
console.log('Sensor is not supported by the User Agent.');
} else {
throw error;
}
}
Полифилл
Для браузеров, которые не поддерживают API Generic Sensor, доступен полифилл . Полифилл позволяет загружать только реализации соответствующих датчиков.
// Import the objects you need.
import { Gyroscope, AbsoluteOrientationSensor } from './src/motion-sensors.js';
// And they're ready for use!
const gyroscope = new Gyroscope({ frequency: 15 });
const orientation = new AbsoluteOrientationSensor({ frequency: 60 });
Что это за датчики? Как я могу их использовать?
Датчики — это область, которая, возможно, нуждается в кратком представлении. Если вы знакомы с датчиками, вы можете сразу перейти к практическому разделу кодирования . В противном случае давайте подробно рассмотрим каждый поддерживаемый датчик.
Акселерометр и датчик линейного ускорения
Датчик Accelerometer
измеряет ускорение устройства, на котором установлен датчик, по трем осям (X, Y и Z). Этот датчик является инерционным датчиком. Это означает, что, когда устройство находится в линейном свободном падении, общее измеренное ускорение будет 0 м/с 2 , а когда устройство лежит ровно на столе, ускорение в направлении вверх (ось Z) будет быть равным силе тяжест�� Земли, т.е. g ≈ +9,8 м/с 2 , так как измеряется сила стола, толкающая устройство вверх. Если вы толкнете устройство вправо, ускорение по оси X будет положительным или отрицательным, ��сл�� ��стройство ускоряется с��рав�� налево.
Акселерометры можно использовать для подсчета шагов, определения движения или простой ориентации устройства. Довольно часто измерения акселерометра объединяются с данными из других источников для создания термоядерных датчиков, например датчиков ориентации.
LinearAccelerationSensor
измеряет ускорение, приложенное к устройству, на котором размещен датчик, без учета влияния силы тяжести. Когда устройство находится в состоянии покоя, например, лежит на столе, датчик будет измерять ускорение ≈ 0 м/с 2 по трем осям.
Датчик силы тяжести
Пользователи уже могут вручную получать показания, близкие к показаниям датчика силы тяжести, вручную проверяя показания Accelerometer
и LinearAccelerometer
, но это может быть обременительно и зависеть от точности значений, предоставляемых этими датчиками. Такие платформы, как Android, могут предоставлять показания гравитации как часть операционной системы, которая должна быть дешевле с точки зрения вычислений, предоставлять более точные значения в зависимости от оборудования пользователя и быть проще в использовании с точки зрения эргономики API. GravitySensor
возвращает эффект ускорения по осям X, Y и Z устройства под действием силы тяжести.
Гироскоп
Датчик Gyroscope
измеряет угловую скорость в радианах в секунду вокруг локальных осей X, Y и Z устройства. Большинство потребительских устройств оснащены механическими ( MEMS ) гироскопами, которые представляют собой инерционные датчики, измеряющие скорость вращения на основе инерционной силы Кориолиса . МЭМС-гироскопы склонны к дрейфу, вызванному гравитационной чувствительностью датчика, которая деформирует внутрен��юю механическую систему датчика. Гироскопы колеблются на относительно высоких частотах, например, 10 кГц, и поэтому могут потреблять больше энергии по сравнению с другими датчиками.
Датчики ориентации
AbsoluteOrientationSensor
— это термоядерный датчик, который измеряет вращение устройства относительно системы координат Земли, а RelativeOrientationSensor
предоставляет данные, представляющие вращение устройства, на котором размещены датчики движения, относительно стационарной опорной системы координат.
Все современные 3D-фреймворки JavaScript поддерживают кватернионы и матрицы вращения для представления вращения; однако, если вы используете WebGL напрямую, OrientationSensor
имеет как свойство quaternion
, так и метод populateMatrix()
. Вот несколько фрагментов:
let torusGeometry = new THREE.TorusGeometry(7, 1.6, 4, 3, 6.3);
let material = new THREE.MeshBasicMaterial({ color: 0x0071c5 });
let torus = new THREE.Mesh(torusGeometry, material);
scene.add(torus);
// Update mesh rotation using quaternion.
const sensorAbs = new AbsoluteOrientationSensor();
sensorAbs.onreading = () => torus.quaternion.fromArray(sensorAbs.quaternion);
sensorAbs.start();
// Update mesh rotation using rotation matrix.
const sensorRel = new RelativeOrientationSensor();
let rotationMatrix = new Float32Array(16);
sensor_rel.onreading = () => {
sensorRel.populateMatrix(rotationMatrix);
torus.matrix.fromArray(rotationMatrix);
};
sensorRel.start();
const mesh = new BABYLON.Mesh.CreateCylinder('mesh', 0.9, 0.3, 0.6, 9, 1, scene);
const sensorRel = new RelativeOrientationSensor({ frequency: 30 });
sensorRel.onreading = () => mesh.rotationQuaternion.FromArray(sensorRel.quaternion);
sensorRel.start();
// Initialize sensor and update model matrix when new reading is available.
let modMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
const sensorAbs = new AbsoluteOrientationSensor({ frequency: 60 });
sensorAbs.onreading = () => sensorAbs.populateMatrix(modMatrix);
sensorAbs.start();
// Somewhere in rendering code, update vertex shader attribute for the model
gl.uniformMatrix4fv(modMatrixAttr, false, modMatrix);
Датчики ориентации позволяют использовать различные варианты использования, такие как захватывающие игры, дополненная �� виртуальная реальность.
Для получения дополнительной информации о датчиках движения, расширенных вариантах использования и требованиях ознакомьтесь с пояснительным документом по датчикам движения .
Синхронизация с координатами экрана
По умолчанию показания пространственных датчиков разрешаются в локальной системе координат, привязанной к устройству и не учитывающей ориентацию экрана.
![Система координат устройства](https://cdn.statically.io/img/developer.chrome.google.cn/static/docs/capabilities/web-apis/generic-sensor/image/device-coordinate-system-c67b130c9d772.png?hl=ru)
Однако во многих случаях использования, таких как игры или дополненная и виртуальная реальность, требуется, чтобы показания датчиков обрабатывались в системе координат, которая вместо этого привязана к ориентации экрана.
![Система координат экрана](https://cdn.statically.io/img/developer.chrome.google.cn/static/docs/capabilities/web-apis/generic-sensor/image/screen-coordinate-system-e3fae643f502a.png?hl=ru)
Раньше переназначение показаний датчиков на экранные координаты приходилось реализовывать на JavaScript. Такой подход неэффективен, а также существенно увеличивает сложность кода веб-приложения; веб-приложение должно отслеживать изменения ориентации экрана и выполнять преобразования координат для показаний датчиков, что нетривиально для углов Эйлера или кватернионов.
API Generic Sensor предоставляет гораздо более простое и надежное решение! Локальная система координат настраивается для всех определенных классов пространственных датчиков: Accelerometer
, Gyroscope
, LinearAccelerationSensor
, AbsoluteOrientationSensor
, RelativeOrientationSensor
и Magnetometer
. Передавая опцию referenceFrame
конструктору объекта датчика, пользователь определяет, будут ли возвращаемые показания разрешаться в координатах устройства или экрана .
// Sensor readings are resolved in the Device coordinate system by default.
// Alternatively, could be RelativeOrientationSensor({referenceFrame: "device"}).
const sensorRelDevice = new RelativeOrientationSensor();
// Sensor readings are resolved in the Screen coordinate system. No manual remapping is required!
const sensorRelScreen = new RelativeOrientationSensor({ referenceFrame: 'screen' });
Давайте кодировать!
API универсального датчика очень прост и удобен в использовании! Интерфейс Sensor имеет методы start()
и stop()
для управления состоянием датчика и несколько обработчиков событий для получения уведомлений об активации датчика, ошибках и новых доступных показаниях. Конкретные классы датчиков обычно добавляют свои особые атрибуты чтения к базовому классу.
Среда разработки
Во время разработки вы сможете использовать датчики через localhost
. Если вы занимаетесь разработкой для мобильных устройств, настройте переадресацию портов на своем локальном сервере, и все готово!
Когда ваш код будет готов, разверните его на сервере, поддерживающем HTTPS. Страницы GitHub обслуживаются через HTTPS, что делает их отличным местом для обмена демонстрациями.
Вращение 3D-модели
В этом простом примере мы используем данные датчика абсолютной ориентации для изменения кватерниона вращения 3D-модели. model
представляет собой экземпляр класса Three.js Object3D
, который имеет свойство quaternion
. Следующий фрагмент кода из демонстрации телефона для ориентации иллюстрирует, как можно использовать датчик абсолютной ориентации для вращения 3D-модели.
function initSensor() {
sensor = new AbsoluteOrientationSensor({ frequency: 60 });
sensor.onreading = () => model.quaternion.fromArray(sensor.quaternion);
sensor.onerror = (event) => {
if (event.error.name == 'NotReadableError') {
console.log('Sensor is not available.');
}
};
sensor.start();
}
Ориентация устройства будет отражена в вращении 3D- model
внутри сцены WebGL.
![Датчик обновляет ориентацию 3D-модели](https://cdn.statically.io/img/developer.chrome.google.cn/static/docs/capabilities/web-apis/generic-sensor/image/sensor-updates-3d-models-270d2e43cbcb1.png?hl=ru)
Перфоратор
Следующий фрагмент кода извлечен из демо-версии перфорометра и иллюстрирует, как можно использовать датчик линейного ускорения для расчета максимальной скорости устройства в предположении, что оно первоначально лежит неподвижно.
this.maxSpeed = 0;
this.vx = 0;
this.ax = 0;
this.t = 0;
/* … */
this.accel.onreading = () => {
let dt = (this.accel.timestamp - this.t) * 0.001; // In seconds.
this.vx += ((this.accel.x + this.ax) / 2) * dt;
let speed = Math.abs(this.vx);
if (this.maxSpeed < speed) {
this.maxSpeed = speed;
}
this.t = this.accel.timestamp;
this.ax = this.accel.x;
};
Текущая скорость рассчитывается как приближение к интегралу функции ускорения.
![Демонстрационное веб-приложение для измерения скорости пуансона](https://cdn.statically.io/img/developer.chrome.google.cn/static/docs/capabilities/web-apis/generic-sensor/image/demo-web-application-pun-b24949530ffe1.png?hl=ru)
Отладка и переопределение датчиков с помощью Chrome DevTools
В некоторых случаях вам не нужно физическое устройство для работы с API универсального датчика. Chrome DevTools отлично поддерживает имитацию ориентации устройства .
![Chrome DevTools используется для переопределения данных пользовательской ориентации виртуального телефона.](https://cdn.statically.io/img/developer.chrome.google.cn/static/docs/capabilities/web-apis/generic-sensor/image/chrome-devtools-used-ove-80ebd2eaae558.png?hl=ru)
Конфиденциальность и безопасность
Показания датчиков — это конфиденциальные данные, которые могут подвергаться различным атакам со стороны вредоносных веб-страниц. Реализации API-интерфейсов Generic Sensor налагают некоторые ограничения для снижения возможных рисков безопасности и конфиденциальности. Эти ограничения необходимо учитывать разработчикам, которые собираются использовать API, поэтому кратко перечислим их.
Только HTTPS
Поскольку API Generic Sensor — это мощная функция, браузер разрешает использовать ее только в безопасном контексте. На практике это означает, что для использования API Generic Sensor вам потребуется доступ к вашей странице через HTTPS. Во время разработки вы можете сделать это через http://localhost , но для производства вам понадобится HTTPS на вашем сервере. Рекомендации и рекомендации см. в коллекции «Безопасно и надежно» .
Интеграция политики разрешений
Интеграция политики разрешений в API универсального датчика контролирует доступ к данным датчиков для кадра.
По умолчанию объекты Sensor
могут создаваться только внутри основного фрейма или подкадров одного и того же происхождения, что предотвращает несанкционированное чтение данных датчиков iframe из разных источников. Это поведение по умолчанию можно изменить, явно включив или отключив соответствующие функции, контролируемые политикой .
В приведенном ниже фрагменте показано предоставление доступа к данным акселерометра iframe с перекрестным происхождением. Это означает, что теперь там можно создавать объекты Accelerometer
или LinearAccelerationSensor
.
<iframe src="https://third-party.com" allow="accelerometer" />
Выдачу показаний датчиков можно приостановить
Показания датчиков доступны только на видимой веб-странице, т. е. когда пользова��ель фактически взаимодействует с ней. Более того, данные датчиков не будут передаваться в родительский кадр, если фокус пользователя изменится на подкадр с перекрестным происхождением. Это предотвращает ввод данных пользователем из родительского фрейма.
Что дальше?
В ближайшем будущем будет реализован набор уже определенных классов датчиков, таких как датчик в��ешней освещенности или датчик приближения ; однако благодаря большой расширяемости структуры Generic Sensor мы мож��м ��ж��д��ть появления еще большего количества новых классов, представляющих различные типы датчиков.
Еще одним важным направлением будущей работы является улучшение самого API Generic Sensor. Спецификация Generic Sensor в настоящее время является кандидатом в рекомендацию, а это значит, что еще есть время внести исправления и внедрить новые функциональные возможности, необходимые разработчикам.
Вы можете помочь!
Спецификации датчиков достигли уровня зрелости «Кандидатская рекомендация» , поэтому мы высоко ценим отзывы разработчиков веб-сайтов и браузеров. Сообщите нам, какие функции было бы полезно добавить или что вы хотели бы изменить в текущем API.
Пожалуйста, не стесняйтесь сообщать о проблемах со спецификациями , а также об ошибках в реализации Chrome.
Ресурсы
- Демо-проекты: https://intel.github.io/generic-sensor-demos/
- Спецификация API общего датчика: https://w3c.github.io/sensors/
- Проблемы со спецификациями: https://github.com/w3c/sensors/issues .
- Список рассылки рабочей группы W3C: public-device-apis@w3.org
- Статус функции Chrome: https://www.chromestatus.com/feature/5698781827825664 .
- Ошибки реализации: http://crbug.com?q=comComponent:Blink>Sensor .
Благодарности
Эта статья была рецензирована Джо Медли и Кейси Баскс . Изображение героя создано Миско через Wikimedia Commons .