Guide de montage · Débutant · dès 9 ans

Assemble ton Mark I

On monte le Mark I ensemble, étape par étape. À chaque étape : une animation 3D que tu peux faire tourner avec ton doigt ou la souris pour la voir sous tous les angles, et une vraie vidéo qui te montre le geste. Prends ton temps — quand tu es prêt, passe à l'étape suivante.

Glisse pour tourner · pince/molette pour zoomer
Chargement du modèle 3D…
Étape 1
Le montage va commencer…

Tu n'as pas encore ton Mark I ? Compose le tien en 3D et choisis tes couleurs.

Personnaliser mon Mark I ← Centre d'apprentissage
Le cerveau du robot

Comment marche le code ?

Maintenant que ton Mark I est monté, découvrons son cerveau : le code. Pas besoin de savoir programmer — on va le lire ensemble, petit morceau par petit morceau. Un programme, c'est juste une liste d'instructions toutes simples que le robot suit très vite, encore et encore.

#include <AFMotor_R4.h>

On donne au robot un livre de recettes tout prêt pour commander ses moteurs. Comme ça, pas besoin de tout réexpliquer : on réutilise des recettes déjà écrites pour nous.

AF_DCMotor moteur1(1);
AF_DCMotor moteur2(2);

On présente les deux moteurs au robot et on leur donne un nom : moteur1 et moteur2. Le (1) et le (2) disent sur quelle prise de la carte ils sont branchés. Maintenant, quand on dira « moteur1 », le robot saura de qui on parle.

#define TRIG A0
#define ECHO A1

Le robot a des yeux spéciaux : un capteur qui envoie un petit « bip » et écoute l'écho qui revient, exactement comme une chauve-souris. TRIG, c'est le fil qui envoie le bip ; ECHO, c'est le fil qui écoute le retour. On dit juste sur quelles prises ils sont branchés (A0 et A1).

const int SEUIL_CM = 20;
const int VITESSE  = 200;

On règle deux nombres une fois pour toutes. SEUIL_CM = 20, c'est la distance de sécurité : si un obstacle est à moins de 20 centimètres, le robot dira « attention ! ». VITESSE = 200, c'est la vitesse des moteurs, sur une échelle de 0 (arrêté) à 255 (à fond).

long lireDistanceCm() {
  digitalWrite(TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long duree = pulseIn(ECHO, HIGH, 30000UL);
  if (duree == 0) return 999;
  return duree * 0.034 / 2;
}

C'est la recette « mesurer la distance ». Le robot envoie un tout petit bip (il allume TRIG un court instant), puis il chronomètre le temps que met l'écho à revenir (ECHO). Plus l'écho met de temps, plus le mur est loin. La dernière ligne transforme ce temps en centimètres. Et s'il n'entend aucun écho, il répond 999 — sa façon de dire « je ne vois rien devant, la voie est libre ».

void avancer() {
  moteur1.run(BACKWARD);
  moteur2.run(FORWARD);
}
void reculer() {
  moteur1.run(FORWARD);
  moteur2.run(BACKWARD);
}
void pivoter() {
  moteur1.run(FORWARD);
  moteur2.run(FORWARD);
}
void arret() {
  moteur1.run(RELEASE);
  moteur2.run(RELEASE);
}

Voici les jambes du robot : quatre petites recettes pour bouger. avancer = tout droit, reculer = en arrière, pivoter = tourner sur place, et arret = s'arrêter (on relâche les moteurs). Les mots BACKWARD/FORWARD (arrière/avant) ont été réglés exprès pour correspondre à la façon dont les moteurs sont montés sur TON robot : l'important, c'est qu'« avancer » le fasse vraiment aller tout droit.

void setup() {
  Serial.begin(9600);
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  moteur1.setSpeed(VITESSE);
  moteur2.setSpeed(VITESSE);

setup, c'est ce que le robot fait UNE seule fois en se réveillant, quand on l'allume. Il ouvre une ligne de discussion avec l'ordinateur (pour pouvoir nous écrire des messages), il explique que TRIG sert à parler et ECHO à écouter, puis il règle la vitesse des deux moteurs.

  Serial.println(F("=== Demarrage ==="));
  long test = lireDistanceCm();
  if (test >= 999) {
    Serial.println(F("ATTENTION: capteur muet (AUCUN ECHO)."));
    Serial.println(F("-> corrige Trig/Echo / 5V / GND, le robot n'evitera RIEN."));
  } else {
    Serial.print(F("Capteur OK, distance initiale: "));
    Serial.print(test);
    Serial.println(F(" cm"));
  }
  delay(1500);
}

Avant de bouger, le robot fait un petit test de ses yeux : il mesure la distance une fois. Si le capteur ne répond pas (999), il écrit un message d'alerte pour te prévenir qu'il n'évitera rien (à vérifier : les fils et le branchement). Sinon il écrit « Capteur OK » avec la distance. Puis il attend 1,5 seconde, le temps que tu lises le message et que tu poses le robot par terre.

void loop() {
  long distance = lireDistanceCm();
  Serial.println(distance);

loop, c'est ce que le robot répète en boucle, encore et encore, très vite, tant qu'il est allumé — c'est sa façon de réfléchir tout le temps. À chaque tour, il mesure la distance devant lui et l'écrit (pour qu'on puisse la voir sur l'ordinateur).

  if (distance < SEUIL_CM) {
    arret();    delay(150);
    reculer();  delay(400);
    arret();    delay(150);

    pivoter();
    unsigned long debut = millis();
    while (lireDistanceCm() < SEUIL_CM && millis() - debut < 2000) {
      delay(50);
    }
    arret();    delay(150);
  } else {
    avancer();
  }
}

Puis il prend une décision. SI un obstacle est trop près (moins de 20 cm) : il s'arrête, recule un peu, s'arrête encore, puis pivote (tourne sur place) jusqu'à ce que la voie soit dégagée — mais 2 secondes maximum, pour ne pas tourner sans fin. SINON, la voie est libre, alors il avance tout droit. Et comme tout ça se répète des dizaines de fois par seconde, le robot a l'air de se promener tout seul en évitant les murs !

Et voilà — c'est ça, programmer : donner au robot une liste d'instructions toutes simples, qu'il suit très vite. Bientôt, tu pourras changer ces nombres toi-même : essaie une autre VITESSE, ou un SEUIL_CM plus grand, et observe comment ton Mark I se comporte !

Voir le code complet (à copier)
#include <AFMotor_R4.h>

AF_DCMotor moteur1(1);
AF_DCMotor moteur2(2);

#define TRIG A0
#define ECHO A1

const int SEUIL_CM = 20;
const int VITESSE  = 200;

long lireDistanceCm() {
  digitalWrite(TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long duree = pulseIn(ECHO, HIGH, 30000UL);
  if (duree == 0) return 999;
  return duree * 0.034 / 2;
}

void avancer() {
  moteur1.run(BACKWARD);
  moteur2.run(FORWARD);
}
void reculer() {
  moteur1.run(FORWARD);
  moteur2.run(BACKWARD);
}
void pivoter() {
  moteur1.run(FORWARD);
  moteur2.run(FORWARD);
}
void arret() {
  moteur1.run(RELEASE);
  moteur2.run(RELEASE);
}

void setup() {
  Serial.begin(9600);
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  moteur1.setSpeed(VITESSE);
  moteur2.setSpeed(VITESSE);

  Serial.println(F("=== Demarrage ==="));
  long test = lireDistanceCm();
  if (test >= 999) {
    Serial.println(F("ATTENTION: capteur muet (AUCUN ECHO)."));
    Serial.println(F("-> corrige Trig/Echo / 5V / GND, le robot n'evitera RIEN."));
  } else {
    Serial.print(F("Capteur OK, distance initiale: "));
    Serial.print(test);
    Serial.println(F(" cm"));
  }
  delay(1500);
}

void loop() {
  long distance = lireDistanceCm();
  Serial.println(distance);

  if (distance < SEUIL_CM) {
    arret();    delay(150);
    reculer();  delay(400);
    arret();    delay(150);

    pivoter();
    unsigned long debut = millis();
    while (lireDistanceCm() < SEUIL_CM && millis() - debut < 2000) {
      delay(50);
    }
    arret();    delay(150);
  } else {
    avancer();
  }
}