From 2881c29eafda48cabed77a876a282c8e6b91bebd Mon Sep 17 00:00:00 2001 From: Dynesshely Date: Sat, 30 Mar 2024 18:48:21 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=BE=20Feat(Rotation):=20Better=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acceleration_display_stand.dart | 152 +++++++++++++++++- .../gyroscope_display_stand.dart | 28 ++-- .../utils/emulators/rotation_emulator.dart | 4 + kitx_mobile/pubspec.lock | 8 + kitx_mobile/pubspec.yaml | 1 + 5 files changed, 172 insertions(+), 21 deletions(-) diff --git a/kitx_mobile/lib/pages/test_pages/sensors_display_stands/acceleration_display_stand.dart b/kitx_mobile/lib/pages/test_pages/sensors_display_stands/acceleration_display_stand.dart index 9974725..8b6972a 100644 --- a/kitx_mobile/lib/pages/test_pages/sensors_display_stands/acceleration_display_stand.dart +++ b/kitx_mobile/lib/pages/test_pages/sensors_display_stands/acceleration_display_stand.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'dart:collection'; +import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:sensors_plus/sensors_plus.dart'; @@ -15,16 +17,46 @@ class AccelerationDisplayStandState extends State { /// Acceleration x-axis, y-axis, z-axis final accX = 0.0.obs, accY = 0.0.obs, accZ = 0.0.obs; + /// Sampling Rage + var samplingRate = 0.05.obs; + /// User accelerometer sensor data listener StreamSubscription? userAccelerometerDataListener; + /// Is listener paused + var listenerPaused = false.obs; + + /// Chart related data + var minX = 0.0.obs, maxX = 0.05.obs, xCount = 10.obs; + + /// Acceleration x-axis, y-axis, z-axis values + var xValues = [], yValues = [], zValues = []; + @override void initState() { - userAccelerometerDataListener = userAccelerometerEventStream(samplingPeriod: Duration(milliseconds: 50)).listen((event) { - accX.value = event.x; - accY.value = event.y; - accZ.value = event.z; - }); + userAccelerometerDataListener = userAccelerometerEventStream( + samplingPeriod: Duration(milliseconds: (samplingRate * 1000).toInt()), + ).listen( + (event) { + accX.value = event.x; + accY.value = event.y; + accZ.value = event.z; + maxX.value += samplingRate.value; + if ((maxX.value - minX.value) >= samplingRate.value * xCount.value) { + minX.value += samplingRate.value; + } + xValues.add(FlSpot(maxX.value, event.x)); + yValues.add(FlSpot(maxX.value, event.y)); + zValues.add(FlSpot(maxX.value, event.z)); + if (xValues.length > xCount.value + 1) { + xValues.removeAt(0); + yValues.removeAt(0); + zValues.removeAt(0); + } + }, + onError: (error) {}, + cancelOnError: true, + ); super.initState(); } @@ -42,14 +74,118 @@ class AccelerationDisplayStandState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Acceleration Data', style: TextStyle(fontSize: 32)), + Container( + height: 300, + margin: EdgeInsets.fromLTRB(0, 30, 20, 30), + child: Obx( + () => LineChart( + LineChartData( + minX: minX.value, + maxX: maxX.value, + minY: -5, + maxY: 5, + lineBarsData: [ + LineChartBarData( + spots: xValues, + color: Colors.redAccent, + isStrokeCapRound: true, + isStrokeJoinRound: true, + ), + LineChartBarData( + spots: yValues, + color: Colors.greenAccent, + isStrokeCapRound: true, + isStrokeJoinRound: true, + ), + LineChartBarData( + spots: zValues, + color: Colors.blueAccent, + isStrokeCapRound: true, + isStrokeJoinRound: true, + ), + ], + titlesData: FlTitlesData( + show: true, + rightTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40, + interval: 1, + getTitlesWidget: (a, b) => Padding( + padding: EdgeInsets.only(top: 10), + child: Text(a.toStringAsFixed(3).toString()), + ), + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + interval: 1, + getTitlesWidget: (a, b) => Text(a.toInt().toString()), + reservedSize: 30, + ), + ), + ), + gridData: FlGridData( + show: true, + drawVerticalLine: true, + horizontalInterval: 1, + verticalInterval: samplingRate.value, + getDrawingHorizontalLine: (value) { + return const FlLine( + color: Colors.indigo, + strokeWidth: 1, + ); + }, + getDrawingVerticalLine: (value) { + return const FlLine( + color: Colors.indigo, + strokeWidth: 1, + ); + }, + ), + borderData: FlBorderData( + show: true, + border: Border.all(color: Colors.indigo), + ), + ), + duration: const Duration(milliseconds: 0), + ), + ), + ), + Obx( + () => Text('${accX > 0 ? "⏪" : "⏩"} \tx: ${accX.value}', style: TextStyle(fontSize: 16, color: Colors.redAccent)), + ), + Obx( + () => Text('${accY > 0 ? "⏬" : "⏫"} \ty: ${accY.value}', style: TextStyle(fontSize: 16, color: Colors.greenAccent)), + ), Obx( - () => Text('x: ${accX.value}', style: TextStyle(fontSize: 14)), + () => Text('${accZ > 0 ? "⬇" : "⬆"} \tz: ${accZ.value}', style: TextStyle(fontSize: 16, color: Colors.blueAccent)), ), Obx( - () => Text('y: ${accY.value}', style: TextStyle(fontSize: 14)), + () => Text('⏱ \tSampling Rate: ${samplingRate.value} s', style: TextStyle(fontSize: 16)), ), + const Text('↔ \tUnit: m/s^2', style: TextStyle(fontSize: 16)), + const SizedBox(height: 20), Obx( - () => Text('z: ${accZ.value}', style: TextStyle(fontSize: 14)), + () => ElevatedButton( + onPressed: () { + if (userAccelerometerDataListener?.isPaused ?? true) { + userAccelerometerDataListener?.resume(); + listenerPaused.value = false; + } else { + userAccelerometerDataListener?.pause(); + listenerPaused.value = true; + } + }, + child: listenerPaused.value ? const Text('Resume') : const Text("Pause"), + ), ), ], ), diff --git a/kitx_mobile/lib/pages/test_pages/sensors_display_stands/gyroscope_display_stand.dart b/kitx_mobile/lib/pages/test_pages/sensors_display_stands/gyroscope_display_stand.dart index 146e1ea..6431df3 100644 --- a/kitx_mobile/lib/pages/test_pages/sensors_display_stands/gyroscope_display_stand.dart +++ b/kitx_mobile/lib/pages/test_pages/sensors_display_stands/gyroscope_display_stand.dart @@ -17,15 +17,15 @@ class GyroscopeDisplayStandState extends State { /// Gyroscope x-axis, y-axis, z-axis final dirX = 0.0.obs, dirY = 0.0.obs, dirZ = 0.0.obs; - /// Gyroscope direction x, y, z - final directionX = 'none'.obs, directionY = 'none'.obs, directionZ = 'none'.obs; - /// Drawing canvas size static double canvasWidth = 400, canvasHeight = 300; /// Is drawing paused var rotationPaused = false.obs; + /// Sampling Rage + var samplingRate = 0.05.obs; + /// Gyroscope sensor data listener StreamSubscription? gyroscopeDataListener; @@ -36,21 +36,19 @@ class GyroscopeDisplayStandState extends State { void initState() { painter.initialize(); - gyroscopeDataListener = gyroscopeEventStream(samplingPeriod: Duration(milliseconds: 50)).listen( + gyroscopeDataListener = gyroscopeEventStream( + samplingPeriod: Duration(milliseconds: (samplingRate.value * 1000).toInt()), + ).listen( (event) { - DeviceRotationHost.rotateWithAcceleration(event.x, event.y, event.z, 0.05); + DeviceRotationHost.rotateWithAcceleration(event.x, event.y, event.z, samplingRate.value); dirX.value = event.x; dirY.value = event.y; dirZ.value = event.z; - - directionX.value = dirX >= 0 ? '⇊' : '⇈'; - directionY.value = dirY >= 0 ? '↻' : '↺'; - directionZ.value = dirZ >= 0 ? '↶' : '↷'; }, onError: (error) { Timer.periodic(Duration(milliseconds: 50), (timer) { - DeviceRotationHost.rotateWithAcceleration(0, 0, 0.5, 0.05); + DeviceRotationHost.rotateWithAcceleration(0.5, 0.5, 0.5, samplingRate.value); }); }, cancelOnError: true, @@ -122,14 +120,18 @@ class GyroscopeDisplayStandState extends State { ], ), Obx( - () => Text('${directionX.value} x: ${dirX.value}', style: TextStyle(fontSize: 16)), + () => Text('${dirX >= 0 ? '⏬' : '⏫'} \tx: ${dirX.value}', style: TextStyle(fontSize: 16)), + ), + Obx( + () => Text('${dirY >= 0 ? '⤵' : '⤴'} \ty: ${dirY.value}', style: TextStyle(fontSize: 16)), ), Obx( - () => Text('${directionY.value} y: ${dirY.value}', style: TextStyle(fontSize: 16)), + () => Text('${dirZ >= 0 ? '⏪' : '⏩'} \tz: ${dirZ.value}', style: TextStyle(fontSize: 16)), ), Obx( - () => Text('${directionZ.value} z: ${dirZ.value}', style: TextStyle(fontSize: 16)), + () => Text('⏱ \tSampling Rate: ${samplingRate.value} s', style: TextStyle(fontSize: 16)), ), + const Text('↔ \tUnit: rad/s', style: TextStyle(fontSize: 16)), ], ), ); diff --git a/kitx_mobile/lib/utils/emulators/rotation_emulator.dart b/kitx_mobile/lib/utils/emulators/rotation_emulator.dart index 635ca95..bbe5982 100644 --- a/kitx_mobile/lib/utils/emulators/rotation_emulator.dart +++ b/kitx_mobile/lib/utils/emulators/rotation_emulator.dart @@ -70,6 +70,10 @@ class DeviceRotationHost { np = zDirR * np * zDirRInv; points[i] = np; } + + lastXDirR = xDirR; + lastYDirR = yDirR; + lastZDirR = zDirR; } /// Set points diff --git a/kitx_mobile/pubspec.lock b/kitx_mobile/pubspec.lock index 471da4b..52697ba 100644 --- a/kitx_mobile/pubspec.lock +++ b/kitx_mobile/pubspec.lock @@ -265,6 +265,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + sha256: "2b7c1f5d867da9a054661641c8f499c55c47c39acccb97b3bc673f5fa9a39e74" + url: "https://pub.dev" + source: hosted + version: "0.67.0" flutter: dependency: "direct main" description: flutter diff --git a/kitx_mobile/pubspec.yaml b/kitx_mobile/pubspec.yaml index b9756df..29cf925 100644 --- a/kitx_mobile/pubspec.yaml +++ b/kitx_mobile/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: crypto: ^3.0.3 device_info_plus: ^9.1.1 f_logs: ^2.0.1 + fl_chart: ^0.67.0 flutter: sdk: flutter flutter_blue_plus: ^1.31.15