Skip to content

Commit 8eb04be

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

File tree

8 files changed

+389
-2
lines changed

8 files changed

+389
-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: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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+
// Clean up subscriptions
53+
void disposeSensors() {
54+
_magnetometerSubscription?.cancel();
55+
_accelerometerSubscription?.cancel();
56+
}
57+
58+
@override
59+
void dispose() {
60+
disposeSensors();
61+
super.dispose();
62+
}
63+
64+
void _updateCompassDirection() {
65+
double radians = _getRadiansForAxis(_selectedAxis);
66+
double degrees = radians * (180 / pi);
67+
if (degrees < 0) {
68+
degrees += 360;
69+
}
70+
71+
degrees = (degrees - 90) % 360;
72+
if (degrees < 0) {
73+
degrees += 360;
74+
}
75+
76+
const double alpha = 0.45;
77+
double angleDiff = degrees - _smoothedHeading;
78+
if (angleDiff > 180) {
79+
angleDiff -= 360;
80+
} else if (angleDiff < -180) {
81+
angleDiff += 360;
82+
}
83+
_smoothedHeading = _smoothedHeading + alpha * angleDiff;
84+
if (_smoothedHeading >= 360) {
85+
_smoothedHeading -= 360;
86+
} else if (_smoothedHeading < 0) {
87+
_smoothedHeading += 360;
88+
}
89+
switch (_selectedAxis) {
90+
case 'X':
91+
_currentDegree = -(_smoothedHeading * pi / 180);
92+
break;
93+
case 'Y':
94+
_currentDegree = ((_smoothedHeading - 10) * pi / 180);
95+
break;
96+
case 'Z':
97+
_currentDegree = -((_smoothedHeading + 90) * pi / 180);
98+
break;
99+
}
100+
}
101+
102+
double _getRadiansForAxis(String axis) {
103+
double ax = _accelerometerEvent.x;
104+
double ay = _accelerometerEvent.y;
105+
double az = _accelerometerEvent.z;
106+
double mx = _magnetometerEvent.x;
107+
double my = _magnetometerEvent.y;
108+
double mz = _magnetometerEvent.z;
109+
110+
double pitch = atan2(ay, sqrt(ax * ax + az * az));
111+
double roll = atan2(-ax, az);
112+
113+
double xH = mx * cos(pitch) + mz * sin(pitch);
114+
double yH = mx * sin(roll) * sin(pitch) +
115+
my * cos(roll) -
116+
mz * sin(roll) * cos(pitch);
117+
double zH = -mx * cos(roll) * sin(pitch) +
118+
my * sin(roll) +
119+
mz * cos(roll) * cos(pitch);
120+
121+
switch (axis) {
122+
case 'X':
123+
return atan2(yH, xH);
124+
case 'Y':
125+
return atan2(-xH, zH);
126+
case 'Z':
127+
return atan2(yH, -zH);
128+
default:
129+
return atan2(yH, xH);
130+
}
131+
}
132+
133+
double getDegreeForAxis(String axis) {
134+
double radians = _getRadiansForAxis(axis);
135+
double degree = radians * (180 / pi);
136+
137+
switch (axis) {
138+
case 'X':
139+
degree = (degree - 90) % 360;
140+
break;
141+
case 'Y':
142+
degree = (-degree + 100) % 360;
143+
break;
144+
case 'Z':
145+
degree = (degree + 90) % 360;
146+
break;
147+
}
148+
149+
return degree < 0 ? degree + 360 : degree;
150+
}
151+
152+
void onAxisSelected(String axis) {
153+
_selectedAxis = axis;
154+
switch (axis) {
155+
case 'X':
156+
_direction = 0;
157+
break;
158+
case 'Y':
159+
_direction = 1;
160+
break;
161+
case 'Z':
162+
_direction = 2;
163+
break;
164+
}
165+
notifyListeners();
166+
}
167+
}

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)