Vous allez aujourd'hui réaliser un programme pour que le robot puisse se rapprocher du plus proche objet autour de lui.
Et autant c'est facile pour un être humain, autant c'est compliqué pour faire comprendre cela à un circuit numérique !
Commençons par fournir un programme fonctionnel qui permet d'afficher quelque chose sur votre afficheur. Je l'ai placé sur le port RJ45 numéro 3 sur mon propre robot.
Pensez à adapter les numéros de port à votre propre robot.
J'utilise donc un objet-afficheur nommé disp de classe Me7SegmentDisplay.
J'ai rajouté les déclarations des objets moteurs (nommés motor3 et motor4) et de l'objet capteur ultrasonore . Ils vous serviront plus tard.
#include "MeOrion.h"
Me7SegmentDisplay disp(PORT_3);
MeUltrasonicSensor ultraSensor(PORT_6); /* Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield. */
MeDCMotor motor3(M1);
MeDCMotor motor4(M2);
uint8_t motorSpeed = 100;
void setup()
{
for (int i=0; i < 5 ; i++) {
disp.display(i);
delay(1000);
}
}
void loop()
{
}
Comme vous pouvez le voir, l'utilisation de l'afficheur pour afficher un nombre est très simple : on donne la variable de l'objet-afficheur, on place le point, on donne le nom de la méthode display et on donne en argument le nombre à afficher.
01° Tester le code et vérifier sa validité sur votre robot.
02° Compter jusqu'à dix au démarrage puis afficher la distance à l'obstacle perçu par le capteur dans la fonction loop().
Cette notion est très importante en informatique.
Chaque partie du programme possède son propre espace des noms. C'est à dire qu'une variable portant un nom toto dans la fonction setup() ne désigne pas le même espace mémoire que la variable de nom toto dans la fonction loop().
03° Créer deux variables toto dans les deux fonctions. On prendra 10 par la première variable et 55 pour la seconde variable. Demander à afficher leur valeurs respectives pendant 2s.
...CORRECTION...
#include "MeOrion.h"
Me7SegmentDisplay disp(PORT_3);
MeUltrasonicSensor ultraSensor(PORT_6); /* Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield. */
MeDCMotor motor3(M1);
MeDCMotor motor4(M2);
uint8_t motorSpeed = 100;
void setup()
{
int toto = 10;
disp.display(toto);
delay(2000);
}
void loop()
{
int toto = 55;
disp.display(toto);
delay(2000);
}
L'ordinateur remplace donc le nom dans le contexte : si vous demandez disp.display(toto);
Vous devriez avoir constaté que lorsqu'on utilise toto dans la fonction loop(), on affiche bien 55 : le programme comprend "Va chercher le contenu de la variable toto déclarée dans la fonction loop".
On devrait voir ceci s'afficher sur l'afficheur :
void setup()
{
int toto = 10;
disp.display(toto);
delay(2000);
}
void loop()
{
int toto = 55;
disp.display(toto);
delay(2000);
}
CLIQUEZ ICI POUR VOIR L'ANIMATION :
motorSpeed :
i :
04° Compter jusqu'à dix au démarrage puis afficher la distance à l'obstacle perçu par le capteur dans la fonction loop().
Vous devriez obtenir un code proche de celui-ci :
#include "MeOrion.h"
Me7SegmentDisplay disp(PORT_3);
MeUltrasonicSensor ultraSensor(PORT_6); /* Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield. */
MeDCMotor motor3(M1);
MeDCMotor motor4(M2);
uint8_t motorSpeed = 100;
void setup()
{
int toto = 10;
disp.display(toto);
delay(2000);
}
void loop()
{
int toto = 55;
disp.display(toto);
delay(2000);
}
05° Faire disparaitre le int
dans int toto = 55;
. Dans la mesure où une variable toto avait été déclarée dans la fonction précédente, on aurait pu penser que cette autre fonction allait pouvoir comprendre quelque chose. Mais que constate-t-on ?
On retiendra donc qu'une variable déclarée dans une fonction n'est visible que depuis l'intérieur de la fonction et pas depuis une autre fonction, ni même le corps du programme.
Imaginez le corps du programme comme le couloir d'un lycée et les fonctions comme les salles. Les variables sont les élèves.
Nous venons ainsi de voir qu'une variable(élève) située dans une fonction(salle) n'est pas visible depuis une autre fonction(salle). C'est logique.
La question qu'on peut alors se poser est alors :
"Une variable située dans une fonction peut-elle être vue depuis le programme principal ?"
Et la réponse est toujours non. Pourquoi ? Simplement parce qu'une variable de fonction n'est créée que le temps que la fonction s'exécute. Dés qu'on sort de son exécution, toutes les parties mémoires qu'elle a utilisé sont rendues et donc disparaissent.
Il nous reste encore à voir une chose : les variables globales.
Vous les avez déjà rencontré de nombreuses fois : il s'agit de variables qui sont déclarées dans le corps du programme et pas dans une fonction.
Reprenons l'exemple ci-dessus :
#include "MeOrion.h"
Me7SegmentDisplay disp(PORT_3);
MeUltrasonicSensor ultraSensor(PORT_6); /* Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield. */
MeDCMotor motor3(M1);
MeDCMotor motor4(M2);
uint8_t motorSpeed = 100;
void setup()
{
disp.display(motorSpeed);
delay(1000);
}
void loop()
{
}
06° Parvient-on à lire la variable globale motorSpeed depuis une fonction ?
06° Tenter de modifier la variable globale depuis la fonction loop(). Y parvient-on ?
07° Faire de même en déclarant au préalable une seconde variable motorSpeed localement dans loop(). Y parvient-on ?
Voici le code auquel on peut aboutir :
#include "MeOrion.h"
Me7SegmentDisplay disp(PORT_3);
MeUltrasonicSensor ultraSensor(PORT_6); /* Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield. */
MeDCMotor motor3(M1);
MeDCMotor motor4(M2);
uint8_t motorSpeed = 100;
void setup()
{
motorSpeed = motorSpeed+50;
disp.display(motorSpeed);
delay(1000);
}
void loop()
{
uint8_t motorSpeed = 200;
disp.display(motorSpeed);
delay(1000);
}
Si on résume :
Une variable globale peut être lue et modifiée depuis une fonction.
Une variable locale ne peut être lue et modifiée que dans sa fonction.
S'il existe deux variables portant le même nom (une locale et une globale), la fonction prendra comme référence sa propre variable locale.
Dernière chose que nous allons voir aujourd'hui : comment réaliser une action en boucle sans savoir précisement quand il va falloir s'arrêter. On parle alors de boucle TANT QUE (en français) ou WHILE (en anglais).
Le principe est simple : TANT QUE la condition est vérifiée (vrai), on recommence la boucle.
La synthaxe est la suivante :
while(expression)
{
// tant que l'expression est vraie
// instructions à effectuer
}
Prenons un petit exemple : on veut multiplier un nombre par 5 sans jamais dépasser 9999 puisqu'on ne dispose que de 4 digits :
void setup()
{
int monNombre = 3;
while(monNombre<=9999)
{
disp.display(monNombre);
delay(2000);
monNombre = monNombre * 5;
}
}
08° Tester le programme pour en comprendre le principe.
09° Créer une fonction setup() qui avance le robot jusqu'à être à 20 cm d'un obstacle puis recule jusqu'à être à 30 cm.
Nous avons fait le robot autonome qui avance seul.
Il est temps de passer au robot qui cherche à se rapprocher de l'obstacle le plus proche.
Pendant ce projet, il faudra utiliser l'afficheur pour tenter de comprendre ce que voit votre robot et ainsi comprendre si votre algorithme est correct ou pas.
Pour cela :
10° Réaliser un programme permettant au robot de tourner sur lui-même au moins une fois et qui sauvegarde en mémoire la distance scannée la plus courte rencontrée.
11° Demander au robot de continuer à tourner tant que la distance mesurée est supérieure à la distance minimale.
12° Demander au robot d'avancer vers l'obstacle tant que la distance est bien en train de diminuer.
13° Le robot doit recommencer le scan et tenter de rejoindre son nouvel objectif. S'il échoue 3 fois de suite, il doit s'arrêter.
14° Etape finale : le robot ne doit pas pouvoir percuter les obtacles et doit s'arrêter à 20 cm de l'objectif.