Cours:MiniQ : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m ({{Bleu|Description et utilisation des commandes moteurs}})
m (Travail à faire : Exercice 1 (arduino))
Ligne 62 : Ligne 62 :
 
</source>
 
</source>
  
===Travail à faire : Exercice 1 (arduino)===
+
==Travail à faire : Exercice 1 (arduino)==
 
Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.
 
Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.
  

Version du 22 mars 2014 à 21:07

documentations

Schéma de la carte électronique du miniQ


programmation avec arduino

Utilisation de l'adaptateur DFRobot Xbee sur le robot
ROB0081 Xbee 2.jpg



1. Si le programme fait avancer le robot dès la mise en route, pensez à le soulever et à le mettre en marche (sinon pb USB)



2. Brancher la carte de programmation (ci contre) et son cordon ! Un voyant rouge s'allume



3. Choisissez le bon type de carte dans le logiciel arduino


Arduino board.jpeg

Description et utilisation des commandes moteurs

Utilisation de analogWrite() pour la MLI

Commande des deux moteurs

Module de commande des moteurs

Le timer 0 comme les autres timers permet une commande simultanée de deux moteurs. Puisqu'il s'agit du timer 0, les deux bits associés sont OC0A en PD6 (bit 6 du PORTD) et OC0B en PD5. Si le concepteur du robot a cablé ces deux bits comme commande des moteurs il est naturel d'utiliser le timer 0. C'est le cas comme on peut le voir sur le schéma de principe. Vous voyez bien PD5 connecté à EN1... mais par contre PD6 connecté à IN2. C'est forcément une erreur : PD6 doit être connecté à EN2.

Côté puissance, la commande nécessite deux signaux :

  • ENi qui reçoit donc la MLI
  • INi qui détermine le sens de rotation

avec i=1 ou i=2 pour chacun des moteurs.

Le code d'utilisation de la PWM (ou MLI) est examiné maintenant.

Code pour utiliser les moteurs

Il est possible de trouver des exemples de programmation du robot. A partir de ces exemples nous présentons un code source légèrement modifié pour être conforme au schéma de principe. Nous avons aussi renommé les paramètres pour savoir qui est moteur gauche et droit et diminué aussi leur taille.

void Motor_Control(char MD_DIR,char MD_EN,char MG_DIR,char MG_EN){
  //////////MGauche////////////////////////
  if(MG_DIR==FORW)//M1 motor direction
    digitalWrite(IN1,FORW);//forward
  else
    digitalWrite(IN1,BACK);//back
    analogWrite(EN1,MG_EN);//set speed
  ///////////MDroit//////////////////////
  if(MD_DIR==FORW)
    digitalWrite(IN2,FORW);
  else
    digitalWrite(IN2,BACK);
    analogWrite(EN2,MD_EN);
}

Travail à faire : Exercice 1 (arduino)

Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.

1°) Voici un code complet d'initialisation et d'utilisation des moteurs :

#define EN1 6//pin for run the right motor 
#define IN1 7//pin for control right motor direction
#define EN2 5//pin for run the left motor 
#define IN2 4//pin for control left motor direction

#define FORW 1//go forward
#define BACK 0//go back

void setup(){
  pinMode(EN1,OUTPUT);
  pinMode(EN2,OUTPUT);
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
}

void Motor_Control(char MD_DIR,char MD_EN,char MG_DIR,char MG_EN){
  //////////MGauche////////////////////////
  if(MG_DIR==FORW)//M1 motor direction
    digitalWrite(IN1,FORW);//forward
  else
    digitalWrite(IN1,BACK);//back
    analogWrite(EN1,MG_EN);//set speed
  ///////////MDroit//////////////////////
  if(MD_DIR==FORW)
    digitalWrite(IN2,FORW);
  else
    digitalWrite(IN2,BACK);
    analogWrite(EN2,MD_EN);
}

void loop(){
  Motor_Control(1,100,1,100);
  delay(100);
  Motor_Control(0,0,0,0);
  delay(1000);
  Motor_Control(0,100,0,100);
  delay(100);
  Motor_Control(0,0,0,0);
  delay(1000);
  while(1);
}

Modifier ce code pour réaliser un simple cercle. Seule la partie loop est à modifier !

Attention : Vos essais seront faits sur la table de travail.

  • Il y a des risques de chutes ! Soyez donc prudents !
  • Ne mettez pas de vitesses excessives !
  • N'oubliez pas que votre câble USB n'est pas infini !
  • N'oubliez pas que loop est appelé sans arrêt. Un moyen de coincer le programme est de faire la boucle infinie de l'exemple !

2°) L'inconvénient du code présenté plus haut est que pendant que les moteurs tournent le micro-contrôleur ne peut rien faire d'autre. Nous allons donc modifier profondément notre philosophie d'écriture du code.

// définition d'une durée de 2,4s
#define temps_ARRET 2400
void loop(){
  unsigned long time = millis();
  static char rapport_cyclique,avant;
  if ((time>1000)&&(time<1200)){
    rapport_cyclique = 100;avant=FORW;
  }    
  if ((time>1200)&&(time<2200)) {
    rapport_cyclique = 0;avant=FORW;
  }
  if ((time>2200)&&(time<2400)) {
    rapport_cyclique = 100;avant=BACK;
  }

//****** c'est ici qu'on arrete tout  
  if (time > temps_ARRET){ // au bout de 20s
    rapport_cyclique = 0;avant=1;
  }
  Motor_Control(avant,rapport_cyclique,avant,rapport_cyclique); 
}

On voit que le code n'est pas bloqué par un "while(1)" et que les actions à entreprendre sont faites en fonction du temps courant qui est obtenu avec "millis()". On voit aussi qu'en fin de boucle on a prévu un arrêt des moteurs. Ceci est important à réaliser systématiquement. Réaliser le cercle de la première question avec cette technique.

3°) Réaliser maintenant votre huit (deux cercles se touchant par un point). On pourra réaliser tout cela dans le noir avec une prise de trajectoire par appareil photo à pose longue.

4°) Étude du rayon du cercle. Nous avons vu en cours que Échec d'analyse (L’exécutable <code>texvc</code> est introuvable. Lisez math/README pour le configurer.): R(t) = \frac{L}{2} \frac{v_g(t)+v_d(t)}{v_g(t)-v_d(t)}

Essayez d'étudier si le rayon peut s'écrire Échec d'analyse (L’exécutable <code>texvc</code> est introuvable. Lisez math/README pour le configurer.): R = K \frac{\alpha_g+\alpha_d}{\alpha_g-\alpha_d}Échec d'analyse (L’exécutable <code>texvc</code> est introuvable. Lisez math/README pour le configurer.): \alpha_g et Échec d'analyse (L’exécutable <code>texvc</code> est introuvable. Lisez math/README pour le configurer.): \alpha_d désignent le rapport cyclique des moteurs gauche et droit (qui varient entre 0 et 255) et K est une constante à déterminer. Une des difficultés de cette question est de trouver une méthode pour essayer d'évaluer le rayon du cercle.

Utilisation de l'infra-rouge pour détecter des obstacles

Utiliser les détecteurs infra-rouge frontaux

Le robot dispose de cinq détecteurs infra-rouge pour le suivi de lignes. Ce n'est pas ces détecteurs que nous allons étudier mais un détecteur et deux émetteurs dirigés respectivement vers la droite et vers la gauche. Cela devrait nous permettre de détecter des obstacles. Le détecteur est relié à INT0/PB0 et peut donc être géré par une interruption.

L'idée générale est d'envoyer un train d'impulsions en émission et de compter ce que l'on reçoit.

Code d'émission

Vous pouvez utiliser le code suivant :

// train d'impulsion Gauche
void L_Send40KHZ(void)//left ir transmitter sends 40kHZ pulse
{
  int i;
  for(i=0;i<24;i++)
  {
    digitalWrite(L_IR,LOW);
    delayMicroseconds(8);
    digitalWrite(L_IR,HIGH);
    delayMicroseconds(8);
  }
}
//train d'impulsion Droit
void R_Send40KHZ(void)//right ir transmitter sends 40kHZ pulse
{
  int i;
  for(i=0;i<24;i++)
  {
    digitalWrite(R_IR,LOW);
    delayMicroseconds(8);
    digitalWrite(R_IR,HIGH);
    delayMicroseconds(8);
  }
}

Si vous regardez attentivement le schéma de principe vous déduisez facilement que l'émission se fait à l'aide d'un zéro. Ce code nécessite les définitions suivantes

#define IR_IN  8//IR receiver pin
#define L_IR 9//left ir transmitter pin
#define R_IR 10//right ir transmitter pin

Réception par interruption

L'interruption est d'abord initialisée à l'aide du code :

void pcint0_init(void)
{
	PCICR = 0X01;
	PCMSK0 = 0X01;//Autorisation de l'interruption INT0
}

Le code de l'interruption est tout simple :

ISR(PCINT0_vect)
{
	count++;//on incrémente le compteur pour chaque impulsion reçue
}

setup() associé

pinMode(L_IR,OUTPUT);//init the left transmitter pin
pinMode(R_IR,OUTPUT);//init the right transmitter pin
pinMode(IR_IN,INPUT);//init the ir receiver pin
digitalWrite(R_IR,HIGH);
digitalWrite(L_IR,HIGH);
pcint0_init();
sei();

Un code pour éviter les obstacles

Tout ce qui précède peut être utilisé pour détecter et donc éviter les obstacles. L'idée générale est très simple :

  • on initialise le compteur à 0
  • On émet à droite 24 impulsions on compte ce que l'on reçoit.
  • si c'est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
  • on initialise le compteur à 0
  • On émet à gauche 24 impulsions on compte ce que l'on reçoit.
  • si c'est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.

La mise au point de ce code peut prendre beaucoup de temps.

Travail à faire : exercice 2

Vous devez mettre au point un code qui permette de ne jamais percuter des bords.