RoboduLAB
Présentation du projet
Un robot pour apprendre à programmer en classe
- Utilisable en écoles primaires, collèges et lycées
- Toutes les pièces mécaniques sont imprimables (impression 3D – fichiers .stl fournis)
- Partie électronique basée sur une carte de prototypage « arduino »
- Libre (copiable, modifiable) et évolutif (de nombreuses options possibles)
RoboduLAB, permet une approche ludique de l’apprentissage du code à l’école primaire, des plots au format lego permettent de personnaliser le robot.
En collège et en lycée RoboduLAB est un support de thème très riche pour le travail en équipes projets : conception, réalisation, expérimentation.
La programmation se fait par assemblage de blocs (type scratch). Le programme se télécharge directement dans le robot depuis le PC ou la tablette en WIFI.
600px
Constitution du robot
RoboduLAB est constiué d'un chassis, de deux roues montées sur des servomoteurs qui sont commandés par une carte de prototypage arduino. Il sera possible de rajouter différentes options au modèle de base :
- suivi de ligne,
- module WIFI,
- détection des vides,
- sons (MP3),
- …
Chassis
Le chassis est constitué d'un ensemble de pièces imprimables par une une imprimante 3D et une roulette à bille.
Électronique
La partie électronique du robot comporte à minima :
- une carte arduino (UNO),
- deux servomoteurs à rotation continue,
- un capteur à ultrasons,
- une LED RGB (ou un NeoPixel Ring),
- un boîtier pour les piles (6 piles AA)
- un interrupteur à glissière.
Programmes
Le programme nécessaire pour le fonctionnement du robot peut être :
- soit écrit directement en C++ et téléchargé dans la carte arduino,
- soit représenté par des blocs graphiques (blokly). Il sera alors possible de produire automatiquement le code en C++ qui sera téléchargé dans le robot.
Code arduino : démonstration du fonctionnement du robot en mode autonome
Programme sans NeoPixel Ring
Voici le programme qu'il faut éditer dans l'IDE Arduino, puis compiler et charger dans la carte Arduino
/*
Ce programme de démonstration permet de faire fonctionner le robot d'une manière autonome
*/
#include <Servo.h> // librairie pour servomoteur
#define broche_servoA 3 // broche servo A
#define broche_servoB 5 // broche servo B
#define trig 2 // broche trig du capteur US HC-SR04
#define echo 4 // broche echo du capteur US HC-SR04
const int MAX_SENS2=1000; // largeur impulsion pour position ANGLE_MIN degrés du servomoteur
const int ARRET=1490; // largeur impulsion pour position ANGLE_MEDIANE degrés du servomoteur
const int MAX_SENS1=2000; // largeur impulsion pour position ANGLE_MAX degrés du servomoteur
// classiquement : centrage sur 1500 - maxi sens 1 = 1000 et maxi sens 2 = 2000
// --- Déclaration des constantes des broches E/S numériques ---
long lecture_echo = 0; // variable sur 4 octets mesure de distance
long cm = 0; // variable sur 4 octets pour la conversion en cm
//--- Création objet servomoteur
Servo servoA; // crée un objet servo pour contrôler le servomoteur A (en dessous du swich ON/OFF
Servo servoB; // crée un objet servo pour contrôler le servomoteur B (à gauche du servo A)
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme
void setup() { // debut de la fonction setup()
// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---
pinMode (broche_servoA,OUTPUT); // Broche broche_servo configurée en sortie
pinMode (broche_servoB,OUTPUT); // Broche broche_servo configurée en sortie
pinMode (trig,OUTPUT); // broche broche trig configurée en sortie
digitalWrite(trig, LOW); // met un niveau logique , LOW (BAS) sur la broche trig
pinMode(echo, INPUT); // la broche echo est initialisée en entree
Serial.begin(115200); // initialisation de la liaison série à 115200 bauds
delay (2000); // on attend 2s
} // fin de la fonction setup()
// ********************************************************************************
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension
void loop(){ // debut de la fonction loop()
Avant();
digitalWrite(trig, HIGH); // met un niveau logique , HIGH (HAUT) sur la broche trig
delayMicroseconds(10); // attente pendant 10 microsecondes
digitalWrite(trig, LOW); // met un niveau logique , LOW (BAS) sur la broche trig.
lecture_echo = pulseIn(echo, HIGH); // lit la durée du niveau HAUT appliqué sur la broche echo
cm = lecture_echo / 58; // conversion de la distance en cm
Serial.print("Distance en cm : "); // affiche le message : "Distance en cm" sur le moniteur série
Serial.println(cm); // affiche la mesure en cm avec retour à la ligne
if (cm < 20) // si mesure < 10 => tourner sens aléatoire
{
if (millis()%2 == 1)
{
Droite();
delay (1000);
}
else
{
Gauche();
delay (1000);
}
}
} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
void Stop() {
if (servoA.attached()) servoA.detach(); // détache le servomoteur de la broche = arret propre servomoteur
if (servoB.attached()) servoB.detach(); // détache le servomoteur de la broche = arret propre servomoteur
}
void Avant() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS1); // crée impulsion - sens2
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS2); // crée impulsion - sens1
}
void Arriere() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS2); // crée impulsion - sens1
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS1); // crée impulsion - sens2
}
void Gauche() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS1); // crée impulsion - sens2
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS1); // crée impulsion - sens1
}
void Droite() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS2); // crée impulsion - sens1
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS2); // crée impulsion - sens2
}
Programme avec NeoPixel Ring
Voici le programme qu'il faut éditer dans l'IDE Arduino, puis compiler et charger dans la carte Arduino
/*
Ce programme de démonstration permet de faire fonctionner le robot équipé d'un Neopixel Ring d'une manière autonome
*/
#include <Servo.h> // librairie pour servomoteur
#include <Adafruit_NeoPixel.h> // librairie pour NeoPixel Ring
#define broche_servoA 3 // broche servo A
#define broche_servoB 5 // broche servo B
#define trig 2 // broche trig du capteur US HC-SR04
#define echo 4 // broche echo du capteur US HC-SR04
#define ring 6 // broche Data du NeoPixel Ring
const int MAX_SENS2=1000; // largeur impulsion pour position ANGLE_MIN degrés du servomoteur
const int ARRET=1490; // largeur impulsion pour position ANGLE_MEDIANE degrés du servomoteur
const int MAX_SENS1=2000; // largeur impulsion pour position ANGLE_MAX degrés du servomoteur
// classiquement : centrage sur 1500 - maxi sens 1 = 1000 et maxi sens 2 = 2000
// --- Déclaration des constantes des broches E/S numériques ---
long lecture_echo = 0; // variable sur 4 octets mesure de distance
long cm = 0; // variable sur 4 octets pour la conversion en cm
//--- Création objet servomoteur
Servo servoA; // crée un objet servo pour contrôler le servomoteur A
Servo servoB; // crée un objet servo pour contrôler le servomoteur B
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, ring, NEO_GRB + NEO_KHZ800); //
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme
void setup() { // debut de la fonction setup()
// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---
pinMode (broche_servoA,OUTPUT); // Broche broche_servo configurée en sortie
pinMode (broche_servoB,OUTPUT); // Broche broche_servo configurée en sortie
pinMode (trig,OUTPUT); // broche broche trig configurée en sortie
digitalWrite(trig, LOW); // met un niveau logique , LOW (BAS) sur la broche trig
pinMode(echo, INPUT); // la broche echo est initialisée en entree
Serial.begin(115200); // initialisation de la liaison série à 115200 bauds
strip.begin();
strip.show(); // Initialisation du NeoPixel Ring
rainbowCycle(10); // LED RING = Arc en ciel
}
// fin de la fonction setup()
// ********************************************************************************
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension
void loop(){ // debut de la fonction loop()
Avant();
digitalWrite(trig, HIGH); // met un niveau logique , HIGH (HAUT) sur la broche trig
delayMicroseconds(10); // attente pendant 10 microsecondes
digitalWrite(trig, LOW); // met un niveau logique , LOW (BAS) sur la broche trig.
lecture_echo = pulseIn(echo, HIGH); // lit la durée du niveau HAUT appliqué sur la broche echo
cm = lecture_echo / 58; // conversion de la distance en cm
Serial.print("Distance en cm : "); // affiche le message : "Distance en cm" sur le moniteur série
Serial.println(cm); // affiche la mesure en cm avec retour à la ligne
if (cm < 20) // si mesure < 20 cm => tourner sens aléatoire
{
if (millis()%2 == 1)
{
Droite(); // appel fonction Droite()
delay (1000);
}
else
{
Gauche(); // appel fonction Gauche()
delay (1000);
}
}
} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
void Stop() {
if (servoA.attached()) servoA.detach(); // détache le servomoteur de la broche = arret propre servomoteur
if (servoB.attached()) servoB.detach(); // détache le servomoteur de la broche = arret propre servomoteur
}
void Avant() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS2); // crée impulsion - sens2
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS1); // crée impulsion - sens1
ringOff(); // appel fonction extinction de toutes les LED
strip.setPixelColor(14, strip.Color(0,150,0)); // LED verte brillance moyenne.
strip.setPixelColor(15, strip.Color(0,150,0)); // LED verte brillance moyenne.
strip.setPixelColor(0, strip.Color(0,150,0)); // LED verte brillance moyenne.
strip.show(); // Envoi des données vers le Ring.
}
void Arriere() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS1); // crée impulsion - sens1
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS2); // crée impulsion - sens2
}
void Gauche() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS1); // crée impulsion - sens2
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS1); // crée impulsion - sens1
ringOff(); // appel fonction extinction de toutes les LED
for(int i=2;i<5;i++){
strip.setPixelColor(i, strip.Color(150,0,0)); // LED rouge brillance moyenne.
strip.show(); // Envoi des données vers le Ring.
}
}
void Droite() {
if (!servoA.attached()) servoA.attach(broche_servoA); // attache le servomoteur à la broche si pas attaché
servoA.writeMicroseconds(MAX_SENS2); // crée impulsion - sens1
if (!servoB.attached()) servoB.attach(broche_servoB); // attache le servomoteur à la broche si pas attaché
servoB.writeMicroseconds(MAX_SENS2); // crée impulsion - sens2
ringOff(); // appel fonction extinction de toutes les LED
for(int i=10;i<13;i++){
strip.setPixelColor(i, strip.Color(150,0,0)); // LED rouge brillance moyenne.
strip.show(); // Envoi des données vers le Ring.
}
}
void ringOff()
{
for(int i=0;i<16;i++){
strip.setPixelColor(i, strip.Color(0,0,0)); // Toutes les LED éteintes
strip.show(); // Envoi des données vers le Ring.
}
}
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) { // 1 cycle couleur arc en ciel j<256*n = n cycles couleur arc en ciel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
Programmation du robot en langage graphique (blokly)
Pour programmer le robot en langage graphique, il faut :
- se connecter sur la page :
- composer le programme en assemblant les blocs,
- copier le code produit dans l'IDE arduino
- télécharger le code dans la carte de prototypage arduino
Téléchargements
Documents de présentation
Pièces imprimables
Les pièces imprimables : base, roue, support capteur Ultra-sons et plaque pour support de piles sont téléchargeable sur Thingiverse:
http://www.thingiverse.com/thing:833005