Датчики для Интернета,Датчики для Интернета

Используйте API универсального датчика, чтобы получить доступ к датчикам на устройстве, таким как акселерометры, гироскопы и магнитометры.

Алекс Шаламов
Alex Shalamov
Михаил Поздняков
Mikhail Pozdnyakov

Сегодня данные датчиков используются во многих приложениях для конкретных платформ, чтобы обеспечить такие варианты использования, как захватывающие игры, отслеживание фитнеса, а также дополненная или виртуальная реальность. Разве не было бы здорово преодолеть разрыв между платформерными и веб-приложениями? Введите 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() . Вот несколько фрагментов:

три.js

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);

Датчики ориентации позволяют использовать различные варианты использования, такие как захватывающие игры, дополненная �� виртуальная реальность.

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

Синхронизация с координатами экрана

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

Система координат устройства
Система координат устройства

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

Система координат экрана
Система координат экрана

Раньше переназначение показаний датчиков на экранные координаты приходилось реализовывать на 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-модели
Датчик обновляет ориентацию 3D-модели

Перфоратор

Следующий фрагмент кода извлечен из демо-версии перфорометра и иллюстрирует, как можно использовать датчик линейного ускорения для расчета максимальной скорости устройства в предположении, что оно первоначально лежит неподвижно.

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;
};

Текущая скорость рассчитывается как приближение к интегралу функции ускорения.

Демонстрационное веб-приложение для измерения скорости пуансона
Измерение скорости удара

Отладка и переопределение датчиков с помощью Chrome DevTools

В некоторых случаях вам не нужно физическое устройство для работы с API универсального датчика. Chrome DevTools отлично поддерживает имитацию ориентации устройства .

Chrome DevTools используется для переопределения данных пользовательской ориентации виртуального телефона.
Имитация ориентации устройства с помощью Chrome DevTools

Конфиденциальность и безопасность

Показания датчиков — это конфиденциальные данные, которые могут подвергаться различным атакам со стороны вредоносных веб-страниц. Реализации 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.

Ресурсы

Благодарности

Эта статья была рецензирована Джо Медли и Кейси Баскс . Изображение героя создано Миско через Wikimedia Commons .