系列文章《鸿蒙开发从入门到专家》第 26 篇 · 高级
运动类应用离不开传感器。计步、摇一摇、姿态识别、游戏操控,背后都是加速度计、陀螺仪、磁力计在提供原始数据。但传感器数据有个特点:单独看某一个往往不够,融合多个传感器才能得到稳定可用的结果。
本文讲鸿蒙传感器 API 的核心用法,以及常见的融合策略。
一、传感器 API 基本结构
鸿蒙通过 @kit.SensorServiceKit 访问传感器。无论哪种传感器,调用模式都类似:
sensor.getSensorList()查询设备支持的传感器。sensor.on()注册数据回调。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 或自己做滤波。
二、三种核心传感器
陀螺仪数据:
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() 掉传感器监听。持续后台采集还需要申请后台任务权限。
六、实战:简易计步器
计步不需要复杂的机器学习,用加速度计峰值检测就能实现一个基础版本:
以 50Hz 采样加速度计。
用滑动窗口计算合加速度模长。
检测波峰:当前值大于前后值且超过动态阈值。
两步之间设置最小时间间隔(比如 250ms),过滤抖动。
这个算法在步行场景下准确率够用,跑步或骑车时需要更复杂的模型。
小结
传感器开发的关键不是会调 API,而是理解数据的物理意义和噪声来源:
加速度计:含重力,适合静态倾角和冲击检测。
陀螺仪:测角速度,适合动态姿态但会漂移。
磁力计:指北,适合方位但易受干扰。
实际产品里多用互补滤波或直接使用融合后的方向传感器。
下一篇我们进入垂直设备领域,先聊车机应用开发的特殊之处。