lundi 21 avril 2014

Robot éviteur d'obstacles version 2.0


Il y a quelques mois, j'avais construit un robot éviteur d'obstacles muni d'un capteur à ultrasons HC-SR04.  Mais ce robot avait une vision périphérique très limitée: il ne détectait que les obstacles situés directement devant lui, et ses roues s'accrochaient régulièrement dans des obstacles qui n'avaient pas été détectés.

Cette nouvelle version du robot est munie de 3 capteurs à ultrasons HC-SR04 situés côte à côte à l'avant du robot.  Les deux capteurs situés sur les côtés sont légèrement inclinés vers l'extérieur, ce qui élargit encore un peu plus le champ de vision du robot.

En plus du champ de vision amélioré, l'ajout des deux capteurs supplémentaires permet de faire tourner le robot du bon côté:  si un obstacle est détecté en avant à droite, mais pas à gauche, on fera tourner le robot vers la gauche, et vice-versa si  un obstacle est détecté à gauche mais pas à droite.

Matériel 

C'est le même matériel que la dernière fois, mais avec deux capteurs HC-SR04 supplémentaires:  un châssis pour robot à deux roues motrices (chaque roue étant directement reliée à un motoréducteur), un Arduino Uno (en fait c'est un Duemilanove, mais peu importe), un contrôleur de moteur L293D, 3 sondes ultrasonores HC-SR04, 6 piles AA rechargeables NiMh pour alimenter les moteurs, et une pile de 9 V pour alimenter l'Arduino.


Circuit

Là encore, je n'ai rien changé aux branchements du robot initial, ce qui explique au moins partiellement l'utilisation quelque peu désordonnée des différentes pins de l'Arduino.

Le schéma ci-dessous indique les branchements du L293D à l'Arduino, aux deux moteurs et à son alimentation.  Ne pas oublier de relier ensemble toutes les masses:  le GND de l'Arduino, les 4 pins GND du L293D et la pin GND de chaque capteur HC-SR04 sont toutes reliées ensemble.


Chaque capteur ultrasonore est muni de 4 pins:  la pin Vcc est reliée à la sortie 5 V de l'Arduino (ou à la pin 16 du L293D) et, comme je l'ai indiqué plus haut, la pin GND qui doit être reliée aux GND de l'Arduino.

Il nous reste à brancher les pins qui permettent l'échange d'information entre chaque capteur ultrasonore et l'Arduino.  Puisque les pins disponibles sur l'Arduino devenaient rares, j'ai décidé d'utiliser les pins A0, A1, A2 et A3 comme des entrées/sorties numériques plutôt que comme des entrées analogiques.  C'est permis! Pour ce faire, il s'agit d'utiliser dans le sketch les fonctions digitalRead ou digitalWrite.

Capteur A (à droite)      
        Pin Trig à Arduino 12
        Pin Echo à Arduino 11

Capteur B (au centre)    
        Pin Trig à Arduino A0
        Pin Echo à Arduino A1
    
Capteur C (à gauche)
        Pin Trig à Arduino A2
        Pin Echo à Arduino A3
     
Le sketch:

/***************************************************************
*
* Robot éviteur d'obstacle muni de trois capteurs à ultrasons HC-SR04.
*
* Comportement: Le robot avance en ligne droite, sauf s'il
* rencontre un obstacle, auquel cas il tourne sur place jusqu'à
* ce qu'il n'y ait plus d'obstacle devant lui.
*
* http://electroniqueamateur.blogspot.com/2014/04/robot-eviteur-dobstacles-version-20.html
*
****************************************************************/
// définitions de constantes
#define motorPin1a 3 // Marche avant du premier moteur
#define motorPin1b 4 // Marche arrière du premier moteur
#define speedPin1 9 // pin d'activation L293D pour le premier moteur
#define motorPin2a 5 // Marche avant du deuxième moteur
#define motorPin2b 6 // Marche arrière du deuxième moteur
#define speedPin2 10 // pin d'activation L293D pour le deuxième moteur
// capteur à ultrasons:
#define trigPinDroite 12
#define echoPinDroite 11
#define trigPinCentre A0
#define echoPinCentre A1
#define trigPinGauche A2
#define echoPinGauche A3
// variables globales
int Mspeed = 0; // vitesse du moteur
int seuil = 30; // distance minimale pour laquelle on accepte un obstacle
long look (short capteur){ // évaluation de la distance de l'obstacle
long temps;
short trigPin, echoPin;
if (capteur == 0){ // capoteur de droite
trigPin = trigPinDroite;
echoPin = echoPinDroite;
}
if (capteur == 1){ // capoteur du centre
trigPin = trigPinCentre;
echoPin = echoPinCentre;
}
if (capteur == 2){ // capoteur de gauche
trigPin = trigPinGauche;
echoPin = echoPinGauche;
}
// Nous envoyons un signal haut d'une durée de 10 microsecondes, en sandwich
// entre deux signaux bas. Des ultrasons sont émis pendant que le signal est haut
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Lors de la réception de l'écho, le module HC-SR04 émet
// un signal logique haut (5 v) dont la durée est égale au
// temps écoulé entre l'émission et la réception de l'ultrason.
pinMode(echoPin, INPUT);
temps = pulseIn(echoPin, HIGH);
return temps * 340/(2*10000);
}
void setup() {
// réglage des broches à output
pinMode(motorPin1a, OUTPUT);
pinMode(motorPin1b, OUTPUT);
pinMode(speedPin1, OUTPUT);
pinMode(motorPin2a, OUTPUT);
pinMode(motorPin2b, OUTPUT);
pinMode(speedPin2, OUTPUT);
pinMode(echoPinDroite, INPUT);
pinMode(trigPinDroite, OUTPUT);
digitalWrite(trigPinDroite, LOW);
pinMode(echoPinCentre, INPUT);
pinMode(trigPinCentre, OUTPUT);
digitalWrite(trigPinCentre, LOW);
pinMode(echoPinGauche, INPUT);
pinMode(trigPinGauche, OUTPUT);
digitalWrite(trigPinGauche, LOW);
}
void loop() {
long distanceDroite, distanceCentre, distanceGauche;
long previousDroite, previousCentre, previousGauche;
Mspeed = 700; // vitesse du moteur 0 à 1023
distanceDroite = look(0); // y a-t-il un obstacle à droite?
distanceCentre = look(1); // y a-t-il un obstacle au centre?
distanceGauche = look(2); // y a-t-il un obstacle à gauche?
if (distanceDroite > seuil && distanceCentre > seuil && distanceGauche > seuil){
// aucun obstacle détecté, donc marche avant:
analogWrite(speedPin1, Mspeed);
digitalWrite(motorPin1a, HIGH);
digitalWrite(motorPin1b, LOW);
analogWrite(speedPin2, Mspeed);
digitalWrite(motorPin2a, HIGH);
digitalWrite(motorPin2b, LOW);
delay(100);
}
else { // on a détecté un obstacle
// nouvelle vérification pour éviter les faux positifs
previousDroite = distanceDroite;
previousCentre = distanceCentre;
previousGauche = distanceGauche;
distanceDroite = look(0); // y a-t-il un obstacle à droite?
distanceCentre = look(1); // y a-t-il un obstacle au centre?
distanceGauche = look(2); // y a-t-il un obstacle à gauche?
if ((distanceDroite <= seuil) && (previousDroite)<= seuil ){
// obstacle confirmé
if (distanceDroite < distanceGauche) { // on tourne à gauche
analogWrite(speedPin1, Mspeed);
digitalWrite(motorPin1a, HIGH);
digitalWrite(motorPin1b, LOW);
analogWrite(speedPin2, Mspeed);
digitalWrite(motorPin2a, LOW);
digitalWrite(motorPin2b, HIGH);
delay(110);
if (distanceGauche <= seuil){ // il y a aussi un obstacle proche à gauche
delay(700); // on continue de tourner un peu plus
}
}
else // l'obtacle à gauche est plus proche que l'obstacle à droite
{
// on tourne assez longtemps vers la droite
analogWrite(speedPin1, Mspeed);
digitalWrite(motorPin1a, LOW);
digitalWrite(motorPin1b, HIGH);
analogWrite(speedPin2, Mspeed);
digitalWrite(motorPin2a, HIGH);
digitalWrite(motorPin2b, LOW);
delay(900); // tournons de façon significative
}
}
else if ((distanceGauche <= seuil) &&(previousGauche <= seuil)) {
// obstacle à gauche seulement, on tourne à droite
analogWrite(speedPin1, Mspeed);
digitalWrite(motorPin1a, LOW);
digitalWrite(motorPin1b, HIGH);
analogWrite(speedPin2, Mspeed);
digitalWrite(motorPin2a, HIGH);
digitalWrite(motorPin2b, LOW);
delay(100);
}
else if ((distanceCentre <= seuil) && (previousCentre <= seuil)){
// mince obstacle droit devant, on tourne à droite
analogWrite(speedPin1, Mspeed);
digitalWrite(motorPin1a, LOW);
digitalWrite(motorPin1b, HIGH);
analogWrite(speedPin2, Mspeed);
digitalWrite(motorPin2a, HIGH);
digitalWrite(motorPin2b, LOW);
delay(90);
}
}
}


Comportement du robot:  


Le robot tourne à gauche s'il perçoit la présence d'un obstacle en avant à droite, et il tourne à droite s'il perçoit la présente d'un obstacle en avant à gauche.  Si l'obstacle est droit devant, il tourne à droite.  Il n'est doté d'aucune mémoire, ce qui peut le rendre assez hésitant lorsqu'il arrive face à un coin de mur, mais le sketch induit juste assez d'asymétrie pour éviter que le robot se prenne dans une boucle sans fin.  Il finit généralement par trouver une voie de sortie, même si ce n'est pas toujours de la façon la plus élégante et efficace!

Yves Pelletier (Twitter:  @ElectroAmateur)

3 commentaires:

  1. Bonjour,
    Avez vous déjà testé un pan & tilt pour n'utiliser qu'un seul capteur ?

    RépondreSupprimer
  2. Merci pour cet article, il m'a bien aidé.

    RépondreSupprimer