Exploitation centrale inertielle avec Arduino UNO

Bonjour.

Actuellement en Terminale S SI, dans le cadre de projets interdisciplinaires, je dois exploiter une centrale inertielle à l'aide d'un arduino UNO afin de récupérer les accélérations sur les 3 axes. Je possède déjà un programme ( mélange de bouts de codes trouvés ça et là sur internet). Cependant, hormis les inprécisions, dès qu'il y a rotation selon certains axes, les accélérations mersurées deviennent incohérentes.
Le programme utilisant des notions mathématiques complexes (quaternion, angles d'Euler) pour m'affranchir de l'accéleration de la pesanteur, je ne parviens pas à corriger ce souci.

Quelq'un a t-il déjà exploité une centrale inertielle ?

J'ai attaché le code que j'ai actuellement si cela peut aider...

 #include <FreeSixIMU.h>
#include <FIMU_ADXL345.h>
#include <FIMU_ITG3200.h>

#define DEBUG
#ifdef DEBUG
#include "DebugUtils.h"
#endif

#include "CommunicationUtils.h"
#include "FreeSixIMU.h"
#include <Wire.h>

float q[4];
float euler[3];
int valeursBrutes[6];
float acceleration[3];

int lf = 10; // 10 is '\n' in ASCII
byte inBuffer [22]; // this is the number of chars on each line from the Arduino (including /r/n)


// Set the FreeIMU object
FreeSixIMU my3IMU = FreeSixIMU();

void setup() {
  Serial.begin(115200);
  Wire.begin();

  delay(5);
  my3IMU.init();
  delay(5);
}


void loop() { 
  my3IMU.getQ(q);
  my3IMU.getRawValues(valeursBrutes);
  
  quaternionToEuler(q, euler);
  calculAcceleration(valeursBrutes, euler, acceleration);
  
  Serial.print(acceleration[0]);
  Serial.print(",      ");
  Serial.print(acceleration[1]);
  Serial.print(",      ");
  Serial.println(acceleration[2]);
 
  delay(60);
}

void quaternionToEuler(float q[], float euler[]) {
  euler[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1); // psi
  euler[1] = -asin(2 * q[1] * q[3] + 2 * q[0] * q[2]); // theta
  euler[2] = atan2(2 * q[2] * q[3] - 2 * q[0] * q[1], 2 * q[0] * q[0] + 2 * q[3] * q[3] - 1); // phi
}

void calculAcceleration(int valeursBrutes[], float euler[], float accelerationFinale[]) {
  float accelerationInitiale[3] = {-valeursBrutes[2]*9.81/255, valeursBrutes[1]*9.81/255, -valeursBrutes[0]*9.81/255};
  accelerationFinale[0] = cos(euler[0]) * cos(euler[1]) * accelerationInitiale[0] + (-sin(euler[0]) * cos(euler[2]) + cos(euler[0]) * sin(euler[1]) * sin(euler[2])) * accelerationInitiale[1] + (sin(euler[0]) * sin(euler[2]) + cos(euler[0]) * sin(euler[1]) * cos(euler[2])) * accelerationInitiale[2];
  accelerationFinale[1] = sin(euler[0]) * cos(euler[1]) * accelerationInitiale[0] + (cos(euler[0]) * cos(euler[2]) + sin(euler[0]) * sin(euler[1]) * sin(euler[2])) * accelerationInitiale[1] + (-cos(euler[0]) * sin(euler[2]) + sin(euler[0]) * sin(euler[1]) * cos(euler[2])) * accelerationInitiale[2];
  accelerationFinale[2] = -sin(euler[1]) * accelerationInitiale[0] + cos(euler[1]) * sin(euler[2]) * accelerationInitiale[1] + cos(euler[1]) * cos(euler[2]) * accelerationInitiale[2];
  accelerationFinale[0] = accelerationFinale[0] + 9.81;
  Serial.print(valeursBrutes[0]);
  Serial.print(",");
  Serial.print(valeursBrutes[1]);
  Serial.print(",");
  Serial.print(valeursBrutes[2]);
  Serial.print("    ");
  Serial.print(accelerationInitiale[0]);
  Serial.print(",");
  Serial.print(accelerationInitiale[1]);
  Serial.print(",");
  Serial.print(accelerationInitiale[2]);
  Serial.print("    ");
  Serial.print(degrees(euler[0]));
  Serial.print(",");
  Serial.print(degrees(euler[1]));
  Serial.print(",");
  Serial.print(degrees(euler[2]));
  Serial.print("    ");
}

Je suis disponible pour toutes questions. Merci d'avance.

Bonjour,

As-tu essayé d'exploiter les bibliothèques fournies avec ce composant ?

Et bien non, je n'avais pas trouver ceci à vrai dire.

Mais en y regardant , je vois des codes particulièrement long. Je tenterais cela lors de mon prochain cours de SI.
Je crains cependant de ne pas avoir correctement les utiliser. Pourrais-je avoir des précisions s'il vous plait ?

J'ai juste cherché à ta place, mais je n'ai jamais travaillé sur ce composant, je ne l'ai pas sous la main et je ne pourrai pas t'aider beaucoup plus.

C'est déjà une bonne piste que je pourrais exploiter pendant les 4 heures que j'aurais demain. Donc merci :slight_smile:

En attendant, je pense que je vais un peu plus détailler le projet, pour que vous puissiez en comprendre d'avantage.

Notre projet consiste en une trasformation de mouvement en son. Le son se génère et se module à partir de la position de la centrale inertielle dans un boitier accrohé au poignet de l'utilisateur (Quand on monte le poignet , la fréquence du signal augmente, quand on le bouge de gauche à droite, le volume augmente ou diminue). A partir de là, je me suis proposé de m'occuper de l'acquisition du mouvement. J'ai donc pensé à utiliser un accéléromètre, qui me permet à partir des accélérations mesurées. de remonter à la postion (Double intégration par rapport au temps). Cependant, l'accélération de la pesanteur rendait notre petit accéléromètre Tinkerkit inutilisable pour notre projet. Après plusieurs renseignement, j'ai trouvé qu'en utilisant une centrale inertielle, et avec des formules de maths assez complexes pour que je puisse les déchiffer moi-même, je pouvais m'affranchir de cette accélération de la pesanteur.
J'ai donc bidouillé avec une des mes camarades, pour obtenir le programme suivant.
La fonction quaterniontoEuler, utilise des quaternions pour obtenir 3 angles sur la centrale inertielle (Pitch, Roll, Yaw).
Le seconde fonction, calculAcceleration, permet à l'aide de matrice de passage des angles d'Euler, de remonter aux accélérations, mais dans le référetiel terrestre. En effet les accélérations acquises sans ce traitement sont celles dans le référentiel de la centrale.
J'aimerais aussi préciser, que j'ai pu voir par mes recherches que l'utilisation d'un filtre de Kalman était indispensable mais je n'arrive pas à savoir si tous les calculs déjà effectués, ne sont déjà pas des parties du filtre de Kalman.
Mes accélérations étant toujours inchérentes dans le référentiel terrestre... Je demande donc votre aide ici.

J'espère avoir été assez clair :sweat_smile: Si vous avez d'autres questions, je peux surement y répondre.
J'espère aussi que le fait d'avoir été plus explicatif permetra à certains d'essayer de m'aider.

Merci d'avance.

Le problème et qu'à cause des offsets et bruits de mesure, la double intégration de l'accélération va rapidement donner des valeurs complètement fausses pour la position.
Tu ferais mieux d'utiliser justement le fait que l'accéléromètre mesure la pesanteur pour calculer l'orientation de celui-ci (oui, paradoxalement un accéléro bas de gamme est surtout utile pour calculer des orientations et pas des positions).
Tu pourrais alors faire varier la fréquence quand l'utilisateur lève l'avant-bras et modifier le volume quand il tourne le poignet.

Vu que le projet n'est pas de calculer une position précisément sans dérive, on doit pouvoir s'épargner le filtrage Kalman, et même la plupart des formules de math (angles d'Euler, ...) et les doubles intégrations temporelles (source de dérive...).

La pesanteur terrestre ne devrait pas poser de problème, même en partant des simples données brutes sorties du capteur.
Tu détermine le module du vecteur de l'accélération (à partir des 3 axes x y z) . A = sqr(Ax² + Ay² + Az²).
Immobile, tu dois retomber sur g=9.81 m/s2, quelle que soit l'orientation du capteur.
Tu soustrait cette valeur fixe, pour centrer A sur 0.
Il ne reste alors que l'accélération du bras (peu importe dans quelle direction).
Chaque mouvement fait varier ce module d'accélération centré, tu en déduis la fréquence.

Ouah merci :slight_smile:

Deux réponses rapides et qui apportent de toutes nouvelles pistes !
Je vais tester les deux solutions et je réponds ici dès que les tests sont terminés. Je n'avais absolument pas pensé au module du vecteur. Sachant que l'on avait placer la barre assez haute selon nos professeurs, ce nouveau modèle nous permettra de revenir au principe même du sujet.

Je met à jour ce sujet au fil de mes avancées. J'aurais surement d'autres questions.
Encore merci !