You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Flutter传感器包计算被竖直抛起的手机的上升距离

竖直抛手机上升距离计算方案

核心原理

要通过加速度传感器计算上升高度,需要做两次积分:

  • 第一次:对竖直方向的加速度按时间积分,得到当前竖直速度
  • 第二次:对竖直速度按时间积分,得到累计的竖直位移
    当手机上升到最高点时,竖直方向速度为0,此时的累计位移就是你要的上升高度。

现有代码的问题

  • 单位换算错误:时间差取的是微秒,转成秒需要除以1000000,不是1000,量级差了1000倍
  • 积分逻辑错误:直接用单次加速度乘时间差当作位移,跳过了速度累积的步骤,结果完全不准确
  • 没有结束判断:没有检测最高点的逻辑,会一直累加位移

修正后的实现方案

参考如下代码修改,核心是增加速度累积、基线校准、最高点判断逻辑:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:sensors/sensors.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 抛高计算',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(title: '抛高计算 demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<StreamSubscription> _streamSubscriptions = [];
  // 加速度基线校准值,抵消静止时的传感器偏移
  double _accelYOffset = 0;
  // 当前竖直速度 单位:m/s
  double _currentVelocityY = 0;
  // 累计上升位移 单位:m
  double _totalHeight = 0;
  // 上次采样的时间
  DateTime? _lastTime;
  // 是否处于抛射计算状态
  bool _isCounting = false;
  // 存储历史高度结果
  List<double> heightResults = [];

  @override
  void initState() {
    super.initState();
    // 先校准1秒的加速度基线,降低静态误差
    _calibrateOffset();
  }

  Future<void> _calibrateOffset() async {
    List<double> tempOffsets = [];
    StreamSubscription sub = userAccelerometerEvents.listen((event) {
      tempOffsets.add(event.y);
    });
    await Future.delayed(const Duration(seconds: 1));
    sub.cancel();
    // 取平均值作为偏移值
    _accelYOffset = tempOffsets.reduce((a, b) => a + b) / tempOffsets.length;
    // 校准完成后开始监听加速度数据
    _startListening();
  }

  void _startListening() {
    _streamSubscriptions.add(
      userAccelerometerEvents.listen((UserAccelerometerEvent event) {
        setState(() {
          // 减去偏移得到真实的Y轴加速度,Y轴向上为正方向
          double realAccelY = event.y - _accelYOffset;
          DateTime now = DateTime.now();

          if (_lastTime != null) {
            // 计算两次采样的时间差,转换为秒
            double deltaT = now.difference(_lastTime!).inMicroseconds / 1e6;

            // 第一次积分:加速度*时间差 = 速度增量,累加得到当前速度
            _currentVelocityY += realAccelY * deltaT;

            // 检测抛射开始:速度超过0.5m/s阈值就启动位移计算
            if (_currentVelocityY > 0.5 && !_isCounting) {
              _isCounting = true;
              _totalHeight = 0;
            }

            // 处于计算状态时累加位移
            if (_isCounting) {
              // 第二次积分:速度*时间差 = 位移增量,累加得到总上升高度
              _totalHeight += _currentVelocityY * deltaT;

              // 检测最高点:速度从正变负,说明到达最高点
              if (_currentVelocityY <= 0) {
                _isCounting = false;
                // 保留两位小数存入结果列表
                heightResults.insert(0, double.parse(_totalHeight.toStringAsFixed(2)));
                // 重置速度等待下一次抛射
                _currentVelocityY = 0;
              }
            }
          }
          _lastTime = now;
        });
      }),
    );
  }

  @override
  void dispose() {
    for (var sub in _streamSubscriptions) {
      sub.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          const Text('抛射高度结果(单位:米):', style: TextStyle(fontSize: 18)),
          const SizedBox(height: 16),
          for (double height in heightResults)
            Text(
              '$height m',
              style: Theme.of(context).textTheme.headline4,
            ),
        ],
      ),
    );
  }
}

使用注意事项

  • 测试时竖直握持手机,保证Y轴方向和重力方向平行
  • 抛射时尽量保持手机竖直向上,不要有旋转,避免其他方向加速度干扰结果
  • 消费级传感器存在固有误差,多次测试取平均值可以提高精度

内容的提问来源于stack exchange,提问作者Happyriri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 18:06:07