RobotGEII 16-17

De troyesGEII
Révision datée du 30 novembre 2016 à 00:45 par Robot (discussion | contributions) ({{Bleu|Présentation projet}})
Aller à : navigation, rechercher

Présentation

Présentation projet

Ce projet consiste à réaliser un robot pour participer à la coupe robotique GEII. Pour fabriquer ce robot nous devons respecter un cahier des charges définit par le règlement(reglement).Le principe de ce concours est aller le plus rapidement possible d'un coin à l'autre tout en esquivant les obstacles et les autres robots.Une fois arriver dans le coin le robot doit exploser un ballon qui lui est accroché dessus en début de course.

Cahier de charges fonctionnelles

Schema fonctionnelle de degrés II

Shema fonctionnelle.png

shema fonctionnelle 1er degres

Shema fonctionnelle 1er degres.png
Shema fonctonnelle 2.png

Solution technique

Pour fabriquer ce robot nous avion plusieurs choix pour procéder à l’évitement des obstacles, nous avons choisie de lier trois technologie pour éviter d’être influencer par les kart adverse lors de la course,nous allons donc utiliser des capteur infrarouge,de capteur ultrason et un caméra CMU cam 5. Pour contrôler tous les capteur ainsi que la caméra nous allons utiliser une carte rasberrie pi.Nous allons également utiliser la camera pour pour déterminer le coin d'arriver du robot grâce à une balise que la caméra reconnaîtra.

Etude du Robot

Batterie, Moteurs, Hacheurs

Description technique

...

Contrôle deux moteurs CC par un shield (L298P)

Pour commander les moteurs nous allons utiliser le pont H L298P [ datasheet].

L298P

Le composant est ci-dessous:

L298P

Pour faire des tests nous avons utlisé le Motor Shield For Arduino. En conectant ce shield à l'arduino nous pouvons commander les deux moteurs moteurs (commande du sens et de la vitesse).

L298P
  • PWM

Nous allons utiliser le shild en mode PWM, on placera donc les jumpers en conséquence.

L298P
  • Borne du moteur

Nous avons deux bornes (blues) pour connecter les moteurs CC. Les connecteurs mâles derrière sont identiques à celui des bornes blues.

L298P
  • PWRIN

Les moteurs peuvent être alimentés par une alimentation externe lorsque le courant du moteur dépasse les limites fournies par l'Arduino (Il est conseillé de séparer les alimentations d’Arduino et des moteurs). Le switch entre la puissance externe et l'arduino est mis en oeuvre par deux jumpers .

PWRIN: Alimentation externe.
VIN: Alimentation du Arduino.

On placera donc les jumpers d’alimentation sur PWRIN.

Arduino Shield6.png


On doit avoir quelque chose comme cela:

L298P
  • Signal de contrôle Tableau de vérité
E1 M1 E2 M2 Texte de l’en-tête
L X Moteur 1 desactivé L X Moteur 2 desactivé
H H Moteur 1 en arrière H H Moteur 2 en arrière
H L Moteur 1 en avant H L Moteur 2 en avant
PWM X Control vitesse PWM PWM X Control vitesse PWM

NOTE:

H: Niveau haut
L: Niveau bas
X: N'importe quel niveau.

  • Mode PWM
Commande Pin Arduino Siginification
M1 4 Contrôle du sens de rotation
E1 5 Contrôle de la vitesse de rotation
M2 7 Contrôle du sens de rotation
E2 6 Contrôle de la vitesse de rotation


  • Exemple de code basique
int E1 = 5;  
int M1 = 4; 
int E2 = 6;                      
int M2 = 7;                        

void setup() 
{ 
    pinMode(M1, OUTPUT);   
    pinMode(M2, OUTPUT); 
} 

void loop() 
{ 
  int value;
  for(value = 0 ; value <= 255; value+=5) 
  { 
    digitalWrite(M1,HIGH);   
    digitalWrite(M2, HIGH);       
    analogWrite(E1, value);
    analogWrite(E2, value);
    delay(30); 
  }  
}


  • Exemple simple de code pour eviter des obtacles avec un seule capteur ultrason
//Moteur 1
int E1 = 5; // Vitesse (PWM)
int M1 = 4; // Direction

//Motor 2
int E2 = 6; // Vitesse (PWM)
int M2 = 7; // Direction


  ///////////////
 // Constantes//
///////////////

const int MOTEUR_1=0;
const int MOTEUR_2=1;

const int AVANT=0;
const int ARRIERE=1;

  ///////////////
 // UltrasonG//
//////////////

int trig = 13;
int echo1 = 12;
long lecture_echo1;
long cm1;

  //////////
 // Setup//
//////////

void setup()
{

  pinMode(E1, OUTPUT);
  pinMode(M1, OUTPUT);

  pinMode(E2, OUTPUT);
  pinMode(M2, OUTPUT);

 pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  pinMode(echo1, INPUT);
  Serial.begin(9600);

}

  //////////
 // Loop///
//////////

void loop(){

  
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  lecture_echo1 = pulseIn(echo1, HIGH);
  cm1 = lecture_echo1 / 58;
 Serial.print("Distancem : ");
  Serial.println(cm1);
  delay(200);

  if(cm1>15 )
  {
  activer(MOTEUR_1, AVANT, 128);
  activer(MOTEUR_2, AVANT, 128);
  }else if(cm1>2) {
    
   activer(MOTEUR_1, ARRIERE, 128); 
   activer(MOTEUR_2, AVANT, 128);
   delay(500);
   activer(MOTEUR_1, AVANT, 128); 
   activer(MOTEUR_2, AVANT, 128);
   delay(1000);
   activer(MOTEUR_1, AVANT, 128); 
   activer(MOTEUR_2, ARRIERE, 128);
  delay(500);
  activer(MOTEUR_1, AVANT, 128);
  activer(MOTEUR_2, AVANT, 128);
  delay(1000); 
    }
}

  /////////////////////
 // Fonction activer//
/////////////////////

void activer(int moteur, int sens, int vitesse)
// moteur : MOTEUR_1 ou MOTEUR_2
// sens : AVANT ou ARRIERE
// vitesse : entre 0 et 255

{

  switch (moteur)
  {
  case MOTEUR_1 :
    if (sens==AVANT)
    {
      digitalWrite(M1, HIGH);       
      analogWrite(E1, vitesse);
    }
    else
    {
      digitalWrite(M1, LOW);       
      analogWrite(E1, vitesse);
    }
    break;

  case MOTEUR_2 :
    if (sens==AVANT)
    {
      digitalWrite(M2, HIGH);       
      analogWrite(E2, vitesse);
    }
    else
    {
      digitalWrite(M2, LOW);       
      analogWrite(E2, vitesse);
    }
    break;
  }
}

  //////////////////////////
 // Fonction arreter_tout//
//////////////////////////

void arreter_tout()
{
  analogWrite(E1, 0);
  analogWrite(E2, 0);
}

  /////////////////////
 // Fonction arreter//
/////////////////////

void arreter(int moteur)
{
  switch (moteur)
  {
  case MOTEUR_1 :
    analogWrite(E1, 0);

  case MOTEUR_2 :
    analogWrite(E2, 0);
  }
}

Estimation de la position du robot

Carte Capteur

L'odométrie nous permettra d'estimer la position du robot en mouvement, des le debut et jusqu'à la détéction de la balise par la caméra. C'est à partir de la mesure des déplacements des roues, qu'on pourra reconstituer le mouvement du robot. En partant d'une position initiale connue et en intégrant les déplacements mesurés, on peut ainsi calculer à chaque instant la position courante du véhicule.


Pour mésurer le déplacement des roues, nous allons utiliser un encodeur, monté sur l'axe de chaque roue.

Encodeur roue.PNG


On doit obtenir: 1.LA VITESSE 2.LE SENS DE ROTATION DES ROUES


ENCODEUR DE BASE: Ce montage basique permet de mesurer la vitesse de rotation à partir de la fréquance, mais il ne permet pas de connaitre le sens de rotation.

principe


ENCODEUR EN QUADRATURE: Celui-ci nous permettra de connaitre à la fois le sens et la vitesse des roues. Il est composé d’un disque rotatif, 1 led infrarouge et 2 capteurs optique décalé un par rapport à l’autre de 90°. C’est justement ce décalage la qui va nous permettre de connaitre le sens de rotation de la roue. Suivant le sens de rotation, nous auront deux signaux déphasés en avance/retard de 90°.La vitesse sera déterminé en fonction de la fréquence.

Encodeur en quadrature.PNG


Signaux de sortie.PNG
            Les signaux de sortie à l’oscilloscope 


Roue codeuse

Pour determiner la frequence des moteurs nous allons utiliser une Roue Codeuse et un capteur. Nous avons créé le roue sur le logiciel GEFAO et fabrication avec la machine charlyrobot. Vous trouverez ici le fichier le la roue (Fichier:RoueCodeuse.zip).


Roue Codeuse composée de 30 dents


Cette roue sera placer sur l'arbre des motors et sur les deux capteurs, lorsque le moteur est en train de tourner les capteurs va nous envoyer une signal qui se resamblera à celui-ci:


  • Si la roue en avant


Signal capteurRC.jpg


  • Si la roue en avant arriere


Signal capteurRCarriere.jpg


il faut remarquer que si le robot avance, la roue codeuse est en arriere et si le robot recule la roue codeuse est en avant. Ce effet est du aux engranages qui sont sur les moteurs.


  • Determination de la position du robot

Dans cette partie on va s'en servir des interruption est de timers. On utilisera les inturruptions (INT0 et INT1) pour dechancher un code a chaque fois que les dents de la roue travers le flux lumineuse du capteurs (sur le front montant et front descendant). Nous allons aussi utliser un timer qui sera dechancher sur un temps assez petit (<10ms) pour calculer un deltaX, un deltaY et un detaTeta qui nous permetront de determiner la position du robot.

#include <math.h>

volatile uint8_t NbDentsD=0;
volatile uint8_t NbDentsG=0;

float Delta_X=0;
float Delta_Y=0;

float d=51.17;//Rayon de la roue codeuse
float Delta_Dent=PI*d/60.0;//verificar el verdadero valor o sino hacer que los dientes y el espaciado entre dientes sea el mismo
//Preguntar al profesor.
float L=230.0;//230mm entre les roues

float Position_X=0;
float Position_X_precendent=0;//en realidad tiene un valor inicial

float Position_Y=0;
float Position_Y_precendent=0;

float Teta=0;
float Teta_precedent=0;

int n=0;

/*float position_X()
{
  Position_X=Position_X_precendent+Delta_X;
  Position_X_precendent=Position_X; 
  return Position_X;
}*/

/*  float position_Y()
{
  Position_Y=Position_Y_precendent+Delta_Y;
  Position_Y_precendent=Position_Y;
  return Position_Y;
}*/


 ISR(TIMER1_COMPA_vect)
 {
  float Delta_D=(NbDentsD*Delta_Dent);//*((52.45/2.0)*(12/60.0));//mm
  float Delta_G=(NbDentsG*Delta_Dent);//*((52.45/2.0)*(12/60.0));//mm
  
   
  float Delta_moy=(1/2.0)*(Delta_D+Delta_G);
  float Delta_dif=Delta_D-Delta_G;
  float Delta_teta=Delta_dif/L;
  
    
  Delta_X=Delta_moy*cos(Teta_precedent);//Teta_precedent
  Delta_Y=Delta_moy*sin(Teta_precedent);
  
  Teta=Teta_precedent+Delta_teta;
  Teta_precedent=Teta;

  Position_X=Position_X_precendent+Delta_X;
  Position_X_precendent=Position_X; 
  
  Position_Y=Position_Y_precendent+Delta_Y;
  Position_Y_precendent=Position_Y;
  
  ///TEST
  /*Serial.print(NbDentsD);
  Serial.print("  ");
  Serial.println(NbDentsG);*/
  
  ///TEST
  /*Serial.print(NbDentsD);
  Serial.print("  ");
  Serial.print(Delta_D);
  Serial.print("  ");
  Serial.print(NbDentsG);
  Serial.print("  ");
  Serial.println(Delta_G);*/

  //TEST
  /*Serial.print(Delta_D);
  Serial.print("  ");
  Serial.print(Delta_G);
  Serial.print("  ");
  Serial.println(Delta_moy);*/

  //TEST
  /*Serial.print(NbDentsD);
  Serial.print("  ");
  Serial.print(NbDentsG);
  Serial.print("  ");
  Serial.println(Delta_moy);*/

  //TEST
  /*Serial.print(Delta_D);
  Serial.print("  ");
  Serial.print(Delta_G);
  Serial.print("  ");
  Serial.println(Delta_dif);/*

  //TEST
  /*Serial.print(Delta_dif);
  Serial.print("  ");
  Serial.print(Delta_teta);Serial.print("rad");
  Serial.print("  ");
  Serial.print(Delta_teta*(180.0/PI));Serial.println("gr");*/

  //TEST
  /*Serial.print(Delta_dif);
  Serial.print("  "); 
  Serial.print(Delta_teta*(180.0/PI));
  Serial.print("  ");
  Serial.println(Teta*(180.0/PI));*/
  
  //TEST
  /*Serial.print(Teta_precedent);
  Serial.print("  ");
  Serial.print(Delta_moy);
  Serial.print("  "); 
  Serial.print(Delta_X);
  Serial.print("  ");
  Serial.println(Delta_Y);*/

  //TEST
 // Serial.print(Delta_X);
 // Serial.print("  ");
  //Serial.print(Delta_Y);
 // Serial.print("  ");
  /*Serial.print(position_X());
  Serial.print("  ");
  Serial.println(position_Y());*/
  
  if(n<100)
  {
  Serial.print(NbDentsD);
  Serial.print(" ");
  Serial.print(NbDentsG);
  Serial.print(" ");
  Serial.print(Position_X);
  Serial.print(" ");
  Serial.println(Position_Y);
  n++;
  }
  
  /*Serial.print("NbDentsD: "); Serial.print(NbDentsD);
  Serial.print("   ");
  Serial.print("NbDentsG: "); Serial.println(NbDentsG);*/
  

  /*Serial.print("Delta_Y: "); Serial.print(Delta_Y);
  Serial.print("   "); 
  Serial.print("Delta_teta: "); Serial.println(Delta_teta);*/
  
  //Serial.print("NbDentsD TIMER1: "); Serial.print(NbDentsD);
  
  //Serial.print("position_X: "); Serial.println(position_X());
  //Serial.print("   "); 
  //Serial.print("position_Y: "); Serial.println(position_Y());
  PORTB^=(1<<PB5);
  //Serial.println("TIMEEEEEEEEEEEEEEEEEEEEEER1");
  NbDentsG=0;
  NbDentsD=0;
  

  }
  
ISR(INT0_vect)
{
  uint8_t Pin2= PIND & (1<<PD2);//INTERRUPTION INT0 sur PD2
  uint8_t Pin8= PINB & (1<<PB0);

  //Serial.println("Interruption INT0");
  
  if(Pin2!=0)
  {
    if(Pin8==0) NbDentsD++;
           else NbDentsD--;
    }
   else if(Pin2==0)
   {
    if(Pin8!=0) NbDentsD++;
           else NbDentsD--;
    }
  /*Serial.print("Pin2: "); Serial.print(Pin2);
  Serial.print("   ");
  Serial.print("Pin4: "); Serial.print(Pin4); */
 // Serial.print("   ");
 /* Serial.print("NbDentsG: "); Serial.print(NbDentsG);
  Serial.print("   ");
  Serial.print("NbDentsD: "); Serial.println(NbDentsD);*/
  
  //Serial.print("   ");
  //Serial.print("NbDentsD INT0: "); Serial.println(NbDentsD);
}


ISR(INT1_vect)
{
  uint8_t Pin3 = PIND & (1<<PD3);//INTERRUPTION INT1 sur PD3
  uint8_t Pin9 = PINB & (1<<PB1);

  if(Pin3!=0)
  {
    if(Pin9==0) NbDentsG++;
           else {NbDentsG--; }//if (NbDentsG<0 || NbDentsG==255) NbDentsG=0;}
    }
   else if(Pin3==0)
   {
    if(Pin9!=0) NbDentsG++;
           else {NbDentsG--;}// if (NbDentsG<0 || NbDentsG==255) NbDentsG=0;}
    }
}

void int0()
{
  //INTERRUPTION INT0
  //PIN2 -->PD2--> INT0 entrée
  EIMSK |= 1<<INT0; //Autorisation interruption INT0
  EICRA |= 1<<ISC00; //Activation sur changement d'etat sur PD2
}


void int1()
{
  //INTERRUPTION INT1
  //PIN3 -->PD3--> INT1 entrée
  EIMSK |= 1<<INT1; //Autorisation interruption INT0
  EICRA |= 1<<ISC10; //Activation sur changement d'etat sur PD2
}


void timer1()
{
  //TIMER1 declanchement chaque 100ms.

  TCCR1B|=(1<<CS10)|(1<<CS11);//Prediviseur p=8 1<<CS11; p=64 (1<<CS10)|
  TCCR1B|=1<<WGM12;//RAZ (CTC)
  TIMSK1|=1<<OCIE1A;//Autorisation d'interruption de comparaison A
  OCR1A=7500;//Comparaison avec p=8 20000 10ms p = 64 25000 100
  }

void sei_interruption()
{
  sei(); //Autorisation global d'interruptions
}

int main()
{   
    DDRB|=1<<PB5;
    //DDRD|=1<<PD6;
   // DDRD|=1<<PD7;
    int0();
    int1();
    timer1();
    sei_interruption();
    Serial.begin(9600);
   while(1)
  {
     /*_delay_ms(100);
     PORTB^=(1<<PB5);*/
    /*PORTD|=1<<PD6;
    _delay_ms(15);
    PORTD|=1<<PD7;
    _delay_ms(15);
    PORTD&=~(1<<PD6);
    _delay_ms(15);
    PORTD&=~(1<<PD7);
    _delay_ms(15);*/
    }
  }

Commande moteurs

Nous allons gerer les moteurs par des signaux PWM (-255 a 255), le signe moins(-) indique motor en arrier et le plus(+) en avant. Cette code pour permet de gerer le deux motors par la fonction setVitesse(vG,vD). Dans la suit nous allons l'utiliser pour gerer le deplacement du robot.


#include <avr/io.h>

#define topPWM 255
 
void initMoteur()
{
  //Sorties
  DDRB|=(1<<PB0)|(1<<PB1);
  DDRD|=(1<<PD5)|(1<<PD6);
  //Prediviseur P=64  
  TCCR0B|=(1<<CS00)|(1<<CS01);
  //Mode FAST PWM
       //TCCR0B|=1<<WGM02;
  TCCR0A|=(1<<WGM00)|(1<<WGM01);
  //PWM sur OC0A
  TCCR0A|=1<<COM0A1;
  //PWM sur OC0B
  TCCR0A|=1<<COM0B1;  
  //Valeur de comparaison
  OCR0A=0;// valeur max PWM -> fmli = fq / (topPWM * prediv )
  OCR0B=0;
}

void setVitesse(int16_t vG, int16_t vD)
{
  setMoteurD(vD);
  setMoteurG(vG);
}

void setMoteurG(int16_t vit)
{
  if (vit<0)
  {
    vit = -vit;
    PORTD |= (1<<PD4);
  }
  else PORTD &=~ (1<<PD4);
  if (vit>topPWM) vit=topPWM;
  OCR0A = vit;
}

void setMoteurD(int16_t vit)
{
  if (vit<0)
  {
    vit = -vit;
    PORTD |= (1<<PD7);
  }
  else PORTD &=~ (1<<PD7);
  if (vit>topPWM) vit=topPWM;
  OCR0B = vit;
}
  
// la vitesse des moteurs varie de -topPWM à topPWM
 
int main()
{

  initMoteur();
  while(1)
  {
    setVitesse(100,100);
    }
  
  }

Deplacement


Detection d'obstacles

Caméra

Choix camera

Nous avons tester 3 camera différente, la , la cmu cam 3 et la cmu cam 5

Cmu Cam 3.jpeg
vignette


Nous avons choisie d'utiliser la CMU cam 5(site CMU cam 5) car elle est beaucoup plus simple d'utilisation que les deux autres,en effet il suffit de de télécharger le logiciel de la camera(telechargement) qui est assez simple d'utilisation,de plus il y a des programes predefinie dans ce logicel qui permettent de faire de la reconnaissance.Nous avons egalement choisie cette caméra car elle est fourni avec des servomoteur qui vont lui permettre de bouger sur son axe. (montage servo).

Camera CMU cam 5

Tout d’abord nous avons réaliser une simple reconnaissance d'objet grâce au logiciel, il suffit pour cela de sélectionner l'objet en question. Nous avons ensuite choisie d'utiliser une balise lumineuse pour que la camera la repère le plus loin possible. balise test.



Grace à cette balise nous avons pu déterminer jusqu’ou la camera repérerait notre balise avec la taille maximum autoriser. Pour cela il suffisait d’éloigner la camera le plus possible et ensuite de faire un produit en croix.Nous avons relever que la camera pouvait capter correctement la balise dont le plus petit coté est de 3cm jusqu’à 1m20 donc on en a deduit que la camera capterait 21m.

Perçage du ballon

Choix du perçage

Nous avons testé deux moteurs ,un petit moteur et SM-S4303R et deux matériaux,le fer et le plastique pour faire la perçage:

Finalement nous avons choisi SM-S4303R,car le petit moteur est moins fort que SM-S4303R et utiliser SM-S4303R est plus facile de faire de l'aiguille pour exploser de ballon, pour l'aiguille,nous avons choisi le fer,à cause de fer est plus dure et utilisons le fer fait de la pointe d'aiguille est mieux.

montage du perçage




Bibliographie/références