Centrale à inertie 6 axes LSM303D
Ce tutoriel explique comment mettre en oeuvre le module Grove 6-Axis Accelerometer & Compass v2.0 en MicroPython. Le capteur utilisé est le composant MEMS LSM303D de STMicroelectronics.

Crédit images : Seeed Studio
Ce module est également désigné comme une centrale à inertie, ou encore, en anglais, une Inertial Motion Unit (IMU). En effet, puisqu’il intègre un accéléromètre et une boussole, il est possible de cumuler les informations de ces deux capteurs pour réaliser des applications de postionnement dans l’espace avec le LSM303D. L’exemple que nous allons traiter, programmer une boussole compensée en inclinaison, montre une application pratique de l’IMU.
Matériel requis
- Une carte d’extension de base Grove
- La carte NUCLEO-WB55
- Un module Grove 6-Axis Accelerometer & Compass v2.0
Programmer une boussole compensée en inclinaison avec le LSM303D
Le LSM303D, qui intègre à la fois un magnétomètre et un accéléromètre, se prête naturellement à la programmation d’une boussole compensée en inclinaison. Ce sujet est largement couvert par ce tutoriel concernant la X-NUCLEO IKS01A3. Toutes les explications données pour le LIS2MDL et le LIS2DW12 s’appliquent également au LSM303D, avec toutefois deux différences notables :
-
Il n’est pas nécessaire de procéder au calibrage du magnétomètre pour le LSM303D, tout du moins pour le module Grove que nous utilisons car il est déjà correctement calibré en usine. le recalibrer aura probablement pour conséquence de dégrader sa précision, nous déconseillons donc cette opération. Cependant, elle pourrait être utile si le module est fixé sur un système plus gros qui introduit des distorsions Hard Iron et Soft Iron supplémentaires.
-
Les axes de référence sur le LSM303D, pour calculer les angles d’Euler de tangage (pitch), roulis (roll) et cap (heading ou yaw), sont conformes à la note d’application AN3192 et sont illustrés par la figure ci-dessous :

Le code MicroPython
Les scripts présentés ci-après sont disponibles dans la zone de téléchargement.
Nous aurons besoin de copier deux fichiers sur le disque PYBFLASH : le script principal, main.py et le pilote du LSM303D, lsm303.py.
Editez maintenant le script main.py et collez-y le code ci-dessous :
# Objet du script : mise en oeuvre du module Grove "6 Axis Accelerometer And Compass_V2.0".
# Il utilise un bus I2C.
# Cet exemple montre comment programmer une boussole avec compensation d'inclinaison
# à l'aide de ce module.
# La compensation d'inclinaison est calculée à l'aide des instructions du document AN3192
# de STMicroelectronics disponible en téléchargement sur le site Web STM32python.
# Source : https://github.com/Seeed-Studio/Grove_6Axis_Accelerometer_And_Compass_v2/blob/master/LSM303D.cpp
from machine import I2C
from lsm303 import LSM303D # Pilote de l'IMU
from time import sleep_ms
from math import sqrt, atan2, pi, asin, cos, sin
# On utilise l'I2C n°1 de la carte NUCLEO-WB55 pour communiquer avec le capteur
i2c = I2C(1)
# Pause d'une seconde pour laisser à l'I2C le temps de s'initialiser
sleep_ms(1000)
# Liste des adresses I2C des périphériques présents
print("Adresses I2C utilisées : " + str(i2c.scan()))
# Paramètres pour calibrer le magnétomètre (par défaut, "neutres" car le module est déjà parfaitement
# calibré en usine).
OFFSET_X = 0
OFFSET_Y = 0
OFFSET_Z = 0
SCALE_X = 1
SCALE_Y = 1
SCALE_Z = 1
# Initialisation de l'instance de l'IMU
imu = LSM303D(i2c, ox = OFFSET_X, oy = OFFSET_Y, oz = OFFSET_Z, sx = SCALE_X, sy = SCALE_Y, sz = SCALE_Z)
# Facteur de conversion entre les radians et les degrés pour les angles
RadToDeg = 180 / pi
# Doit-on lancer la procédure de collecte de données pour calibrer le magnétomètre ?
# ATTENTION : ce module étant déjà calibré en usine le recalibrer aura probablement pour conséquence de dégrader
# sa précision, nous déconseillons donc cette opération. Cependant, elle pourrait être utile si le module est
# fixé sur un système plus gros qui introduit des distorsions Hard Iron et Soft Iron supplémentaires.
CALIBRATE_COMP = False
if CALIBRATE_COMP:
# Lance la routine de calibrage
imu.calibrate_mag()
else:
# Simule une boussole avec compensation d'inclinaison
while True:
# Mesure des vecteurs accélération et champ magnétique
acc = imu.get_acc()
mag = imu.get_mag()
# Calcule la norme des vecteurs
norm_acc = sqrt(acc[0]*acc[0] + acc[1]*acc[1] + acc[2]*acc[2])
norm_mag = sqrt(mag[0]*mag[0] + mag[1]*mag[1] + mag[2]*mag[2])
# Si les deux normes sont non-nulles
if norm_acc > 0 and norm_mag > 0:
# Normalise les composantes des vecteurs afin de pouvoir calculer
# les arcsinus et arccosinus qui suivent.
inv_acc = 1 / norm_acc
ax = acc[0] * inv_acc
ay = acc[1] * inv_acc
az = acc[2] * inv_acc
inv_mag = 1 / norm_mag
bx = mag[0] * inv_mag
by = mag[1] * inv_mag
bz = mag[2] * inv_mag
# Calcule les angles d'Euler
pitch = asin(-ax)
roll = asin(ay/cos(pitch))
xh = bx * cos(pitch) + bz * sin(pitch)
yh = bx * sin(roll) * sin(pitch) + by * cos(roll) - bz * sin(roll) * cos(pitch)
#zh = -bx * cos(roll) * sin(pitch) + by * sin(roll) + bz * cos(roll) * cos(pitch)
heading = atan2(yh, xh)
# Expression des angles en degrés pour affichage
pitch_deg = pitch * RadToDeg
roll_deg = roll * RadToDeg
heading_deg = heading * RadToDeg
# Si le cap obtenu est négatif, calcule son complément à 360°
if heading_deg < 0:
heading_deg += 360
# Affichage des angles
print("Pitch (tangage) = %.1f°" % pitch_deg)
print("Roll (roulis) = %.1f°" % roll_deg)
print("Heading (cap) = %.1f°" % heading_deg)
print("")
sleep_ms(250)
Affichage sur le terminal série de l’USB User
Une fois le script lancé avec CTRL-D, faites varier l’orientation du module autour des axes Ox
et Oy
. Observez les valeurs affichées pour le cap : elles ne varient pas significativement selon les rotations roll
et pitch
. C’était précisément l’objectif de la compensation d’inclinaison.

Egalement, et conformément aux explications de AN3192, on vérifie bien que dans cette configuration :
- L’angle Heading varie de 0 à 359° lorsqu’on fait tourner l’axe z dans le sens horaire.
- L’ange Pitch varie de 0 à 90° lorsqu’on effectue une rotation autour de l’axe y dans le sens qui fait tourner l’axe x vers le haut.
- L’angle Roll varie de 0 à 90° lorsqu’on effectue une rotation autour de l’axe x dans le sens qui fait tourner l’axe y vers le bas.