I'm trying to create a reliable compass in Javascript/JQuery (using deviceorientation) so that it works on iOS and Android mobile devices. I know nearly every (very old) question/answer here in Stackoverflow about this topic. I have created a pretty simple compass that is working fine on iOS devices. On Android devices (Galaxy S8) I have a weird behaviour: Like every day I'm testing it the compass direction North switches by an offset to -45/+45, 90 (North is in East), 180 (North is in South) or 270 degrees (North is in West). Yes, I considered compass calibration (8-figure movement, turning the mobile around it's 3 axes before testing).
Here's the Javascript code for the compass:
if (isIos()) // // Function in the background evaluating OS
{
window.addEventListener('deviceorientation', function(event) {
var alpha;
// Use Webkit heading for iOS
alpha = event.webkitCompassHeading;
if (alpha < 0) { alpha += 360; }
if (alpha > 360) { alpha -= 360; }
// Calculated heading
console.log (alpha);
});
}
else {
// Any other device, with Chrome browser
if ('ondeviceorientationabsolute' in window) {
// Chrome 50+ specific
window.addEventListener('deviceorientationabsolute', function (event) {
var alpha = 360 - event.alpha;
if (alpha < 0) { alpha += 360; }
if (alpha > 360) { alpha -= 360; }
// Calculated heading
console.log (alpha);
});
}
else {
window.addEventListener('deviceorientation', function (event) {
var alpha = 180 - event.alpha;
if (alpha < 0) {
alpha += 360;
}
if (alpha > 360) {
alpha -= 360;
}
// Calculated heading
console.log (alpha);
});
}
}
In short:
I am aware I have to consider also beta and gamma axis. For my tests I put the mobile on a table, so only alpha is relevant.
By my research I've found a very advanced/complete javascript compass mentioned in Stackoverflow (fulltilt-min.js) considering all 3 axes. Here's the demo to it. Even this compass shows me the exactly same wrong heading as my compass does.
So can anyone explain this behaviour on Android mobiles or knows how to fix that?
The problem is that your alpha is not absolute, means 0 is not north instead 0 is where the device is pointing on activation.
The best way to fix for chrome-based browsers, like most standard Android Browsers ist using an AbsoluteOrientationSensor from W3C Generic Sensor API polyfills. Github
The Project I used it in is Typescript based. So here is a Typescript example:
import {AbsoluteOrientationSensor} from 'motion-sensors-polyfill'
const options = { frequency: 60, referenceFrame: 'device' };
const sensor = new AbsoluteOrientationSensor(options);
sensor.addEventListener('reading', e => {
//this.zone.run() if you are using an Angular Project to run it in the context of the component.
//If you using plain Javascript, you don't need this
this.zone.run(() => {
var q = e.target.quaternion;
let alpha = Math.atan2(2*q[0]*q[1] + 2*q[2]*q[3], 1 - 2*q[1]*q[1] - 2*q[2]*q[2])*(180/Math.PI);
if(alpha < 0) alpha = 360+ alpha;
this.rotateCompassClockwise(360 - alpha)
})
});
sensor.start();