Je veux construire une application qui calcule avec précision la distance parcourue par l'iPhone (pas de longue distance) à l'aide de Gyro + Accelerometer. Pas besoin de GPS ici.
Comment devrais-je aborder ce problème?
Le calcul de base derrière ce problème est dans l'expression
(et expressions similaires pour les déplacements en y et z) et la géométrie de base est le théorème de Pythagore
Ainsi, une fois que les signaux de votre accéléromètre sont passés à travers un filtre passe-bas et regroupés dans le temps avec un intervalle d'échantillonnage dt, vous pouvez trouver le déplacement dans x comme ( pardon my C ... )
float dx=0.0f;
float vx=0.0f;
for (int i=1; i<n; i++)
{
vx+=(acceleration_x[i-1] + acceleration_x[i])/2.0f*dt;
dx+=vx*dt;
}
et de même pour dy et dz. Ici
float acceleration_x[n];
contient les valeurs d'accélération x du début à la fin de la mesure aux moments 0, dt, 2 * dt, 3 * dt, ... (n-1) * dt.
Pour trouver le déplacement total, il suffit de faire
dl=sqrt(dx*dx + dy*dy + dz*dz);
Le gyroscope n'est pas nécessaire pour cela, mais si vous mesurez des distances linéaires, vous pouvez utiliser la lecture du gyroscope pour contrôler que la rotation de l'appareil n'est pas trop importante. Si la rotation était trop forte, demandez à l'utilisateur de refaire la mesure.
Vous obtenez la position en intégrant l'accélération linéaire deux fois mais l'erreur est horrible. C'est inutile en pratique.
Voici une explication pourquoi (Google Tech Talk) à 23h20. Je recommande fortement cette vidéo.
Questions similaires:
Quelle est la précision réelle des accéléromètres téléphoniques utilisés pour le positionnement?
comment calculer le mouvement du téléphone dans le sens vertical depuis le repos?
Comment utiliser Accelerometer pour mesurer la distance pour le développement d'applications Android
Mise à jour (24 février 2013): @Simon Oui, si vous en savez plus sur le mouvement, par exemple une personne qui marche et que le capteur est sur son pied, vous pouvez en faire beaucoup plus. Ceux-ci s'appellent
hypothèses spécifiques au domaine.
Ils se brisent lamentablement si les hypothèses ne sont pas vérifiées et peuvent être assez lourdes à mettre en œuvre. Néanmoins, s'ils fonctionnent, vous pouvez faire des choses amusantes. Voir les liens dans ma réponse Précision de l'accéléromètre Android (navigation par inertie) au positionnement à l'intérieur.
Vous devez utiliser l'interface Core Motion comme décrit dans Détection de mouvement d'un iPhone simple . Surtout toutes les rotations peuvent être suivies de manière très précise. Si vous envisagez de faire quelque chose lié aux mouvements linéaires, c'est très difficile. Jetez un coup d’œil à Obtenir un déplacement à partir des données de l’accéléromètre avec Core Motion .
J'ai pris un risque et abandonné (tard dans la nuit, ne semblait pas aller nulle part). Ceci est pour un projet Unity3d.
Si quelqu'un veut reprendre là où je me suis arrêté, je me ferai un plaisir de vous expliquer ce que font toutes ces choses.
Fondamentalement, après une partie de ce qui s’est avéré être de faux positifs, je pensais essayer de filtrer cela à l’aide d’un filtre passe-bas, puis de supprimer les rebonds en trouvant une tendance, puis )/2.
On dirait que le faux positif vient toujours de l'inclinaison que j'ai tenté de supprimer.
Si ce code est utile ou vous mène quelque part, s'il vous plaît faites le moi savoir!
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// [email protected]
/// </summary>
public class AccelerometerInput : MonoBehaviour
{
Transform myTransform;
Gyroscope gyro;
GyroCam gyroCam;
void Awake()
{
gyroCam= FindObjectOfType<GyroCam> ();
myTransform = transform;
if (SystemInfo.supportsGyroscope) {
gyro = Input.gyro;
gyro.enabled = true;
}
}
bool shouldBeInitialized = false;
void Update ()
{
transform.Translate (GetAccelerometer ());// * Time.deltaTime * speed);
//GetComponent<Rigidbody> ().AddForce (GetAccelerometer ());
}
public float speed = 10.0F;
public Vector3 dir;
public float f;
Vector3 GetAccelerometer()
{
dir = Input.acceleration;
dir.x *= gyro.attitude.x;
dir.z *= gyro.attitude.z;
if (Mathf.Abs (dir.x) < .001f)
dir.x = 0;
dir.y = 0;
if (Mathf.Abs (dir.z) < .001f)
dir.z = 0;
RecordPointsForFilter (dir);
//print ("Direction : " + dir.ToString("F7"));
return TestPointsForVelocity();
}
Vector3[] points = new Vector3[20];
int index;
void RecordPointsForFilter(Vector3 recentPoint)
{
if (index >= 20)
index = 0;
points [index] = EvaluateTrend (recentPoint);;
index++;
}
//try to remove bounces
float xTrend = 0;
float zTrend = 0;
float lastTrendyX = 0;
float lastTrendyZ = 0;
Vector3 EvaluateTrend(Vector3 recentPoint)
{
//if the last few points were positive, and this point is negative, don't pass it along
//accumulate points into a trend
if (recentPoint.x > 0)
xTrend += .01f;
else
xTrend -= .1f;
if (recentPoint.z > 0)
zTrend += .1f;
else
zTrend -= .1f;
//if point matches trend, keep it
if (xTrend > 0) {
if (recentPoint.x > 0)
lastTrendyX = recentPoint.x;
} else // xTrend < 0
if (recentPoint.x < 0)
lastTrendyX = recentPoint.x;
if (zTrend > 0) {
if (recentPoint.z > 0)
lastTrendyZ = recentPoint.z;
} else // xTrend < 0
if (recentPoint.z < 0)
lastTrendyZ = recentPoint.z;
return new Vector3( lastTrendyX, 0, lastTrendyZ);
}
Vector3 TestPointsForVelocity()
{
float x = 0;
float z = 0;
float xAcc = 0;
float zAcc = 0;
int successfulHits = 0;
for(int i = 0; i < points.Length; i++)
{
if(points[i]!=null)
{
successfulHits ++;
xAcc += points[i].x;
zAcc += points[i].z;
}
}
x = xAcc / successfulHits;
z = zAcc / successfulHits;
return new Vector3 (x, 0, z);
}
}
Voici la réponse . Quelqu'un a demandé avant.
Il existe une application appelée RangeFinder qui fait la même chose (disponible dans App Store).
(acc_x [i-1] + acc_x [i])/2 est un filtre passe-bas, c'est la valeur moyenne entre deux mesures dans le temps
regardez aussi ici: http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf pag: 3