Aide capteur IMU LSM6DSO32

Bonjour à tous,

Je fait un petit projet à base d'un IMU LSM6DSO32. Overview | LSM6DSOX, ISM330DHC, & LSM6DSO32 6 DoF IMUs | Adafruit Learning System
Mais j'ai des doutes sur les valeurs que je récupère. J'ai donc suivit le tuto d'adafruit, pour commencer, la température, quand je souffle un peu sur la carte pour voir si la température varie, le capteur indique une valeur énorme du genre 145 deg, et bloque pour ensuite me sortir en tout temps une valeur de 25 je suis obligé de faire un reset pour avoir de nouvelle valeurs.

Ensuite pour le gyro je récupére des valeurs brutes du capteur via

sensors_event_t accel;
sensors_event_t gyro;
sensors_event_t temp;
dso32.getEvent(&accel, &gyro, &temp);

Ces valeurs étant en radian je les convertit en degrées via une multiplcation par un coeff de 57 et quelques.

J'ai une structure (structure global déclaré avant le setup)

t_data_gyro data = {};

dans laquel je vais avoir mes valeurs, et dans ma boucle loop je récuprére les données brutes du capteurs et je fait un += sur ma structure

data.dso32_x += (gyro.gyro.x - offset.dso32_x) * RAD_DEG;
data.dso32_y += (gyro.gyro.y - offset.dso32_y) * RAD_DEG;
data.dso32_z += (gyro.gyro.z - offset.dso32_z) * RAD_DEG;
typedef struct{
  float dso32_x;
  float dso32_y;
  float dso32_z;
} t_data_gyro;

data étant ma structure global et offset une autre structure dans laquel je boucle 1000 fois au setup en ne touchant pas le capteurs pour avoir un offset que je retire à chaque lecture de valeurs brutes.

Mon soucis c'est quand j'affiche les valeurs au début pas de soucis si je ne touche à rien j'ai bien des valeurs qui tournent autour de 0, c'est bon, mais dès que je bouge à peine le capteur les valeurs bougent mais ne reviennent pas à zéro.
Par exemple j'incline mon capteur à 45 degrès j'ai bien une valeur proche de 45 mais si je remet le capteur à plat la valeur reste à 45 ou alors je me retrouve par exemple à 30 degrès enfin tous sauf 0, et je ne comprend pas trop pourquoi auriez vous une idée?

ne postez pas de snippets (Snippets R Us!)

offset une autre structure dans laquel je boucle 1000 fois au setup en ne touchant pas le capteurs pour avoir un offset que je retire à chaque lecture de valeurs brutes

c'est la moyenne uniquement pour le gyro sur ces 1000 valeurs?

Ces valeurs étant en radian je les convertit en degrées via une multiplcation par un coeff de 57 et quelques.

Non ces valeurs sont des valeurs instantanées en radians par seconde.

Le cumul dans le temps

data.dso32_x += (gyro.gyro.x - offset.dso32_x) * RAD_DEG;
data.dso32_y += (gyro.gyro.y - offset.dso32_y) * RAD_DEG;
data.dso32_z += (gyro.gyro.z - offset.dso32_z) * RAD_DEG;

n'a donc pas trop de sens si vous ne tenez pas compte de la vitesse d'échantillonnage et ça pourrait donc expliquer pourquoi vous ne revenez pas à 0.

ne postez pas de snippets (Snippets R Us!)

Oui le code étant assez long et voluminieux je ne voulais pas poster un gros tas de ligne inutile :confused:

c'est la moyenne uniquement pour le gyro sur ces 1000 valeurs?

Oui c'est bien une moyenne faite uniquement sur les valeurs x,y,z du gyro

Non ces valeurs sont des valeurs instantanées en radians par seconde.

Ok mais si je fait une multiplication par RAD_TO_DEG je trouve bien des valeurs en degrées non?

n'a donc pas trop de sens si vous ne tenez pas compte de la vitesse d'échantillonnage et ça pourrait donc expliquer pourquoi vous ne revenez pas à 0.

Ok, donc si je comprend bien, de base mon capteur étant echantilloné à 104 HZ je doit donc prendre en compte cette valeurs quand je récupère mes daonnées brutes ? Je devrait donc diviser la valeur brute que je récupère par cette fréquence et la multiplier par l'angular rate sensitivity ?
Quelque chose du genre peut être si je suis en 500dps ?

data.dso32_x += (gyro.gyro.x - offset.dso32_x) / (LSM6DS_RATE_104_HZ * LSM6DS_GYRO_RANGE_500_DPS));

Ok mais si je fait une multiplication par RAD_TO_DEG je trouve bien des valeurs en degrées non?

en degrés par seconde

Non pour les maths. Pour passer des degrés / seconde à des degrés il faut l'intégrale (qui va malheureusement cumuler des erreurs) dans le temps. Ça ne dépend pas des 104Hz, mais de la vitesse à laquelle votre code tourne. Vous obtenez en appelant dso32.getEvent(&accel, &[color=blue]gyro[/color], &temp); une vitesse angulaire instantanée pour gyro, il faut la multiplier par le ∆t (temps entre la dernière mesure et la mesure actuelle) pour avoir la modification d'angle pendant ces ∆t (en espérant que l'interpolation reste bonne si ∆t est petit)

Ça ne dépend pas des 104Hz, mais de la vitesse à laquelle votre code tourne

Ok donc si je comprend bien je doit mesurer entre chaque mesure le temps qui s'est écoulé et multiplier la valeur retourné par dso32.getEvent pour le gyro par ce delta temps pour avoir mon angle en degrés ?

Quand vous me parlez de la vitesse d'échantillonage vous me parlez de ce delta temps et non pas des 104Hz du gyro c'est ça ?

Si je comprend bien aussi : par exemple si le gyro fait un tour complet en 1 minute, ça signifie qu'il fait 360° en 60s, soit 6°/s en moyenne. Ce qui fait que si mon gyro est calibré en 500dps je doit avoir ensortie une valeur brute de 105 non ? (17.5 * 6 , 17.5 correspond à angular rate sensitivity pour 500dps)

le gyro met à disposition de l'arduino 104 valeurs par seconde (dans un buffer de l'IMU) mais suivant ce que vous faites dans le code, vous n'allez pas lire 104 fois par seconde - peut-être plus, peut-être moins.
==> le ∆t est le temps que votre code met pour faire "une boucle de lecture"

le ∆t est le temps que votre code met pour faire "une boucle de lecture"

Ok je suis un peu perdue alors je ne vois pas comment je peux récupérer ce delta temps ? C'est le temps entre le début de l'appel de dso32.getEvent(&accel, &gyro, &temp); et la récupération des données ?

un truc du genre

...
uint32_t ancienTemps;

void setup() {
   ...
   ancienTemps = millis();
}

void loop() {
  ...
  uint32_t maintenant = millis();
  dso32.getEvent(&accel, &gyro, &temp);
  uint32_t deltaT = (maintenant - ancienTemps);
  ... vos maths et autre code
  ancienTemps = maintenant;
}

le ∆t sera en millisecondes donc vous aurez un facteur 1000 à prendre en compte puisque la vitesse de rotation est en radians/seconde

Ok donc si je comprend bien une fois que j'ai deltaT je multiplie par exemple ma valeur brute du gyro en x par ce deltaT diviser par 1000 pour l'avoir en seconde ?

oui ça fait l'integration (mais comme dit précédemment, ça va dériver dans le temps sans doute car l'intégration cumulera les erreurs)

comme ils le disent sur cette page produit

Si vous avez déjà commandé et câblé un capteur 9-DOF, il y a de fortes chances que vous ayez également réalisé la difficulté de transformer les données d'un accéléromètre, d'un gyroscope et d'un magnétomètre en une véritable "orientation spatiale 3D"!

L'orientation est un problème difficile à résoudre. Les algorithmes de fusion de capteurs (la sauce secrète qui mélange les données de l'accéléromètre, du magnétomètre et du gyroscope dans une sortie d'orientation stable à trois axes) peuvent être extrêmement difficiles à obtenir et à mettre en œuvre sur des systèmes en temps réel à faible coût.

(google translate)

==> il existe des techniques pour obtenir les Quaterions ou angles d'Euler mais c'est mieux quand l'IMU le fait

Ok je vois je vais faire des essaies alors déjà pour voir un peu ce que ça donne :slight_smile:

==> il existe des techniques pour obtenir les Quaterions ou angles d'Euler mais c'est mieux quand l'IMU le fait

Oui c'est sur qu'avec un IMU qui le fait ça doit vraiment simplifier les choses il n'y a pas photo, après le prix de la carte n'est plus le même aussi :smiley:

certes :slight_smile: après si vous avez le temps et que vous l'achetez en Asie sur eBay ou Ali, c'est bien moins cher (~12 ou 13€)

Du coup n'existe t-il pas des librairies "génériques" qui permettent de calculer les Quaterions ou angles d'Euler des produits Adafruit ? Je suis tombé sur ça Overview | How to Fuse Motion Sensor Data into AHRS Orientation (Euler/Quaternions) | Adafruit Learning System mais j'ai bien l'impression que mon LSM6DSO32 n'est pas pris en compte...

J'ai beau chercher comment faire pour interpréter les données brutes du capteurs avec Quaterions etc je ne trouve pas d'exemple concret

Vous êtes sur quel type d'Arduino ? sur un 328P (Uno, Mega) le seul algorithme qui va "tenir" c'est Mahony.

Même si l'exemple ne supporte pas votre IMU ce n'est pas grave.

La bibliothèque propose une classe Adafruit_Mahony et vous déclarez un filtre de ce typeAdafruit_Mahony filter;et dans le setup() appelez filter.begin(5);(prenez note du commentaire dans l'exemple sur le refresh rate)

Ensuite dans la loop vous alimentez le filtre avec les 9 axesfilter.update(gx, gy, gz, ax, ay, az, mx, my, mz);après avoir calibré / compensé les valeurs (cf leur tuto) et mis les gx,gy et gz et deg/s

Vous obtenez ensuite le quaternion par

float qw, qx, qy, qz;
filter.getQuaternion(&qw, &qx, &qy, &qz);

ou les angles d'Euler

float roll = filter.getRoll();
float pitch = filter.getPitch();
float heading = filter.getYaw();

(mais les angles d'Euler présentent un souci (cherchez "gimbal lock") aux limites lorsque les angles approchent 180°)

je n'ai jamais utilisé leur bibliothèque cela dit, donc à voir si ça fonctionne bien

Je suis sur un SAMD21 avec Arm cortex M0, je vais allez voir cette librairie alors et essayer de l'utilsier avec mon capteur :slight_smile:

OK donc ça pédale un peu plus vite :wink: vous pourrez envisager aussi les autres algos - c'est le même principe

Par contre uen chose que je ne comprend pas dans l'exemple sur cette ligne il utilise uns instance gyro dans mon cas si je comprend bien pour mon lsm6dso32 je doit récupréer le capteur du gyro comme fait dans le _init ici
Deuxième question dans le filtre si je regarde le code je vois qu'il utilise aussi un mag_event qui correspond a une boussole mais quand je regarde dans la librairie du capteur je ne vois pas comment récupérer ces valeurs la via un getEvent car dans le _init du capteur les capteurs initialisé sont seulent accel gyro et temp aucune trace d'une boussole quelque part peut être que je cherche mal...

oui ils n'ont pas le même capteur, donc l'extraction des valeurs ne se fait pas de la même façon.

En revanche je n'avais pas percuté... votre capteur n'a que 6 degrés de liberté et l'algorithme en demande 9...

Oui donc c'est bien ce que je me suis dit pas possible d'utiliser cet algo alors car il me manque le capteur mag ?