App Inventor 2 计步传感器与距离测量教程

« 返回首页

概述

App Inventor 2可以通过以下方式实现计步和距离测量:

方案 组件 精度 说明
计步器传感器 Pedometer扩展 高 硬件计步器
加速度分析 AccelerometerSensor 中 软件算法
GPS距离 LocationSensor 户外高 基于GPS轨迹

方案一:计步器传感器

原理

现代Android手机内置硬件计步器传感器(TYPE_STEP_COUNTER),精度高且功耗低。

使用扩展

需要计步器扩展(如StepCounter扩展)。

when Screen1.Initialize() {
  var 今日步数 = 微数据库1.GetValue("today_steps", 0)
  var 今日日期 = 计时器1.FormatDateTime(计时器1.Now(), "yyyy-MM-dd")
  var 保存日期 = 微数据库1.GetValue("today_date", "")
  if 保存日期 != 今日日期 {
    // 新的一天,重置步数
    var 今日步数 = 0
    微数据库1.StoreValue("today_date", 今日日期)
    微数据库1.StoreValue("today_steps", 0)
  }
  StepCounter1.Start()
  标签_步数.Text = 今日步数
}
while StepCounter1.步数变化(步数) {
  var 今日步数 = 步数
  标签_步数.Text = join(步数, " 步")
  微数据库1.StoreValue("today_steps", 步数)
  // 计算距离(估算)
  var 步幅 = 0.7  // 平均步幅0.7米
  var 距离米 = 步数 * 步幅
  if 距离米 < 1000 {
    标签_距离.Text = join(formatDecimal(距离米, 0), " 米")
  } else {
    标签_距离.Text = join(formatDecimal(距离米 / 1000, 2), " 公里")
    // 计算卡路里(估算)
  }
  var 体重KG = 70  // 假设体重
  var 卡路里 = 步数 * 0.04 * 体重KG / 70  // 粗略估算
  标签_卡路里.Text = join(formatDecimal(卡路里, 1), " 千卡")
}

步数距离单位说明

计步传感器返回的步数是计数(步),distance是传感器估算的距离(如果传感器支持的话)。需要换算:

  • 1步 ≈ 0.6-0.8米(因人而异)
  • 1000步 ≈ 600-800米
  • 10000步 ≈ 6-8公里

方案二:加速度计检测步数

没有硬件计步器时,用加速度传感器算法检测:

原理

走路时加速度有周期性波动。检测加速度的模值超过阈值即为一步。

global 步数 = 0
global 上次峰值时间 = 0
global 最小步间隔 = 250  // 毫秒,两步之间最小间隔
global 加速度阈值 = 12.5  // 检测阈值
when 加速度传感器1.Speed(xAccel, yAccel, zAccel) {
  var 加速度模 = sqrt(xAccel*xAccel + yAccel*yAccel + zAccel*zAccel)
  var 当前时间 = 计时器1.GetMillis(计时器1.Now())
  if 加速度模 > 加速度阈值 {
    var 时间差 = 当前时间 - 上次峰值时间
    if 时间差 > 最小步间隔 {
      var 步数 = 步数 + 1
      var 上次峰值时间 = 当前时间
      标签_步数.Text = join(步数, " 步")
    }
  }
}

优化算法(带滤波)

global 滤波值 = 9.8  // 初始化为重力加速度
global 滤波系数 = 0.1
global 步数 = 0

when 加速度传感器1.AccelerationChanged(xAccel, yAccel, zAccel) {
  var 原始模 = sqrt(xAccel * xAccel + yAccel * yAccel + zAccel * zAccel)
  
  // 低通滤波
  global 滤波值 = 滤波值 + 滤波系数 * (原始模 - 滤波值)
  
  // 检测峰值
  var 偏差 = 滤波值 - 9.8  // 去除重力
  if 偏差 > 2.5 {  // 阈值
    var 当前时间 = 计时器1.GetMillis(计时器1.Now())
    if (当前时间 - 上次峰值时间) > 300 {
      global 步数 = 步数 + 1
      global 上次峰值时间 = 当前时间
    }
  }
}

方案三:GPS距离测量

已有文档

sensors.md 介绍了LocationSensor基本用法,map_geofence.md 介绍了Haversine距离计算。此处补充轨迹记录和总距离计算。

记录GPS轨迹计算总距离

global 轨迹点 = []
global 总距离 = 0

when 位置传感器1.LocationChanged(纬度, 经度, 海拔, 速度) {
  var 新点 = {"lat": 纬度, "lng": 经度, "time": 计时器1.GetMillis(计时器1.Now())}
  
  if 列表长度(轨迹点) > 0 {
    var 上一点 = 列表第(列表长度(轨迹点))项(轨迹点)
    var 段距离 = Haversine距离(
      上一点.get("lat"), 上一点.get("lng"),
      纬度, 经度
    )
    global 总距离 = 总距离 + 段距离
  }
  
  global 轨迹点 = 添加列表项(轨迹点, 新点)
  
  // 显示
  if 总距离 < 1000 {
    标签_总距离.Text = 数学.保留小数(总距离, 0) + " 米"
  } else {
    标签_总距离.Text = 数学.保留小数(总距离 / 1000, 2) + " 公里"
  }
  标签_轨迹点数.Text = 列表长度(轨迹点) + " 个轨迹点"
  标签_当前速度.Text = 数学.保留小数(速度 * 3.6, 1) + " km/h"  // m/s -> km/h
}

实战案例:运动记录App

功能

  • 实时计步
  • GPS轨迹记录
  • 运动距离/时间/卡路里
  • 运动历史记录

界面设计

Screen_Run
├── 标签_步数
├── 标签_距离
├── 标签_时间
├── 标签_卡路里
├── 标签_速度
├── 按钮_开始/暂停
├── 按钮_结束
├── 地图1(轨迹地图)
├── 位置传感器1
├── StepCounter1
├── 计时器1(计时)
└── 微数据库1(存储记录)

核心积木块

global 运动中 = false
global 开始时间 = 0
global 总步数 = 0
global 总距离 = 0
global 轨迹点 = []

when 按钮_开始.Click {
  global 运动中 = true
  global 开始时间 = 计时器1.GetMillis(计时器1.Now())
  位置传感器1.Enabled = true
  StepCounter1.Start()
  Clock_计时.TimerInterval = 1000
  Clock_计时.TimerEnabled = true
  按钮_开始.Text = "暂停"
}

when Clock_计时.Timer {
  if 运动中 {
    var 已用毫秒 = 计时器1.GetMillis(计时器1.Now()) - 开始时间
    var 分钟 = 数学.向下取整(已用毫秒 / 60000)
    var 秒 = 数学.向下取整((已用毫秒 % 60000) / 1000)
    标签_时间.Text = 文本格式("%02d:%02d", 分钟, 秒)
  }
}

when 按钮_结束.Click {
  global 运动中 = false
  位置传感器1.Enabled = false
  Clock_计时.TimerEnabled = false
  
  // 保存运动记录
  var 记录 = {
    "date": 计时器1.FormatDateTime(计时器1.Now(), "yyyy-MM-dd HH:mm"),
    "steps": 总步数,
    "distance": 数学.保留小数(总距离, 0),
    "duration": 标签_时间.Text,
    "calories": 标签_卡路里.Text
  }
  var 历史记录 = 微数据库1.GetValue("run_history", [])
  var 历史记录 = 添加列表项(历史记录, 记录)
  微数据库1.StoreValue("run_history", 历史记录)
}

常见问题

Q1: 计步传感器distance是什么单位?

如果传感器返回distance值,通常是米。但很多Android设备的计步传感器不提供distance,只提供步数(steps)。需要用 步数 × 步幅 估算距离。

Q2: 加速度计计步不准确?

软件算法受以下影响:

  • 手机放置位置(口袋/手中/桌上)
  • 走路速度和姿势
  • 其他运动干扰(骑车、颠簸)

建议使用硬件计步器扩展更准确。

Q3: GPS轨迹记录耗电?

持续GPS定位很耗电。优化:

  • 增大 DistanceInterval(如5米才更新一次)
  • 降低更新频率
  • 使用 TimerEnabled 间歇性获取位置

总结

方案 精度 耗电 适用
硬件计步器 ⭐⭐⭐⭐ 低 计步
加速度算法 ⭐⭐ 低 无硬件计步器时
GPS轨迹 ⭐⭐⭐⭐ 高 户外运动距离
文档反馈