重力感知应用


欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

一、项目概述

运行效果图

image-20260408190842563

image-20260408190847829

image-20260408190852201

1.1 应用简介

重力感知是一款基于传感器技术的数据记录应用,通过模拟重力传感器记录一天的重力变化轨迹。应用将抽象的重力数据转化为直观的可视化图表,让用户能够看到地球引力在一天中的微妙变化。

应用以深蓝色为主色调,象征宇宙与科技。界面设计现代感十足,采用深色主题营造科技氛围。通过轨道动画展示重力场的概念,将三轴加速度数据实时展示,帮助用户理解重力的本质。

1.2 核心功能

功能模块 功能描述 实现方式
重力感知 实时显示重力数据 模拟传感器
轨道动画 重力场可视化 CustomPaint绘制
三轴显示 X/Y/Z轴加速度 数值展示
数据记录 记录重力轨迹 Timer定时采集
历史查看 查看历史记录 列表展示
数据分析 统计分析重力数据 算法计算

1.3 重力数据说明

数据项 说明 单位
X轴加速度 水平方向加速度 m/s²
Y轴加速度 垂直方向加速度 m/s²
Z轴加速度 深度方向加速度 m/s²
重力大小 合成加速度大小 m/s²
标准重力 地球标准重力加速度 9.80665 m/s²

1.4 技术栈

技术领域 技术选型 版本要求
开发框架 Flutter >= 3.0.0
编程语言 Dart >= 2.17.0
设计规范 Material Design 3 -
状态管理 setState -
动画系统 AnimationController -
图形绘制 CustomPaint -
目标平台 鸿蒙OS / Web API 21+

1.5 项目结构

lib/
└── main_gravity_sensor.dart
    ├── GravitySensorApp           # 应用入口
    ├── GravityData                # 重力数据模型
    ├── GravitySession             # 重力会话模型
    ├── GravitySensorHomePage      # 主页面(底部导航)
    ├── _buildSensorPage           # 感知页面
    ├── _buildHistoryPage          # 历史页面
    ├── _buildAnalysisPage         # 分析页面
    ├── OrbitPainter               # 轨道绘制器
    ├── MiniGravityPainter         # 迷你图表绘制器
    └── DetailGravityPainter       # 详情图表绘制器

二、设计理念

2.1 重力感知概念

重力感知

数据采集

可视化

轨迹记录

X轴加速度

Y轴加速度

Z轴加速度

合成重力

轨道动画

三轴显示

重力曲线

实时记录

历史存储

数据分析

2.2 重力场可视化

重力场

轨道动画

三层轨道

运动粒子

循环动画

重力球体

中心显示

数值展示

渐变效果

三轴数据

X轴 红色

Y轴 绿色

Z轴 蓝色

2.3 色彩体系

应用采用深蓝色为主色调:

颜色类型 色值 RGB 用途
主色 #3F51B5 63,81,181 导航、按钮、强调
辅助色 #5C6BC0 92,107,192 渐变、次要元素
背景1 #0F0F1E 15,15,30 主背景
背景2 #1A1A2E 26,26,46 卡片背景
背景3 #16213E 22,33,62 次背景
X轴 Red - X轴加速度
Y轴 Green - Y轴加速度
Z轴 Blue - Z轴加速度

2.4 重力数据流程

存储 可视化 数据处理 传感器 存储 可视化 数据处理 传感器 alt [正在记录] 采集三轴数据 计算合成重力 更新显示 保存数据点 更新历史列表

三、系统架构

3.1 整体架构图

Data Layer

Business Layer

Presentation Layer

主页面
GravitySensorHomePage

感知页

历史页

分析页

轨道动画

三轴显示

重力球体

记录列表

详情弹窗

统计卡片

分布图表

传感器模拟
数据生成

记录系统
Timer采集

分析引擎
统计算法

GravityData
数据模型

GravitySession
会话模型

3.2 类图设计

manages

records

extends

GravitySensorApp

+Widget build()

GravityData

+DateTime timestamp

+double x

+double y

+double z

+double magnitude

GravitySession

+String id

+DateTime startTime

+DateTime endTime

+List<GravityData> dataPoints

+double avgMagnitude

+double maxMagnitude

+double minMagnitude

GravitySensorHomePage

-int _currentIndex

-List<GravitySession> _sessions

-List<GravityData> _currentDataPoints

-bool _isRecording

-Timer _recordingTimer

-double _currentX

-double _currentY

-double _currentZ

-double _currentMagnitude

-AnimationController _orbitController

+void _startRecording()

+void _stopRecording()

+void _startSimulation()

OrbitPainter

+double progress

+double magnitude

+void paint()

+bool shouldRepaint()

CustomPainter

3.3 数据记录流程

存储 记录系统 传感器模拟 感知页 用户 存储 记录系统 传感器模拟 感知页 用户 loop [每100ms] 打开应用 启动模拟 实时数据更新 开始记录 启动Timer 采集数据点 保存数据 停止记录 停止Timer 创建会话 显示摘要

四、核心功能实现

4.1 传感器模拟

模拟重力传感器数据:

void _startSimulation() {
  Timer.periodic(const Duration(milliseconds: 100), (timer) {
    if (!mounted) {
      timer.cancel();
      return;
    }

    final random = Random();
    setState(() {
      // 模拟三轴加速度
      _currentX = (random.nextDouble() - 0.5) * 2;
      _currentY = (random.nextDouble() - 0.5) * 2;
      _currentZ = 9.8 + (random.nextDouble() - 0.5) * 0.5;
      
      // 计算合成重力
      _currentMagnitude = sqrt(
        _currentX * _currentX + 
        _currentY * _currentY + 
        _currentZ * _currentZ,
      );
    });
  });
}

4.2 轨道动画绘制

绘制重力场轨道动画:

class OrbitPainter extends CustomPainter {
  final double progress;
  final double magnitude;

  
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final baseRadius = size.width / 2 - 20;

    // 绘制三层轨道
    for (int i = 0; i < 3; i++) {
      final orbitProgress = (progress + i * 0.33) % 1.0;
      final radius = baseRadius - i * 30;
      final angle = orbitProgress * 2 * pi;

      // 绘制轨道圆
      final paint = Paint()
        ..color = const Color(0xFF3F51B5).withValues(alpha: 0.3 - i * 0.1)
        ..style = PaintingStyle.stroke
        ..strokeWidth = 1;
      canvas.drawCircle(center, radius, paint);

      // 绘制轨道上的粒子
      final dotX = center.dx + radius * cos(angle);
      final dotY = center.dy + radius * sin(angle);
      final dotPaint = Paint()
        ..color = const Color(0xFF3F51B5).withValues(alpha: 0.8)
        ..style = PaintingStyle.fill;
      canvas.drawCircle(Offset(dotX, dotY), 4, dotPaint);
    }
  }
}

4.3 数据记录系统

记录重力轨迹:

void _startRecording() {
  setState(() {
    _isRecording = true;
    _currentDataPoints = [];
    _recordingStartTime = DateTime.now();
  });

  _recordingTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
    setState(() {
      _currentDataPoints.add(GravityData(
        timestamp: DateTime.now(),
        x: _currentX,
        y: _currentY,
        z: _currentZ,
        magnitude: _currentMagnitude,
      ));
    });
  });
}

void _stopRecording() {
  _recordingTimer?.cancel();

  if (_currentDataPoints.isEmpty) {
    setState(() {
      _isRecording = false;
    });
    return;
  }

  // 计算统计数据
  final magnitudes = _currentDataPoints.map((d) => d.magnitude).toList();
  final session = GravitySession(
    id: DateTime.now().millisecondsSinceEpoch.toString(),
    startTime: _recordingStartTime!,
    endTime: DateTime.now(),
    dataPoints: List.from(_currentDataPoints),
    avgMagnitude: magnitudes.reduce((a, b) => a + b) / magnitudes.length,
    maxMagnitude: magnitudes.reduce(max),
    minMagnitude: magnitudes.reduce(min),
  );

  setState(() {
    _sessions.insert(0, session);
    _isRecording = false;
    _currentDataPoints = [];
  });
}

4.4 重力曲线绘制

绘制重力变化曲线:

class DetailGravityPainter extends CustomPainter {
  final List<GravityData> dataPoints;

  
  void paint(Canvas canvas, Size size) {
    if (dataPoints.isEmpty) return;

    final paint = Paint()
      ..color = const Color(0xFF3F51B5)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    final path = Path();
    final points = <Offset>[];

    // 计算数据点位置
    for (int i = 0; i < dataPoints.length; i++) {
      final x = (i / (dataPoints.length - 1)) * size.width;
      final y = size.height - ((dataPoints[i].magnitude - 9.5) / 1.0 * size.height);
      points.add(Offset(x, y.clamp(0, size.height)));
    }

    // 绘制平滑曲线
    for (int i = 0; i < points.length; i++) {
      if (i == 0) {
        path.moveTo(points[i].dx, points[i].dy);
      } else {
        final prevPoint = points[i - 1];
        final controlPoint = Offset(
          (prevPoint.dx + points[i].dx) / 2,
          (prevPoint.dy + points[i].dy) / 2,
        );
        path.quadraticBezierTo(
          prevPoint.dx, prevPoint.dy,
          controlPoint.dx, controlPoint.dy,
        );
      }
    }

    canvas.drawPath(path, paint);

    // 绘制填充渐变
    final fillPaint = Paint()
      ..shader = LinearGradient(
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
        colors: [
          const Color(0xFF3F51B5).withValues(alpha: 0.3),
          const Color(0xFF3F51B5).withValues(alpha: 0.0),
        ],
      ).createShader(Rect.fromLTWH(0, 0, size.width, size.height))
      ..style = PaintingStyle.fill;

    final fillPath = Path.from(path);
    fillPath.lineTo(size.width, size.height);
    fillPath.lineTo(0, size.height);
    fillPath.close();

    canvas.drawPath(fillPath, fillPaint);
  }
}

五、UI设计规范

5.1 配色方案

应用采用深蓝色为主色调:

颜色类型 色值 用途
主色 #3F51B5 (Indigo) 导航、按钮、强调
辅助色 #5C6BC0 渐变、次要元素
背景1 #0F0F1E 主背景
背景2 #1A1A2E 卡片背景
背景3 #16213E 次背景

5.2 字体规范

元素 字号 字重 颜色
页面标题 24-28px Bold #FFFFFF
重力数值 24px Bold #FFFFFF
轴标签 14px Bold 动态颜色
数值显示 16-18px Bold #3F51B5
辅助文字 11-14px Regular 50-70% White

5.3 组件规范

5.3.1 重力球体
        ╭─────────────╮
       ╱   ╭───────╮   ╲
      │   ╱  9.81   ╲   │
      │  │  m/s²   │  │
      │   ╲       ╱   │
       ╲   ╰───────╯   ╱
        ╰─────────────╯
5.3.2 三轴显示
┌──────────────────────────────────┐
│     X          Y          Z      │
│   ╭───╮      ╭───╮      ╭───╮  │
│   │0.5│      │-0.3│      │9.8│  │
│   ╰───╯      ╰───╯      ╰───╯  │
│    红         绿         蓝     │
└──────────────────────────────────┘
5.3.3 重力曲线
┌────────────────────────────────────┐
│                                    │
│      ╱╲    ╱╲                      │
│     ╱  ╲  ╱  ╲    ╱╲               │
│    ╱    ╲╱    ╲  ╱  ╲              │
│   ╱              ╲╱    ╲           │
│                                    │
└────────────────────────────────────┘

六、交互设计

6.1 数据记录流程

存储 Timer 记录按钮 感知页 用户 存储 Timer 记录按钮 感知页 用户 loop [每100ms] 查看实时数据 显示重力球体 点击开始 启动定时器 保存数据点 更新计数 点击停止 停止定时器 创建会话 显示摘要

6.2 轨道动画机制

轨道动画

三层轨道

外层轨道

中层轨道

内层轨道

最大半径

最慢速度

中等半径

中等速度

最小半径

最快速度

粒子运动

6.3 页面切换状态

点击历史Tab

点击分析Tab

点击感知Tab

点击分析Tab

点击感知Tab

点击历史Tab

感知页

历史页

分析页


七、数据分析

7.1 重力数据统计

统计项 计算方式 说明
平均重力 所有数据点的平均值 整体水平
最大重力 所有数据点的最大值 峰值
最小重力 所有数据点的最小值 谷值
波动范围 最大值 - 最小值 变化幅度

7.2 三轴数据分析

// X轴加速度:水平方向
_currentX = (random.nextDouble() - 0.5) * 2;  // -1 到 1

// Y轴加速度:垂直方向
_currentY = (random.nextDouble() - 0.5) * 2;  // -1 到 1

// Z轴加速度:深度方向(主要重力分量)
_currentZ = 9.8 + (random.nextDouble() - 0.5) * 0.5;  // 约 9.55 到 10.05

// 合成重力
_currentMagnitude = sqrt(x*x + y*y + z*z);

7.3 重力分布分析

正常范围 说明
X轴 -1 ~ 1 m/s² 水平方向加速度
Y轴 -1 ~ 1 m/s² 垂直方向加速度
Z轴 9.5 ~ 10.0 m/s² 主要重力分量
合成 9.5 ~ 10.2 m/s² 总体重力大小

八、扩展功能规划

8.1 后续版本规划

2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 传感器模拟 轨道动画 数据记录 历史查看 真实传感器 数据导出 分享功能 地理定位 云端同步 AI分析 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 重力感知开发计划

8.2 功能扩展建议

8.2.1 真实传感器接入

接入真实重力传感器:

  • 使用sensors_plus插件
  • 获取真实加速度计数据
  • 支持陀螺仪数据
  • 实时数据流处理
8.2.2 地理位置关联

关联地理位置信息:

  • GPS定位集成
  • 海拔高度影响
  • 地理位置标记
  • 地图可视化
8.2.3 数据导出

支持多种格式导出:

  • CSV格式导出
  • JSON数据导出
  • 图表图片导出
  • 数据分析报告

九、注意事项

9.1 开发注意事项

  1. 传感器模拟:当前使用模拟数据,实际应用需接入真实传感器

  2. 动画性能:轨道动画需要优化性能

  3. 数据存储:大量数据点需要注意内存管理

  4. 状态管理:使用setState管理本地状态

9.2 常见问题

问题 原因 解决方案
轨道不显示 CustomPaint未正确实现 检查OrbitPainter
数据不更新 Timer未启动 检查_startSimulation
记录为空 Timer未正确保存 检查_recordingTimer
曲线不显示 数据点为空 检查dataPoints

9.3 使用提示

🌍 重力感知使用小贴士 🌍

地球标准重力加速度约为 9.80665 m/s²。
重力会因地理位置和海拔而略有不同。
记录重力轨迹可以了解设备运动状态。
持续记录可以发现重力的微小变化。

提示:建议在静止状态下记录,数据更准确。


十、运行说明

10.1 环境要求

环境 版本要求
Flutter SDK >= 3.0.0
Dart SDK >= 2.17.0
鸿蒙OS API 21+

10.2 运行命令

# 查看可用设备
flutter devices

# 运行到Web服务器
flutter run -d web-server -t lib/main_gravity_sensor.dart --web-port 8127

# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_gravity_sensor.dart

# 运行到Windows
flutter run -d windows -t lib/main_gravity_sensor.dart

# 代码分析
flutter analyze lib/main_gravity_sensor.dart

十一、总结

重力感知是一款基于传感器技术的数据记录应用,通过模拟重力传感器记录一天的重力变化轨迹。应用将抽象的重力数据转化为直观的可视化图表,让用户能够看到地球引力在一天中的微妙变化。

从技术实现来看,应用使用模拟数据模拟重力传感器,通过CustomPaint绘制轨道动画和重力曲线,使用Timer定时采集数据点,实现了完整的重力数据记录和分析系统。

从用户体验来看,应用提供直观的重力场可视化,通过轨道动画展示重力场的概念。三轴加速度实时显示,帮助用户理解重力的本质。重力曲线绘制,让用户看到重力的变化轨迹。

应用不仅是一个数据记录工具,更是一个科学教育平台。它提醒我们:地球标准重力加速度约为 9.80665 m/s²;重力会因地理位置和海拔而略有不同;记录重力轨迹可以了解设备运动状态;持续记录可以发现重力的微小变化。在科技与自然的交汇点,重力感知为我们提供了一种探索世界的新方式。

记录地球引力的轨迹


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐