For an augmented reality web app for smartphones I\'m trying to calculate the compass heading when the user is holding the device in their hand, with the screen in a vertica
I have also played some with the DeviceOrientationEvent (might adopt you formula...) and seen similar problems from time to time. You might wanna try a calibration as in this video. You could search youtube for more examples.
It seems that getting compass heading from device orientation events is deprecated, perhaps for privacy reasons. You should look at the Geolocation API, which requires permissions. The events have Coordinates.heading.
The steps you need to determine the compass heading according to the worked example provided in the specification* are as follows:
alpha
, beta
and gamma
values from degrees to radians as alphaRad
, betaRad
, gammaRad
.rA
) and rotationB (rB
) components per the worked example in the specification using alphaRad
, betaRad
and gammaRad
(as shown in the example code below).compassHeading = Math.atan(rA / rB)
.compassHeading
from radians back to degrees (optional).Here is the worked 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 code provided above.
As of the time of writing (17th Feb 2014) this currently works in:
Other browsers do not yet conform to the DeviceOrientation calibration described in the DeviceOrientation Event specification and/or do not provide absolute
DeviceOrientation data values making it impossible to determine compassHeading
with non-complete data.
* Determining the compass heading of the horizontal component of a vector which is orthogonal to the device's screen and pointing out of the back of the screen.