Compute compass title from DeviceOrientation event API

For an augmented reality web application for smartphones, I am trying to calculate the compass heading when the user is holding the device in his hands and the screen is in a vertical plane and the top of the screen is pointing up.

I used the proposed formula from http://dev.w3.org/geo/api/spec-source-orientation (see. Working example) and implemented the following function:

function compassHeading(alpha, beta, gamma) { var a1, a2, b1, b2; if ( beta !== 0 || gamma !== 0 ) { a1 = -Math.cos(alpha) * Math.sin(gamma); a2 = Math.sin(alpha) * Math.sin(beta) * Math.cos(gamma); b1 = -Math.sin(alpha) * Math.sin(gamma); b2 = Math.cos(alpha) * Math.sin(beta) * Math.cos(gamma); return Math.atan((a1 - a2) / (b1 + b2)).toDeg(); } else { return 0; } } 

while.toDeg () is an extension of the object of the Number object http://www.movable-type.co.uk/scripts/latlong.html

 /** Converts radians to numeric (signed) degrees */ if (typeof Number.prototype.toDeg == 'undefined') { Number.prototype.toDeg = function() { return this * 180 / Math.PI; }; } 

However, the problem is that the compass header computed value jumps from about -75 to 80, even if the device (Google Galaxy Nexus) is set to store a static position. This happens in both Google Chrome BETA and FF BETA 23.

Does anyone see a mistake in my approach or know a more reliable way to compass the compass header?

+3
math html5 firefox google-chrome
source share
2 answers

The steps required to determine the compass heading in accordance with the processed example given in the specification * are as follows:

  • Convert the return values ​​of DeviceOrientation alpha , beta and gamma from degrees to radians like alphaRad , betaRad , gammaRad .
  • Calculate the rotation parameters A ( rA ) and rotationB ( rB ) in the processed example in the specification using alphaRad , betaRad and gammaRad (as shown in the example below).
  • Compute compassHeading = Math.atan(rA / rB) .
  • Convert the returned half unit headers to whole unit headers in the range [0-360).
  • Convert compassHeading from radians back to degrees (optional).

Here is the processed example from the specification implemented in JavaScript:

 function compassHeading(alpha, beta, gamma) { // Convert degrees to radians var alphaRad = alpha * (Math.PI / 180); var betaRad = beta * (Math.PI / 180); var gammaRad = gamma * (Math.PI / 180); // Calculate equation components var cA = Math.cos(alphaRad); var sA = Math.sin(alphaRad); var cB = Math.cos(betaRad); var sB = Math.sin(betaRad); var cG = Math.cos(gammaRad); var sG = Math.sin(gammaRad); // Calculate A, B, C rotation components var rA = - cA * sG - sA * sB * cG; var rB = - sA * sG + cA * sB * cG; var rC = - cB * cG; // Calculate compass heading var compassHeading = Math.atan(rA / rB); // Convert from half unit circle to whole unit circle if(rB < 0) { compassHeading += Math.PI; }else if(rA < 0) { compassHeading += 2 * Math.PI; } // Convert radians to degrees compassHeading *= 180 / Math.PI; return compassHeading; } window.addEventListener('deviceorientation', function(evt) { var heading = null; if(evt.absolute === true && evt.alpha !== null) { heading = compassHeading(evt.alpha, evt.beta, evt.gamma); } // Do something with 'heading'... }, false); 

You can also view a demo of the above code .

At the time of this writing (February 17, 2014) this is currently working in:

  • Google Chrome for Android
  • Opera Mobile for Android
  • Firefox Beta for Android

Other browsers do not yet comply with the DeviceOrientation calibration described in the DeviceOrientation event specification and / or do not provide absolute values ​​for DeviceOrientation data, making it impossible to define compassHeading with incomplete data.

* Definition of the compass heading of the horizontal component of the vector, which is orthogonal to the screen of the device and indicates the back of the screen.

+11
source share

I also played with DeviceOrientationEvent (can take the formula ...) and have seen similar problems from time to time. You can try calibration, as in this video . You can search YouTube for more examples.

0
source share

All Articles