Cảm biến cho web

Sử dụng API cảm biến chung để truy cập vào các cảm biến trên thiết bị như gia tốc kế, con quay hồi chuyển và từ kế.

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

Ngày nay, dữ liệu cảm biến được dùng trong nhiều ứng dụng dành riêng cho nền tảng để hỗ trợ các trường hợp sử dụng như chơi trò chơi sống động, theo dõi hoạt động thể dục và thực tế tăng cường hoặc thực tế ảo. Sẽ thật tuyệt nếu có thể thu hẹp khoảng cách giữa ứng dụng dành riêng cho nền tảng và ứng dụng web. Hãy nhập Generic Sensor API (API cảm biến chung) cho web!

API cảm biến chung là một tập hợp các giao diện hiển thị thiết bị cảm biến cho nền tảng web. API này bao gồm giao diện Sensor cơ sở và một tập hợp các lớp cảm biến cụ thể được xây dựng dựa trên đó. Việc có một giao diện cơ sở giúp đơn giản hoá quy trình triển khai và quy trình quy cách cho các lớp cảm biến cụ thể. Ví dụ: hãy xem lớp Gyroscope. Nó rất nhỏ! Chức năng cốt lõi được chỉ định bởi giao diện cơ sở và Gyroscope chỉ mở rộng chức năng đó bằng ba thuộc tính đại diện cho tốc độ góc.

Một số lớp cảm biến giao tiếp với các cảm biến phần cứng thực tế, chẳng hạn như lớp gia tốc kế hoặc con quay hồi chuyển. Đây được gọi là cảm biến cấp thấp. Các cảm biến khác, được gọi là cảm biến hợp nhất, hợp nhất dữ liệu từ một số cảm biến cấp thấp để hiển thị thông tin mà tập lệnh cần tính toán. Ví dụ: cảm biến AbsoluteOrientation cung cấp một ma trận xoay 4x4 sẵn sàng sử dụng dựa trên dữ liệu thu được từ gia tốc kế, con quay hồi chuyển và máy đo từ trường.

Bạn có thể nghĩ rằng nền tảng web đã cung cấp dữ liệu cảm biến và bạn hoàn toàn đúng! Ví dụ: sự kiện DeviceMotionDeviceOrientation hiển thị dữ liệu cảm biến chuyển động. Vậy tại sao chúng ta cần một API mới?

So với các giao diện hiện có, API cảm biến chung mang lại nhiều lợi thế:

  • API cảm biến chung là một khung cảm biến có thể dễ dàng mở rộng bằng các lớp cảm biến mới và mỗi lớp trong số này sẽ giữ lại giao diện chung. Mã ứng dụng được viết cho một loại cảm biến có thể được sử dụng lại cho một loại cảm biến khác mà chỉ cần sửa đổi rất ít!
  • Bạn có thể định cấu hình cảm biến. Ví dụ: bạn có thể đặt tần suất lấy mẫu phù hợp với nhu cầu của ứng dụng.
  • Bạn có thể phát hiện xem có cảm biến nào trên nền tảng hay không.
  • Các lần đọc cảm biến có dấu thời gian có độ chính xác cao, cho phép đồng bộ hoá tốt hơn với các hoạt động khác trong ứng dụng.
  • Các mô hình dữ liệu cảm biến và hệ toạ độ được xác định rõ ràng, cho phép các nhà cung cấp trình duyệt triển khai các giải pháp có khả năng tương tác.
  • Các giao diện dựa trên cảm biến chung không liên kết với DOM (nghĩa là chúng không phải là đối tượng navigator hay window). Điều này mở ra cơ hội trong tương lai để sử dụng API trong worker dịch vụ hoặc triển khai API trong môi trường thời gian chạy JavaScript không có giao diện người dùng, chẳng hạn như các thiết bị nhúng.
  • Các khía cạnh bảo mật và quyền riêng tư là ưu tiên hàng đầu của API cảm biến chung và mang lại khả năng bảo mật tốt hơn nhiều so với các API cảm biến cũ. Có tích hợp với API Quyền.
  • Bạn có thể tự động đồng bộ hoá với toạ độ màn hình cho Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensorMagnetometer.

Các API cảm biến chung hiện có

Tại thời điểm viết bài, bạn có thể thử nghiệm một số cảm biến.

Cảm biến chuyển động:

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

Cảm biến môi trường:

  • AmbientLightSensor (Phía sau cờ #enable-generic-sensor-extra-classes trong Chromium.)
  • Magnetometer (Phía sau cờ #enable-generic-sensor-extra-classes trong Chromium.)

Phát hiện tính năng

Việc phát hiện tính năng của API phần cứng khá phức tạp, vì bạn cần phát hiện cả việc trình duyệt có hỗ trợ giao diện có liên quan hay không, thiết bị có cảm biến tương ứng hay không. Việc kiểm tra xem trình duyệt có hỗ trợ giao diện hay không rất đơn giản. (Thay thế Accelerometer bằng bất kỳ giao diện nào khác được đề cập ở trên.)

if ('Accelerometer' in window) {
  // The `Accelerometer` interface is supported by the browser.
  // Does the device have an accelerometer, though?
}

Để có kết quả phát hiện tính năng thực sự có ý nghĩa, bạn cũng cần cố gắng kết nối với cảm biến. Ví dụ này minh hoạ cách thực hiện việc đó.

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

Polyfill

Đối với các trình duyệt không hỗ trợ API cảm biến chung, bạn có thể sử dụng polyfill. Polyfill cho phép bạn chỉ tải các phương thức triển khai cảm biến có liên quan.

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

Tất cả các cảm biến này là gì? Làm cách nào để sử dụng các tính năng này?

Cảm biến là một lĩnh vực có thể cần được giới thiệu ngắn gọn. Nếu đã quen thuộc với cảm biến, bạn có thể chuyển ngay đến phần thực hành lập trình. Nếu không, hãy cùng tìm hiểu chi tiết về từng cảm biến được hỗ trợ.

Gia tốc kế và cảm biến gia tốc tuyến tính

Đo lường cảm biến gia tốc kế

Cảm biến Accelerometer đo gia tốc của một thiết bị lưu trữ cảm biến trên ba trục (X, Y và Z). Cảm biến này là cảm biến quán tính, nghĩa là khi thiết bị rơi tự do theo đường thẳng, tổng gia tốc được đo sẽ là 0 m/s2 và khi thiết bị nằm phẳng trên mặt bàn, gia tốc theo hướng lên trên (trục Z) sẽ bằng trọng lực của Trái Đất, tức là g ≈ +9, 8 m/s2 vì cảm biến này đang đo lực của mặt bàn đẩy thiết bị lên trên. Nếu bạn đẩy thiết bị sang phải, gia tốc trên trục X sẽ là dương hoặc âm nếu thiết bị được tăng tốc từ phải sang trái.

Bạn có thể sử dụng gia tốc kế cho các mục đích như: đếm bước, cảm biến chuyển động hoặc hướng thiết bị đơn giản. Thông thường, các phép đo gia tốc kế được kết hợp với dữ liệu từ các nguồn khác để tạo cảm biến kết hợp, chẳng hạn như cảm biến hướng.

LinearAccelerationSensor đo lường gia tốc được áp dụng cho thiết bị lưu trữ cảm biến, ngoại trừ gia tốc do trọng lực. Khi thiết bị ở trạng thái nghỉ, chẳng hạn như nằm phẳng trên mặt bàn, cảm biến sẽ đo gia tốc ≈ 0 m/s2 trên ba trục.

Cảm biến trọng lực

Người dùng có thể tự lấy các kết quả đo lường gần giống với kết quả đo lường của cảm biến trọng lực bằng cách kiểm tra kết quả đo lường AccelerometerLinearAccelerometer theo cách thủ công, nhưng việc này có thể gây phiền toái và phụ thuộc vào độ chính xác của các giá trị do các cảm biến đó cung cấp. Các nền tảng như Android có thể cung cấp thông tin đọc trọng lực như một phần của hệ điều hành. Thông tin này sẽ rẻ hơn về mặt tính toán, cung cấp các giá trị chính xác hơn tuỳ thuộc vào phần cứng của người dùng và dễ sử dụng hơn về mặt công thái học API. GravitySensor trả về hiệu ứng gia tốc dọc theo trục X, Y và Z của thiết bị do trọng lực.

Con quay hồi chuyển

Đo lường cảm biến con quay hồi chuyển

Cảm biến Gyroscope đo tốc độ góc tính bằng radian/giây xung quanh trục X, Y và Z cục bộ của thiết bị. Hầu hết thiết bị tiêu dùng đều có con quay hồi chuyển cơ học (MEMS). Đây là các cảm biến quán tính đo tốc độ xoay dựa trên lực Coriolis quán tính. Con quay hồi chuyển MEMS dễ bị trôi do độ nhạy trọng lực của cảm biến làm biến dạng hệ thống cơ học bên trong của cảm biến. Con quay hồi chuyển dao động ở tần số tương đối cao, ví dụ: 10 kHz, do đó, có thể tiêu thụ nhiều năng lượng hơn so với các cảm biến khác.

Cảm biến hướng

Đo lường cảm biến hướng tuyệt đối

AbsoluteOrientationSensor là một cảm biến kết hợp đo lường độ xoay của thiết bị so với hệ toạ độ của Trái Đất, trong khi RelativeOrientationSensor cung cấp dữ liệu thể hiện độ xoay của một thiết bị lưu trữ cảm biến chuyển động so với hệ toạ độ tham chiếu cố định.

Tất cả khung JavaScript 3D hiện đại đều hỗ trợ quaternionsmatrices xoay để biểu thị việc xoay; tuy nhiên, nếu bạn sử dụng WebGL trực tiếp, OrientationSensor sẽ thuận tiện có cả thuộc tính quaternionphương thức populateMatrix(). Sau đây là một vài đoạn mã:

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

Cảm biến hướng hỗ trợ nhiều trường hợp sử dụng, chẳng hạn như chơi trò chơi sống động, thực tế tăng cường và thực tế ảo.

Để biết thêm thông tin về cảm biến chuyển động, các trường hợp sử dụng nâng cao và yêu cầu, hãy xem tài liệu giải thích về cảm biến chuyển động.

Đồng bộ hoá với toạ độ màn hình

Theo mặc định, các chỉ số của cảm biến không gian được phân giải trong một hệ toạ độ cục bộ liên kết với thiết bị và không tính đến hướng màn hình.

Hệ toạ độ thiết bị
Hệ toạ độ thiết bị

Tuy nhiên, nhiều trường hợp sử dụng như trò chơi hoặc thực tế tăng cường và thực tế ảo yêu cầu phải phân giải kết quả đọc của cảm biến trong một hệ toạ độ liên kết với hướng màn hình.

Hệ toạ độ màn hình
Hệ toạ độ màn hình

Trước đây, bạn phải triển khai việc ánh xạ lại các lần đọc cảm biến thành toạ độ màn hình trong JavaScript. Phương pháp này không hiệu quả và cũng làm tăng đáng kể độ phức tạp của mã ứng dụng web; ứng dụng web phải theo dõi các thay đổi về hướng màn hình và thực hiện phép biến đổi toạ độ cho các lần đọc cảm biến, đây không phải là việc đơn giản đối với các góc Euler hoặc quaternion.

Generic Sensor API cung cấp một giải pháp đơn giản và đáng tin cậy hơn nhiều! Bạn có thể định cấu hình hệ toạ độ cục bộ cho tất cả các lớp cảm biến không gian đã xác định: Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensorMagnetometer. Bằng cách truyền tuỳ chọn referenceFrame vào hàm khởi tạo đối tượng cảm biến, người dùng xác định xem các giá trị đọc được trả về sẽ được phân giải theo toạ độ thiết bị hay màn hình.

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

Hãy lập trình!

API cảm biến chung rất đơn giản và dễ sử dụng! Giao diện cảm biến có các phương thức start()stop() để kiểm soát trạng thái cảm biến và một số trình xử lý sự kiện để nhận thông báo về việc kích hoạt cảm biến, lỗi và các lần đọc mới có. Các lớp cảm biến cụ thể thường thêm các thuộc tính đọc cụ thể vào lớp cơ sở.

Môi trường phát triển

Trong quá trình phát triển, bạn có thể sử dụng cảm biến thông qua localhost. Nếu bạn đang phát triển cho thiết bị di động, hãy thiết lập tính năng chuyển tiếp cổng cho máy chủ cục bộ và bạn đã sẵn sàng để bắt đầu!

Khi mã của bạn đã sẵn sàng, hãy triển khai mã đó trên một máy chủ hỗ trợ HTTPS. GitHub Pages được phân phát qua HTTPS, là một nơi tuyệt vời để chia sẻ các bản minh hoạ của bạn.

Xoay mô hình 3D

Trong ví dụ đơn giản này, chúng ta sử dụng dữ liệu từ cảm biến hướng tuyệt đối để sửa đổi quaternion xoay của mô hình 3D. model là một thực thể lớp Object3D three.js có thuộc tính quaternion. Đoạn mã sau đây trong bản minh hoạ điện thoại hướng minh hoạ cách sử dụng cảm biến hướng tuyệt đối để xoay mô hình 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();
}

Hướng của thiết bị sẽ được phản ánh trong chế độ xoay model 3D trong cảnh WebGL.

Cảm biến cập nhật hướng của mô hình 3D
Cảm biến cập nhật hướng của mô hình 3D

Máy đo lỗ

Đoạn mã sau đây được trích xuất từ bản minh hoạ máy đo tốc độ, minh hoạ cách sử dụng cảm biến gia tốc tuyến tính để tính toán vận tốc tối đa của thiết bị với giả định ban đầu là thiết bị này nằm yên.

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

Tốc độ hiện tại được tính toán dưới dạng giá trị gần đúng của tích phân của hàm gia tốc.

Ứng dụng web minh hoạ để đo tốc độ đấm
Đo tốc độ đấm

Gỡ lỗi và ghi đè cảm biến bằng Công cụ của Chrome cho nhà phát triển

Trong một số trường hợp, bạn không cần thiết bị thực để chơi với API cảm biến chung. Công cụ của Chrome cho nhà phát triển hỗ trợ rất tốt việc mô phỏng hướng thiết bị.

Công cụ của Chrome cho nhà phát triển từng ghi đè dữ liệu hướng tuỳ chỉnh của điện thoại ảo
Mô phỏng hướng thiết bị bằng Công cụ của Chrome cho nhà phát triển

Quyền riêng tư và bảo mật

Kết quả đọc của cảm biến là dữ liệu nhạy cảm có thể chịu nhiều cuộc tấn công từ các trang web độc hại. Việc triển khai API cảm biến chung sẽ thực thi một số hạn chế để giảm thiểu các rủi ro về bảo mật và quyền riêng tư có thể xảy ra. Những nhà phát triển có ý định sử dụng API này phải tính đến các giới hạn này. Hãy cùng liệt kê ngắn gọn các giới hạn đó.

Chỉ HTTPS

Vì Generic Sensor API là một tính năng mạnh mẽ, nên trình duyệt chỉ cho phép sử dụng API này trong các ngữ cảnh an toàn. Trên thực tế, điều này có nghĩa là để sử dụng API cảm biến chung, bạn cần truy cập vào trang của mình thông qua HTTPS. Trong quá trình phát triển, bạn có thể thực hiện việc này thông qua http://localhost, nhưng đối với môi trường phát hành công khai, bạn cần có HTTPS trên máy chủ. Hãy xem bộ sưu tập An toàn và bảo mật để biết các phương pháp hay nhất và nguyên tắc.

Tích hợp Chính sách về quyền

Tính năng tích hợp Chính sách quyền trong API cảm biến chung kiểm soát quyền truy cập vào dữ liệu cảm biến cho một khung hình.

Theo mặc định, bạn chỉ có thể tạo các đối tượng Sensor trong một khung chính hoặc các khung con cùng nguồn gốc, nhờ đó ngăn các iframe trên nhiều nguồn gốc đọc dữ liệu cảm biến trái phép. Bạn có thể sửa đổi hành vi mặc định này bằng cách bật hoặc tắt rõ ràng các tính năng do chính sách kiểm soát tương ứng.

Đoạn mã dưới đây minh hoạ việc cấp quyền truy cập dữ liệu gia tốc kế vào một iframe trên nhiều nguồn gốc, nghĩa là giờ đây, bạn có thể tạo các đối tượng Accelerometer hoặc LinearAccelerationSensor ở đó.

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

Hoạt động phân phối kết quả đo lường của cảm biến có thể bị tạm ngưng

Chỉ có thể truy cập vào kết quả đo lường của cảm biến thông qua một trang web hiển thị, tức là khi người dùng thực sự tương tác với trang web đó. Hơn nữa, dữ liệu cảm biến sẽ không được cung cấp cho khung mẹ nếu tiêu điểm của người dùng thay đổi thành khung con trên nhiều nguồn gốc. Điều này giúp ngăn khung mẹ suy luận dữ liệu đầu vào của người dùng.

Tiếp theo là gì?

Sắp tới, chúng tôi sẽ triển khai một bộ các lớp cảm biến đã được chỉ định, chẳng hạn như Cảm biến ánh sáng xung quanh hoặc Cảm biến khoảng cách; tuy nhiên, nhờ khả năng mở rộng tuyệt vời của khung Cảm biến chung, chúng ta có thể dự đoán sự xuất hiện của nhiều lớp mới hơn nữa đại diện cho nhiều loại cảm biến.

Một lĩnh vực quan trọng khác cho công việc trong tương lai là cải thiện chính API cảm biến chung. Thông số kỹ thuật của cảm biến chung hiện là Đề xuất đề xuất, nghĩa là vẫn còn thời gian để khắc phục và mang lại chức năng mới mà nhà phát triển cần.

Bạn có thể giúp!

Thông số kỹ thuật của cảm biến đã đạt đến cấp độ trưởng thành Đề xuất đề xuất. Do đó, chúng tôi rất mong nhận được ý kiến phản hồi của các nhà phát triển web và trình duyệt. Hãy cho chúng tôi biết những tính năng nào bạn muốn thêm hoặc nếu có điều gì bạn muốn sửa đổi trong API hiện tại.

Vui lòng gửi vấn đề về thông số kỹ thuật cũng như lỗi khi triển khai Chrome.

Tài nguyên

Lời cảm ơn

Bài viết này đã được Joe MedleyKayce Basques xem xét.