Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a reliable compass for iOS and Android in Javascript?

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:

  • iOS (iPhone, iPad): use event.webkitCompassHeading -> works fine
  • Chrome: use ondeviceorientationabsolute -> leads to described deviation problem
  • Else: deviceorientation considering alpha -> leads to described deviation problem

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?

like image 970
Jonny Avatar asked Jul 30 '18 11:07

Jonny


Video Answer


1 Answers

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();
like image 174
Buzzet Avatar answered Oct 22 '22 13:10

Buzzet