Associacion Robot ICAM Toulouse
  Dimanche 18 Mai 2025
RobotICAM
Coupe 2006
Notre Robot
Support Elec
Support Info
Support Meca

Tutorial: Programmation Accelerométre

By Benjamin BAQUE
 
       

Télécharger

 

Nous avons essayé de faire une balise capable de calculer ses propres déplacements sur un terrain plat. Son but était de calculer les variations de coordonnée du robot sur des temps relativement court. Pour cela, nous avons utilisons des accéléromètre 2 axes, placé à une distance fixe l'un de l'autre. Théoriquement il est donc possible de connaitre la variation de coordonnée et d'attitude (angle du robot par rapport à un bord du terrain) du robot. Le problème c'est qu'un sol parfaitement plat n'existe pas. Même avec la procédure d'étalonnage, il suffit que l'inclinaison du terrain varie de 1/10eme de degrés, pour que les calculs divergent.

La solution présentée ici n'est donc pas fiable. Mais c'est une base permettant de développer un système avec des accéléromètres 3 axes.

Il est en effet important d'avoir des accelerométres 3axes afin de pouvoir enlever la composante de gravitation universelle. Une fois celle ci éliminé, le système devient assez fiable et permet d'avoir des mesures avec une précision de 1% théoriquement.

Avec le système 2 axes, sur un terrain le plus plat possible, nous obtenions une précision de 5%. Mais la gravitation faussait bien entendu les résultats.

La Méthode1, permet de lire un total de 4 axes. Etant donnée la rapidité du microcontrôleur, un algorithme de détection de front montant et décendant suffit. Cependant, la méthode 2 illustre l'utilisation des Captures du pic.

Enfin, nous avons utilisé un module USB afin de pouvoir transféré les résultats rapidement, sans perdre d'information. Si la vitesse du quartz est assez élevé (voir datasheet), il est possible de transmettre jusqu'a un 1Mbps.

 

Methode1 :

//--------------------------------------------------------------
//--------------------------------------------------------------
//              ACELEROMETRE 4 AXES   BY BEN
//              Version 1.0.1 du 28 avril 2006
//              VITESSE a 16Mips
//--------------------------------------------------------------
//--------------------------------------------------------------

//
//Le code suivant detecte les fronts montants et d�endant d'un signal
//de type PWM, g���par les acc��om�res doubles axes.
//Dans cette version, les captures ne sont pas utilis�
//

#include <p30f2010.h>
#include <uart.h>
#include <stdio.h>
#include <stdlib.h>

_FOSC(CSW_FSCM_OFF & XT_PLL16); //XT with 16xPLL oscillator, Failsafe clock off
_FWDT(WDT_OFF);                 //Turn off the Watch-Dog Timer.
_FBORPOR(MCLR_EN & PWRT_OFF);   //Enable MCLR reset pin and turn off the
                                //power-up timers.
_FGS(CODE_PROT_OFF);            //Disable Code Protection


//----------------------------------------------------------------------------
//      VARIABLE
//----------------------------------------------------------------------------

char buffer[16];        // Buffer com serie

//Variable Port Serie
#define FCY             16000000
#define BAUDRATE        57600

unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
unsigned char Digit1 = 0;
unsigned char Digit2 = 0;
unsigned char Digit3 = 0;
unsigned char Digit4 = 0;
unsigned char Digit5 = 0;

//variables d'acceleration
unsigned char front = 0;
unsigned int TimeL[2];
unsigned int TimeH[2];
signed int buffA = 0;

unsigned int T1[4];
unsigned int T2 = 0;
unsigned int buf[16];


//----------------------------------------------------------------------------
//      INITIALISATION PORTS                   
//----------------------------------------------------------------------------
void inipic(void)
{       
        OSCCON = 0b0011001101000000;    //Config Oscillateur...
        TRISC = 24575;                  // Initialisation des ports     
        TRISE = 3;      PORTE = 0;      // RE0-8: input
}

//----------------------------------------------------------------------------
//      INIT TIMER
//----------------------------------------------------------------------------

void init_timer(void)
{
        T1CONbits.TGATE = 0;
        T1CONbits.TCKPS = 0b01;         //Prescaler
        T1CONbits.TCS   = 0;            //Selectione l'oscilateur du pic
        PR1             = 60000;        //Valeur Max
        T1CONbits.TON   = 0;            //Demarrer/Eteindre le timer
}

//----------------------------------------------------------------------------
// INIT PORT SERIE
//----------------------------------------------------------------------------
void init_serie(void)
{
        unsigned int baudvalue;
        unsigned int U1MODEvalue;
        unsigned int U1STAvalue;

        ConfigIntUART1(UART_RX_INT_DIS & UART_TX_INT_DIS );
        U1MODEvalue = UART_EN & UART_IDLE_CON & UART_ALTRX_ALTTX &
                                 UART_DIS_WAKE & UART_DIS_LOOPBACK &
                                 UART_DIS_ABAUD & UART_NO_PAR_8BIT &
                                 UART_1STOPBIT;
        U1STAvalue =  UART_INT_TX_BUF_EMPTY &
                                 UART_TX_PIN_NORMAL &
                                 UART_TX_ENABLE & UART_INT_RX_CHAR &
                                 UART_ADR_DETECT_EN &
                                 UART_RX_OVERRUN_CLEAR;
        baudvalue = ((FCY/16)/BAUDRATE) - 1;
        OpenUART1(U1MODEvalue, U1STAvalue, baudvalue);
}

//----------------------------------------------------------------------------
//      COM SERIE
//----------------------------------------------------------------------------
void putsUSART_rom(char *data) // Envoi d'une chaine de caractere sur serie
{
        //Envoie
        do
        {
        while (BusyUART1());
                putcUART1(*data);
        }
        while (*data++);
}

//----------------------------------------------------------------------------
//      ENVOYER CHIFFRE PAR PORT SERIE
//----------------------------------------------------------------------------
void SendData(signed int mynumber)
{
        // Ecris sur le port le mot
        //Premiere variable
        Digit1 = 0; Digit2 = 0; Digit3 = 0; Digit4 = 0;
        //Le signe
        if (mynumber < 0) { buffer[0]=0x2D;     mynumber = -mynumber; }
        else { buffer[0]=0x2B; }
       
        //Les chiffres
        while (mynumber>9999){Digit1++; mynumber = mynumber-10000;}
        while (mynumber>999) {Digit2++; mynumber = mynumber-1000;}
        while (mynumber>99)  {Digit3++; mynumber = mynumber-100;}
        while (mynumber>9)   {Digit4++; mynumber = mynumber-10;}
        Digit5 = mynumber;
       
        buffer[1] = Digit1+0x30;
        buffer[2] = Digit2+0x30;
        buffer[3] = Digit3+0x30;
        buffer[4] = Digit4+0x30;
        buffer[5] = Digit5+0x30;
        putsUSART_rom(buffer);
}

//----------------------------------------------------------------------------
//      INITIALISATION DE T1 SUR CHAQUES AXES
//----------------------------------------------------------------------------
void initT1_E0()
{       signed long T1buff =0;
        //Effectue 5 messures
        for (i=0;i<16;i++)
        {       
                while (!PORTEbits.RE0);                                 // Attend le front montant
                T1CONbits.TON   = 0;TMR1 = 0;T1CONbits.TON      = 1;    //Amorce le Timer1
                while (PORTEbits.RE0){buf[i] = TMR1;}                   //Attend le front d�endant
                T1buff = T1buff + (signed long) buf[i];
        }
       
        T1[0] = T1buff/16;      //D�ermine T1
        T1[0] = (buf[1]+buf[2])/4 +(buf[3]+buf[4])/4;
}

void initT1_E1()
{       //Effectue 5 messures
        for (i=0;i<16;i++)
        {       
                while (!PORTEbits.RE1);                                 // Attend le front montant
                T1CONbits.TON   = 0;TMR1 = 0;T1CONbits.TON      = 1;    //Amorce le Timer1
                while (PORTEbits.RE1){buf[i] = TMR1;}                   //Attend le front d�endant
        }
        T1[1] = (buf[1]+buf[2])/4 +(buf[3]+buf[4])/4;           //D�ermine T1
}

//----------------------------------------------------------------------------
//      INITIALISATION DE T2 SUR LES 2 ACCELERO
//----------------------------------------------------------------------------
void initT2(void)
{       //Effectue 5 messures
        for (i=0;i<5;i++)
        {
                while (!PORTEbits.RE0) {buf[i] = TMR1;}         // Attend le front montant     
                T1CONbits.TON   = 0;TMR1 = 0;T1CONbits.TON = 1; //Amorce le Timer1
                while (PORTEbits.RE0);                          //Attend le front d�endant
        }
        T2 = (buf[1]+buf[2])/4 +(buf[3]+buf[4])/4;              //D�ermine T2
}

//----------------------------------------------------------------------------
//      DETECTION DES FRONTS
//----------------------------------------------------------------------------
void detection(void)
{
        //Detection du premier front montant avant de lancer le timer
        while (!PORTE);
        T1CONbits.TON   = 1;

        //Detection des fronts
        front = 0;
        TimeH[0] =0; TimeL[0] = 0;
        TimeH[1] =0; TimeL[1] = 0;
        while (front != 3)
        {
                //Detection des fronts montants
                if ((PORTEbits.RE0 == 1) && (TimeH[0] == 0)) {TimeH[0] = TMR1; front = front+1;}
                //Detection des fronts decendant
                if ((PORTEbits.RE0 == 0) && (TimeL[0] == 0) && (TimeH[0] !=0)) {TimeL[0] = TMR1;front = front+1;}
                if ((PORTEbits.RE1 == 0) && (TimeL[1] == 0) && (TimeH[0] !=0)) {TimeL[1] = TMR1;front = front+1;}
        }              
}

//----------------------------------------------------------------------------
//      MAIN
//----------------------------------------------------------------------------
int main(void)
{
        //Initialisation PIC
        inipic();
        init_serie();
        init_timer();

        //Initialisation Accelero
        initT1_E0();
        initT1_E1();

        initT2();

        signed long mytest = 0; //2 miliards
        signed long myfloat;
        signed long A0 =0;
        signed long V0 =0;
        signed long X0 =0;
        signed long A1 =0;
        signed long V1 =0;
        signed long X1 =0;

        //Lancement boucle principale
        while (1)
        {       
                //Messures des 8 fronts
                detection();

                //Calcul apr� que le dernier signal soit red�endu �0
                //Acceleration: 500 = 9,80m/s
                        //Accelero1:
                        buffA = TimeL[0] - TimeH[0] - T1[0];
                        buffA = buffA * 2 ;
                        A0 = (signed long) buffA;       
                        X0 = X0 + A0 + V0;      //Calcul position
                        V0 = 2*A0+V0;           //Calcul de la vitesse

                        //Accelero2:
                        buffA = TimeL[1] - TimeH[0] - T1[1];
                        buffA = buffA * 2 ;
                        A1 = (signed long) buffA;       
                        X1 = X1 + A1 + V1;      //Calcul position
                        V1 = 2*A1+V1;           //Calcul de la vitesse         


                //Envoi des r�ultats
                k++;
                if ( k == 200)
                {       k = 0;
                        mytest = X0/10000;
                        buffA = (signed int) mytest;
                        SendData(buffA);

                        mytest = X1/10000;
                        buffA = (signed int) mytest;
                        SendData(buffA);
                        X0 = 0; V0 = 0;
                        X1 = 0; V1 = 0;
                }

                //Eteint le timer
                T1CONbits.TON   = 0;
                TMR1 = 1;
        }
}
//---------------------------------------------------------------------------

Pour toutes questions: benjamin.baque AT polymtl.ca

Copyright © 2006 RobotIcamToulouse