Création d'un robot timide pour un projet scolaire.

Article cloné depuis Eirlab

Dans le cadre de l’option Makers proposée en deuxième année à l’ENSEIRB-MATMECA, en filière Informatique, un robot timide a vu le jour au sein d’Eirlab. Cet article est un guide pour expliquer comment reproduire notre travail, dans le plus pur esprit Maker.

Une vue de 3/4 face du robot finalisé

Concept de base

Nous voulions mettre en oeuvre un robot qui détecterait en temps réel la luminosité autour de lui et ce dans le but de se déplacer vers l’endroit le plus sombre de la pièce dans lequel il se trouve, et de s’y cacher. Un autre mode est aussi disponible, permettant non pas d’aller vers l’endroit le plus sombre, mais à l’inverse de fuir l’endroit le plus lumineux, pour avoir deux manières de voir le problème.

Une vue de face du robot timide dans sa forme finale.

Du matériel

Avant de pouvoir travailler sur une partie logicielle du projet, il faut évidemment avoir une base physique pour accueillir et exécuter ce code.

À noter que ce projet n’a nécessité aucune dépense et a été réalisé entièrement avec du matériel déjà disponible au sein du Fablab.

Liste du matériel

Pour pouvoir reproduire ce projet, il vous faudra avoir en votre possession les éléments suivants :

  • 1x Arduino Uno (ou clone équivalent) – c’est la tête pensante de ce projet
  • 1x Arduino Motor Shield – pour contrôler les deux moteurs du robot
  • 2x moteurs à courant continu, ici des FT DC 130D – pour se mouvoir dans l’espace
  • 3x capteurs de distance à ultrasons HC-SR04 – pour éviter de rencontrer des murs trop souvent
  • 4x photo résistances – une par côté, pour pouvoir détecter la luminosité autour de lui
  • 4x résistances de 2kΩ – pour le circuit des photo résistances, permettant d’avoir une amplitude optimale
  • 1x pile 9 Volts – pour alimenter tout le système
  • 1x boîtier pour pile 9 Volts [OPTIONNEL] – pour éviter de perdre l’unique source d’alimentation du robot

Base du châssis

Le châssis est une plaque en bois, ici du contreplaqué de 5 millimètres d’épaisseur, qui a été usinée à l’aide de la découpeuse laser du Fablab. Elle mesure 17×15,5 centimètres, et dispose de deux bords biseautés pour avoir une vue frontale des obstacles que le robot pourrait rencontrer. Ici, ces biseaux ont des angles de 20 degrés, sur 4,5 centimètres. La plaque de base est ensuite percée pour accueillir les différents modules du robot. Les éléments les plus légers ou risquant moins de se détacher sont fixés par un simple système de mâchoire, prenant en étau la plaque de bois dans une forme de U.

La forme de U pour prendre la plaque de base en mâchoire et tenir un capteur par pression.

Alimentation

Pour l’alimentation du robot, on vient envoyer 9 Volts d’une source quelconque, d’une pile ou d’une alimentation stabilisée par exemple, dans l’entrée VIN de l’Arduino, qui sera après régulée en interne pour donner les différents rails d’alimentation. Cette entrée d’alimentation est connectée en interne au port DC “barrel jack” de l’Arduino, donc avant les régulateurs de courant, et prend donc des tensions entre 5 et 9 Volts.

Dans ce projet, nous utilisons une pile 9 Volts rechargeable dans un boîtier vissé au châssis.

Une vue de la pile 9 Volts que nous utilisons, rechargeable en micro USB.

Moteurs

Les moteurs ici sont vissés au châssis, car juste pris en mâchoire ils ne tiennent pas et se détachent à la moindre accélération.

Ils sont directement alimentés et pilotés via la carte Arduino Motor Shield, qui permet de sélectionner leur vitesse sur une échelle de 0 à 255, d’actionner les freins et de leur donner un sens de rotation, et ce très simplement dans le code.

Des roues ont été imprimées en 3D pour aller sur les embouts des moteurs, et un joint torique sert de pneu pour améliorer l’adhérence du robot et éviter les démarrage en “burn”.

PCB

Au début de ce projet, nous avons utilisé une carte de prototypage électronique, aussi appelé breadboard. Dans un second temps et pour éviter toute déconnexion de câbles liée à une potentielle accélération violente, nous avons fait un PCB, soudé manuellement sur une carte de prototypage prévu à cet effet.

Une vue du dessus de notre PCB fait main.

Au niveau électronique, le PCB est routé de la manière suivante :

Le routage du PCB sur une carte de protypage de type Breadboard.

Les différents composants viennent se connecter sur le PCB au moyen de différentes broches femelles, pour que ce dernier puisse être détaché et modifié sans devoir dessouder le moindre composant.

Et du logiciel

D’un point de vue logiciel, notre projet est assez simple. En pseudo-algorithme, on peut tout simplement le résumer à “on regarde parmi les 4 photo résistances et on tourne ou avance vers celle ayant la valeur la plus sombre” dans le cas où followDark est à true. Si au contraire cette valeur est à false, alors il ira dans la direction opposée à la photorésistance ayant la plus haute valeur.

Une mesure des distances en face des trois capteurs à ultrasons permet d’arrêter le robot (presque) avant collision frontale, et le robot ne se déplacera pas tant que l’objet en face est toujours présent, et donc en théorie tant qu’il a trouvé l’endroit le plus sombre.

#define echo1Pin 5
#define trig1Pin 4
#define echo2Pin 7
#define trig2Pin 6
#define echo3Pin 10
#define trig3Pin 2
#define rotMot1Pin 12
#define brakeMot1Pin 9
#define vitMot1Pin 3
#define rotMot2Pin 13
#define brakeMot2Pin 8
#define vitMot2Pin 11
#define photoRes1Pin A2
#define photoRes2Pin A3
#define photoRes3Pin A4
#define photoRes4Pin A5

#define followDark false

long duration;
int distance;

void setup() {
  Serial.begin(9600);
  pinMode(rotMot1Pin, OUTPUT);
  pinMode(brakeMot1Pin, OUTPUT);
  pinMode(vitMot1Pin, OUTPUT);

  pinMode(rotMot2Pin, OUTPUT);
  pinMode(brakeMot2Pin, OUTPUT);
  pinMode(vitMot2Pin, OUTPUT);

  pinMode(photoRes1Pin, INPUT);
  pinMode(photoRes2Pin, INPUT);
  pinMode(photoRes3Pin, INPUT);
  pinMode(photoRes4Pin, INPUT);

  pinMode(trig1Pin, OUTPUT);
  pinMode(echo1Pin, INPUT);
  pinMode(trig2Pin, OUTPUT);
  pinMode(echo2Pin, INPUT);
  pinMode(trig3Pin, OUTPUT);
  pinMode(echo3Pin, INPUT);

  delay(3000);
}

void loop(){
  byte echoPins[3] = {echo1Pin,echo2Pin,echo3Pin};
  byte trigPins[3] = {trig1Pin,trig2Pin,trig3Pin};
  long int durations[3] = {};
  long int distances[3] = {};

  for(int i = 0; i < 3; i++){
    digitalWrite(trigPins[i], LOW);
    delayMicroseconds(2);

    digitalWrite(trigPins[i], HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPins[i], LOW);
    durations[i] = pulseIn(echoPins[i], HIGH);
    distances[i] = durations[i] * 0.034 / 2;
  }

  int photoRes[4] = {};
  Serial.print("Capteur infra : 1[");
  photoRes[0] = analogRead(photoRes1Pin);
  Serial.print(photoRes[0]);
  Serial.print("] 2[");
  photoRes[1] = analogRead(photoRes2Pin);
  Serial.print(photoRes[1]);
  Serial.print("] 3[");
  photoRes[2] = analogRead(photoRes3Pin);
  Serial.print(photoRes[2]);
  Serial.print("] 4[");
  photoRes[3] = analogRead(photoRes4Pin);
  Serial.print(photoRes[3]);

  for(int i = 0; i < 3; i++){
    Serial.print("] - distance(cm) : ");
    Serial.print(distances[i]);
   }

  Serial.println();

  bool b = false;
  for(int i = 0; i < 3; i++){
    if (distances[i] < 30) {
      b= true;
    }
  }

  int photoResRef = photoRes[0];
  bool photoStop = true;
  int photoResMinPos = 0;

  if (followDark){
    int photoResMin = 1024;
    for (int i = 0; i < 4; i++){
      if (photoResMin > photoRes[i]){
        photoResMin = photoRes[i];
        photoResMinPos = i;
      }
      if (abs(photoResRef - photoRes[i]) > 20){
        photoStop = false;
      }
    }
  } else{
    int photoResMax = 0;
    for (int i = 0; i < 4; i++){
      if (photoResMax < photoRes[i]){
        photoResMax = photoRes[i];
        photoResMinPos = (i + 2)%4;
      }
      if (abs(photoResRef - photoRes[i]) > 20){
        photoStop = false;
      }
    }
  }
  Serial.println(photoResMinPos);

  if (b || photoStop){
    digitalWrite(brakeMot1Pin, HIGH);
    digitalWrite(brakeMot2Pin, HIGH);
  } else {
    digitalWrite(brakeMot1Pin, LOW);
    digitalWrite(brakeMot2Pin, LOW);
  }

  if (photoResMinPos == 0){
    digitalWrite(rotMot1Pin, LOW);
    digitalWrite(rotMot2Pin, LOW);
  }
   if (photoResMinPos == 1){
    digitalWrite(rotMot1Pin, LOW);
    digitalWrite(rotMot2Pin, LOW);
  }
   if (photoResMinPos == 2){
    digitalWrite(rotMot1Pin, HIGH);
    digitalWrite(rotMot2Pin, HIGH);
  }
   if (photoResMinPos == 3){
    digitalWrite(rotMot1Pin, HIGH);
    digitalWrite(rotMot2Pin, LOW);
  }
  analogWrite(vitMot1Pin, 150);
  analogWrite(vitMot2Pin, 150);
}

Remerciements

Merci au Fablab de l’ENSEIRB-MATMECA, Eirlab, pour nous avoir permis de travailler sur ce projet et d’avoir contribué matériellement au projet.

Merci aussi aux différents Fabmanagers qui nous ont aidés tout au long du projet en répondant à nos questions plus ou moins posées sous l’emprise de la fatigue.

À la mémoire de Kaitlin Rooke.