This guide covers how to use an Inertial Measurement Unit (IMU) with a Raspberry Pi to create an inclinometer, just like the type you will find in a 4WD.

A prerequisite for this guide is to have a gyro and accelerometer from an IMU already up and running on your Raspberry Pi. A guide to interfacing an IMU with a Raspberry Pi can be found here.

We will be covering some basic SDL which will be used to produce our graphics.

The IMU used in this guide is the BerryIMU. However, other IMUs or accelerometers and gyroscopes can be used.. Eg Pololu MinIMU, Adafruit IMU and Sparkfun IMUs

Git repository here

The code can be pulled down to your Raspberry Pi with;

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

The code for this guide can be found under the gyro_accelerometer_tutorial02_inclinometer directory.

Installing SDL

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

If you want to test to see if SDL installed correctly, you can create a file called test.c and copy in the code below;

#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; }

The above code can be compiled with;

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

And to run the program;

pi@raspberrypi ~ $ sudo ./test

You should see your screen go white or a white square should be shown.

Setup SDL and Load Images

We will be adding to the code which was already created in the Guide to interfacing a Gyro and Accelerometer with a Raspberry Pi guide.

As we are using SDL, we will need to include the SDL header files in our program;

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

When using SDL, you first have to initialize SDL and setup your surfaces before you can start displaying information on the screen. The next section shows how this is done.

The two lines below initialize SDL and sets it to not display a cursor;

SDL_Init(SDL_INIT_VIDEO); SDL_ShowCursor(SDL_DISABLE);

We then use the SDL_GetVideoInfo() function to get information about our display. E.g. Resolution and bits per pixel,etc. This is stored in the structure 'videoinfo'. To view what height was returned, we would use 'videoInfo->current_h'

We then use this information to create our screen, using the SDL_SetVideoMode() function. This function needs these parameters, X Resolution, Y resolution, bits per pixel and display surface type. In the code below we are using a software surface for the display type.

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: %s

", SDL_GetError()); exit(1); }

Once we have setup SDL, we can start loading our images.

inclinometerOverlay = IMG_Load("inclinometerOverlay.png"); if (inclinometerOverlay == NULL){ printf("error loading Overlay image

"); SDL_Quit(); exit(1); }

After we load the image, which is a PNG, we need to convert it to the correct format so it keeps its transparency

compatibleInclinometerOverlay = SDL_DisplayFormatAlpha(inclinometerOverlay);

Rotate Images Based on Gyroscope and Accelerometer Angles

We will create a function to rotate our images as this will need to be done every time the main program loop is processed. We will pass two parameters to this function, carRoll(which is the X angle) and CarPitch(which is the Y angle).

int graphics(float carRoll, float carPitch)

The first task we want to do in the function is erase all information on the current surface. This can be done by using SDL_FillRect() and the value 0x000000, which is black.

SDL_FillRect(screen,NULL,0x000000);

The next section of code will position the two jeep images correctly onto our surface. The formula for the 'y' position will place it in the middle of the 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);

We can now rotate our images based on the angle from the IMU. To do this we will use the rotozoomSurface() function. We will pass to it our compatible jeep images, the roll and pitch angles, the zoom factor(1.0 for no zoom) and smoothness (0 for no smooth).

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

After we rotate the image, we need to recenter the pivot point.

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;

We can now flip our surface so we can see it on our display

SDL_Flip(screen);

And finally, we need to free our surfaces for the next time the graphic() function is called. This prevents a memory leak.

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

Update Main Loop

You can now call the graphics() function from your main loop and pass the angles CFangleX & CFangleY

graphics(CFangleX,CFangleY);

Compile and Run

As there are a number of libraries we are using to create this program, we have to include them when compiling. You can use this to compile;

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

To run;

pi@raspberrypi ~ $ sudo ./gyro_accelerometer_tutorial02

Displaying the Output on a Small TFT

If you are using a small TFT connected to your Raspberry Pi, you can have the output shown on this TFT just like in the video above.

To do this, you fist need to specify /dev/fb1 as the framebuffer device.

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

The above command needs to be place just before SDL_Init();

You will also need to increase the time that each pass of the main loop takes. This is because writing to the TFT will cause some delays in loop and the loop needs to run at a consistent time so that the gyro tracking will work. The bellow snipped forces the main loop to take at least 130ms to run.

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

.