Position XYZ à partir des données de l'accéléromètre (devicemotion)

a marqué ce sujet comme résolu.

Bonjour,

JE vais sûrement être très ridicule avec ce sujet, mais enfin… je n’ai rien trouvé sur la toile qui réponde à ma question, et pourtant elle paraît assez évidente je pense.

JE développe un jeu HTML5/JavaScript… du moins j’essaye.

A partir des données envoyées par la’ccéléromètre via l’évènement devicemotion, j’aimerais connaître la position absolue de mon téléphone dans l’espace (coordonnées X, Y, Z).

Pour que ce soit bien clair, il ne s’agit évidemment pas de coordonnées GPS ici, mais de coordonées absolues à partir d’un point de référence. Point de référence (0;0;0) qui sera probablement par convention la position du téléphone au moment où le jeu est démarré ou celui où le premier évènement est envoyé. Mais il y a probablement de nombreuses choses qui m’échappent avant de parvenir au but.

En faisant des recherches, j’ai trouvé 2-3 choses concernant l’orientation et la rotation (deviceorientation). Par contre très peu pour devicemotion. Est-ce que ce que je cherche à faire est impossible en fait ? OU beaucoup trop compliqué pour ce que je veux en faire ? (Ce qui expliquerait pourquoi Google n’a pas envie d’être beaucoup mon ami). C’est pour un jeu, donc pas non plus besoin d’une précision au millimètre. Si c’est impossible ou trop compliqué, comment font les jeux mobile habituellement ? OU même les podomètres… Deviceorientation à lui seul n’est pas suffisant pour calculer une position absolue en (X;Y;Z), si ?

Ce que je voudrais c’est ceci: le jeu démarre, je suis en position (0;0;0). Je ne bouge pas, je reste à (0;0;0). JE glisse mon téléphone sur la table, sur 1m, vers la droite et ja’rrive en (1;0;0). Si je reviens à ma position de départ et que je le pousse loin de moi, je dois arriver en (0;1;0), et enfin si je le décolle verticalement de la table, c’est l’axe (0;0;1). Évidemment en vrai dans le jeu final le téléphone n’est pas destiné à rester à plat, mieux vaudrait avoir 1m50 de libre autour de soi.

Visiblement je m’y prends très mal, puisque les chiffres bougent tout seuls même si je laisse mon téléphone posé à plat sur la table et que je ne le touche pas. Et les variations sont loin d’être anodines puisqu’en une minute le script croit facilement que j’ai bougé de 100m alors qu’en réalité il est resté posé là. Suis-je totalement à côté de la plaque ? Qu’est-ce que je dois faire ? Vous avez au moins quelques pistes, un algorithme ?

Je ne sais pas si ça a une importance, au cas où je fais mes essais sur un iPhone (iOS 10.3.3) qui a Safari et Firefox. Même constatation dans les deux cas, X et Y augmentent, Z diminue fortement, même si je ne fais rien. Si j’essaie de compenser l’augmentation de X en glissant le téléphone sur la table vers la gauche, X se met alors à diminuer, mais continue à diminuer même si je ne bouge plus.

Voici mon code actuel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let x=0, y=0, z=0, vx=0, vy=0, vz=0;

window.addEventListener('devicemotion', function(e){
let a = e.acceleration, i = e.interval;
let ax = a.x*i, ay=a.y*i, az=a.z*i; // L'accélération est censée être en m/s², donc je la multiplie par l'intervalle pour avoir la'ccélération durant le dernier intervalle
vx+=ax*i; vy+=ay*i; vz+=az*i; // ON met à jour la vitesse
x+=vx; y+=vy; z+=vz; // et la position
if (!timer) timer = setTimeout(__=>{ // On temporise l'affichage parce que sinon ça va tellement vite qu'on n'arrive pas à lire. L'intervalle est souvent de 16.67ms.
timer=null;
let X=Math.round(100*x), Y=Math.round(100*y), Z=Math.round(100*z); // à ce state je suis censé afficher une position au centimètre
info.innerHTML = X + ', ' + Y + ', ' + Z;
}, 1000);
});

Merci pour votre aide.

+0 -0

Malheureusement, tu es confronté à ce qu’on appelle le drift.

Les accéléromètres ont la fâcheuse tendance à ne pas être stable. Si tu fais une simple intégration des données, tu es sûr de te retrouver avec des données de plus en plus erronées. Il faut que tu filtres tes entrées.

Edit: après, 100 mètres en une minute ça me paraît beaucoup pour du drift ^^

+0 -0

Les accéléromètres ont la fâcheuse tendance à ne pas être stable. Si tu fais une simple intégration des données, tu es sûr de te retrouver avec des données de plus en plus erronées. Il faut que tu filtres tes entrées.

Ah ? Et comment s’y prend-on pour filtrer les données ?

Petit rappel de math

Tu n’as peut-être pas 100% tort, je n’ai peut-être pas tout juste, je pense qu’il doit me manquer un facteur 2 quelque part puisque $x = 1/2 a t^2$. Mais je verrai plus tard, ça n’explique pas mon premier problème, cette histoire de filtre.

+0 -0

Je dirais bien un filtre de Kalman à tout hasard.

Hmmm… d’après la page wikipedia, ça n’a pas l’air si simple que ça. Il faut que je trouve une lib ou quelque chose qui peut le faire, en js donc.

Merci pour vos réponses jusqu’ici.

+0 -0

Sinon, peux-tu fournir un tableau avec une mesure chaque seconde de ton accélération mesurée en X, Y et Z avec le téléphone posé sur la table ?

Oui, voici: http://vrac.quentinc.net/accelerometer.json

Je l’ai laissé tourner 1 minute, il enregistre à peu près 60 échantillons par seconde; je ne peux pas ralentir la cadence. Pour être vraiment sûr, pendant qu’il enregistrait, j’ai même fait attention d’enlever mes mains de la table

Le fichier fait 367 Ko, en voici le début. Les temps sont en secondes.

1
[{"time":0.01666666753590107,"x":0.011777076039212988,"y":0.00497206991619314,"z":-0.07408888017013669},{"time":0.03333333507180214,"x":0.011777076039212988,"y":0.00497206991619314,"z":-0.07408888017013669}, ...]
+0 -0

J’ai regardé tes valeurs et écrit un petit programme, effectivement, ça part loin si on ne fait rien :P

Pour le filtre de Kalman, tu peux transformer le code dans le cookbook de scipy.

Je l’ai utilisé sur tes valeurs (uniquement en x), et j’obtiens ça :

Application d’un filtre de Kalman en considérant un bruitage faible
Application d’un filtre de Kalman en considérant un bruitage fort

Comme tu le vois, c’est beaucoup plus stable après le filtrage.

Le travail ne s’arrête pas là. L’accéléromètre captant mieux l’accélération que la décélération (même si c’est une accélération en sens inverse, ne chipotons pas !) Il faut toujours que tu réduises ta vitesse après l’avoir utilisé dans tes calculs. En la multipliant par un facteur entre 0 et 1 (plutôt proche de 1) à chaque fois, elle devrait tendre vers 0 quand il n’y a pas d’accélération.

+0 -0

Bonsoir,

J’ai essayé d’adapter l’algorithme mis en lien et suivi ton conseil. Ca a l’air d’aller un peu mieux mais ce n’est encore pas ça.

Le téléphone croit toujours qu’il se déplace dans une direction plus ou moins constante (x croît, y croît, z décroît). Moins vite qu’avant, mais toujours.

Si c’était vraiment du bruit dans la mesure, les valeurs variraient mais tourneraient globalement toujours autour de 0 quand même non ? Là ça paraît vraiment être du bruit que j’appellerais dirigé, ou biaisé, toujours dans la même direction. Bref c’est clairement pas du bruit random.

Cette fois-ci j’ai essayé de bouger un peu, en glissant le téléphone sur la table, doucement, puis un peu plus vite. Je n’ai pas l’impression de voir beaucoup de différence dans les valeurs par rapport à quand je reste immobile. Sur l’axe des X j’ai quelques semblants, mais sur l’axe des Y pas trop, et ne parlons même pas de l’axe Z où le téléphone reste en simili de chute libre.

J’ai essayé de jouer avec les paramètres Q, R et Mu… rien de très concluant.

Je n’ai peut-être pas adapté l’exemple correctement ? J’ai cru déduire du code d’exemple que l’algorithme ne gardait pas en mémoire plus que la mesure précédente. Voici les parties de mon code qui ont changé:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Initialisation
const Mu = 0.9, Q = 1e-5, R = 0.1 ** 2;
let x=0, y=0, z=0, vx=0, vy=0, vz=0,
xHat=0, yHat=0, zHat=0, xHatMinus, yHatMinus, zHatMinus, px=1, py=1, pz=1, pxMinus, pyMinus, pzMinus, kx, ky, kz;

// ET dans la fonction ondevicemotion
let a = e.acceleration, i = e.interval;
let ax = a.x*i, ay=a.y*i, az=a.z*i;
xHatMinus=xHat; yHatMinus=yHat; zHatMinus=zHat;
pxMinus = px+Q; pyMinus = py+Q; pzMinus=pz+Q;
kx = pxMinus / (pxMinus + R);
ky = pyMinus / (pyMinus + R);
kz = pzMinus / (pzMinus + R);
xHat = xHatMinus + kx * (ax -xHatMinus);
yHat = yHatMinus + ky * (ay -yHatMinus);
zHat = zHatMinus + kz * (az -zHatMinus);
px = (1-kx) * pxMinus;
py = (1-ky) * pyMinus;
pz = (1-kz) * pzMinus;
vx+=xHat*i; vy+=yHat*i; vz+=zHat*i;
x+=vx; y+=vy; z+=vz;
vx*=Mu; vy*=Mu; vz*=Mu;

Merci.

+0 -0

Je viens de tomber sur ce site. Il correspond exactement à ce que tu veux faire. :)

Non, le bruit moyen ne tourne pas forcément autour de 0 sinon la courbe sur le filtre de Kalman serait sur le 0, ou très proche (car il n’y a pas forcément convergence). C’est pour cela qu’il faut faire une estimation du bruit.

ne parlons même pas de l’axe Z où le téléphone reste en simili de chute libre

QuentinC

Chez moi une application qui m’affiche les valeurs des capteurs de mon téléphone (à plat sur la table) m’indique que le devicemotion en z n’est pas loin de -9.81, constamment. Coïncidence ? Je ne crois pas. On ne voit pas ce genre de comportement sur les extraits que tu as fourni mais ce que tu décris m’y fait penser.

ne parlons même pas de l’axe Z où le téléphone reste en simili de chute libre

QuentinC

Chez moi une application qui m’affiche les valeurs des capteurs de mon téléphone (à plat sur la table) m’indique que le devicemotion en z n’est pas loin de -9.81, constamment. Coïncidence ? Je ne crois pas. On ne voit pas ce genre de comportement sur les extraits que tu as fourni mais ce que tu décris m’y fait penser.

tleb

La bibliothèque retire la gravité d’après ce que j’ai lu (ou il faut la demander explicitement).

Au fait, l’effet "chute libre" du capteur posé à plat sur une table est dû au calibrage, non?

ThomasC

Je ne comprends pas ce que tu entends par effet "chute libre". En cas de chute libre, l’accélération devrait avoisiner 0 (le capteur et sa masse tombent à la même vitesse). Sur une table, tu as donc les +/- 9.81 m/s² (retirés par la lib).

Effectivement, s’il est mal calibré, ça part n’importe où.

Sinon, tu peux toujours ajouter des zones mortes. Si l’accélération est faible, tu considères que c’est 0.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte