Créer une boussole numérique avec le Raspberry Pi – Partie 1 – « Les bases »

Créer une boussole numérique avec le Raspberry Pi - Partie 1 - "Les bases"

Ce sera une série en plusieurs parties sur la façon d’utiliser une boussole numérique (magnétomètre) avec votre Raspberry Pi.

Le magnétomètre utilisé dans ces tutoriels est un LSM9DS0 qui se trouve sur un BerryIMU. Nous indiquerons également où certaines des informations peuvent être trouvées dans la fiche technique du LSM9DS0. Cela vous aidera à comprendre comment fonctionne le LSM9DS0.

YouTube video

Les mathématiques et la logique de cette série peuvent également être utilisées avec d’autres magnétomètres ou IMU.

Nous verrons également comment établir une communication de base sur le bus i2c. En plus d’utiliser SDL pour afficher le cap de la boussole comme une boussole traditionnelle, comme le montre la vidéo ci-dessus.

Dépôt Git ici
Le code peut être extrait sur votre Raspberry Pi avec ;

pi@raspberrypi ~ $ git clone https://github.com/ozzmaker/BerryIMU.git

Le code de ce guide se trouve sous le boussole_tutorial01_basics annuaire.

Boussole Raspberry Pi

Une boussole magnétique traditionnelle (par opposition à une boussole gyroscopique) se compose d’un petit aimant léger équilibré sur un point de pivot presque sans friction. L’aimant est généralement appelé aiguille. Le champ magnétique de la Terre fera pointer l’aiguille vers le pôle Nord.

Pour être plus précis, l’aiguille pointe vers le nord magnétique. La différence d’angle entre le nord vrai et le nord magnétique est appelée déclinaison. La déclinaison est différente selon les endroits. Cet angle varie en fonction de la position à la surface de la Terre et change avec le temps.

La force du champ magnétique terrestre est d’environ 0,5 à 0,6 gauss.

Il existe également une composante parallèle à la surface de la terre qui pointe toujours vers le pôle nord magnétique. Dans l’hémisphère nord, ce champ pointe vers le bas. A l’équateur, il pointe horizontalement et dans l’hémisphère sud, il pointe vers le haut. Cet angle entre le champ magnétique terrestre et le plan horizontal est défini comme un angle d’inclinaison.

Le magnétomètre est généralement un instrument de système microélectromécanique (MEMS) pour mesurer la force et la direction d’un champ magnétique sur 3 axes.

L’image ci-dessous montre comment connecter le magnétomètre ou BerryIMU au Raspberry Pi.

Framboise Pi BerryIMU

Les composants sur le BerryIMU parler au Raspberry Pi via i2c.

Vous pouvez suivre ce guide pour activer i2c sur votre Raspberry Pi

Accéléromètre gyroscope BerryIMU Raspberry Pi

i2c est un protocole de communication qui fonctionne sur un bus à deux fils. Les deux fils sont appelés SDA (Serial Data) et SCL (Serial Clock). Le bus i2c possède un ou plusieurs maîtres (le Raspberry Pi) et un ou plusieurs appareils esclaves, comme le LSM9DS0 sur le BerryIMU. Comme les mêmes données et lignes d’horloge sont partagées entre plusieurs esclaves, nous avons besoin d’un moyen de choisir avec quel appareil communiquer. Avec i2c, chaque appareil a une adresse avec laquelle chaque communication doit être préfacée. Le LSM9DS0 peut avoir deux adresses, soit 0x1E ou 0x1D. Cette adresse est contrôlée par une broche sur le LSM9DS0. Si cette broche est connectée à une alimentation en tension, l’adresse sera 0x1D. Et s’il est connecté à la terre, ce sera 0x1E.
Sur le BerryIMU, l’adresse de LSM9DS0 est 0x1E.

Ces informations se trouvent à la page 33 de la fiche technique.

i2cdetect peut être utilisé pour confirmer les adresses utilisées par le magnétomètre ou BerryIMU

pi@raspberrypi ~ $ sudo /usr/sbin/i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- 1e -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- 6a -- -- -- --
70: -- -- -- -- -- -- -- --

Dans l’exemple ci-dessus, le magnétomètre (LSM303D) utilise l’adresse 0x1D.

Nous lisons et écrivons des valeurs dans différents registres du magnétomètre pour effectuer différentes tâches. Par exemple, allumez le magnétomètre, réglez le niveau de sensibilité, lisez les valeurs magnétiques. etc..

Le référentiel git inclut également LSM9DS0.h qui répertorie tous les registres que nous utilisons pour ce capteur.

Nous utilisons des appels ioctl pour lire et écrire des informations sur le bus i2c. Donc, la première tâche à faire est d’ouvrir le fichier de périphérique de bus I2C, comme suit ;


        char filename[20];
        sprintf(filename, "/dev/i2c-%d", 1);
        file = open(filename, O_RDWR);
        if (file<0) {
                printf("Unable to open I2C bus!");
                exit(1);
        }

Comme nous utilisons sprintf, vous devrez inclure le fichier d’en-tête stdio.h

Sélection du magnétomètre
Avant de pouvoir commencer à écrire et à lire les valeurs du magnétomètre, nous devons sélectionner l’adresse du magnétomètre ;

        if (ioctl(file, I2C_SLAVE, MAG_ADDRESS) < 0) {
                printf("Error: Could not select magnetometern");
        }

Vous devrez inclure les en-têtes de contrôle de fichier dans votre programme, fcntl.h.
Vous devrez également inclure les en-têtes pour le bus i2c – linux/i2c-dev.h

MAG_ADDRESS est défini dans LSM9DS0.h

Pour activer le magnétomètre, nous devrons définir des valeurs de registre sur le capteur.

La fonction i2c_smbus_write_byte_data() peut être utilisée pour écrire dans le registre d’un périphérique sur le bus i2c.
Cette fonction se trouve dans les en-têtes linux/i2c-dev.h.

La déclaration pour cette fonction est;
i2c_smbus_write_byte_data (struct i2c_client * client, commande u8, valeur u8) ;

i2c_client est le pointeur que nous avons utilisé pour ouvrir le bus i2c, command est le registre dans lequel nous voulons écrire et value est la valeur que nous voulons écrire.

Comme nous écrirons souvent sur le magnétomètre, nous devrions créer une fonction ;

void writeMagReg(uint8_t reg, uint8_t value)
{
  int result = i2c_smbus_write_byte_data(file, reg, value);
    if (result == -1)
    {
        printf ("Failed to write byte to I2C Mag.");
        exit(1);
    }
}

Vous pouvez maintenant continuer et activer le magnétomètre ;

 writeMagReg( CTRL_REG5_XM, 0b11110000);
 writeMagReg( CTRL_REG6_XM, 0b01100000);
 writeMagReg( CTRL_REG7_XM, 0b00000000);

Une brève description des paramètres et où les informations peuvent être trouvées dans la fiche technique ;

  • CTRL_REG5_XM – Activer le capteur de température interne – Réglez le magnétomètre sur haute résolution – définissez un débit de données de 50 Hz – page 59 sur la fiche technique.
  • CTRL_REG6_XM – Définit la sélection pleine échelle à +/- 12 Gauss – page 60 sur la fiche technique.
  • CTRL_REG7_XM – Mettez le magnétomètre en mode de conversion continue – page 60 sur la fiche technique.

La lecture des données du magnétomètre est similaire à l’écriture de données, mais plutôt que de simplement lire un octet, nous lirons un bloc d’octets. Par exemple 6 octets.

Nous utiliserons la fonction i2c_smbus_read_i2c_block_data() trouvée dans linux/i2c-dev.h.

Nous allons créer deux de nos propres fonctions qui nous serviront à lire les données du magnétomètre.

Il s’agit de la fonction de lecture de bloc qui effectue également une vérification d’erreur ;

void  readBlock(uint8_t command, uint8_t size, uint8_t *data)
{
    int result = i2c_smbus_read_i2c_block_data(file, command, size, data);
    if (result != size)
    {
       printf("Failed to read block from I2C.");
        exit(1);
    }
}

Cette fonction utilise la fonction ci-dessus pour lire les valeurs magnétiques brutes du magnétomètre ;

void readMAG(int  *m)
{
        uint8_t block[6];

        readBlock(0x80 | OUT_X_L_M, sizeof(block), block);
        *m = (int16_t)(block[0] | block[1] << 8);
        *(m+1) = (int16_t)(block[2] | block[3] << 8);
        *(m+2) = (int16_t)(block[4] | block[5] << 8);

}

Voici ce qui se passe dans la fonction readMAG();
1) Un tableau de 6 octets est d’abord créé pour stocker les valeurs.
2) En utilisant la fonction readBlock(), nous lisons 6 octets à partir de OUT_X_L_M (0x08). Ceci est indiqué à la page 52 de la fiche technique.
3) Les valeurs sont exprimées en complément à 2 (MSB pour le signe puis 15 bits pour la valeur) il faut donc combiner ;
bloquer[0] & bloquer[1] pour l’axe X
bloquer[2] & bloquer[3] pour l’axe Y
bloquer[4] & bloquer[5] pour l’axe Z

Nous pouvons maintenant créer une boucle dans notre programme pour lire les valeurs brutes du magnétomètre et les imprimer à l’écran.
J’ai ajouté un délai de 0,25 seconde pour rendre la sortie plus facile à lire.

int magRaw[3];
while(1)
{
        readMAG(magRaw);
	printf("magRaw X %i    tmagRaw Y %i tMagRaw Z %i n", magRaw[0],magRaw[1],magRaw[2]);
        usleep(250000);
}

La sortie doit être similaire à la sortie ci-dessous. Vous remarquerez que la sortie change même si le magnétomètre ne bouge pas. C’est parce que tous les magnétomètres sont bruyants. Dans un prochain article, nous montrerons comment filtrer ce bruit.

magRaw X 1024    magRaw Y 1024   MagRaw Z 17920
magRaw X 1280    magRaw Y 256    MagRaw Z 18176
magRaw X 1280    magRaw Y 512    MagRaw Z 17152
magRaw X 512     magRaw Y -513   MagRaw Z 16384
magRaw X 1792    magRaw Y -1     MagRaw Z 18432
magRaw X 512     magRaw Y -257   MagRaw Z 17408
magRaw X 256     magRaw Y -257   MagRaw Z 16384
magRaw X 1280    magRaw Y -257   MagRaw Z 17920
magRaw X 1024    magRaw Y 768    MagRaw Z 17920
magRaw X 768     magRaw Y -513   MagRaw Z 16640
magRaw X 1536    magRaw Y -257   MagRaw Z 18432
magRaw X 768     magRaw Y -1     MagRaw Z 18176
magRaw X 1024    magRaw Y -257   MagRaw Z 17664

Nous pouvons utiliser la formule ci-dessous pour calculer le cap. Cela ne fonctionne que si le magnétomètre est sur une surface plane.

 heading = 180 * atan2(magRawY,magRawX)/M_PI;

Vous devrez inclure le fichier d’en-tête mathématique dans votre programme, math.h et lors de la compilation, vous devrez également lier la bibliothèque mathématique. ‘-lm’

Avec juste la formule ci-dessus, nous obtiendrons le cap entre les valeurs -180 à 180.
Nous utiliserons le coupé ci-dessous pour changer cela en une valeur de cap comprise entre 0 et 360

        if(heading < 0)
              heading += 360;

Nous ajouterons le code pertinent à notre boucle principale et imprimerons également la valeur de l’en-tête.

Votre boucle principale devrait ressembler à ceci ;

        while(1)
        {
                readMAG(magRaw);
		printf("magRaw X %i    tmagRaw Y %i tMagRaw Z %i n", magRaw[0],magRaw[1],magRaw[2]);

                float heading = 180 * atan2(magRaw[1],magRaw[0])/M_PI;

                if(heading < 0)
                      heading += 360;

                printf("heading %7.3f t ", heading);
                usleep(250000);

        }

Compiler;

pi@raspberrypi ~ $ gcc compass_tutorial01.c -o compass_tutorial01 -lm

votre sortie devrait maintenant ressembler à ceci ;

heading 118.078          magRaw X -2305  magRaw Y -3073  MagRaw Z 13312
heading 126.873          magRaw X -2305  magRaw Y -1281  MagRaw Z 12800
heading 150.937          magRaw X -769   magRaw Y -2561  MagRaw Z 11776
heading 106.714          magRaw X -2561  magRaw Y -2561  MagRaw Z 12288
heading 135.000          magRaw X -2049  magRaw Y -1537  MagRaw Z 12800
heading 143.126          magRaw X -1537  magRaw Y -1793  MagRaw Z 12288
heading 130.604          magRaw X -2049  magRaw Y -1793  MagRaw Z 12800
heading 138.812          magRaw X -1281  magRaw Y -1793  MagRaw Z 12288
heading 125.544          magRaw X -1537  magRaw Y -1793  MagRaw Z 12288
heading 130.604          magRaw X -2049  magRaw Y -2561  MagRaw Z 13056
heading 128.663          magRaw X -2817  magRaw Y -1537  MagRaw Z 12544
heading 151.382          magRaw X -769   magRaw Y -2817  MagRaw Z 13568

Lorsque vous tournez votre magnétomètre dans le sens des aiguilles d’une montre, le cap devrait augmenter. Il devrait diminuer lorsqu’il est tourné dans le sens inverse des aiguilles d’une montre.
Si ce n’est pas le cas, vous devez convertir l’axe Y. Cela se produira si le magnétomètre est à l’envers, comme lorsque le BerryIMU est assis sur les en-têtes GPIO du Raspberry Pi ;

                magRaw[1] = -magRaw[1];

La ligne ci-dessus doit être ajoutée juste avant le calcul du cap.

Dans les prochains articles, nous aborderons l’étalonnage de la boussole, la compensation d’inclinaison et l’affichage du cap comme une boussole traditionnelle à l’aide de SDL.

PiScreen TFT Raspberry Pi

Guides et tutoriels