Comment créer un inclinomètre à l’aide d’un Raspberry Pi et d’un IMU

Comment créer un inclinomètre à l'aide d'un Raspberry Pi et d'un IMU
YouTube video

Ce guide explique comment utiliser une unité de mesure inertielle (IMU) avec un Raspberry Pi pour créer un inclinomètre, tout comme le type que vous trouverez dans un 4×4.

Une condition préalable à ce guide est d’avoir un gyroscope et un accéléromètre d’un IMU déjà opérationnel sur votre Raspberry Pi. Un guide pour interfacer un IMU avec un Raspberry Pi peut être trouvé ici.

Nous allons couvrir quelques bases SDL qui sera utilisé pour produire nos graphiques.

L’IMU utilisé dans ce guide est le BerryIMU. Cependant, d’autres IMU ou accéléromètres et gyroscopes peuvent être utilisés. Pololu MinIMU, Adafruit IMU et IMU Sparkfun

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 gyro_accelerometer_tutorial02_inclinometer annuaire.

Accéléromètre gyroscope BerryIMU Raspberry Pi

Installation de SDL

pi@raspberrypi ~ $ sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-gfx1.2-dev libi2c-dev

Si vous souhaitez tester pour voir si SDL est correctement installé, vous pouvez créer un fichier appelé test.c et copier le code ci-dessous ;

#include <SDL/SDL.h>

int main(int argc, char** argv) {
        SDL_Init(SDL_INIT_EVERYTHING);
        SDL_Surface *screen;

        screen = SDL_SetVideoMode( 480, 320, 16, SDL_SWSURFACE );
        SDL_Rect rect;
        rect.x = 10;
        rect.y = 10;
        rect.w = 20;
        rect.h = 20;

        Uint32 color = SDL_MapRGB(screen->format, 0xff,0xff,0xff);
        Uint32 color2 = SDL_MapRGB(screen->format, 0,0,0);
        SDL_FillRect(screen, &rect, color);
        SDL_Flip(screen);
        getchar();

        SDL_Quit();
        return 0;
}

Le code ci-dessus peut être compilé avec ;

pi@raspberrypi ~ $ gcc -o test test.c `sdl-config –cflags` `sdl-config –libs`

Et pour exécuter le programme ;

pi@raspberrypi ~ $ sudo ./test

Vous devriez voir votre écran devenir blanc ou un carré blanc devrait être affiché.

Nous allons ajouter au code qui a déjà été créé dans le Guide pour interfacer un gyroscope et un accéléromètre avec un guide Raspberry Pi.

Comme nous utilisons SDL, nous devrons inclure les fichiers d’en-tête SDL dans notre programme ;

#include "SDL.h"
#include "SDL/SDL_image.h"

Lorsque vous utilisez SDL, vous devez d’abord initialiser SDL et configurer vos surfaces avant de pouvoir commencer à afficher des informations à l’écran. La section suivante montre comment cela est fait.

Les deux lignes ci-dessous initialisent SDL et le configurent pour qu’il n’affiche pas de curseur ;

        SDL_Init(SDL_INIT_VIDEO);
        SDL_ShowCursor(SDL_DISABLE);

Nous utilisons ensuite la fonction SDL_GetVideoInfo() pour obtenir des informations sur notre affichage. Par exemple, résolution et bits par pixel, etc. Ceci est stocké dans la structure ‘videoinfo’. Pour voir quelle hauteur a été retournée, nous utiliserions ‘videoInfo->current_h’

Nous utilisons ensuite ces informations pour créer notre écran, en utilisant la fonction SDL_SetVideoMode(). Cette fonction a besoin de ces paramètres, résolution X, résolution Y, bits par pixel et type de surface d’affichage. Dans le code ci-dessous, nous utilisons une surface logicielle pour le type d’affichage.

        videoInfo = SDL_GetVideoInfo();

        screen = SDL_SetVideoMode(videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel, SDL_SWSURFACE );
        if ( screen == NULL ) {
                fprintf(stderr, "Unable to setvideo: %sn", SDL_GetError());
                exit(1);
        }

Une fois que nous avons configuré SDL, nous pouvons commencer à charger nos images.

        inclinometerOverlay =  IMG_Load("inclinometerOverlay.png");
                if (inclinometerOverlay == NULL){
                         printf("error loading Overlay imagen");
                        SDL_Quit();
                        exit(1);
                }

Après avoir chargé l’image, qui est un PNG, nous devons la convertir au bon format afin qu’elle conserve sa transparence

         compatibleInclinometerOverlay = SDL_DisplayFormatAlpha(inclinometerOverlay);

Nous allons créer une fonction pour faire pivoter nos images car cela devra être fait à chaque fois que la boucle principale du programme est traitée. Nous allons passer deux paramètres à cette fonction, carRoll (qui est l’angle X) et CarPitch (qui est l’angle Y).

int graphics(float carRoll, float carPitch)

La première tâche que nous voulons faire dans la fonction est d’effacer toutes les informations sur la surface actuelle. Cela peut être fait en utilisant SDL_FillRect() et la valeur 0x000000, qui est noire.

        SDL_FillRect(screen,NULL,0x000000);

La prochaine section de code positionnera correctement les deux images de jeep sur notre surface. La formule pour la position ‘y’ la placera au milieu de la surface.

        inclinometerJeepFrontPosition.x = 30;
        inclinometerJeepFrontPosition.y = (videoInfo->current_h/2)-(compatibleInclinometerJeepFront->h/2);
        inclinometerJeepSidePosition.x = 262;
        inclinometerJeepSidePosition.y = (videoInfo->current_h/2)-(compatibleInclinometerJeepFront->h/2);

Nous pouvons maintenant faire pivoter nos images en fonction de l’angle de l’IMU. Pour ce faire, nous utiliserons la fonction rotozoomSurface(). Nous y passerons nos images de jeep compatibles, les angles de roulis et de tangage, le facteur de zoom (1,0 pour pas de zoom) et le lissage (0 pour pas de lissage).

        rotationInclinometerJeepSide = rotozoomSurface(compatibleInclinometerJeepSide, carPitch, 1.0, 0);
        rotationInclinometerJeepFront = rotozoomSurface(compatibleInclinometerJeepFront, carRoll, 1.0, 0);

Après avoir fait pivoter l’image, nous devons recentrer le point de pivot.

        inclinometerJeepFrontPosition.x -= rotationInclinometerJeepFront->w/2-compatibleInclinometerJeepFront->w/2;
        inclinometerJeepFrontPosition.y -= rotationInclinometerJeepFront->h/2-compatibleInclinometerJeepFront->h/2;
        inclinometerJeepSidePosition.x -= rotationInclinometerJeepSide->w/2-compatibleInclinometerJeepSide->w/2;
        inclinometerJeepSidePosition.y -= rotationInclinometerJeepSide->h/2-compatibleInclinometerJeepSide->h/2;

Nous pouvons maintenant retourner notre surface pour pouvoir la voir sur notre écran

        SDL_Flip(screen);

Et enfin, nous devons libérer nos surfaces pour le prochain appel de la fonction graphic(). Cela évite une fuite de mémoire.

        SDL_FreeSurface(screen);
        SDL_FreeSurface(rotationInclinometerJeepFront);
        SDL_FreeSurface(rotationInclinometerJeepSide);

Vous pouvez maintenant appeler la fonction graphics() depuis votre boucle principale et passer les angles CFangleX & CFangleY

  graphics(CFangleX,CFangleY);

Comme il existe un certain nombre de bibliothèques que nous utilisons pour créer ce programme, nous devons les inclure lors de la compilation. Vous pouvez l’utiliser pour compiler ;

pi@raspberrypi ~ $ gcc -o gyro_accelerometer_tutorial02 -lm gyro_accelerometer_tutorial02.c `sdl-config –cflags` `sdl-config –libs` -lSDL_image -lSDL_gfx

Courir;

pi@raspberrypi ~ $ sudo ./gyro_accelerometer_tutorial02

1625600891 688 Comment creer un inclinometre a laide dun Raspberry Pi et

Si vous utilisez un petit TFT connecté à votre Raspberry Pi, vous pouvez afficher la sortie sur ce TFT comme dans la vidéo ci-dessus.

Pour ce faire, vous devez d’abord spécifier /dev/fb1 comme périphérique framebuffer.

putenv("SDL_FBDEV=/dev/fb1");

La commande ci-dessus doit être placée juste avant SDL_Init();

Vous devrez également augmenter le temps que prend chaque passage de la boucle principale. En effet, l’écriture sur le TFT entraînera des retards dans la boucle et la boucle doit s’exécuter à une heure cohérente pour que le suivi gyroscopique fonctionne. Le soufflet coupé force la boucle principale à prendre au moins 130 ms pour s’exécuter.

#define DT 0.13

        while(mymillis() - startInt < (DT*1000))
        {
            usleep(100);
        }

.