Aller au contenu


Information tutoriel

  • Ajouté le: oct. 03 2010 11:04
  • Date Updated: mars 26 2017 12:14
  • Lectures: 94104
 


* * * * *
3 Notes

Roby, mon premier robot Arduino

Posté par robocop on oct. 03 2010 11:04
Bonjour,

Je vous propose ici la construction d'un nouveau robot, Roby, qui pédagogiquement pourra se placer après avec les deux Cocotix, Cocotix V1, et Cocotix V2.
Roby sera programmable avec la plateforme arduino et intègrera différents capteurs : capteurs d'obstacles et de lumière comme dans cocotix V1 et V2, mais également d'autres comme capteurs de distance infrarouge ou ultrason si vous le désirez : le robot se veut extensible.

-------------------------------------
Liste des composants (par microrupteurman2) :

- 2 servomoteurs type s3003 modifiés en rotation continue
- 1 arduino
- 2 micro-rupteurs
- Les piles indiquées sur le schéma avec leur boîtier
- Une plaque d'essai (breadboard)
- Des roues pour servo, facilement réalisables
- Une roulette pour le 3e point d'appui
- fil électrique,
- vis
- matériel de soudure
- 1 interrupteur
- 2 résistances de 10k0
- 1 capteur Sharp Gp2d112
-------------------------------------

Le robot aura comme base mécanique la structure présentée ici.
Bien évidemment, vous pouvez utiliser la structure de votre choix, mais dans le code du robot, j'utiliserai bien deux servomoteurs pour la propulsion.

Image IPB

But du robot

Comme vu sur la vidéo, Roby aura pour but de naviguer dans une pièce, en évitant les obstacles, soit grâce a un capteur infrarouge de distance, soit avec des "antennes", des capteurs de contact.



Roby, robot basé sur une carte arduino

Par la suite, si vous le souhaitez, encore une fois, vous pourrez très simplement rajouter des capteurs, de l'enregistrement de données sur carte SD, une petite caméra, une liaison sans fil, etc.

Tout cela se fait très simplement avec certains modules pour Arduino.

Structure mécanique

Le structure mécanique est axée sur deux servomoteurs modifiés en courant continu.
Si vous n'avez pas d'idées, vous pouvez vous inspirer de ce tutoriel.

Image IPB

L'Arduino

Image IPB

Toute l'électronique du robot sera basée sur la carte Arduino Duemilanove. Arduino Duemilanove est une carte électronique qui comporte un microcontrolleur atmel ATmga328 et des composants supplémentaires pour faciliter la programmation du composant.

Ainsi la carte intègre directement un port usb pour programmer la carte en USB, un quartz 16MHz, un régulateur linéaire de tension 5, différentes LED, un bouton de reset, bref, pleins de bonnes choses pour commencer très rapidement sans soucis.
Cerise sur le gâteau, la carte est très accessible, moins de 30 euros.

Installation de la carte

Pour pouvoir programmer la carte, il faut déjà installer les drivers et les outils de programmation sur votre ordinateur.
La carte fonctionne aussi bien sur une architecture windows que linux.

Pour l'installation, je vous renvoi sur le chapitre dédié à l'installation d'Arduino sur l'ouvrage débuter avec Arduino

Test de la carte

On va voir si l'installation s'est bien passée en faisant clignoter une DEL.
La carte arduino équivalente à une carte clone Arduino Uno intègre d'office une petite DEL sur la patte 13.

On va donc mettre successivement la patte de 0 à 1, et de 1 à 0, toutes les 1.5 secondes.

On ouvre donc leur IDE, et on tape le programme suivant :
Code : C
int ledPin = 13;

void setup() {
// On initialise la patte 13 en pin de sortie
pinMode(ledPin, OUTPUT);
}

void loop()
{
digitalWrite(ledPin, HIGH); // on met la patte à 1
delay(1000); // on attend une seconde
digitalWrite(ledPin, LOW); // on met la patte à 0
delay(1000); // on attend une seconde
}
On remarque que chaque code possède au minimum deux fonctions, setup() et loop().
setup() est appelée au lancement de la carte, et loop() et executée en boucle, tant que la carte reçoit du courant.

Compilez votre code, puis envoyer le sur la carte.
Au bout de quelques secondes, la DEL de la carte devrait clignoter.
 
Ressources


Pour à peu près tout, il existe une librairie pour votre carte arduino : vous pouvez controler un servomoteur avec la librairie de servomoteurs, controler un écran LCD, communiquer avec l'ordinateur à travers le port USB, etc.

Voici un lien qui présente pleins d'exemples amusant à réaliser, et un autre, qui présente rapidement le langage avec lequel vous travaillez.

Amusez-vous bien !

Alimentation

Il y a dans ce robot deux alimentations : une pile 9 V pour alimenter l'arduino et 4 piles 1.5 V en série pour alimenter les servomoteurs et autres capteurs.

L'avantage de ce système, c'est que l'on peut alimenter l'arduino par la prise USB lorsque l'on écrira le programme, tout en gardant alimenté les servomoteurs : le débogage est donc plus aisé.

Attention cependant : il faut faire attention a bien relier les deux masses entre elle, cela peut être source de bogues assez vicieux.
Vous pouvez fixer vos piles commme sur cette photo :

Commencez par fixez les deux alimentation comme sur la photo :

Image IPB

Faites un trou au milieu du robot pour laisser passer les fils de l'alimentation et un trou sur le coté pour fixer l'interrupteur.
L'idéal c'est d'avoir un interrupteur capable d'avoir de couper/alimenter deux circuits à la fois. De cette façon, vous pourrez éteindre ou allumer votre robot en une fois.
Maintenant, si vous n'avez que deux interrupteurs normaux, ça fonctionnera aussi.

Fixez sur le robot l'arduino et la plaque d'essai.

Cablez alors les alimentations, l'arduino et les servomoteurs de cette façon :

Image IPB

Vous avez donc avec ce schéma 6V pour les deux servomoteurs et 9 V pour l'arduino.
Les deux masses sont bien reliées entres elles.
Sur la plaque d'essai, la première ligne correspond donc aux +6V et la deuxième à la masse.
Voici une photo de mon robot à cette étape :

Image IPB

Test des moteurs

On va écrire dans un premier temps un programme qui fait avancer le robot tout droit.

Tout d'abord, nous allons écrire une fonction toute simple, getNeutral(moteur) qui retournera la valeur du neutre de vos servomoteurs :
Code : C++
#include <Servo.h>

#define SERVOG 1
#define SERVOD 0

Servo servog;
Servo servod;

int getNeutral(int s)
{
if(s == SERVOG)
return 86;
else
return 84;
}
Chaque servomoteur est représenté par un entier naturel : le servomoteur gauche 1 et le servomoteur droit 0.
Remplacez les valeurs 86 et 84 respectivement par les valeurs du neutre que vous trouvez pour le servomoteur gauche et pour le servomoteur droit de votre robot.

Essayez de faire bouger vos servomoteurs en utilisant cette fonction.
Tout va bien ? Ok, nous allons écrire une fonction handleS(servomoteur, vitesse) qui envoit une commande au servomoteur. Cette commande est caractérisé par une vitesse qui va de -5 à 5. Si la vitesse est négative, on dira au moteur d'aller dans un sens et si le vitesse est positive on dira au robot d'aller dans l'autre sens.

Les différentes vitesses sont obtenues en se rapprochant du neutre. Je vous conseil de faire vos propres tests.
Attention cependant : nos servomoteurs ne sont pas dans le même sens. Pour avancer tout droit, un des servomoteurs doit aller dans un sens, et l'autre servomoteur doit aller dans l'autre sens.
On ne va donc pas oublier d'inverser le sens de rotation pour un des moteurs.
Code : C++
void handleS(int s, int speed)
{
//Vitesse :
// 0 -> 0; 1 -> 1; 2 -> 3; 3 -> 8; 4 -> 10; v => 5 -> 30
int tab[6] = {0,1,3,8,10,30};
int pos = getNeutral(s);

int acc;
// A chaque vitesse on fait correspondre un nombre qui est la différence de ce que l'on va envoyer au servomoteur par rapport au neutre.
// Les valeurs que je donne sont mes valeurs, je vous conseille de chercher vos propres valeurs, cela dépend de votre servomoteur.
if (speed < 0)
acc = - tab[abs(speed)];
else
acc = tab[speed];

if(s == SERVOG)
servog.write(pos += acc);
// On inverse le sens de rotation pour le moteur droit car les deux servomoteurs ne sont pas montés dans le même sens.
else
servod.write(pos -= acc);
}
A partir de là, on peut écrire une fonction move(direction) qui fait déplacer le robot dans une direction donnée :
Code : C++
#define AVANT 1
#define ARRIERE 0
#define GAUCHE 2
#define DROITE 3

#define VMAX 5

void move(int direction)
{
int m1 = 0, m2 = 0;
switch(direction)
{
case DROITE: m1 = 1; m2 = -1; break;
case GAUCHE: m1 = -1; m2 = 1; break;
case AVANT: m1 = 1; m2 = 1; break;
case ARRIERE: m1 = -1; m2 = -1; break;
}
handleS(SERVOG, m1*VMAX);
handleS(SERVOD, m2*VMAX);
}
Rien de bien compliqué : en fonction du déplacement, on indique dans quel sens doit se déplacer chaque moteur.

Code complet


On va, en utilisant toutes ces fonctions, demander au robot d'avancer tout droit :
Code : C++
#include <Servo.h>

#define AVANT 1
#define ARRIERE 0
#define GAUCHE 2
#define DROITE 3

#define SERVOG 1
#define SERVOD 0

#define VMAX 5

Servo servog;
Servo servod;

int getNeutral(int s)
{
if(s == SERVOG)
return 86;
else
return 84;
}


void handleS(int s, int speed)
{
//Vitesse :
// 0 -> 0; 1 -> 1; 2 -> 3; 3 -> 8; 4 -> 10; v => 5 -> 30
int tab[6] = {0,1,3,8,10,30};
int pos = getNeutral(s);

int acc;
if (speed < 0)
acc = - tab[abs(speed)];
else
acc = tab[speed];

if(s == SERVOG)
servog.write(pos += acc);
else
servod.write(pos -= acc);
}


void move(int direction)
{
int m1 = 0, m2 = 0;
switch(direction)
{
case DROITE: m1 = 1; m2 = -1; break;
case GAUCHE: m1 = -1; m2 = 1; break;
case AVANT: m1 = 1; m2 = 1; break;
case ARRIERE: m1 = -1; m2 = -1; break;
}
handleS(SERVOG, m1*VMAX);
handleS(SERVOD, m2*VMAX);
}



void setup()
{
servog.attach(10);
servod.attach(9);
move(AVANT);
}

void loop()
{
delay(15);
}
Cela est très simple avec la fonction move : move(AVANT);
Maintenant, on va faire faire avancer le robot pendant 8 secondes, lui faire faire un demi-tour, le faire avancer pendant 8 secondes, et ainsi de suite.
Pour faire tourner le robot, on va le faire tourner vers la gauche pendant un certain temps.
Personnellement, je trouve qu'il faut le laisser tourner 2 secondes pour qu'il fasse un demi-tour complet.
Ainsi, tout naturellement, le code est le suivant :
Code : C++
void loop()
{
move(AVANT);
delay(8000);
move(GAUCHE);
delay(2000);
}

Capteurs de contact : détecter les obstacles


Nous allons rajouter des capteurs de contact de type UPDD comme dans Cocotix. Il faut donc les connecter a deux pattes de l'arduino, et nous allons simplement regarder les états des deux pattes de l'arduino : si l'une est à 1, il faut enclencher un virage Image IPB.

Voici donc le schéma de ce montage :

Image IPB

Les deux résistances sont des résistances de "pull-down", reliées à la masse pour éviter d'avoir des pattes flottantes et pour forcer l'état normal des deux pattes à 0.

Le code pour faire éviter les obstacles fait reculer, puis de tourner le robot à la détection de chaque obstacle :
Code : C++
#define UPDDG 3 // on utilise la patte 2 pour le capteur de gauche et 4 pour le capteur de droite.
#define UPDDD 4

void handleUPDD(int updd)
{
if(digitalRead(updd) == HIGH) //Si le capteur est enclenché
{
move(ARRIERE); // on recule d'abord pendant 0.4 sec
delay(400);

if (updd == UPDDG) // Puis on tourne dans le sens inverse du capteur détecté...
{
move(DROITE);
}
else
{
move(GAUCHE);
}
delay(600); // ...pendant 0.6 sec
}
}

Voici le schéma complet du robot à ce stade :

Image IPB

Et le code complet :
Code : C++
 
#include <Servo.h>

#define AVANT 1
#define ARRIERE 0
#define GAUCHE 2
#define DROITE 3

#define SERVOG 1
#define SERVOD 0

#define UPDDG 3
#define UPDDD 4

#define VMAX 5

Servo servog;
Servo servod;

int getNeutral(int s)
{
if(s == SERVOG)
return 86;
else
return 84;
}


void handleS(int s, int speed)
{
//Vitesse :
// 0 -> 0; 1 -> 1; 2 -> 3; 3 -> 8; 4 -> 10; v => 5 -> 30
int tab[6] = {0,1,3,8,10,30};
int pos = getNeutral(s);

int acc;
if (speed < 0)
acc = - tab[abs(speed)];
else
acc = tab[speed];

if(s == SERVOG)
servog.write(pos += acc);
else
servod.write(pos -= acc);
}


void move(int direction)
{
int m1 = 0, m2 = 0;
switch(direction)
{
case DROITE: m1 = 1; m2 = -1; break;
case GAUCHE: m1 = -1; m2 = 1; break;
case AVANT: m1 = 1; m2 = 1; break;
case ARRIERE: m1 = -1; m2 = -1; break;
}
handleS(SERVOG, m1*VMAX);
handleS(SERVOD, m2*VMAX);
}

void handleUPDD(int updd)
{
if(digitalRead(updd) == HIGH)
{
move(ARRIERE);
delay(500);

if (updd == UPDDG)
{
move(DROITE);
}
else
{
move(GAUCHE);
}
delay(800);
}
}



void setup()
{
pinMode(UPDDG, INPUT);
pinMode(UPDDD, INPUT);

servog.attach(10);
servod.attach(9);
move(AVANT);
}

void loop()
{
handleUPDD(UPDDG);
handleUPDD(UPDDD);
move(AVANT);
delay(15);
}

Capteur de distance infrarouge

Pour finir je vous propose de rajouter un capteur de distance pour détecter les obstacles sans les percuter.
Nous allons utiliser un capteur Sharp gp2d120 qui permet de voir de 4 cm à 80 cm.
Le capteur est simplement composé de 3 fils, deux pour l'alimentation (+5v et masse) et un pour la sortie analogique : le capteur renvoie une tension comprise entre 0 et 5v proportionnel à la distance des objets.

Image IPB

Branchez donc le capteur sur l'arduino : le fil rouge sur le +5V, le fil noir à la masse, et le jaune sur la patte 4 de l'arduino, qui est une patte analogique : on peut directement lire la tension envoyée à cette patte.

Vous pouvez le fixer sur le robot comme sur cette image :

Image IPB


Pour lire une patte la valeur de la tension envoyée à la patte 4, il suffit de faire :
Code : C++
int v = analogRead(4);
Après quelques tests de mon capteur, j'ai constaté que si v était supérieur à 180 (obstacle à 10 cm), alors il fallait reculer pour éviter l'obstacle, alors que si v est supérieur à 100 (obstacle à 30 cm) il suffisait de ralentir d'un coté pour éviter l'obstacle.

Voici donc le code que je vous propose :
Code : C++
void sharp()
{
int v = analogRead(4);
if (v >= 180) // si on est à moins de 10 cm d'un obstacle
{
move(ARRIERE); //on recule
delay(300);
move(DROITE); //puis on part sur la droite
delay(900);
}
else if (v >= 100) //sinon si on est à moins de 30 cm d'un obstacle
{
handleS(SERVOG, VMAX);
handleS(SERVOD, 0); // on ralentit simplement la roue droite pour engager un virage en douceur
delay(1500);
}
}
Au final, voici le code complet :
Code : C++
#include <Servo.h>

#define AVANT 1
#define ARRIERE 0
#define GAUCHE 2
#define DROITE 3

#define SERVOG 1
#define SERVOD 0

#define UPDDG 3
#define UPDDD 4

#define SHARP 4

#define VMAX 5

Servo servog;
Servo servod;

int vLdr = 5;

int getNeutral(int s)
{
if(s == SERVOG)
return 86;
else
return 84;
}


void handleS(int s, int speed)
{
//Vitesse :
// 0 -> 0; 1 -> 1; 2 -> 3; 3 -> 8; 4 -> 10; v => 5 -> 30
int tab[6] = {0,1,3,8,10,30};
int pos = getNeutral(s);

int acc;
if (speed < 0)
acc = - tab[abs(speed)];
else
acc = tab[speed];

if(s == SERVOG)
servog.write(pos += acc);
else
servod.write(pos -= acc);
}


void move(int direction)
{
int m1 = 0, m2 = 0;
switch(direction)
{
case DROITE: m1 = 1; m2 = -1; break;
case GAUCHE: m1 = -1; m2 = 1; break;
case AVANT: m1 = 1; m2 = 1; break;
case ARRIERE: m1 = -1; m2 = -1; break;
}
handleS(SERVOG, m1*VMAX);
handleS(SERVOD, m2*VMAX);
}

void handleUPDD(int updd)
{
if(digitalRead(updd) == HIGH)
{
move(ARRIERE);
delay(500);

if (updd == UPDDG)
{
move(DROITE);
}
else
{
move(GAUCHE);
}
delay(800);
}
}

void sharp()
{
int v = analogRead(SHARP);
if (v >= 180)
{
move(ARRIERE);
delay(300);
move(DROITE);
delay(900);
}
else if (v >= 100)
{
handleS(SERVOG, VMAX);
handleS(SERVOD, 0);
delay(1500);
}
}
void setup()
{
pinMode(UPDDG, INPUT);
pinMode(UPDDD, INPUT);

Serial.begin(9600);
servog.attach(10);
servod.attach(9);
move(AVANT);
}

void loop()
{
handleUPDD(UPDDG);
handleUPDD(UPDDD);
sharp();
move(AVANT);
delay(100);
}
Comme vous pouvez le voir, rajouter un capteur n'a pas été difficile Image IPB.

Roby, robot basé sur une carte arduino.

Et voilà, c'est fini pour ce tutoriel.
Évidemment, la réalisation proposée ici n'est qu'une base à améliorer.
N'hésitez pas à nous faire par de vos améliorations, quelles soient électronique ou algorithmique soit en postant sur le forum, soit en créant votre tutoriel Image IPB.

Remerciement : cgizmo, avec qui j'ai écrit le code du robot.