SQYbot - le projet

SQYbot est un projet global de DIY destiné au monde de l’éducation.
C’est une plateforme de développement et d’apprentissage de la programmation.
Dans l’esprit, il s’adresse à une école primaire de la maternelle à l’entrée au collège.

SQYbot nécessitera l’utilisation d’un grand nombre des compétences et ressources d’un FabLab, (découpe laser, impression de pièces spécifiques, Arduino, Scratch, Python, fiches pédagogiques…).

A quoi ressemblera SQYbot, mystère. Il pourra être « habillé » et décoré par les élèves de maternelles qui en seront les utilisateurs finaux. Des gabarits à découper seront proposés.

Que pourra faire SQYbot ?

Ce sera un robot « tortue ». Kezaco, j’en vois au fond la salle qui ouvre de grands yeux…

Once upon a time, Logo

Le langage Logo appelé aussi et à tort langage tortue est à la fois une philosophie de l’éducation et une famille de langages de programmation en constante évolution qui aident à la mettre en pratique.

Le projet est né à la fin des années soixante de la rencontre entre le courant cognitiviste en intelligence artificielle et des théories sur l’apprentissage issues de travaux de Jean Piaget et de ses conceptions en matière d’éducation. Ces deux volets sont respectivement représentés par ses promoteurs, Marvin Minsky et Seymour Papert — qui sera le moteur du projet —, au sein du Computer Science and Artificial Intelligence Laboratory (Laboratoire d'intelligence artificielle et d'informatique) du MIT (Massachussetts Institute of Technology).

Je ne vais pas vous recopier toute la fiche Wikipedia https://fr.wikipedia.org/wiki/Logo_(langage)

Tiens, tiens, le MIT, mais ne serait-ce pas là qu’a été conçu le génial langage Scratch. Décidément, ils ont de la suite dans les idées.

Pour ceux qui souhaitent aller plus loin sur ce sujet, je vous conseille la lecture du livre de Seymour Papert , « Mindstorms: Children, Computers, and Powerful Ideas », 1980 (ISBN 0-465-04674-6) Traduction française : “Jaillissement de l'esprit. Ordinateurs et apprentissage”, Flammarion, 1981.

Même si le titre fout un peu les jetons, c’est passionnant et pas chiant du tout.

Revenons à nos moutons, ou plutôt à notre tortue.

Il existe aujourd’hui de nombreux robots tortues pour l’apprentissage de la programmation. Il semble que les plus connus et les plus sympa (à mon avis) sont ceux fabriqués par :

http://www.tts-group.co.uk/primary/computing-ict/programming/

beebot.jpg

Les Bee-Bot et Blue-Bot sont utilisés sur différents tapis d’activité pédagogique. Ceux-ci peuvent aussi être dessinés par les élèves. La contrainte est de garder des carrés de 15 cm.

          Source: www.easytis.com/fr

Vous trouverez un grand nombre de ressources pédagogiques pour les Bee-Bot et Blue-Bot sur le site : http://www.edurobot.ch/?tag=beebot

Est-ce un hasard si nos amis suisses s’intéressent tant aux robots tortues ?

Un produit open dans toutes ses composantes, mécaniques, électroniques et logicielles.

En résumé, les plus grands se chargeront de la programmation de l’électronique, de la conception de l’IHM, de la fabrication des pièces mécaniques et les plus petits utiliseront les SQYbot comme des produits finis (type Bee-Bot) mais qu’ils pourront « customiser ».

Rêvons un peu.

Demain, par l’intermédiaire de SQYbot connectés qu’ils auront fabriqué au sein de leurs écoles, des élèves du monde entier manipulerons, programmerons et s’échangeront en temps réels des dessins et les améliorations de leurs SQYbot.

Reconnaissez qu’un SQYbot qui se déplace sur un tapis de jeu d’une école suédoise programmé en direct par un petit africain, ça en jette, non !

Mécanique et structure

Y a-t-il un designer industriel dans la salle ? Jamal rappelle-moi ton job.

Pour les plus grands, la plateforme devra permettre l’usage de différents capteurs. Une ou plusieurs connexions mécaniques au format Lego permettraient l’ajout de ces capteurs sans nécessité de vis ni d’écrou.

Electronique

Arduino (modèle à définir)
Une connexion Bluetooth (HC05)
Une connexion WiFi ?
Un adaptateur MicroSD
Shield Arduino Ethernet
Deux leds tricolors pour les yeux
Un afficheur 16×2 ou 20×4

Alimentation

Bloc de 6 piles LR6 rechargeables

Déplacements

Hypothèse 1 :
2 servomoteurs à rotation continue à l’arrière
1 roue libre à l’avant

Hypothèse 2 :
2 servomoteurs à rotation continue à l’arrière
1 servomoteur 90° activant un train avant de deux roues.

1 servomoteur 90° pour la montée et descente du crayon.

IHM

Contrairement aux robots montrés ci-dessus. La programmation des SQYbot ne se fera qu’a distance. Ordinateurs, tablettes, smartphones en utilisant une liaison internet, Bluetooth ou WiFi.

Logiciel

Scratch 2.0 et Arduino

La programmation en Arduino est un peu absconse pour des enfants de moins de 11 ans. L’idéal serait de tout pouvoir programmer en Scratch. Malheureusement et pour l’instant cela ne me paraît pas possible. Contrairement à Scratch Junior, Scratch 2.0 ne fonctionne pas sur les tablettes.

N’ayant aucune expérience en enseignement, je laisse le soin aux hommes et femmes de l’art de relever et de corriger les incongruités du tableau ci-dessous.

Année 1Année 2Année 3

Les petits de maternelle
(3 à 4 ans)

Ils colorient les gabarits de customization
des SQYbot.

Idem année 1
Apprentissage à la programmation
avec les SQYbot.
Version light :
Angle 90°

Idem année 2
Les grands de maternelle
(5 à 6 ans)
Ils s’initient à Scratch Junior et préparent
les gabarits pour les plus petits.
Idem année 1.
Apprentissage à la programmation avec les SQYbot.
Version medium :
Angle 45°
Idem année 2
CPIls s’initient à Scratch Junior. En milieu d’année,
dès les premiers rudiments de lecture acquis,
l’initiation à Scratch peut commencer.
Idem année 1.
Apprentissage à la programmation avec les SQYbot.
Version CP :
Angle 45°
Fonction repeat
Usage du crayon
Idem année 2
Les moyens
CE1 & CE2

Ils s’initient à Scratch. Ils fabriquent les pièces mécaniques
à partir d’une imprimante 3D et font découper les pièces
de structure dans le FabLab le plus proche à partir des
fichiers conçus par le SQYLab.

Idem année 1.
Apprentissage à la programmation avec les SQYbot.
Version CE :
Angle libre
Fonction repeat
If, else
Usage du crayon
Idem année 2
Les grands
CM1 & CM2
Ils s’initient à Scratch et à Arduino.
Avec les pièces fabriqués par les moyens, ils assemblent
les SQYbot et les programment à l’aide des sources
fournit par le SQYlab.
Idem année 1.
Apprentissage à la programmation avec les SQYbot.
Version CM :
Angle libre
Fonction repeat
If, else
Usage du crayon
Gestion d’évènements par l’introduction de
nouveaux capteurs.
Idem année 2
A la fin de l’année, un ou plusieurs SQYbot sont opérationnels. A la fin de l’année, encore plus de SQYbot sont opérationnels.

Si ce projet ambitieux et de long terme vous intéresse, inscrivez-vous à la liste de diffusionhttp://lists.hatlab.fr/mailman/listinfo/sqybot

______________________________________

SQYbot - les réalisations

Cette première version était équipé de deux servo moteurs à rotation continu.

Un autre petit moteur permettait de faire monter et descendre un crayon.

sqybot-proto-lego9.jpgsqybot-proto-lego7.jpg

Pour l'instant les commandes sont envoyées en mode terminal,
mais l'objectif est de pouvoir programmer et contrôler le SQYbot
avec Scratch.
Le cercle est “presque” parfait.
sqybot-proto-lego5.jpgsqybot-proto-lego4.jpg
sqybot-proto-lego1.jpgsqybot-proto-lego3.jpg

La led rouge indique que la liaison Bluetooth de la carte HC05
est bien synchronisée avec le terminal Android.

L'ensemble est alimenté avec un bloc de 6 piles rechargeables LR6.
Après essais, le LCD ne sert à rien. On peut en faire l'économie
d'autant qu'il est très vorace en ressources (6 pins de l'Arduino).

Dans cette version et les suivantes, la possibilité d'insérer un crayon que l'on peut lever et descendre a été abandonné. Il y a déjà suffisamment de problèmes de déplacements pour ne pas compliquer les choses.

Le SQYbot doit pouvoir fonctionner comme la tortue de Logo. Pour cela, il est indispensable que ses déplacements soient très précis.

Par exemple:

Si j'envoie:
Répète 4 fois, Avance 100, TourneGauche 90°.

SQYbot doit revenir impeccablement à sa position d'origine.

Hors, avec les servo moteurs, je n'ai jamais réussi à obtenir ce résultat. Avec un carré, ça va à peu près mais dès que l'on dépasse une dizaine d'instructions, ça devient du grand n'importe quoi.

Donc, bye bye version 2 avec servo moteurs.

Là, c'est mieux. Même après l'exécution d'une trentaine de déplacements, le robot revient parfaitement (enfin presque) à sa position initiale. Cette version a été testé et présenté lors de l'inauguration du SQYLAB et de la fête de la ville de La Verrière. Beaucoup d'enfants ont pu jouer avec et tester leurs compétences.

Je rappelle que l'objectif n'est pas d'exécuter les instructions pas à pas mais de réfléchir à une suite d'instructions de déplacement pour résoudre un trajet.

La pièce devant la roue libre noire est un capteur de profondeur pour éviter que le robot ne tombe lorsqu'il est sur un table. Cette pièce n'est pas indispensable.

Avantages par rapport aux servo-moteur.

Une bonne précision des déplacements gérée par logiciel.

Inconvénients par rapport aux servo moteurs

Chaque moteur pas à pas utilise 4 pins de l'Arduino. Les servo moteur n'en utilisent qu'une.

Les déplacements du robot sont beaucoup plus lents.

Liste du matériel:

QuantitéDésignation
28byj-48_5v.jpg2
Stepper motor 28BYJ-48 5v DC avec carte SBT0811
entre 2 et 6 euros
hc05.jpg1Module Bluetooth HC05entre 3 et 10 euros
paire_de_roues.jpg1Paire de roues 60mmenviron 8 euros
roue_libre.jpg1Roue libreenviron 6 euros
boitier_piles.jpg1Boitier pilesenviron 6 euros
vis_a_bois.jpg4Petites vis à bois pour fixer les moteurs
sqybot.jpg1
Structure en contre-plaqué de peuplier 5mm
Fichier disponible sur le poste découpe laser
arduino.jpg1Arduino Unoentre 2 et 20 euros

IHM

Le code Arduino

//************************************************************
// SQYbot projet SQYLAB - F. LALANNE 28-05-2016
//************************************************************
//**************************************************************
// 2 Moteurs pas à pas 28BYJ-48 5V DC avec carte SBT0811
// 1 carte Bluetooth HC05
//
// Commande de moteur pas-à-pas unipolaire 4 fils
//  tiptopboards.com 05/12/2013
//  Driver ULN2003 et moteur réducté au 1:64
//
// Pour un moteur de ce type : http://tiptopboards.com/151-moteur-pas-%C3%A0-pas-r%C3%A9duct%C3%A9-de-5v-4-fils-driver-.html
// 64 pas par tour, 4 phases, angle de 5.625° selon les spécifications du moteur
// Démultiplication 1:64 pour ce moteur réducté mécaniquement
//   360° / 5.625° * 64 = 4096 angles avec la démultiplication
//   360° / 5.625° * 64  * 4 bobines / 2 bipolaire = 2048 step / tour
//************************************************************

#include <avr/wdt.h>                                        // librairie utilisée pour le reboot
#include <SoftwareSerial.h>                                 // librairie utilisée pour le Bluetooth
#include <Stepper.h>                                        // librairie utilisée pour les stepper
#define STEPS 100
SoftwareSerial serieHC05(2, 3);                              // broches pour le port Série Bluetooth HC05
const int Sensor1 = 0;
int mesureSensor1 = 0;
int buzzer = 12;
int octetReception = 0;                                     // variable de réception octet
char caractereReception = 0;                                // variable de réception caractère
String chaineReception = "";
String chaineUtilePart1 = "";
String chaineUtilePart2 = "";

String myTab[20];                                           // table des instructions entrées par l'utilisateur
int j = 0;
int i = 0;
int z = 0;

                                                            // Le moteur droit (fils 1 2 3 4) est branché sur les sorties 8 9 10 11 de l'Arduino (et sur GND, +V)
                                                            // Le moteur gauche (fils 1 2 3 4) est branché sur les sorties 4 5 6 7 de l'Arduino (et sur GND, +V)
                                                            // Stepper mpapR(STEPS, 11, 10, 9, 8);  // Sens anti-horaire en inversant 8 et 11 (si on préfère)
Stepper mpapR(STEPS, 8, 10, 9, 11);                         // Créer une instance de la classe stepper pour le moteur droit
Stepper mpapL(STEPS, 7, 5, 6, 4);                           // Créer une instance de la classe stepper pour le moteur gauche

int StepsH = 1;                                             // Nombre de pas de rotation demandé au moteur en sens horaire
int StepsAH = -1;                                           // Nombre de pas de rotation demandé au moteur en sens anti horaire
int nbStepsH = 2048;
int nbStepsAH = 2048;
long temps =0;                                              //Durée de rotation pour un tour

void setup() {
  serieHC05.begin(9600);                                   // initialise la vitesse de la connexion série
  Serial.begin(9600);     // 9600 bps
  Serial.println("Test de moteur pas a pas");
  pinMode(buzzer, OUTPUT);
}

void loop() {

  while (serieHC05.available()> 0) {                         // si un caractère en réception
    octetReception = serieHC05.read();                        // lit le 1er octet de la file d'attente
    if (octetReception == 10) {                               // si Octet reçu est le saut de ligne
      serieHC05.print ("Chaine recu : ");
      serieHC05.println (chaineReception);
       if ((chaineReception) == "ce") {
               myTab[j-1] = ("");
               j=j-1;
       }
       else{
            if ((chaineReception) == "ca") {
              for (i = 0; i <20; i++) {
                myTab[i] = ("");
              }
              serieHC05.print ("myTab : ");
              serieHC05.print (i);
              serieHC05.print (" ");
              serieHC05.println (myTab[i]);
              j = 0;
            }
            else {
              if ((chaineReception) == "go1") {
              test1();                                        // fonction pour programme auto
            }
            else {

              if ((chaineReception) == "go") {
                serieHC05.print ("chaineReception : ");
                serieHC05.println ("go");
                myTab[j] = ("stop");
                for (i = 0; i <20; i++) {
                  serieHC05.print ("myTab : ");
                  serieHC05.print (i);
                  serieHC05.print (" ");
                  serieHC05.println (myTab[i]);
                }
                 for (i = 0; i <20; i++) {
                   if (myTab[i]=="a") enAvant();
                   if (myTab[i]=="b") enArriere();
                   if (myTab[i]=="tg") tourneGauche();
                   if (myTab[i]=="td") tourneDroite();
//                   if (myTab[i]=="stop") servosStop();
//                   if (myTab[i]=="") leds();
                 }
              }
              else {
                myTab[j] = (chaineReception);
                serieHC05.print ("myTab : ");
                serieHC05.print (j);
                serieHC05.print (" ");
                serieHC05.println (myTab[j]);
                serieHC05.print ("j = ");
                serieHC05.println (j);
                j++;
                serieHC05.print ("j = ");
                serieHC05.println (j);
              }
             }
           }
          }
      chaineReception = "";                                   //RAZ le String de réception
      delay(100);                                             // pause
      break;                                                  // sort de la boucle while
    }
    else {                                                  // si le caractère reçu n'est pas un saut de ligne
      caractereReception = char(octetReception);            // récupere le caractere à partir du code Ascii
      chaineReception = chaineReception + caractereReception; // ajoute la caractère au String
      delay(1);                                             // laisse le temps au caractères d'arriver
    }
  }

}

void enAvant() {

  Serial.println("Moteurs gauche et droit en marche avant");
  mpapR.setSpeed(300);
  mpapL.setSpeed(300);
  StepsH  = 1;
  StepsAH = -1;
  nbStepsH = 1790;
  temps = millis();
//  sensor_test1();
     for (int i = 0; i <nbStepsH; i++) {
       sensor_test1();
        mpapR.step(StepsH);
        mpapL.step(StepsH);
    }
  temps =  millis()- temps ;  //Chronomètre un rour complet  6.236 sec par tour à vitesse 200
  Serial.println(temps);      //Affiche le temps (en ms) pour un tour complet
  delay(2000);  //pause
}

void enArriere() {
  Serial.println("Moteurs gauche et droit en marche arriere");
  mpapR.setSpeed(300);
  mpapL.setSpeed(300);
  StepsH  = 1;
  StepsAH = -1;
  nbStepsH = 1790;
  temps = millis();
       for (int i = 0; i <nbStepsAH; i++) {
          mpapR.step(StepsAH);  //Ca tourne
          mpapL.step(StepsAH);  //Ca tourne
      }
  temps =  millis()- temps ;  //Chronomètre un rour complet  6.236 sec par tour à vitesse 200
  Serial.println(temps);      //Affiche le temps (en ms) pour un tour complet
  delay(2000);  //pause
}
void tourneGauche() {
  Serial.println("Moteurs gauche et droit en marche avant");
  mpapR.setSpeed(300);
  mpapL.setSpeed(300);
  StepsH  = 1;
  StepsAH = -1;
  temps = millis();
  nbStepsH = 180;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsH);
        mpapL.step(StepsH);
     }
  nbStepsH = 1080;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsH);
        mpapL.step(StepsAH);
    }
  nbStepsH = 300;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsAH);
        mpapL.step(StepsAH);
    }
  temps =  millis()- temps ;  //Chronomètre un rour complet  6.236 sec par tour à vitesse 200
  Serial.println(temps);      //Affiche le temps (en ms) pour un tour complet
  delay(2000);  //pause
}
void tourneDroite() {
  Serial.println("Moteurs gauche et droit en marche avant");
  mpapR.setSpeed(300);
  mpapL.setSpeed(300);
  StepsH  = 1;
  StepsAH = -1;
  nbStepsH = 1150;
  temps = millis();
  nbStepsH = 180;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsH);
        mpapL.step(StepsH);
     }
  nbStepsH = 1080;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsAH);
        mpapL.step(StepsH);
    }
  nbStepsH = 300;
     for (int i = 0; i <nbStepsH; i++) {
        mpapR.step(StepsAH);
        mpapL.step(StepsAH);
    }
  temps =  millis()- temps ;  //Chronomètre un rour complet  6.236 sec par tour à vitesse 200
  Serial.println(temps);      //Affiche le temps (en ms) pour un tour complet
  delay(2000);  //pause
}
void test1() {
  enAvant();
  enAvant();
  tourneGauche();
  enAvant();
  tourneDroite();
  enAvant();
  enAvant();
  tourneDroite();
  enAvant();
  enAvant();
  tourneDroite();
  enAvant();
  enAvant();
  tourneDroite();
  enAvant();
  enAvant();
  enAvant();
  tourneGauche();
  enAvant();
  enAvant();
  tourneGauche();
  enAvant();
  enAvant();
  tourneGauche();

  software_Reboot();
}
void buzzer1(){
  for (int x = 0; x<5; x++) {
  for(i=0;i<80;i++){               // Output a frequency of sound
    digitalWrite(buzzer,HIGH);//sound
    delay(1);//delay 1ms
    digitalWrite(buzzer,LOW);//mute
    delay(1);//delay 1ms
  }
  for(i=0;i<100;i++){              // Output the other frequency of sound
    digitalWrite(buzzer,HIGH);//sound
    delay(2);//delay 2ms
    digitalWrite(buzzer,LOW);//mute
    delay(2);//delay 2ms
  }
  }
  enArriere();
  tourneGauche();
}
void sensor_test1(){
  mesureSensor1=analogRead(Sensor1);
  if (mesureSensor1>1000){
  buzzer1();
  }
}

void software_Reboot()
{
  wdt_enable(WDTO_15MS);

  while(1)
  {

  }
}

Le code APP Inventor 2

Il y a deux modes: Le mode Design (ci-dessus) qui permet de créer l'IHM…

etlemodeBlocksquipermetd'écrire le programme.

Ci-dessus, on voit la connection Bluetooth lors d'un clic sur le bouton SQYBOT (en haut à gauche de l'IHM) et la déconnexion lors du clic sur le bouton Hatlab (en haut à droite de l'IHM).

Ici, on voit que lorsque l'on clique sur les différents boutons de déplacement, on envoie “a” pour “avance”, “b” pour pour “arrière”, “td” pour “tourne à droite” et ainsi de suite. DanslecodeArduino, on retrouve lors de la réception “Si je reçoistdalorsvoidtournedroite”.

Problèmes rencontrés

La librairie Stepper.h ne permet de commander qu'un moteur à la fois. Ce qui fait que pour faire avancer ou reculer le robot par exemple de 100 pas, j'utilise une boucle:

répète 100 fois, avance 1 moteur gauche, avance 1 moteur droit.

Visuellement, ce n'est pas gênant mais cela divise au moins par deux la vistesse maximale du robot et du point de vue du code ce n'est pas très “élégant”.

Il existe d'autres solutions que la librairie Stepper.h mais je ne les ai pas testées.