I'm trying to get the change in orientation between two deviceorientation
events along the left-right axis, and top-bottom axis, those axis being usually defined as the phone x
and y
axis (https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained)
ie between instants t1
and t2
where those phone axis move from (x1, y1)
to (x2, y2)
, It'd like to get (angle(x2-x1), angle(y1-y2))
.
When the device is in portrait mode (in opposition to landscape mode), those axis seems to correspond to the beta
and gamma
. However when the phone is vertical (bottom facing the ground), the gamma
value becomes extremely instable, and jumps from 90 to -90 degrees (at the same occasion, the alpha jumps by 180 degrees) You can easily see that here on your phone
I'd like to avoid that, and also get values in the 360 range. Here is what I have so far:
// assuming portrait mode
var beta0, gamma0;
window.addEventListener('deviceorientation', function(orientation) {
if (typeof beta0 === 'undefined') {
beta0 = beta;
gamma0 = gamma;
}
console.log('user has moved to the left by', gamma - gamma0, ' and to the top by', beta - beta0);
});
That works ok when the device is mostly horizontal, and not at all when it is vertical
All right. First, a simple explanation of the device orientation input:
The absolute coordinate system,
(X, Y, Z)
is such thatX
is East,Y
is North andZ
is up. The device relative coordinate system,(x, y, z)
is such thatx
is right,y
is top andz
is up. Then the orientation angles,(alpha, beta, gamma)
are the angles that describe the succession of three simple rotations that change(X, Y, Z)
to(x, y, z)
as so:Z
byalpha
degrees, which transforms(X, Y, Z)
to(X', Y', Z')
withZ'
=Z
X'
bybeta
degrees, which transforms(X', Y', Z')
to(X'', Y'', Z'')
withX''
=X'
Y''
bygamma
degrees, which transforms(X'', Y'', Z'')
to(x, y, z)
withy
=Y''
(they are called intrinsic Tait-Bryan angles of type
Z-X'-Y''
)Now we can get the corresponding rotation matrix by composing simple rotation matrix that each correspond to one of the three rotations.
where
A, B, C
are short foralpha, beta, gamma
ands, c
forsin, cos
.Now, we are interested in the angles of the right-left (
y
axis) and top-down (x
axis) rotations deltas between two positions(x, y, z)
and(x', y', z')
that correspond to the orientations(A, B, C)
and(A', B', C')
The coordinates of
(x', y', z')
in term of(x, y, z)
are given byR(A', B', C') * R(A, B, C)^-1 = R(A', B', C') * R(A, B, C)^T
since the inverse is the transpose for orthogonal (rotation) matrix. Finally, ifz' = p*x + q*y + r*z
, the angle of those rotations arep
around the right-left axis andq
around the top-down one (this is true for small angles, which assume frequent orientation update, elseasin(p)
andasin(r)
are closer from the truth)So here is some javascript to get the rotation matrix:
and now we get the angular deltas:
Finally, to account for screen orientation, we have to replace
by
Note that the cumulative right-left and top-bottom angles will depend of the path chosen by the user, and cannot be infer directly from the device orientation but have to be tracked through the movement. You can arrive to the same position with different movements:
method 1:
method 2: