Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

LegoduinoCar - Informations techniques

Accès rapide :
La vidéo
Présentation de la LegoduinoCar
Les principaux composants électroniques
Le cablage de la carte Arduino
Le programme de contrôle
Pour aller plus loin...

La vidéo

Cette vidéo vous montre comment construire un petit véhicule autonome à base de composants électroniques Arduino et de briques de construction. Un programme de déplacement autonome du véhicule est proposé. Il peut aussi être piloté par Bluetooth ou par télécommande infrarouge.


Legoduino Car - Un petit véhicule autonome

Présentation de la LegoduinoCar

La Legoduino est un petit véhicule autonome géré par une carte Arduino. Il peut aussi être controllé soit par bluetooth, soit par télécommande infra-rouge. Il a été fabriqué par les jeunes du club d'informatique de Valderoure (petite commune française).

La structure est basée sur des briques de construction célèbres que vous aurez certainnement reconnu. Peut-être en avez vous déjà un peu chez vous. Sinon, vous pouvez même commander les pièces sur ce site. Il en va de même pour les moteurs qui sont produits par le même frabriquant de jouets.

Le véhicule peut très facilement avancer ou reculer, tant que les deux rouges motorisées tournent dans le même sens. Il peut aussi effectuer des rotations sur lui même, dans un sens ou dans l'autre, en inversant le sens de rotation des deux roues. Voici une seconde vue, avec un autre angle de vision sur la structure du véhicule : on y voit notament que les moteurs sont solidement attachés sur la structure formant le chassis (dans un prototype précédent, nous avions les moteurs qui se décrochaient trop facilement). On y voit aussi, en bas et à droite, un support pour l'un des deux modules de detection d'obstacles par ultrasons (HC-SR04). Il y en un devant et un autre derrière le véhicule. Enfin, on y voit différentes briques permettant de bloquer la breadboard ainsi que la carte Arduino.

Et voici encore une autre vue sur le dessous du véhicule. Notez la présence des petites roues qui peuvent pivoter sur elles-mêmes en cas de rotation du véhicule. Ce point serait très certainement à améliorer ! Les plaques permettent de bien renforcer la structure (le chassis).

Les principaux composants électroniques

Bien entendu, il nous faut une carte Arduino : nous avons choisi une carte Arduino Uno R3 (ou compatible). Mais d'autres cartes pourraient aussi convenir (Arduino Mega, ...).

Le véhicule est donc motorisé via deux blocs moteurs. Ils doivent pouvoir fonctionner indépendemment l'un de l'autre pour pouvoir permettre la rotation du véhicule. Nous avons donc choisis d'utiliser un composant L293D : il permet de contrôler chaque moteur indépendemment de l'autre (arrêt, allumage, puissance et sens de rotation). Un schéma de cablage vous est présenté plus bas dans ce document.

les connectiques proposées par les briques ne sont pas compatibles avec le système Arduino. Quelques soudures sont donc nécessaires. Ensuite j'y ai placé des câles en liège pour bloquer le tout, mais je ne pense pas que cela soit très utile. Relativement par rapport à la connectique des moteurs, je vous propose de consulter ce lien.

Ensuite, nous avons utilisé deux modules de detection d'obstacles par ultrasons (HC-SR04). Ils permettent de détecter les risques de collisions et d'arrêter le véhicule avant impact. Il y en a un pour quand le véhicule recule et un autre pour quand il avance. Notez que nous avons cherché à coincer les cables avec des axes situés dans la structure (moins çà bouge, mieux c'est). La bibliothèque de code associée à ce composant est disponible en activant le lien suivant : HCSR04 - Library for HC-SR04 ultrasonic distance sensor.

En termes de communication avec le véhicule, nous avons deux solutions : soit par bluetooth, soit par télécommande infrarouge. Pour le bluetooth, nous avons utilisé un composant de type HC-05.

Pour l'infrarouge, les kits Arduino en fournissent plus ou moins systématiquement. La bibliothèque de code associée au composant IR-Receiver est disponible à l'adresse suivante : https://www.arduinolibraries.info/libraries/i-rremote

On utilise aussi un buzzer qui signale toute détection d'obstacle. Quelques résistances seront aussi utiles (buzzer et composant HC-05). Enfin, on alimente le tout avec une pile 9V.

Le cablage de la carte Arduino

Maintenant, il faut assembler le tout. Je vous propose de suivre le schémat de cablage ci-dessous. Vous pouvez de plus télécharger le fichier d'origine de ce cablage : LegoduinoCar.fzz

Le programme de contrôle

Et voici maintenant le programme. Pour les explications complémentaires, je vous renvois vers la vidéo.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 
 137 
 138 
 139 
 140 
 141 
 142 
 143 
 144 
 145 
 146 
 147 
 148 
 149 
 150 
 151 
 152 
 153 
 154 
 155 
 156 
 157 
 158 
 159 
 160 
 161 
 162 
 163 
 164 
 165 
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173 
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 
 200 
 201 
 202 
 203 
 204 
 205 
 206 
 207 
 208 
 209 
 210 
 211 
 212 
 213 
 214 
 215 
 216 
 217 
 218 
 219 
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228 
 229 
 230 
 231 
 232 
 233 
 234 
 235 
 236 
 237 
 238 
 239 
 240 
 241 
 242 
 243 
 244 
 245 
 246 
 247 
 248 
 249 
 250 
 251 
 252 
 253 
 254 
 255 
 256 
 257 
 258 
#include "Arduino.h"
#include "stdlib.h"
#include "time.h"
#include "IRremote.h"

// Configuration du récepteur infrarouge
const int receiver = 7;
IRrecv irrecv(receiver);
decode_results results;

// Configuration des capteurs ultrasons
#include "SR04.h"
const int TRIG_PIN1 = 3;
const int ECHO_PIN1 = 2;
const int TRIG_PIN2 = 6;
const int ECHO_PIN2 = 5;
SR04 sr04_1 = SR04(ECHO_PIN1,TRIG_PIN1);
SR04 sr04_2 = SR04(ECHO_PIN2, TRIG_PIN2);

// Configuration du buzzer
const int pinBuzzer = 4;

// Gestion bas-niveau des moteurs
const int motor1_enablePin = 11; //pwm
const int motor1_in1Pin = 13;
const int motor1_in2Pin = 12;

const int motor2_enablePin = 10; //pwm
const int motor2_in1Pin = 9;
const int motor2_in2Pin = 8;

void setMotor1(int speed, bool reverse) {
    analogWrite(motor1_enablePin, speed);
    digitalWrite(motor1_in1Pin, ! reverse);
    digitalWrite(motor1_in2Pin, reverse);
}

void setMotor2(int speed, bool reverse) {
    analogWrite(motor2_enablePin, speed);
    digitalWrite(motor2_in1Pin, ! reverse);
    digitalWrite(motor2_in2Pin, reverse);
}

// Gestion plus haut niveau des moteurs 
const int SENS_AVANCE = 1;
const int SENS_RECULE = 0;

bool modeAuto = false;   // false -> pilotage manuel
                         // true -> mode autonome

int speed1 = 0;
bool sens1 = true;

int speed2 = 0;
bool sens2 = true;

bool choisirSens()  {
    return rand() % 2 == 0;
}

void stop() {
    speed1 = 0;    sens1 = SENS_AVANCE;
    speed2 = 0;    sens2 = SENS_AVANCE;
    setMotor1( speed1, sens1 );
    setMotor2( speed2, sens2 );
}

void avance() {
    speed1 = 255;    sens1 = SENS_AVANCE;
    speed2 = 255;     sens2 = SENS_AVANCE;
    setMotor1( speed1, sens1 );
    setMotor2( speed2, sens2 );
}

void recule() {
    speed1 = 255;    sens1 = SENS_RECULE;
    speed2 = 255;     sens2 = SENS_RECULE;
    setMotor1( speed1, sens1 );
    setMotor2( speed2, sens2 );
}

bool checkAvance() {
    return sens1 == sens2 && sens1 == SENS_AVANCE && speed1 == 255;
}

bool checkRecule() {
    return sens1 == sens2 && sens1 == SENS_RECULE && speed1 == 255;
}

void tourneGauche() {
    speed1 = 255;    sens1 = 0;
    speed2 = 255;     sens2 = 1;

    setMotor1( speed1, sens1 );        // Right
    setMotor2( speed2, sens2 );        // Left
    delay( 1650 );

    speed1 = 0;        sens1 = 0;
    speed2 = 0;     sens2 = 0;
    setMotor1( speed1, sens1 );        // Right
    setMotor2( speed2, sens2 );        // Left
}

void tourneDroite() {
    speed1 = 255;    sens1 = 1;
    speed2 = 255;     sens2 = 0;

    setMotor1( speed1, sens1 );        // Right
    setMotor2( speed2, sens2 );        // Left
    delay( 1650 );

    speed1 = 0;        sens1 = 0;
    speed2 = 0;     sens2 = 0;
    setMotor1( speed1, sens1 );        // Right
    setMotor2( speed2, sens2 );        // Left
}

// Traduit la pression des boutons de la télécommande par une des actions
void translateIR() {

  switch(results.value) {

        // Détecte si la touche pressée est la touche Power
      case 0xFFA25D:
          //Serial.println("POWER");
          modeAuto = true;
          avance();
          break;

        // Détecte si la touche pressée est la touche Volume+
      case 0xFF629D:
          avance();
          modeAuto = false;
          break;

        // Détecte si la touche pressée est la touche Arrière
      case 0xFF22DD:
          tourneGauche();
          modeAuto = false;
          break;

        // Détecte si la touche pressée est la touche Play/Pause
      case 0xFF02FD:
          stop();
          modeAuto = false;
          break;

        // Détecte si la touche pressée est la touche Avance
      case 0xFFC23D:
          tourneDroite();
          modeAuto = false;
          break;

        // Détecte si la touche pressée est la touche Volume-
      case 0xFFA857:
          recule();
          modeAuto = false;
          break;

      //default:
        //Serial.println(" other button   ");

  }

}

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

    // On initialise les pins du moteur 1
    pinMode(motor1_in1Pin, OUTPUT);
    pinMode(motor1_in2Pin, OUTPUT);
    pinMode(motor1_enablePin, OUTPUT);

    // On initialise les pins du moteur 2
    pinMode(motor2_in1Pin, OUTPUT);
    pinMode(motor2_in2Pin, OUTPUT);
    pinMode(motor2_enablePin, OUTPUT);

    // On active l'infrarouge
    irrecv.enableIRIn();

    // On initialise le générateur de nombre pseudo aléatoire
    srand( time( NULL ) );
}


void loop(){

    if (irrecv.decode(&results)) {
        translateIR();
        irrecv.resume();
    }

    while ( Serial.available() > 0 ) {
        int code = Serial.read();
        Serial.print( code );

        switch( code ) {
            case 'a':
                avance();
                modeAuto = false;
                break;
            case 's':
                stop();
                modeAuto = false;
                break;
            case 'r':
                recule();
                modeAuto = false;
                break;
            case 'g':
                tourneGauche();
                modeAuto = false;
                break;
            case 'd':
                tourneDroite();
                modeAuto = false;
                break;
            case 't':
                modeAuto = true;
                avance();
        }

    }

    // capteur avant
    long distance_1 = sr04_1.Distance();
    if ( distance_1 > 0 && distance_1 < 10 ) {    // si on voit un obstacle
        if ( checkAvance() ) {
            tone( pinBuzzer, 1000, 500 );
            if ( modeAuto == true ) {
                recule();
                delay(2000);
                if ( choisirSens() ) {
                    tourneGauche();
                } else {
                    tourneDroite();
                }
                avance();
            } else {
                stop();
            }
        }
    }

    // capteur arrière
    long distance_2 = sr04_2.Distance();
    if ( distance_2 > 0 && distance_2 < 10 ) {    // si on voit un obstacle
        if ( checkRecule() ) {
            tone( pinBuzzer, 1000, 500 );
            stop();
        }
    }


    delay( 100 );
}
Le code permettant au véricule d'évoluer
il est possible que le code ne compile pas directement. Par ma part, cela a été le cas. Effectivement il y a un conflit entre la librairie Tone et celle permettant la gestion de le télécommande infrarouge, IRremote. Si c'est aussi votre cas, alors ouvrez le fichier IRremoteInt.h et localisez le bloc de code suivant.
 1 
 2 
 3 
 4 
#else
  //#define IR_USE_TIMER1   // tx = pin 9
  #define IR_USE_TIMER2     // tx = pin 3
#endif
source du conflit

Normalement, si vous permuttez les deux lignes de commentaires, le problème doit être résolu. Voici le code après permutation.

 1 
 2 
 3 
 4 
#else
  #define IR_USE_TIMER1   // tx = pin 9
  //#define IR_USE_TIMER2     // tx = pin 3
#endif
source du conflit

Pour aller plus loin...

Si ce projet vous a plu et que vous souhaitiez poursuivre son développement, sachez que je vous propose le code d'un projet Android permettant de contrôler le véhicule par bluetooth. Vous trouverez ce projet à l'adresse suivante : la télécommande Android.