Skip to content

feat: implementation of the Compass page #2710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: flutter
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/icons/compass_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
<string>Main</string>
<key>NSMicrophoneUsageDescription</key>
<string>App needs Microphone access to capture audio</string>
<key>NSMotionUsageDescription</key>
<string>This app uses motion sensors to determine compass direction.</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
Expand Down
4 changes: 4 additions & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ List<String> connectWithUs = [
'Developers'
];
String softwareLicenses = 'Software Licenses';
String magnetometerError = 'Magnetometer error:';
String accelerometerError = 'Accelerometer error:';
String compassTitle = 'Compass';
String parallelToGround = 'Select axes parallel to ground';
String tryDifferentSearchSuggestion = 'Try a different search term';
String noInstrumentsFoundMessage = 'No instruments found';
String searchInstrumentsHint = 'Search instruments...';
Expand Down
2 changes: 2 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:pslab/view/robotic_arm_screen.dart';
import 'package:pslab/view/settings_screen.dart';
import 'package:pslab/view/about_us_screen.dart';
import 'package:pslab/view/software_licenses_screen.dart';
import 'package:pslab/view/compass_screen.dart';
import 'package:pslab/theme/app_theme.dart';
import 'package:pslab/view/soundmeter_screen.dart';
import 'constants.dart';
Expand Down Expand Up @@ -48,6 +49,7 @@ class MyApp extends StatelessWidget {
routes: {
'/': (context) => const InstrumentsScreen(),
'/oscilloscope': (context) => const OscilloscopeScreen(),
'/compass': (context) => const CompassScreen(),
'/connectDevice': (context) => const ConnectDeviceScreen(),
'/faq': (context) => const FAQScreen(),
'/settings': (context) => const SettingsScreen(),
Expand Down
169 changes: 169 additions & 0 deletions lib/providers/compass_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:sensors_plus/sensors_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:pslab/others/logger_service.dart';

import '../constants.dart';

class CompassProvider extends ChangeNotifier {
MagnetometerEvent _magnetometerEvent =
MagnetometerEvent(0, 0, 0, DateTime.now());
AccelerometerEvent _accelerometerEvent =
AccelerometerEvent(0, 0, 0, DateTime.now());
StreamSubscription? _magnetometerSubscription;
StreamSubscription? _accelerometerSubscription;
String _selectedAxis = 'X';
double _currentDegree = 0.0;
int _direction = 0;
double _smoothedHeading = 0.0;

MagnetometerEvent get magnetometerEvent => _magnetometerEvent;
AccelerometerEvent get accelerometerEvent => _accelerometerEvent;
String get selectedAxis => _selectedAxis;
double get currentDegree => _currentDegree;
int get direction => _direction;
double get smoothedHeading => _smoothedHeading;

void initializeSensors() {
_magnetometerSubscription = magnetometerEventStream().listen(
(event) {
_magnetometerEvent = event;
_updateCompassDirection();
notifyListeners();
},
onError: (error) {
logger.e("$magnetometerError: $error");
},
cancelOnError: false,
);

_accelerometerSubscription = accelerometerEventStream().listen(
(event) {
_accelerometerEvent = event;
_updateCompassDirection();
notifyListeners();
},
onError: (error) {
logger.e("$accelerometerError: $error");
},
cancelOnError: false,
);
}

void disposeSensors() {
_magnetometerSubscription?.cancel();
_accelerometerSubscription?.cancel();
}

@override
void dispose() {
disposeSensors();
super.dispose();
}

void _updateCompassDirection() {
double radians = _getRadiansForAxis(_selectedAxis);
double degrees = radians * (180 / pi);
if (degrees < 0) {
degrees += 360;
}

degrees = (degrees - 90) % 360;
if (degrees < 0) {
degrees += 360;
}

const double alpha = 0.45;
double angleDiff = degrees - _smoothedHeading;
if (angleDiff > 180) {
angleDiff -= 360;
} else if (angleDiff < -180) {
angleDiff += 360;
}
_smoothedHeading = _smoothedHeading + alpha * angleDiff;
if (_smoothedHeading >= 360) {
_smoothedHeading -= 360;
} else if (_smoothedHeading < 0) {
_smoothedHeading += 360;
}
switch (_selectedAxis) {
case 'X':
_currentDegree = -(_smoothedHeading * pi / 180);
break;
case 'Y':
_currentDegree = ((_smoothedHeading - 10) * pi / 180);
break;
case 'Z':
_currentDegree = -((_smoothedHeading + 90) * pi / 180);
break;
}
}

double _getRadiansForAxis(String axis) {
double ax = _accelerometerEvent.x;
double ay = _accelerometerEvent.y;
double az = _accelerometerEvent.z;
double mx = _magnetometerEvent.x;
double my = _magnetometerEvent.y;
double mz = _magnetometerEvent.z;

double pitch = atan2(ay, sqrt(ax * ax + az * az));
double roll = atan2(-ax, az);

double xH = mx * cos(pitch) + mz * sin(pitch);
double yH = mx * sin(roll) * sin(pitch) +
my * cos(roll) -
mz * sin(roll) * cos(pitch);
double zH = -mx * cos(roll) * sin(pitch) +
my * sin(roll) +
mz * cos(roll) * cos(pitch);

switch (axis) {
case 'X':
return atan2(yH, xH);
case 'Y':
return atan2(-xH, zH);
case 'Z':
return atan2(yH, -zH);
default:
return atan2(yH, xH);
}
}

double getDegreeForAxis(String axis) {
double radians = _getRadiansForAxis(axis);
double degree = radians * (180 / pi);

switch (axis) {
case 'X':
degree = (degree - 90) % 360;
break;
case 'Y':
degree = (-degree + 100) % 360;
break;
case 'Z':
degree = (degree + 90) % 360;
break;
}

return degree < 0 ? degree + 360 : degree;
}

void onAxisSelected(String axis) {
_selectedAxis = axis;
switch (axis) {
case 'X':
_direction = 0;
break;
case 'Y':
_direction = 1;
break;
case 'Z':
_direction = 2;
break;
}
notifyListeners();
}
}
Loading