Xbee télécommande (partie 3)

Fichier hébergé par Archive-Host.com

Quand on arrive à allumer des led par télécommande, on n’est pas très loin de pouvoir commander un moteur et un servo et, avec un peu de Meccano, on peut fabriquer un petit véhicule dont on commande la direction et la marche.

Les deux boutons du haut de la télécommande (voir article précédent) commandent le servo de direction ; les deux boutons du bas commandent la marche avant et la marche arrière. Le programme de la carte émetteur est le même que dans l’article précédent.

Côté récepteur, il ne s’agit plus simplement d’allumer des led, on a donc écrit ce qu’il faut pour commander le servo et le moteur. Remarquez qu’on utilise dans le même sketch les fonctions de la classe Serial1 pour communiquer avec le module Xbee et les fonctions de la classe Serial pour afficher des valeurs de contrôle sur le moniteur série dans l’interface de développement Arduino. C’est vraiment confortable à utiliser, notamment dans la phase de mise au point.

Voici le sketch correspondant écrit pour un Romeo V2 :


// Tracteur V2
// Xbee telecommande bouton poussoir
// version récepteur
// Romeo V2
// dans l'IDE Arduino choisir le type de carte Leonardo

#include <Servo.h>

const int nb_BP = 4;


// disposition telecommande

// BP 0                 BP3

//      BP1        BP2

// BP0 : tourner davantage à gauche
// BP1 : diminuer la vitesse de marche
// BP2 : augmenter la vitesse de marche
// BP3 : tourner davantage à droite

Servo myservoD; // un objet de type servo est crée (max 8 objets servo)

// ici un seul moteur mais on a gardé les
// déclarations pour 2 moteurs

int tab_Pin_sens[2] = {4,7} ; // le sens du moteur 1 est commandé par la Pin 4 
                              // le sens du moteur 2 est commandé par la Pin 7

int tab_Pin_pwm[2] = {5,6} ; // la vitesse du moteur 1 est commandée par la Pin 5 
                             // la vitesse du moteur 2 est commandée par la Pin 6

// la vitesse d'avancement varie de 
// -5 (marche arrière rapide) à
// 5 marche avant rapide

int pminM = -5 ; // position  mini marche

int pmaxM = 5 ;  // position  maxi marche

int pminD = 60 ;   // position  mini Direction

int pmaxD = 120; // position  maxi Virection

int pactM= 0 ; // position courante marche

int pactD= 90 ; // position courante direction

// les etats des boutons poussoirs

int BP0=0; 
int BP1=0;
int BP2=0;
int BP3=0;

void lire_etat()
{  

int i = 0;
int data;

for (i=0; i < nb_BP ; i++) {
  // attendre qu'il y ait quelque chose à lire     
  while (Serial1.available () == 0) ; 
    
  data = Serial1.read() -'0';         
  switch (i) {
    case 0:
      BP0=data;
      break;    
    case 1:
      BP1=data;
      break;    
     case 2:
       BP2=data;
       break;     
     case 3:
       BP3=data;
       break;      
     } // case
  } // for
  
} // lire_etat


// avancer plus vite 
void plusM ()          // marche
{
  int sens = 1;
  if ( pactM < pmaxM) {    
      pactM = pactM + 1;   
      if (pactM <= 0) sens = 0;
      controle(1,sens,abs(pactM));       
      delay(50); // attendre 50 ms après chaque changement    
    }     
    // Serial.print("Dans plusM, pact M :"); Serial.println(pactM);
}   

// avancer moins vite    
void moinsM ()          // marche
{
  int sens = 1;
  if ( pactM > pminM) {    
      pactM = pactM - 1;   
     if (pactM <= 0) sens = 0;
        controle(1,sens,abs(pactM)); 
      delay(50); // attendre 50 ms après chaque changement
    }     
}    
// tourner plus
void plusD ()          // direction
{
  if ( pactD < pmaxD) {    
      pactD = pactD + 1;   
      myservoD.write(pactD);      
      delay(50); // attendre 50 ms après chaque changement
    }     
}   
 
// tourner moins    
void moinsD ()          // direction
{
  if ( pactD > pminD) {    
      pactD = pactD - 1;   
      myservoD.write(pactD);      
      delay(50); // attendre 50 ms après chaque changement
    }     
}    

void stop_moteur(int m)
{
  controle(m,0,0) ;
  pactM=0;
  delay(500);
  
}

void init_servo()
{
 
   myservoD.write(90); 
   pactD=90;
   delay(200);   
}

// la procedure de controle des moteurs

void controle (int m, int sens, int v)          // m : 1 ou 2 pour moteur 1 ou moteur 2,                                                                                              
                                                // sens : 1 ou 0 (avant ou arrière)
                                                // v : vitesse de 0 à 3, 
{
        int pwm;
        pwm = map(v, 0,5, 0,255); // ramener vitesse à l'intervalle 0 255
        digitalWrite(tab_Pin_sens[m-1],sens);  // fixer sens
        analogWrite (tab_Pin_pwm[m-1],pwm);    // fixer vitesse
        delay(100);
                             

}

void setup() // executée une seule fois

{    
  int i;
  for(i=4;i<=7;i++)
    pinMode(i, OUTPUT);
     
 myservoD.attach(11); // attache le servo Direction à la pin 11          
 Serial1.begin(9600);    
      
}

void loop() // executée en boucle
{         
// attente de quelque chose à lire   
while (Serial1.available () == 0);  
    
if (Serial1.read () == '#')   {     
       
     lire_etat();       
     //Serial.print("BP0 : ") ;  Serial.println(BP0) ; 
     //Serial.print("BP1 : ") ;  Serial.println(BP1) ; 
     //Serial.print("BP2 : ") ;  Serial.println(BP2) ; 
     //Serial.print("BP3 : ") ;  Serial.println(BP3) ; 
     
    // combinaison de touches pour arret moteur
     if ((BP1 == 1) && (BP2 == 1)) {         
         stop_moteur(1);
     } else {
       if (BP1) moinsM() ;
          else     
          if (BP2) plusM() ;
     } 
      
       
     // combinaison de touches pour direction en position milieu     
     if ((BP0 == 1) && (BP3 == 1)) {
         init_servo() ; 
     } else {       
        if (BP0) moinsD() ; 
            else
               if (BP3) plusD() ;
     }
      
  } // entete # trouvee        
          
} // loop

Si vous n’avez pas de Romeo V2 mais un Romeo V1.1, retirez les lignes utilisant Serial puis remplacez Serial1 par Serial dans le sketch, rien d’autre n’est à changer.

L’alimentation de l’ensemble (carte, moteur, servo) est assurée par 8 piles 1,2 ou 1,5V.

Le même modèle avec un peu de carrosserie en plus, « façon tracteur » :

Fichier hébergé par Archive-Host.com

Xbee télécommande (partie 2)

Les exemples précédents utilisaient un DFRduino Romeo V1.1 et un shield wireless pour monter un module Xbee. DFRobot a sorti une nouvelle version, le DFRobot Romeo V2, qui intègre directement un connecteur Xbee : plus besoin de shield pour monter le module Xbee.

Fichier hébergé par Archive-Host.com

Le DFRduino Romeo V 1.1, celui utilisé depuis le début de ce blog, est basé sur une architecture Arduino Uno, le Romeo V2 est basé sur une architecture plus récente d’Arduino Leonardo (ne pas oublier de sélectionner le type de carte Leonardo dans l’environnement de développement Arduino).

Qu’est ce que ça change ?

Romeo V1.1, shield wireless, et interrupteur !

Sur le shield sans fil que nous utilisions au-dessus du Romeo V1.1 figure un interrupteur à deux positions :

  • position micro : le programme peut échanger des données avec le module Xbee
  • position USB : on peut télécharger le programme depuis le PC

Les commandes Serial.read et Serial.write permettaient, selon la position de ce fameux interrupteur, d’échanger des données avec l’USB ou avec le module Xbee

Sur le Romeo V2, plus de shield wireless, plus d’interrupteur !

Les choses sont plus simples :

Serial.read et Serial.write sont conservées pour communiquer avec l’USB.

De nouvelles commandes apparaissent, Serial1.read, Serial1.write pour communiquer avec le module Xbee.

Pour faire fonctionner le montage ci-dessus, on peut reprendre les programmes de l’article précédent en remplaçant simplement Serial par Serial1.

Xbee télécommande (partie 1)

Comment utiliser des modules Xbee pour réaliser une télécommande ? Je me suis inspiré de ce super tutoriel (en anglais).

Voilà un montage pour débuter dans la télécommande sans-fil avec Xbee :

– un premier DFRduino sur lequel 4 boutons poussoirs sont reliées

– un second DFRduino sur lequel 4 LED sont reliées

Les deux DFRduino portent un shield sans-fil et un module Xbee.

Quand on appuie sur un bouton poussoir la LED correspondante s’allume ; on peut appuyer sur plusieurs boutons en même temps.

On pourrait grâce à ce principe concevoir la télécommande d’un modèle meccano sans recourir à un PC. En effet, dans ce montage on a besoin du PC pour programmer les deux DFRduino mais ensuite le PC n’est plus connecté : c’est différent des articles précedents où on avait un Arduino équipé d’un Xbee à l’écoute des commandes envoyées par un autre Xbee piloté par un PC grâce à un code processing.

Voilà à quoi cela ressemble :

Fichier hébergé par Archive-Host.com

Le sketch côté émetteur :


// Xbee_telecommande_BP_EM

// Partie Emetteur

// 4 boutons poussoirs digitaux 



// le BP 0 est relié à la pin 2
// le BP 1 est relié à la pin 3
// le BP 2 est relié à la pin 8
// le BP 3 est relié à la pin 9

const int nb_BP = 4;

int tab_pin_BP[nb_BP]={2,3,8,9} ;

int tab_etat[nb_BP]={0,0,0,0};

int appui= 0; // quand un bouton poussoir est appuye il est dans l'état bas, 0v


void code_etat()
{

  int i = 0;
  
  for (i=0; i < nb_BP ; i++) 
        (tab_etat[i] = 0);  
     
  for (i=0; i < nb_BP ; i++) 
      if (digitalRead(tab_pin_BP[i]) == appui) 
           (tab_etat[i] = 1);
          
}

void envoie_code()
{

  int i = 0;
  
  Serial.print("#");
  
  for (i=0; i < nb_BP ; i++) {
      Serial.print (tab_etat[i]);   
   }
  
  Serial.println("");         
}


 
void setup() // executée une seule fois

{
 int i;
 for (i=0 ; i < nb_BP ; i++) {
      pinMode (tab_pin_BP[i], INPUT);
    }   
       
 Serial.begin(9600);    
      
}


void loop() // executée en boucle
{         
  

  code_etat() ;
  
  envoie_code();  
  
  delay(50);      
          
}

Côté récepteur, voilà ce que cela donne :


// Xbee telecommande bouton poussoir
// version récepteur

const int nb_BP = 4;

int tab_pin_LED[nb_BP]={8,9,10,11} ;


void lire_etat()
{
    

int i = 0;
int data;

      
  
  for (i=0; i < nb_BP ; i++) {
       
      while (Serial.available () == 0) ; 
      // tant qu'on n'a rien à lire, on ne fait rien
    
      data = Serial.read() -'0';
      
         
      if (data == 1) 
         digitalWrite(tab_pin_LED[i], HIGH);  
       else
          digitalWrite(tab_pin_LED[i], LOW);
  }
  
    
}



void setup() // executée une seule fois

{  
  
 for (int i=0; i < nb_BP ; i++) {
     
     pinMode(tab_pin_LED[i], OUTPUT);
     
   }
  
       
 Serial.begin(9600);    
      
}


void loop() // executée en boucle
{         
   
   
while (Serial.available () == 0);  
 
   
if (Serial.read () == '#')        
       
     lire_etat();    
    
        
}