gyronorm.js
gyronorm.js copied to clipboard
acceleration normalized to direction of motion
Hi, thanks for this excellent library. My use case is to detect acceleration values relative to the direction of motion in a car. In other words, the device could be kept in any orientation but I'd like the x/y/z to be normalized in the direction of motion. What might be the best settings to use ? So far I am using the following options (which is not producing intended results - depending on how my phone is oriented acc x/y/z report different values when I move)
Also note that in the retuned value, I am seeing absolute:false
- my understanding reading the documentation is this should be true
since I am using WORLD
base
I am testing on iPhone 7 (latest OS update)
let gyroNormArgs = {
logger: function (data) {console.log ("Gyr-log:"+JSON.stringify(data))},
gravityNormalized:true,
orientationBase:GyroNorm.WORLD,
frequency:1000,
screenAdjusted:true,
}
Hello there, I am glad to see the library being used in different use cases. Couple of remarks to clarify the use of parameters and the return values:
The parameters you pass are correct.
orientationBase only efects the deviceOrientation values; alpha, beta and gamma values. The acceleration values stay with respect to the axis' of the device. These values are returned like this from the JS API and GyroNorm passes them to your application.
What you are trying can be achieved by some calculation. Something like... getting the orientation world based and accelerationIncludingGravity and using it to calculate the acceleration in world axis. Gyronorm does not contain such calculation at the moment. So you need to implement on your side. You can also implement within Gyronorm and send a pull-request ;) I'll be more than glad to merge.
One last thing: you need to use the accelerationIncludingGravity values.
Let me know if anything is not clear. Cheers, Doruk
(Edited post - added matrix inversion)
Thanks @dorukeker
I did a bit of reading. It looks like if I normalize the values of gx
gy
and gz
(including gravity) with the inverse of the rotation matrix, I'll get earth co-ordinates.
However I am not getting orientation independent values
import {mat3} from 'gl-matrix';
let gyroNormArgs = {
gravityNormalized:false, // tried true too
orientationBase:GyroNorm.WORLD, // tried .GAME too
frequency:1000,
screenAdjusted:false,
}
Inside the callback with data (gdata):
let alpha = gdata.dm.alpha;
let beta = gdata.dm.beta;
let gamma = gdata.dm.gamma;
let rotatematrix = this.getRotationMatrix(alpha, beta, gamma);
let relativeacc = new Array(3);
let earthacc = new Array(3);
let inv = new Array(9)
relativeacc[0] = gdata.dm.gx;
relativeacc[1] = gdata.dm.gy;
relativeacc[2] = gdata.dm.gy;
mat3.invert(inv,rotatematrix);
mat3.multiply(earthacc, inv, relativeacc);
let accEarthX = earthacc[0];
let accEarthY = earthacc[1];
let accEarthZ = earthacc[2];
console.log (`---RAW DATA --- ` + JSON.stringify(gdata));
console.log (`*** EARTH DATA X=${accEarthX}, Y=${accEarthY} Z=${accEarthZ}`)
The rotation matrix:
// credit:https://stackoverflow.com/a/36662093/1361529
getRotationMatrix(alpha, beta, gamma) {
let out = [];
let _z = alpha;
let _x = beta;
let _y = gamma;
let cX = Math.cos( _x );
let cY = Math.cos( _y );
let cZ = Math.cos( _z );
let sX = Math.sin( _x );
let sY = Math.sin( _y );
let sZ = Math.sin( _z );
out[0] = cZ * cY + sZ * sX * sY, // row 1, col 1
out[1] = cX * sZ, // row 2, col 1
out[2] = - cZ * sY + sZ * sX * cY , // row 3, col 1
out[3] = - cY * sZ + cZ * sX * sY, // row 1, col 2
out[4] = cZ * cX, // row 2, col 2
out[5] = sZ * sY + cZ * cY * sX, // row 3, col 2
out[6] = cX * sY, // row 1, col 3
out[7] = - sX, // row 2, col 3
out[8] = cX * cY // row 3, col 3
return out
};
And here is my output (Phone face up, on table, testing in house):
2017-09-10 19:48:34.458837-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":242.09,"beta":0.4,"gamma":-0.8,"absolute":false},"dm":{"x":0,"y":0,"z":0.13,"gx":-0.13,"gy":-0.07,"gz":-9.67,"alpha":0.02,"beta":0.05,"gamma":0}}
2017-09-10 19:48:34.458906-0400 TripData[6642:2247482] *** EARTH DATA X=-0.13144212418873122, Y=-0.07079655168384706 Z=-0.06641397637870017
2017-09-10 19:48:35.461572-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":242.1,"beta":0.4,"gamma":-0.8,"absolute":false},"dm":{"x":0,"y":0,"z":0.12,"gx":-0.13,"gy":-0.07,"gz":-9.69,"alpha":0.02,"beta":-0.07,"gamma":-0.06}}
2017-09-10 19:48:35.461715-0400 TripData[6642:2247482] *** EARTH DATA X=-0.13524640367025567, Y=-0.06279441851157147 Z=-0.06682268550466884
And here is my output (Phone face down, on table, testing in house):
2017-09-10 19:49:32.592124-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":65.79,"beta":179.79,"gamma":-1,"absolute":false},"dm":{"x":0,"y":0.01,"z":0.1,"gx":-0.04,"gy":-0.16,"gz":9.9,"alpha":0.06,"beta":0.06,"gamma":-0.01}}
2017-09-10 19:49:32.592262-0400 TripData[6642:2247482] *** EARTH DATA X=-0.05167393815904252, Y=-0.16648286542066582 Z=-0.14971058625381142
2017-09-10 19:49:33.598502-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":65.8,"beta":179.79,"gamma":-1,"absolute":false},"dm":{"x":-0.01,"y":0,"z":0.09,"gx":-0.05,"gy":-0.17,"gz":9.9,"alpha":-0.01,"beta":-0.06,"gamma":0.11}}
2017-09-10 19:49:33.598629-0400 TripData[6642:2247482] *** EARTH DATA X=-0.02944164169071515, Y=-0.1595350723662996 Z=-0.18434139638083227
2017-09-10 19:49:34.594939-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":65.8,"beta":179.79,"gamma":-1,"absolute":false},"dm":{"x":-0.01,"y":0,"z":0.11,"gx":-0.04,"gy":-0.17,"gz":9.91,"alpha":-0.07,"beta":-0.06,"gamma":0.05}}
2017-09-10 19:49:34.595080-0400 TripData[6642:2247482] *** EARTH DATA X=-0.020228116574781345, Y=-0.16120266970200792 Z=-0.18167146881330154
And here is my output (Phone face up, somewhat perpendicular to table, testing in house):
2017-09-10 19:50:52.147809-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":221.25,"beta":83.19,"gamma":5.78,"absolute":false},"dm":{"x":-0.02,"y":0.02,"z":-0.04,"gx":0.1,"gy":-9.71,"gz":-1.19,"alpha":1.33,"beta":0.21,"gamma":-0.25}}
2017-09-10 19:50:52.147943-0400 TripData[6642:2247482] *** EARTH DATA X=-11.682112584452096, Y=-0.49477805209007863 Z=-7.201502637877455
2017-09-10 19:50:53.147058-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":221.15,"beta":83.36,"gamma":5.9,"absolute":false},"dm":{"x":-0.03,"y":0.03,"z":0.02,"gx":0.09,"gy":-9.72,"gz":-1.11,"alpha":-0.69,"beta":0.39,"gamma":-0.11}}
2017-09-10 19:50:53.147192-0400 TripData[6642:2247482] *** EARTH DATA X=7.309035050034833, Y=-10.39162106453064 Z=-5.249487431032232
2017-09-10 19:50:54.147017-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":221.87,"beta":83.48,"gamma":5.16,"absolute":false},"dm":{"x":0,"y":0.04,"z":-0.01,"gx":0.1,"gy":-9.7,"gz":-1.12,"alpha":0.47,"beta":-1.02,"gamma":0.42}}
2017-09-10 19:50:54.147151-0400 TripData[6642:2247482] *** EARTH DATA X=4.71089937390668, Y=0.3389442491438679 Z=-12.879539738860931
2017-09-10 19:50:55.147900-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":221.78,"beta":83.58,"gamma":5.25,"absolute":false},"dm":{"x":-0.02,"y":0.01,"z":-0.01,"gx":0.08,"gy":-9.73,"gz":-1.1,"alpha":-1.12,"beta":0.39,"gamma":-0.29}}
2017-09-10 19:50:55.148033-0400 TripData[6642:2247482] *** EARTH DATA X=10.120001205152024, Y=-7.904409539460901 Z=-4.945511645947363
2017-09-10 19:50:56.177822-0400 TripData[6642:2247482] ---RAW DATA --- {"do":{"alpha":231.77,"beta":83.98,"gamma":-2.92,"absolute":false},"dm":{"x":-0.02,"y":0.18,"z":0.11,"gx":-0.08,"gy":-9.58,"gz":-0.92,"alpha":-9.31,"beta":0.07,"gamma":0.38}}
As you see above, the readings are dependent on orientation and angle. What am I missing? Thank you.
Hello there @arjunroychowdhury Wow that is some maths. Frankly speaking I am not very good at the matrix operations. Having said that I see in the code you are using the angles from the deviceMotion
let alpha = gdata.dm.alpha;
let beta = gdata.dm.beta;
let gamma = gdata.dm.gamma;
Which are the change rates in these angles; not actual orientation. The orientation are in the deviceOrientation. Like this:
let alpha = gdata.do.alpha;
let beta = gdata.do.beta;
let gamma = gdata.do.gamma;
// do instead of dm
Can this be what you are looking for? Also try to switch orientation base as you mentioned. (WORLD or GAME) Not sure which one should give you the result you are looking for.
Cheers, Doruk
Hi All,
Did you figure this out?
I'll be attempting this as well and would like to save some some time and troubles.
@arjunroychowdhury @ziqbal Anyone figure this out?
@marcusx2 I never found the time to check the last feedback from dorukeker. Maybe it works. My advice is that if you're targeting a single device then you should use whatever is provided on that platform, otherwise a generic library to do absolute orientation on all devices and platforms is going to be a serious PITA. Especially when libraries become out of date and "features" become deprecated and obsolete.