Skip to content

Commit 25a2dad

Browse files
authored
Merge pull request #26 from UteSpiske/database-recording
Database change to .csv + addition of gyroscope and rotation data
2 parents bd3970b + 22237e3 commit 25a2dad

File tree

12 files changed

+300
-78
lines changed

12 files changed

+300
-78
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Best model reached a macro-averaged F1 score of 99.66 % on the validation set, a
8181

8282
</details>
8383

84+
8485
<details>
8586
<summary>
8687

@@ -130,10 +131,11 @@ python dss/keras2tflite.py -m /path/to/pretrained/saved_model/ -o /path/to/save/
130131

131132
### Model integration and testing in app</summary>
132133

133-
A simple Mobile app was developed in Flutter, which demonstrates the AI in action using the accelerometer data from the mobile phone in real time:
134+
A simple Mobile app was developed in Flutter, which demonstrates the AI in action using the accelerometer data from the mobile phone in real time. The data can also be stored and deleted locally.
134135

135136
<p align="center" width="100%">
136-
<img src="sw_app/assets/app_snapshot_data.jpg" width="20%" height="20%"> <img src="sw_app/assets/app_snapshot_charts.jpg" width="20%" height="20%">
137+
<img src="sw_app/assets/HomeScreen.jpg" width="18%" height="20%"> <img src="sw_app/assets/Prediction.jpg" width="18%" height="20%"> <img src="sw_app/assets/ChartWithFPS.jpg" width="18%" height="20%">
138+
<img src="sw_app/assets/Recording.jpg" width="18%" height="20%"> <img src="sw_app/assets/Database.jpg" width="18%" height="20%">
137139
</p>
138140

139141
To use the app, you need an Android phone and have developer mode enabled (see [here](https://developer.android.com/studio/debug/dev-options) for how to enable it). Then simply download the APK from [here](https://github.com/andreped/DSS/releases/tag/v0.1.0), double-click to install, and use the app as you normally would.
@@ -153,6 +155,8 @@ For the app, the following _open_ packages were used (either MIT, BSD-2, or BSD-
153155
* [wakelock](https://pub.dev/packages/wakelock)
154156
* [sqflite](https://pub.dev/packages/sqflite)
155157
* [intl](https://pub.dev/packages/intl)
158+
* [csv](https://pub.dev/packages/csv)
159+
* [path_provider](https://pub.dev/packages/path_provider)
156160

157161
## How to cite
158162

sw_app/assets/ChartWithFPS.jpg

323 KB
Loading

sw_app/assets/Database.jpg

288 KB
Loading

sw_app/assets/HomeScreen.jpg

505 KB
Loading

sw_app/assets/Prediction.jpg

190 KB
Loading

sw_app/assets/Recording.jpg

187 KB
Loading
-127 KB
Binary file not shown.
-66.8 KB
Binary file not shown.

sw_app/lib/widgets/datarecording.dart

Lines changed: 173 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,159 @@
1+
import 'dart:io';
2+
13
import 'package:flutter/material.dart';
24
import 'package:flutter_sensors/flutter_sensors.dart';
35
import 'package:fl_chart/fl_chart.dart';
6+
import 'package:path_provider/path_provider.dart';
47
import 'package:sw_app/widgets/recording_database.dart';
58
import 'package:sw_app/widgets/recording_model.dart';
69
import 'dart:math';
710
import '../utils/datatypes.dart';
811
import '../utils/constants.dart' as _constants;
9-
12+
import 'package:csv/csv.dart';
1013
class DataRecordingPage extends StatefulWidget {
1114
@override
1215
State<DataRecordingPage> createState() => _DataRecordingPageState();
1316
}
1417

1518
class _DataRecordingPageState extends State<DataRecordingPage> {
16-
double x = 0, y = 0, z = 0;
19+
double x_accel = 0, y_accel = 0, z_accel = 0;
20+
double x_gyro = 0, y_gyro = 0, z_gyro = 0;
21+
double x_rot = 0, y_rot = 0, z_rot = 0;
1722
String direction = "none";
23+
var accel_finished = false;
24+
var gyro_finished = false;
25+
var rot_finished = false;
26+
1827

1928
// chart plotter variables
2029
var xPoints = <FlSpot>[const FlSpot(0, 0)];
2130
var yPoints = <FlSpot>[const FlSpot(0, 0)];
2231
var zPoints = <FlSpot>[const FlSpot(0, 0)];
2332

24-
double xValue = 0;
33+
double xValue_accel = 0;
2534
double step = 0.05;
2635

2736
var accelSubscription;
37+
var gyroSubscription;
38+
var rotSubscription;
2839
var isStarted = false;
2940
var recordingList;
3041

31-
void stream_accelerometer_data(listId) async {
32-
final _stream = await SensorManager().sensorUpdates(
42+
List<List<dynamic>> sensor_data_list = [];
43+
44+
45+
46+
47+
48+
// https://github.com/LJaraCastillo/flutter_sensors/blob/master/lib/src/sensors.dart
49+
50+
void stream_sensor_data() async {
51+
52+
List<dynamic> header = [];
53+
header.add("Time Stamp");
54+
header.add("xAccel");
55+
header.add("yAccel");
56+
header.add("zAccel");
57+
header.add("xGyro");
58+
header.add("yGyro");
59+
header.add("zGyro");
60+
header.add("xRot");
61+
header.add("yRot");
62+
header.add("zRot");
63+
64+
sensor_data_list.add(header);
65+
66+
final _stream_accel = await SensorManager().sensorUpdates(
3367
sensorId: Sensors.ACCELEROMETER,
3468
interval: Sensors.SENSOR_DELAY_GAME,
3569
);
3670

37-
accelSubscription = _stream.listen((sensorEvent) {
71+
final _stream_gyro = await SensorManager().sensorUpdates(
72+
sensorId: Sensors.GYROSCOPE,
73+
interval: Sensors.SENSOR_DELAY_GAME,
74+
);
75+
76+
final _stream_rot = await SensorManager().sensorUpdates(
77+
sensorId: Sensors.ROTATION,
78+
interval: Sensors.SENSOR_DELAY_GAME,
79+
);
80+
81+
rotSubscription = _stream_rot.listen((sensorEvent) {
82+
final _rotData = sensorEvent.data;
83+
84+
// get coordinates
85+
try {
86+
x_rot = _rotData[0];
87+
y_rot = _rotData[1];
88+
z_rot = _rotData[2];}
89+
catch(e) {
90+
x_rot = _rotData[0];
91+
y_rot = "" as double;
92+
z_rot = "" as double;
93+
}
94+
95+
setState(() {});
96+
97+
// write datapoints to list
98+
List<dynamic> row_rot = [];
99+
row_rot.add(DateTime.now());
100+
row_rot.add("");
101+
row_rot.add("");
102+
row_rot.add("");
103+
row_rot.add("");
104+
row_rot.add("");
105+
row_rot.add("");
106+
row_rot.add(x_rot);
107+
row_rot.add(y_rot);
108+
row_rot.add(z_rot);
109+
110+
sensor_data_list.add(row_rot);
111+
112+
});
113+
114+
gyroSubscription = _stream_gyro.listen((sensorEvent) {
115+
final _gyroData = sensorEvent.data;
116+
117+
// get coordinates
118+
x_gyro = _gyroData[0];
119+
y_gyro = _gyroData[1];
120+
z_gyro = _gyroData[2];
121+
122+
setState(() {});
123+
124+
// write datapoints to list
125+
List<dynamic> row_gyro = [];
126+
row_gyro.add(DateTime.now());
127+
row_gyro.add("");
128+
row_gyro.add("");
129+
row_gyro.add("");
130+
row_gyro.add(x_gyro);
131+
row_gyro.add(y_gyro);
132+
row_gyro.add(z_gyro);
133+
row_gyro.add("");
134+
row_gyro.add("");
135+
row_gyro.add("");
136+
137+
sensor_data_list.add(row_gyro);
138+
139+
});
140+
141+
142+
accelSubscription = _stream_accel.listen((sensorEvent) {
38143
final _accelData = sensorEvent.data;
39144

40145
// update counter
41-
xValue++;
146+
xValue_accel++;
42147

43148
// get coordinates
44-
x = _accelData[0];
45-
y = _accelData[1];
46-
z = _accelData[2];
149+
x_accel = _accelData[0];
150+
y_accel = _accelData[1];
151+
z_accel = _accelData[2];
47152

48153
// store result in history
49-
xPoints.add(FlSpot(xValue, x));
50-
yPoints.add(FlSpot(xValue, y));
51-
zPoints.add(FlSpot(xValue, z));
154+
xPoints.add(FlSpot(xValue_accel, x_accel));
155+
yPoints.add(FlSpot(xValue_accel, y_accel));
156+
zPoints.add(FlSpot(xValue_accel, z_accel));
52157

53158
while ((xPoints.length > _constants.limitCount) && (xPoints.isNotEmpty)) {
54159
xPoints.removeAt(0);
@@ -58,27 +163,61 @@ class _DataRecordingPageState extends State<DataRecordingPage> {
58163

59164
setState(() {});
60165

61-
var recording = Recording(
62-
listId: listId ,
63-
timeStamp: DateTime.now(),
64-
xAccel: x,
65-
yAccel: y,
66-
zAccel: z);
67-
RecordingDatabase.instance.create(recording);
166+
// write datapoints to list
167+
List<dynamic> row_accel = [];
168+
row_accel.add(DateTime.now());
169+
row_accel.add(x_accel);
170+
row_accel.add(y_accel);
171+
row_accel.add(z_accel);
172+
row_accel.add("");
173+
row_accel.add("");
174+
row_accel.add("");
175+
row_accel.add("");
176+
row_accel.add("");
177+
row_accel.add("");
178+
179+
sensor_data_list.add(row_accel);
180+
68181
});
182+
183+
184+
69185
}
186+
void save_csv (sensor_data_list, listId) async{
187+
188+
String csv = const ListToCsvConverter().convert(sensor_data_list);
70189

71-
void reset_variables() {
190+
Directory? appDocDir = await getExternalStorageDirectory();
191+
var appDocPath = appDocDir?.path;
192+
193+
194+
File f = File(appDocPath! + "/" + listId.toString()+ ".csv");
195+
print(f);
196+
197+
f.writeAsString(csv);
198+
print('CSV File saved in ' + f.path.toString());
199+
200+
}
201+
202+
void reset_variables(listId) {
203+
204+
save_csv(sensor_data_list, listId);
205+
206+
recordingList.clear();
72207
accelSubscription.cancel();
208+
rotSubscription.cancel();
209+
gyroSubscription.cancel();
210+
73211

74-
this.xValue = 0;
212+
this.xValue_accel = 0;
75213
this.step = 0.05;
76214

77-
this.x = 0;
78-
this.y = 0;
79-
this.z = 0;
80215
this.direction = "none";
81216

217+
accel_finished = false;
218+
gyro_finished = false;
219+
rot_finished = false;
220+
82221
// chart plotter variables
83222
this.xPoints = <FlSpot>[const FlSpot(0, 0)];
84223
this.yPoints = <FlSpot>[const FlSpot(0, 0)];
@@ -162,13 +301,14 @@ class _DataRecordingPageState extends State<DataRecordingPage> {
162301
timeStamp: DateTime.now(), duration: 0);
163302
RecordingDatabase.instance.createList(recordingList);
164303

165-
int latestListId = await RecordingDatabase.instance.getLatestListId();
304+
stream_sensor_data();
166305

167-
stream_accelerometer_data(latestListId);
168306
} else {
307+
int latestListId = await RecordingDatabase.instance.getLatestListId();
169308

170309
RecordingDatabase.instance.update();
171-
reset_variables();
310+
reset_variables(latestListId);
311+
172312
}
173313

174314
setState(() {});
@@ -189,7 +329,11 @@ class _DataRecordingPageState extends State<DataRecordingPage> {
189329
@override
190330
void dispose() {
191331
// need to close listener when class is inactive
192-
accelSubscription.cancel();
332+
if (accelSubscription != null) {
333+
accelSubscription.cancel();
334+
rotSubscription.cancel();
335+
gyroSubscription.cancel();
336+
}
193337

194338
super.dispose();
195339
}

0 commit comments

Comments
 (0)