Communication Xbee et Arduino

Bonjour,

Je débute avec Arduino et je suis sur un projet ou je dois pouvoir commander un véhicule motorisé avec une télécommande en HF avec des modules Xbee.

Description du véhicule :

1 x moteur DC à gauche
1 x moteur DC à droite
1 x Carte Arduino Uno
1 x Shield pont en H pour commande moteur DC
1 x Shield xbee
1 x Module Xbee série 1

Description de la télécommande :

1 x Carte Arduino Uno
1 x Shield "DF Robot input shield"
1x Shield xbee
1 x Xbee série 1

Description du projet :

  • la vitesse et la direction des moteurs sont liée à l'axe Y du joystick
  • la diminution de la vitesse du moteur droite ou gauche et liée à l'axe X du joystick
  • l'inversion de la direction entre moteur gauche et moteur droite (pour créer une rotation de l'objet sur luis même) est liée à un bouton ON/OFF de la télécommande

Actuellement les deux sketch (télécommande et récepteur) sont crées et tous fonctionne parfaitement, Xbee, direction, vitesse, rotation.

Mon problème est le suivant, il faudrait que les moteurs se coupent si il y a une coupure de communication entre les Xbee car actuellement si une coupure survient les moteurs continuent dans la direction et la vitesse de la dernière commande.

J'arrive à implémenter cette fonction avec un if (Serial.available () >0) si je connecte la télécommande directement sur le véhicule sans utiliser les Xbee mais avec l'utilisation de la librairie Xbee.H de mon projet, je n'arrive à rien .....

Voilà la config de mes Xbee :

ATID
1234
ATMY
0
ATDL
1
ATIR
0
ATIT
1
ATAP
2

Voila le sketch de ma télécommande :

#include <XBee.h>
//--- XBEE Sender-SETUP ---------------------------
 XBee xbee = XBee();
 unsigned long start = millis();
// allocate two bytes for to hold a 10-bit analog reading
uint8_t payload[7];
// payload array lenght needs to be at least one higher than the number of bytes to be transmitted
// 16-bit addressing: Enter address of remote XBee, typically the coordinator
  Tx16Request tx_1 = Tx16Request(0x1, payload, sizeof(payload));
  TxStatusResponse txStatus = TxStatusResponse();

//values to be transmitted 10 Bit, i.e. (0-1023)
int valueX = 0;
int valueY = 0;
int valueInv = 0;

void setup(void)
{
  
 xbee.begin(9600);
 Serial.begin(9600);
 
}

void loop(void)
{ 

 // start transmitting after a startup delay. Note: this will rollover to 0 eventually so not best way to handle
 if (millis() - start > 5000) {

 valueX = analogRead(A0); //read from pinA0
 Serial.print("Value X: ");
 Serial.println(valueX);

 valueY = analogRead(A1); //read from pinA1
 Serial.print("Value Y: ");
 Serial.println(valueY);
 
 valueInv = digitalRead(6); //read from pinD6
 Serial.print("ValueInv: ");
 Serial.println(valueInv);

 //valueX INTO PAYLOAD
 //break down 10-bit reading into two bytes and place in payload
 payload[0] = valueX >> 8 & 0xff; // payload[0] = MSB.
 payload[1] = valueX & 0xff; // 0xff = 1111 1111, i.e. cuts of the MSB from pin5 and all is left is the LSB

 //valueY INTO PAYLOAD
 payload[2] = valueY >> 8 & 0xff;
 payload[3] = valueY & 0xff; //LSB
 
 //valueInv INTO PAYLOAD
 payload[4] = valueInv >> 8 & 0xff;
 payload[5] = valueInv & 0xff; //LSB
 
 xbee.send(tx_1);

 }

 delay(500);

}

Je n'arrive pas a inclure tout les détails nécessaire dans ce post, j'excède le nb de caractères possible. Je fais suivre les infos

Si quelqu'un pouvais m' aiguiller se serait génial.

En vous remerciant.

Voilà le sketch de mon véhicule :

///////////////////////////////// Déclaration des variables /////////////////////////////////

// Librairie incluse
#include <XBee.h>

// XBEE récepteur setup
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();

// create reusable response objects for responses we expect to handle
Rx16Response rx16 = Rx16Response();
Rx64Response rx64 = Rx64Response();

// Définition des broches
int PWMG = 6; // Vitesse moteur gauche
int DIRG = 8; // Direction moteur gauche
int PWMD = 5; // Vitesse moteur droite
int DIRD = 7; // Direction moteur droite

// Définition des variables de données joystick
int JOYSTICK_X; // Valeur axe X de la télécommande
int JOYSTICK_Y; // Valeur axe Y de la télécommande
int BOUTON_INV; // Valeur bouton inversion moteur de la télécommande

// Définition des états des moteurs
#define MOTEUR_STOP 0
#define MOTEUR_AVANCE 1
#define MOTEUR_RECULE 2
#define MOTEUR_INVERSE_GAUCHE 3
#define MOTEUR_INVERSE_DROITE 4


// Définition de la marge autour du point d'origine (0, 0)
// Permet d'éviter que les moteurs n'oscille entre MOTEUR_AVANCE et MOTEUR_RECULE
#define THRESHOLD 20

// Définition de la valeur maximum pour la vitesse
#define MAX_SPEED 127

// Déclaration des variables global
// calX : calibration en 0 de l'axe X
// calY : calibration en 0 de l'axe Y
// vitesse : vitesse calculé
// direction : direction calculé
int calX, calY, vitesse, direction;

// coefG : coefficient de vitesse (entre 0 et 1) pour le moteur gauche
// coefD : coefficient de vitesse (entre 0 et 1) pour le moteur droit
float coefG, coefD;

///////////////////////////////// Fonction Setup /////////////////////////////////
void setup(void){

  // initialisation du port série
  xbee.begin(9600);  
 
  //Initialisation des I/O 
  pinMode (5, OUTPUT);
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
  pinMode (8, OUTPUT);
  
  // Calibration de la valeur (0, 0) du joystick
  calX = 512;
  calY = 512;
  
//********************** Impression série **********************

  //Serial.print ("calX");
  //Serial.println (calX);
  //Serial.print ("calY");
  //Serial.println (calY);
  
//**************************************************************
  
} // Fin Setup

///////////////////////////////// Fonction Loop /////////////////////////////////
void loop(void){
  
 xbee.readPacket();

 if (xbee.getResponse().isAvailable()) {
 // got something

 if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE) {
 // got a rx packet

 if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
 xbee.getResponse().getRx16Response(rx16);

 //READ VALUE_X
 uint8_t analogHigh = rx16.getData(0);
 uint8_t analogLow = rx16.getData(1);
 int valueX = analogLow + (analogHigh * 256);
 JOYSTICK_X = valueX;
 
 //READ VALUE_Y
 uint8_t analogHigh2 = rx16.getData(2);
 uint8_t analogLow2 = rx16.getData(3);
 int valueY = analogLow2 + (analogHigh2 * 256);
 JOYSTICK_Y = valueY;
 
 //READ VALUE_VALEUR_INV
 uint8_t digitalHigh3 = rx16.getData(4);
 uint8_t digitalLow3 = rx16.getData(5);
 int valueInv = digitalLow3 + (digitalHigh3 * 256);
 BOUTON_INV = valueInv;
 
 
 //********************** Impression série **********************
 
 //Serial.print ("valueX");
 //Serial.println (valueX);
 //Serial.print ("valueY");
 //Serial.println (valueY);
 //Serial.print ("valueInv");
 //Serial.println (valueInv);
 
//************************************************************** 

} // Fin if (xbee.getResponse().getApiId() == RX_16_RESPONSE)
 
 else {
 xbee.getResponse().getRx64Response(rx64);
}

} // Fin if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE)  
 
 // Calcul des données
  getData(calX, calY, &coefG, &coefD, &vitesse, &direction);

  // Affichage de la vitesse du moteur gauche
  Serial.print("Moteur Gauche : ");
  Serial.println((int)(vitesse*coefG));
  analogWrite (PWMG,(vitesse*coefG));
  
  // Affichage de la vitesse du moteur droit
  Serial.print("Moteur Droit : ");
  Serial.println((int)(vitesse*coefD));
  analogWrite (PWMD,(vitesse*coefD));

  // Affichage de la direction des moteurs
  Serial.print("Direction : ");
  if(direction == MOTEUR_AVANCE) // Vers l'avant
  {
    Serial.println("AVANT");
    digitalWrite (DIRG,HIGH);
    digitalWrite (DIRD,HIGH);
  }
  else if(direction == MOTEUR_RECULE) // Vers l'arriére
  {
    Serial.println("ARRIERE");
    digitalWrite (DIRG,LOW);
    digitalWrite (DIRD,LOW);
  }
  else if(direction == MOTEUR_INVERSE_GAUCHE) // Rotation
  {
    Serial.println("Rotation Gauche");
    digitalWrite (DIRG,HIGH);
    digitalWrite (DIRD,LOW);
  }
  else if(direction == MOTEUR_INVERSE_DROITE) // Rotation
  {
    Serial.println("Rotation Droite");
    digitalWrite (DIRG,LOW);
    digitalWrite (DIRD,HIGH);
  }
  else
    Serial.println("ARRET"); // Aucun mouvement

  // Delai de 500ms pour pouvoir lire la console
  delay(500);

} // Fin if (xbee.getResponse().isAvailable())
} // Fin loop

///////////////////////////////// Fonction getData /////////////////////////////////

// Fonction calculant les divers coefficient de vitesse, la direction, ainsi que la vitesse
void getData(int calX, int calY, float *coefG, float *coefD, int *vitesse, int *direction) {
  // rawX : valeur brute en X du joystick centrée sur calX
  // rawY : valeur brute en Y du joystick centrée sur calY
  int rawX, rawY;
  
//********************** Impression série **********************

  //Serial.print ("JOYSTICK_X");
  //Serial.println (JOYSTICK_X);
  //Serial.print ("JOYSTICK_Y");
  //Serial.println (JOYSTICK_Y);
  
//**************************************************************
  
  // Mesure des valeurs brute en X et Y
  rawX = JOYSTICK_X - calX;
  rawY = JOYSTICK_Y - calY;

//********************** Impression série **********************

  //Serial.print ("rawX");
  //Serial.println (rawX);
  //Serial.print ("rawY");
  //Serial.println (rawY);
  
//**************************************************************

  // Si -THRESHOLD < rawY < THRESHOLD
  if(rawY > -THRESHOLD && rawY < THRESHOLD){
    // Les moteurs sont marqués comme arrétés, et vitesse = 0
    *direction = MOTEUR_STOP;
    *vitesse = 0;
  }  // Si rawY >= 0
  else if(rawY >= 0 && BOUTON_INV ==1) {
    // Les moteurs sont marqués en mode "recule"
    *direction = MOTEUR_RECULE;
	// La vitesse est égale à map(rawY) depuis 0 ~ (1023 - calY) vers 0 ~ MAX_SPEED
    *vitesse = map(rawY, 0, 1023 - calY, 0, MAX_SPEED);
  } // Si rawY < 0
  else if(rawY >= 0 && BOUTON_INV ==0) {
    // Les moteurs sont marqués en mode "Rotation gauche"
    *direction = MOTEUR_INVERSE_GAUCHE;
	// La vitesse est égale à map(rawY) depuis 0 ~ (1023 - calY) vers 0 ~ MAX_SPEED
    *vitesse = map(rawY, 0, 1023 - calY, 0, MAX_SPEED);
  } // Si rawY < 0
  else if(BOUTON_INV ==0) {
    // Les moteurs sont marqués en mode "Rotation droite"
    *direction = MOTEUR_INVERSE_DROITE;
	// La vitesse est égale à map(rawY) depuis 0 ~ (1023 - calY) vers 0 ~ MAX_SPEED
    *vitesse = map(-rawY, 0, calY, 0, MAX_SPEED);
  } // Si rawY < 0
  else {
    // Les moteurs sont marqués en mode "avance"
    *direction = MOTEUR_AVANCE;
	// La vitesse est égale à map(rawY) depuis 0 ~ calY vers 0 ~ MAX_SPEED
    *vitesse = map(-rawY, 0, calY, 0, MAX_SPEED);
  }

  // Si rawX < -THRESHOLD alors coefG = -rawX / calX sinon coefG = 1
  float rotG = (rawX < -THRESHOLD) ? -rawX / (float)calX : 0;
  *coefG = 1 - rotG;
  
  // Si rawX > THRESHOLD alors coefD = rawX / calX sinon coefD = 1
  float rotD = (rawX > THRESHOLD) ? rawX / (float)calX : 0;
  *coefD = 1 - rotD;
  
//********************** Impression série **********************
  
  //Serial.print ("coefG");
  //Serial.println (*coefG);
  //Serial.print ("coefD");
  //Serial.println (*coefD);
  
//**************************************************************
} //Fin getData

Bonsoir,

simongeorge:
Mon problème est le suivant, il faudrait que les moteurs se coupent si il y a une coupure de communication entre les Xbee car actuellement si une coupure survient les moteurs continuent dans la direction et la vitesse de la dernière commande.

Une idée de sécurité active: la télécommande envoie systématiquement (toutes les 200ms par exemple) un caractère, une chaîne...
Le programme du mobile vérifie la bonne réception de ce caractère, parmi les données reçues. En cas d'absence dépassant (par exemple 500ms) le programme du mobile stoppe les moteurs. ça suppose des boucles loop avec des delay plus courts..et de trier les données.

Ou supprimer tout delay de la loop, mettre un t0 avec "millis()" dans la loop du mobile.
Si "isAvailable>0" est vrai, alors réinitialiser t0 à "millis", lire les données reçues....
sinon vérifier si (millis-t0)>500, dans ce cas { "ARRET des moteurs"; while(1){}} pour bloquer la loop ici et te laisser le temps de récupérer le mobile. Là, pas de tri supplémentaire parmi les données reçues.

Bonjour,

Merci pour l'information.

Entre temps j'ai implémenté un compteur dans ma boucle loop qui m'as permis de vérifier que je recevais une trame avec des informations de la télécommande environ toutes les 25 cycles de lecture de ma loop. Je remet ce compteur à zéro à chaque fois qu'une trame arrive de ma télécommande et si mon compteur dépasse par exemple 50 alors je coupe mes moteurs :

if (i >= 50) {
analogWrite (PWMG,(vitesse0));
analogWrite (PWMD,(vitesse
0));
}

ça fonctionne mais je vais essayer aussi avec votre solution.

Merci en tout cas d'avoir pris le temps de répondre.

Bonne continuation.