53 lines
1.5 KiB
Dart
53 lines
1.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:math' as math;
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:sensors_plus/sensors_plus.dart';
|
|
|
|
final compassServiceProvider = Provider<CompassService>((ref) {
|
|
return CompassService();
|
|
});
|
|
|
|
final headingStreamProvider = StreamProvider<double>((ref) {
|
|
return ref.watch(compassServiceProvider).headingStream;
|
|
});
|
|
|
|
class CompassService {
|
|
final _headingController = StreamController<double>.broadcast();
|
|
StreamSubscription? _magSub;
|
|
|
|
Stream<double> get headingStream => _headingController.stream;
|
|
|
|
CompassService() {
|
|
_startSensors();
|
|
}
|
|
|
|
void _startSensors() {
|
|
_magSub = magnetometerEventStream(samplingPeriod: const Duration(milliseconds: 200)).listen((MagnetometerEvent event) {
|
|
// Calculate heading from magnetometer (X and Y components).
|
|
// Note: For a phone mounted vertically on a motorcycle, the axes might need mapping.
|
|
// This calculates basic 2D heading assuming phone is flat.
|
|
// Full tilt-compensated compass requires accelerometer fusion.
|
|
|
|
double heading = math.atan2(event.y, event.x) * (180.0 / math.pi);
|
|
|
|
// Adjust to 0-360 degrees
|
|
if (heading < 0) {
|
|
heading += 360;
|
|
}
|
|
|
|
_headingController.add(heading);
|
|
});
|
|
}
|
|
|
|
static String getHeadingString(double heading) {
|
|
const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
|
|
final index = ((heading + 22.5) % 360 / 45).floor();
|
|
return directions[index];
|
|
}
|
|
|
|
void dispose() {
|
|
_magSub?.cancel();
|
|
_headingController.close();
|
|
}
|
|
}
|