Skip to content

Commit 896fb86

Browse files
implementation of the Compass page
1 parent 8fbccb5 commit 896fb86

File tree

8 files changed

+383
-2
lines changed

8 files changed

+383
-2
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<meta-data
3737
android:name="flutterEmbedding"
3838
android:value="2" />
39+
3940
</application>
4041
<!-- Required to query activities that can process text, see:
4142
https://developer.android.com/training/package-visibility and

assets/icons/compass_icon.png

247 KB
Loading

lib/main.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33
import 'package:pslab/providers/board_state_provider.dart';
4+
import 'package:pslab/providers/compass_provider.dart';
45
import 'package:pslab/providers/locator.dart';
56
import 'package:pslab/view/connect_device_screen.dart';
67
import 'package:pslab/view/faq_screen.dart';
@@ -9,7 +10,7 @@ import 'package:pslab/view/oscilloscope_screen.dart';
910
import 'package:pslab/view/settings_screen.dart';
1011
import 'package:pslab/view/about_us_screen.dart';
1112
import 'package:pslab/view/software_licenses_screen.dart';
12-
13+
import 'package:pslab/view/compass_screen.dart';
1314
import 'constants.dart';
1415

1516
void main() {
@@ -22,6 +23,9 @@ void main() {
2223
ChangeNotifierProvider<BoardStateProvider>(
2324
create: (context) => getIt<BoardStateProvider>(),
2425
),
26+
ChangeNotifierProvider<CompassProvider>(
27+
create: (context) => getIt<CompassProvider>(),
28+
),
2529
],
2630
child: const MyApp(),
2731
),
@@ -44,6 +48,7 @@ class MyApp extends StatelessWidget {
4448
routes: {
4549
'/': (context) => const InstrumentsScreen(),
4650
'/oscilloscope': (context) => const OscilloscopeScreen(),
51+
'/compass': (context) => const CompassScreen(),
4752
'/connectDevice': (context) => const ConnectDeviceScreen(),
4853
'/faq': (context) => const FAQScreen(),
4954
'/settings': (context) => const SettingsScreen(),

lib/providers/compass_provider.dart

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import 'dart:async';
2+
import 'dart:math';
3+
import 'package:flutter/material.dart';
4+
import 'package:sensors_plus/sensors_plus.dart';
5+
import 'package:flutter/foundation.dart';
6+
7+
class CompassProvider extends ChangeNotifier {
8+
MagnetometerEvent _magnetometerEvent =
9+
MagnetometerEvent(0, 0, 0, DateTime.now());
10+
AccelerometerEvent _accelerometerEvent =
11+
AccelerometerEvent(0, 0, 0, DateTime.now());
12+
StreamSubscription? _magnetometerSubscription;
13+
StreamSubscription? _accelerometerSubscription;
14+
String _selectedAxis = 'X';
15+
double _currentDegree = 0.0;
16+
int _direction = 0;
17+
double _smoothedHeading = 0.0;
18+
19+
MagnetometerEvent get magnetometerEvent => _magnetometerEvent;
20+
AccelerometerEvent get accelerometerEvent => _accelerometerEvent;
21+
String get selectedAxis => _selectedAxis;
22+
double get currentDegree => _currentDegree;
23+
int get direction => _direction;
24+
double get smoothedHeading => _smoothedHeading;
25+
26+
void initializeSensors() {
27+
_magnetometerSubscription = magnetometerEventStream().listen(
28+
(event) {
29+
_magnetometerEvent = event;
30+
_updateCompassDirection();
31+
notifyListeners();
32+
},
33+
onError: (error) {
34+
debugPrint("Magnetometer error: $error");
35+
},
36+
cancelOnError: true,
37+
);
38+
39+
_accelerometerSubscription = accelerometerEventStream().listen(
40+
(event) {
41+
_accelerometerEvent = event;
42+
_updateCompassDirection();
43+
notifyListeners();
44+
},
45+
onError: (error) {
46+
debugPrint("Accelerometer error: $error");
47+
},
48+
cancelOnError: true,
49+
);
50+
}
51+
52+
void disposeSensors() {
53+
_magnetometerSubscription?.cancel();
54+
_accelerometerSubscription?.cancel();
55+
}
56+
57+
@override
58+
void dispose() {
59+
disposeSensors();
60+
super.dispose();
61+
}
62+
63+
void _updateCompassDirection() {
64+
double radians = _getRadiansForAxis(_selectedAxis);
65+
double degrees = radians * (180 / pi);
66+
if (degrees < 0) {
67+
degrees += 360;
68+
}
69+
70+
degrees = (degrees - 90) % 360;
71+
if (degrees < 0) {
72+
degrees += 360;
73+
}
74+
75+
const double alpha = 0.45;
76+
double angleDiff = degrees - _smoothedHeading;
77+
if (angleDiff > 180) {
78+
angleDiff -= 360;
79+
} else if (angleDiff < -180) {
80+
angleDiff += 360;
81+
}
82+
_smoothedHeading = _smoothedHeading + alpha * angleDiff;
83+
if (_smoothedHeading >= 360) {
84+
_smoothedHeading -= 360;
85+
} else if (_smoothedHeading < 0) {
86+
_smoothedHeading += 360;
87+
}
88+
switch (_selectedAxis) {
89+
case 'X':
90+
_currentDegree = -(_smoothedHeading * pi / 180);
91+
break;
92+
case 'Y':
93+
_currentDegree = ((_smoothedHeading - 10) * pi / 180);
94+
break;
95+
case 'Z':
96+
_currentDegree = -((_smoothedHeading + 90) * pi / 180);
97+
break;
98+
}
99+
}
100+
101+
double _getRadiansForAxis(String axis) {
102+
double ax = _accelerometerEvent.x;
103+
double ay = _accelerometerEvent.y;
104+
double az = _accelerometerEvent.z;
105+
double mx = _magnetometerEvent.x;
106+
double my = _magnetometerEvent.y;
107+
double mz = _magnetometerEvent.z;
108+
109+
double pitch = atan2(ay, sqrt(ax * ax + az * az));
110+
double roll = atan2(-ax, az);
111+
112+
double xH = mx * cos(pitch) + mz * sin(pitch);
113+
double yH = mx * sin(roll) * sin(pitch) +
114+
my * cos(roll) -
115+
mz * sin(roll) * cos(pitch);
116+
double zH = -mx * cos(roll) * sin(pitch) +
117+
my * sin(roll) +
118+
mz * cos(roll) * cos(pitch);
119+
120+
switch (axis) {
121+
case 'X':
122+
return atan2(yH, xH);
123+
case 'Y':
124+
return atan2(-xH, zH);
125+
case 'Z':
126+
return atan2(yH, -zH);
127+
default:
128+
return atan2(yH, xH);
129+
}
130+
}
131+
132+
double getDegreeForAxis(String axis) {
133+
double radians = _getRadiansForAxis(axis);
134+
double degree = radians * (180 / pi);
135+
136+
switch (axis) {
137+
case 'X':
138+
degree = (degree - 90) % 360;
139+
break;
140+
case 'Y':
141+
degree = (-degree + 100) % 360;
142+
break;
143+
case 'Z':
144+
degree = (degree + 90) % 360;
145+
break;
146+
}
147+
148+
return degree < 0 ? degree + 360 : degree;
149+
}
150+
151+
void onAxisSelected(String axis) {
152+
_selectedAxis = axis;
153+
switch (axis) {
154+
case 'X':
155+
_direction = 0;
156+
break;
157+
case 'Y':
158+
_direction = 1;
159+
break;
160+
case 'Z':
161+
_direction = 2;
162+
break;
163+
}
164+
notifyListeners();
165+
}
166+
}

lib/providers/locator.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:pslab/communication/handler/ios_comms_handler.dart';
77
import 'package:pslab/communication/science_lab.dart';
88
import 'package:pslab/others/science_lab_common.dart';
99
import 'package:pslab/providers/board_state_provider.dart';
10+
import 'package:pslab/providers/compass_provider.dart';
1011

1112
final GetIt getIt = GetIt.instance;
1213

@@ -23,4 +24,5 @@ void setupLocator() {
2324
getIt.registerLazySingleton<ScienceLab>(
2425
() => getIt.get<ScienceLabCommon>().getScienceLab());
2526
getIt.registerLazySingleton<BoardStateProvider>(() => BoardStateProvider());
27+
getIt.registerLazySingleton<CompassProvider>(() => CompassProvider());
2628
}

0 commit comments

Comments
 (0)