Administrator
发布于 2026-09-01 / 69 阅读
0
0

鸿蒙传感器开发:加速度计、陀螺仪与传感器融合

系列文章《鸿蒙开发从入门到专家》第 26 篇 · 高级

运动类应用离不开传感器。计步、摇一摇、姿态识别、游戏操控,背后都是加速度计、陀螺仪、磁力计在提供原始数据。但传感器数据有个特点:单独看某一个往往不够,融合多个传感器才能得到稳定可用的结果。

本文讲鸿蒙传感器 API 的核心用法,以及常见的融合策略。

一、传感器 API 基本结构

鸿蒙通过 @kit.SensorServiceKit 访问传感器。无论哪种传感器,调用模式都类似:

  1. sensor.getSensorList() 查询设备支持的传感器。

  2. sensor.on() 注册数据回调。

  3. sensor.off() 取消监听。

以加速度计为例:

import { sensor } from '@kit.SensorServiceKit';

sensor.on(sensor.SensorId.ACCELEROMETER, (data) => {
  console.info(`x: ${data.x}, y: ${data.y}, z: ${data.z}`);
}, {
  interval: sensor.SensorInterval.NORMAL,
});

回调里的 x、y、z 是设备坐标系下的加速度,单位是 m/s²。注意这是包含重力加速度的原始值。如果要去掉重力影响,需要订阅 ACCELEROMETER_UNCALIBRATED 或自己做滤波。

二、三种核心传感器

传感器

测量对象

典型应用

加速度计

三轴加速度(含重力)

计步、摇一摇、屏幕旋转

陀螺仪

三轴角速度

姿态追踪、游戏控制、VR

磁力计

三轴磁场强度

指南针、方向估计

陀螺仪数据:

sensor.on(sensor.SensorId.GYROSCOPE, (data) => {
  // x, y, z 单位是 rad/s
}, { interval: sensor.SensorInterval.GAME });

磁力计数据:

sensor.on(sensor.SensorId.MAGNETIC_FIELD, (data) => {
  // x, y, z 单位是 uT
}, { interval: sensor.SensorInterval.NORMAL });

三、摇一摇检测:简单但有讲究

摇一摇听起来简单,直接判断加速度模长超过阈值就行。但实际操作中有几个坑:

  • 手持静止时加速度模长约 9.8 m/s²,即重力加速度。

  • 大幅度晃动时模长会明显偏离 9.8。

  • 需要设置“冷却时间”,避免一次摇动触发多次。

@State private lastShakeTime: number = 0;

sensor.on(sensor.SensorId.ACCELEROMETER, (data) => {
  const magnitude = Math.sqrt(data.x ** 2 + data.y ** 2 + data.z ** 2);
  const now = Date.now();
  if (magnitude > 20 && now - this.lastShakeTime > 1000) {
    this.lastShakeTime = now;
    console.info('检测到摇动');
    // 触发业务逻辑
  }
}, { interval: sensor.SensorInterval.NORMAL });

阈值 20 和冷却 1 秒是经验值,具体产品里需要结合实际测试调整。

四、传感器融合:互补滤波

加速度计长期稳定但噪声大,陀螺仪短期精确但会漂移。把两者融合,可以得到更平滑的姿态角。

一个简化的互补滤波公式:

angle = alpha * (angle + gyro * dt) + (1 - alpha) * accelAngle
  • alpha 通常取 0.98,相信陀螺仪短期数据。

  • accelAngle 通过加速度计反解,比如 atan2(y, z)。

  • dt 是采样间隔。

private angle = 0;
private lastTime = Date.now();

sensor.on(sensor.SensorId.ACCELEROMETER, (accel) => {
  sensor.getGeomagneticField(); // 如果需要方向,可结合磁力计
});

sensor.on(sensor.SensorId.GYROSCOPE, (gyro) => {
  const now = Date.now();
  const dt = (now - this.lastTime) / 1000;
  this.lastTime = now;

  const accelAngle = Math.atan2(accel.y, accel.z);
  this.angle = 0.98 * (this.angle + gyro.x * dt) + 0.02 * accelAngle;
});

更复杂的场景可以直接用系统提供的方向传感器(ORIENTATION),它内部已经做了融合,返回俯仰角、横滚角和方位角。

五、功耗与生命周期管理

传感器采样频率越高,功耗越大。鸿蒙提供了几档采样间隔:

  • SENSOR_DELAY_NORMAL:约 200ms,适合计步、屏幕旋转。

  • SENSOR_DELAY_UI:约 60ms,适合界面动画。

  • SENSOR_DELAY_GAME:约 20ms,适合游戏。

  • SENSOR_DELAY_FASTEST:尽可能快,功耗最高。

页面退出或应用进入后台时,一定要 off() 掉传感器监听。持续后台采集还需要申请后台任务权限。

六、实战:简易计步器

计步不需要复杂的机器学习,用加速度计峰值检测就能实现一个基础版本:

  1. 以 50Hz 采样加速度计。

  2. 用滑动窗口计算合加速度模长。

  3. 检测波峰:当前值大于前后值且超过动态阈值。

  4. 两步之间设置最小时间间隔(比如 250ms),过滤抖动。

这个算法在步行场景下准确率够用,跑步或骑车时需要更复杂的模型。

小结

传感器开发的关键不是会调 API,而是理解数据的物理意义和噪声来源:

  • 加速度计:含重力,适合静态倾角和冲击检测。

  • 陀螺仪:测角速度,适合动态姿态但会漂移。

  • 磁力计:指北,适合方位但易受干扰。

  • 实际产品里多用互补滤波或直接使用融合后的方向传感器。

下一篇我们进入垂直设备领域,先聊车机应用开发的特殊之处。


评论