Web 传感器

使用 Generic 传感器 API 访问设备上的传感器,例如加速度计、陀螺仪和磁力计。

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

如今,许多平台特定应用都使用传感器数据来实现以下用例: 例如沉浸式游戏、健身跟踪以及增强现实或虚拟现实。桥上不是很酷吗? 平台专用应用和 Web 应用之间的差距呢?输入 通用传感器 API,适用于 Web!

什么是通用传感器 API?

通用传感器 API 是一组接口,用于公开 将传感器设备传输到 Web 平台。该 API 包含 Sensor 接口以及一组具体的 基于其构建而成的传感器类。拥有基接口可以简化实现和规范 了解具体传感器类的整个流程。例如,请查看 Gyroscope 类。它超小了!通过 核心功能由基接口指定,Gyroscope 只是对其使用三个 属性。

某些传感器类与实际的硬件传感器接口,如加速度计或 陀螺仪类。这些传感器称为低层级传感器。其他传感器,也称为 融合传感器,用于合并来自多个低级别的数据 传感器来公开脚本本来需要计算的信息。例如, AbsoluteOrientation 传感器 用于提供一个现成的 4x4 旋转矩阵,该矩阵基于从 加速度计、陀螺仪和磁力计。

您可能会认为网络平台已经提供传感器数据,您完全正确!对于 实例 DeviceMotionDeviceOrientation 事件公开移动传感器数据。那为什么我们需要新的 API?

与现有接口相比,通用传感器 API 具有诸多优势:

  • 通用传感器 API 是一个传感器框架,可通过新的传感器类和 每个类都将保留通用接口。为一种传感器类型编写的客户端代码 可以重复利用,只需极少的修改即可!
  • 您可以配置传感器。例如,您可以设置适合您 应用需求
  • 您可以检测平台上是否有传感器。
  • 传感器读数具有高精度时间戳,能够更好地与其他设备同步 activity。
  • 传感器数据模型和坐标系明确定义,使浏览器供应商能够 实施互操作解决方案。
  • 基于通用传感器的接口未绑定到 DOM(这意味着它们既不是 navigator) 也不是 window 对象),这为在服务中使用 API 开创了未来机会 或是在无头 JavaScript 运行时中实现它,例如 设备。
  • 安全和隐私方面是通用传感器的首要任务 API 并提供更出色的安全性(与旧版传感器 API 相比)。它与 权限 API。
  • 与屏幕坐标同步 适用于 AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer

可用的通用传感器 API

在撰写本文时,您可以尝试多种传感器。

移动传感器

  • Accelerometer
  • Gyroscope
  • LinearAccelerationSensor
  • AbsoluteOrientationSensor
  • RelativeOrientationSensor
  • GravitySensor

环境传感器

  • AmbientLightSensor(位于 Chromium 中的 #enable-generic-sensor-extra-classes 标志后面。)
  • Magnetometer(位于 Chromium 中的 #enable-generic-sensor-extra-classes 标志后面。)

功能检测

对硬件 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 的浏览器, polyfill。通过 polyfill 仅加载相关传感器实现。

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

这些传感器都是什么?如何使用?

传感器这个领域可能需要简单介绍。如果您熟悉传感器, 可直接跳到实操编码部分。否则,让我们来看看每个支持的 详细描述传感器。

加速度计和线性加速度传感器

<ph type="x-smartling-placeholder">
</ph>
加速度计传感器测量结果

Accelerometer 传感器 测量在三个轴(X、Y 和 Z)上托管传感器的设备的加速度。此传感器是 惯性传感器,表示当设备处于线性自由落体状态时,测量到的 加速度为 0 m/s2,当设备平放在桌子上时,加速度 向上的方向(Z 轴)等于地球重力,即 g ~ +9.8 m/s2, 而是要测量桌子将设备向上推的力度如果您将设备推送到 则 X 轴上的加速度为正,如果设备从以下时间加速: 从右向左。

加速度计可用于计步、移动感应或简单设备等用途 屏幕方向。通常情况下,加速度计测量数据会与其他来源的数据相结合, 打造融合传感器,例如方向传感器。

通过 LinearAccelerationSensor 测量应用到托管传感器的设备的加速度,不包括贡献 重力加速度当设备处于静止状态(例如平放在桌子上)时,传感器会测量 三轴加速度约为 0 m/s2

重力传感器

用户已经可以手动获取与重力传感器的读数相近的读数, 手动检查 AccelerometerLinearAccelerometer 读数,但这可能很麻烦 并取决于这些传感器所提供值的准确性。Android 等平台 作为操作系统的一部分提供重力读数 根据用户的硬件提供更准确的值,并且在 API 工效学方面的专业知识。通过 GravitySensor 会返回效果 沿设备 X 轴、Y 轴和 Z 轴的加速度。

陀螺仪

<ph type="x-smartling-placeholder">
</ph>
陀螺仪传感器测量

Gyroscope 传感器会测量 围绕设备的局部 X、Y 和 Z 轴的角速度(以弧度/秒为单位)。消费者最多 具有机械 (MEMS) 的设备 陀螺仪,即惯性传感器,可根据 惯性科里奥利力。MEMS 陀螺仪容易使用 这种漂移是由传感器的重力灵敏度引起的,这种灵敏度会使传感器的 内部机械系统陀螺仪以相对高频率振荡,例如,10 秒的 kHz,以及 因此,与其他传感器相比,可能会消耗更多电量。

屏幕方向传感器

<ph type="x-smartling-placeholder">
</ph>
绝对方向传感器测量结果

通过 AbsoluteOrientationSensor 是一种融合传感器,用于测量设备相对于地球坐标系的旋转情况; 而 RelativeOrientationSensor 提供表示托管移动传感器的设备相对于静止的旋转的数据 参考坐标系。

所有现代 3D JavaScript 框架都支持四元数旋转矩阵来表示旋转; 不过,如果您直接使用 WebGL,则 OrientationSensor 会非常方便 quaternion 媒体资源populateMatrix() 方法。 以下是几个代码段:

three.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();

BABYLON

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

WebGL

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

屏幕方向传感器支持各种应用场景,例如沉浸式游戏、增强和虚拟

如需详细了解移动传感器、高级用例和要求,请参阅 移动传感器说明文档。

与屏幕坐标同步

默认情况下,系统会解析空间传感器的读数 本地坐标系中,该坐标系绑定到设备,并且不将屏幕方向 。

<ph type="x-smartling-placeholder">
</ph> 设备坐标系
设备坐标系

然而,游戏或增强现实和虚拟现实等许多使用场景都需要传感器读取 坐标系中进行解析,而该坐标系则绑定到屏幕方向。

<ph type="x-smartling-placeholder">
</ph> 屏幕坐标系
屏幕坐标系

以前,必须将传感器读数重新映射到屏幕坐标,而且必须使用 JavaScript 实现。 这种方法效率低下,而且还会显著增加 Web 的复杂性 应用代码;Web 应用必须观察屏幕方向变化,并执行坐标 进行传感器读数转换,对于欧拉角或 四元数。

Generic 传感器 API 提供了一个更简单且可靠的解决方案!局部坐标系是 适用于所有定义的空间传感器类:AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer。将 referenceFrame 选项传递给传感器对象构造函数后,用户 定义返回的读数是否在 device屏幕坐标。

// 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' });

让我们开始编码吧!

Generic 传感器 API 非常简单易用!传感器界面具有 start()和 用于控制传感器状态的 stop() 方法 事件处理程序,用于接收有关传感器激活、错误和新增可用通知的通知 读取。具体的传感器类通常会将其特定的读取属性添加到基本 类。

开发环境

在开发过程中,您可以通过 localhost 使用传感器。如果您正在针对 移动设备, 设置, mobile devices, set up 端口转发 然后就可以开始体验了!

代码准备就绪后,将其部署在支持 HTTPS 的服务器上。 GitHub 页面采用 HTTPS 协议,非常便于分享 您的演示。

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

设备的屏幕方向将反映在 WebGL 场景内的 3D model 旋转中。

<ph type="x-smartling-placeholder">
</ph> 传感器更新 3D 模型的方向
传感器更新 3D 模型的方向

冲击计

以下代码段提取自 Punchmeter 演示, 解释如何使用线性加速度传感器计算 并认为它最初是静止不动的。

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

当前速度的计算方法是近似于加速度函数积分。

<ph type="x-smartling-placeholder">
</ph> 用于测量打孔速度的演示 Web 应用
打孔速度

使用 Chrome 开发者工具进行调试和传感器替换

在某些情况下,您不需要实体设备也能使用 Generic 传感器 API。Chrome 开发者工具 提供了强大的支持 模拟设备屏幕方向

<ph type="x-smartling-placeholder">
</ph> 用于替换虚拟手机的自定义屏幕方向数据的 Chrome 开发者工具
使用 Chrome 开发者工具模拟设备屏幕方向

隐私权和安全

传感器读数是敏感数据,可能会受到恶意网页的各种攻击。 通用传感器 API 的实现会强制实施一些限制,以降低可能的安全性 和隐私风险打算使用 因此,我们简单列出一下这些 API。

仅 HTTPS

由于通用传感器 API 是一项强大的功能,因此浏览器只允许在安全上下文中使用该 API。在 实际操作意味着要使用 Generic 传感器 API,您需要通过 HTTPS 访问您的页面。 在开发过程中,您可以通过 http://localhost 执行此操作;但在生产环境中,您将需要 您的服务器上需要有 HTTPS如需了解最佳做法,请参阅安全集合 和准则。

权限政策集成

通用中的权限政策集成 传感器 API 控制对帧的传感器数据的访问。

默认情况下,只能在主框架或同源子框架中创建 Sensor 对象, 从而防止跨源 iframe 在未经批准的情况下读取传感器数据。这种默认行为 来修改代码, 政策控制的功能

以下代码段说明了如何向跨源 iframe 授予加速度计数据访问权限,这意味着 现在可以在其中创建 AccelerometerLinearAccelerationSensor 对象。

<iframe src="https://third-party.com" allow="accelerometer" />

可以暂停传送传感器读数

传感器读数只能通过可见网页访问,即用户实际上 交互方式。此外,如果用户 将焦点移至跨源子框架这可以防止父框架推断用户输入。

后续操作

在不久的将来,会有一组指定的传感器类需要实现,例如 环境光传感器近程传感器;然而,多亏了 通用传感器框架,我们可以预见到会出现更多表示各种新类的新类 传感器类型。

未来工作的另一个重要领域是改进通用传感器 API 本身,即通用传感器, 传感器规范目前是候选建议,这意味着还有时间 修复问题并引入开发者需要的新功能。

您可以提供帮助!

已达到传感器规格 候选建议 成熟度水平,因此,我们非常重视 Web 和浏览器开发者的反馈。让我们 知道哪些功能会很棒,或者想在 当前 API。

此外,欢迎随时提交规范问题 错误修复。

资源

致谢

本文由 Joe MedleyKayce Basques。主打图片提供方 Misko,经过 维基共享资源