Le WellBot est un petit robot développé par la société Didel dans le but d'apprendre aux jeunes à faire un peu d'électronique et de micro-informatique.

Avertissement :
Avertissement :
cet article est en plein chantier pour l'instant, il vaut mieux aller sur l’article Bico64 qui est plus élaboré


Le kit peut être réalisé sans aucune notion de programmation, juste pour le plaisir de se "souder les doigts" et avoir un petit robot rigolo qu'on a eu le plaisir de faire soi-même. C'est déjà beaucoup, et certainement suffisant pour la plupart, mais en même temps on peut faire plus que cela : faire des premier pas en informatique embarquée et comprendre comment fonctionne un système informatique rudimentaire.

Il est vrai que l’on peut apprendre à programmer sur un ordinateur, c’est joli tout de suite, mais en même temps, les PC d'aujourd'hui sont des machines complexes, avec des OS complexes, des environnement de développement complexes, si bien qu’à la fin, tout est assez abstrait sur comment cela fonctionne.

Avec des kits comme le WellBot, on retourne aux débuts de l'informatique : un hardware minimaliste (même hyper simple puisque le WellBot utilise un PIC de la société Microchip[1].

Le but de ce cours est d'aller au delà de la documentation de Didel, pour essayer d'expliquer plus en détail le fonctionnement de ce Kit et de ce que l’on peut en faire. Comme toujours, faire un bon cours est long et n'est jamais achevé... d'où l’idée de le faire sur Wikiversité et que d'autres puissent corriger les erreurs et poursuivre l'effort.



Hardware

modifier

Le processeur

modifier

Le processeur est un PIC16f882, dont on trouve le databook ici [2]

Le Schéma du robot

modifier

Le schéma donné par Didel est le suivant:

 

On voit sur ce schéma que le cœur du système est un PIC 16F882. C'est à lui seul un petit ordinateur. On retrouve dans un PIC tous les concepts de base d'un ordinateur, mais en très simple.

Les moteurs pas à pas

modifier

On voit que le PORTB est utilisé pour piloter deux moteurs pas à pas. On se reportera à la description de Didel sur les moteurs pas à pas.

Les détecteurs de proximités

modifier
 
Le robot WellBot avec ses capteurs de distances IT

Le Robot peut avoir deux capteurs de distance IR.

Attention : pour une raison étrange, le pinning des capteurs ne correspond pas sur mon robot à celui des capteurs ; on voit sur la photo que j’ai dû croiser les pattes des capteurs (en mettant de la gaine thermo pour qu’elles ne se touchent pas). Le pinning des détecteurs est plus visible sur ce document.

 
Les connecteurs des sensors IR

On voit sur cette photo les deux connecteurs pour les détecteurs de distance. On voit aussi quelle I/O (RA0 et RA1) est responsable de quel détecteur. Le système adopté ici est d’utiliser la pin en sortie pour charger le condensateur, puis de la commuter en entrée et de regarder à quelle vitesse le condo se décharge via le photorécepteur IR. Plus il y a de lumière, plus la décharge est rapide et donc plus on est près d'un obstacle. La méthode complète pour lire les capteur est décrite ici.

Dans le code ci-dessous, on voit une implémentation simple de la lecture des capteurs. Cette routine doit être appelée régulièrement. La dernière distance lue se trouve dans DistGauche et DistDroite respectivement. On voit que cette implémentation n'est que partielle : elle ne tient pas compte de la lumière ambiante, ni du fait que la décharge du condensateur n’est pas linéaire avec la distance. Mais cela donne déjà des résultats corrects

 //---------------------------------------------------------------------
 // Capteurs de distance IR
 //---------------------------------------------------------------------
 
 byte EtatIRGauche=255, DistGauche=255;
 byte EtatIRDroite=255, DistDroite=255;
 void GererCapteursIR(void) {
   HP_nSENSOR = 1;  // allume les leds IR
 
   EtatIRDroite++;
   if (EtatIRDroite==0) {
     SENSOR_D_IN = 0;  //on recharge le condensateur en utilisant l'entrée comme sortie
     SENSOR_D = 1;     // qu'on met à 1
   }
   else {
     SENSOR_D_IN = 1;
     if ((SENSOR_D==0) || (EtatIRDroite ==255)) {
        // si la sortie est passée à 0, le capteur a laissé passer assez de courant pour décharger le condo
        // le temps pris est une estimation de la distance
        // si on a mis 255 états, on met aussi la distance à 255, cela ne sert plus à rien d'attendre (trop loin)
       DistDroite = EtatIRDroite;
       EtatIRDroite=255; // on recommence le cycle
       LED_SW = !LED_SW;
     }
   }
   
   EtatIRGauche++;
   if (EtatIRGauche==0) {
     SENSOR_G_IN = 0;  //on recharge le condensateur en utilisant l'entrée comme sortie
     SENSOR_G = 1;     // qu'on met à 1
   }
   else {
     SENSOR_G_IN = 1;
     if ((SENSOR_G==0) || (EtatIRGauche ==255)) {
        // si la sortie est passée à 0, le capteur a laissé passer assez de courant pour décharger le condo
        // le temps pris est une estimation de la distance
        // si on a mis 255 états, on met aussi la distance à 255, cela ne sert plus a rien d'attendre (trop loin)
       DistGauche = EtatIRGauche;
       EtatIRGauche=255; // on recommence le cycle
     }
   }
 }

Cycle de développement

modifier

On se reportera à Bico64#Comprendre le cycle de développement pour une description du cycle de développement et des outils à installer

Exemples de programmes

modifier

Evite Les Bords

modifier

Ce programme est assez simple et minimaliste: il essaie d’éviter les bords d'un labyrinthe.

Il ne met en œuvre que les moteurs, les capteurs de distance et la Led.

La Led représente l'état du capteur de distance Gauche; elle clignote d'autant plus vite qu'on est près du mur.

  //------------------------------------------------------------------------------------------
  // Programme de démonstration WellBot qui évite les bords
  //------------------------------------------------------------------------------------------

  #define __16F882
  #include <pic16f887.h>
  
  //------------------------------------------------------------------------------------------
  // Configuration du PIC 16F882 selon WellBot
  //------------------------------------------------------------------------------------------
  __code __at _CONFIG1 unsigned int Config1 = 
     _INTOSCIO  // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
   & _WDT_OFF   // pas de Watch Dog
   & _PWRTE_ON  // on attend un peu au démarrage
   & _MCLRE_OFF // RE3/MCLR pin function is digital input, MCLR internally tied to VDD
   & _CP_OFF    // Program memory code protection is disabled
   & _CPD_OFF   // Data memory code protection is disabled
   & _BOR_OFF   // BOR Disabled
   & _IESO_OFF  // Internal/External Switchover mode is disabled
   & _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
   & _LVP_OFF   // RB3 pin is digital I/O, HV on MCLR must be used for programming
   & _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
  
  __code __at _CONFIG2 unsigned int Config2 =
     _WRT_OFF // No prog memmory write protection
   & _BOR21V;  // Brown-Out Reset at 2.1V
  
  #define byte unsigned char
  
  #define SENSOR_D           RA0
  #define SENSOR_G           RA1
  #define BICO_DATATOBICO    RA2
  #define MICRO              RA3
  #define BICO_DATAFROMBICO  RA4
  #define BICO_CLK           RA5
  #define SENSOR_D_IN        TRISA0
  #define SENSOR_G_IN        TRISA1
  #define SWITCH_IN          TRISC0
  #define LED_SW             RC0
  #define HP_LEDIR           RC1        // à 1, allume les LEDs IR des Sensors. des transitions entre 0 et 1 font du son
                                        // sur le HP   ==> faire un son perturbe la lecture de distance
  #define IR                 RC2        // pour reception IR



  // la position d'un moteur est gérée de manière un peu particulière:
  // un int contient à la fois le n° de pas du moteur (de 0à5) et
  // un byte contient le micro pas (une fraction de pas)
  // l’idée est que pour faire tourner lentement le moteur,
  // on incrémente (ou décrémente) la position d'une valeur de -256 à + 256
  // Si on incrémente de 256, cela revient à incrémenter d'un pas complet, sinon, de n/256 de pas
  // On pourra donc faire cela de manière régulière (p.ex tous les 300us)
  typedef union {
    struct {
      byte  MicroPas;
      char  Pas;      //on aura le n° du pas (0..5)
    };
    struct {
      int Pos;
    };
  } TPosMoteur;
  
  TPosMoteur PosGauche,PosDroite;


  void Setup(void) {
    ANSEL = 0b00000000;      // aucune pin en analogique
    TRISA = 0b11011011;
    TRISB = 0b00000000;
    TRISC = 0b10111100;      // RC0 peut être programmé comme entrée (lire le switch) ou comme sortie (LED)
    
    PosGauche.Pos = 0;
    PosDroite.Pos = 0;
  }

  byte BitsPas[6] = { // ° sur dessin de Step.pdf
    0b00001100,   //   0
    0b00000100,   //  60
    0b00000111,   // 120
    0b00000011,   // 180
    0b00001011,   // 240
    0b00001000,   // 300
  };

  void GererMoteur(int VitesseGauche, int VitesseDroite){
    // la procedure gérer moteur doit être appelée régulièrement (max toutes les 300us)
    // les vitesses doivent être comprises entre 256 et -256 (256 = 100% vitesse max)
    PosGauche.Pos -= VitesseGauche;    // symétrique par construction ==> faire tourner à l’envers
    if (PosGauche.Pas >= 6) {
      PosGauche.Pas = 0;
    } else if (PosGauche.Pas < 0) {
      PosGauche.Pas = 5;
    }
    PosDroite.Pos += VitesseDroite;
    if (PosDroite.Pas >= 6) {
      PosDroite.Pas = 0;
    } else if (PosDroite.Pas < 0) {
      PosDroite.Pas = 5;
    }
    PORTB = (BitsPas[PosDroite.Pas]<<4 | BitsPas[PosGauche.Pas]);
  }

  //---------------------------------------------------------------------
  // Capteurs de distance IR
  //---------------------------------------------------------------------

  byte EtatIRGauche=255, DistGauche=255;
  byte EtatIRDroite=255, DistDroite=255;

  void GererCapteursIR(void) {
    HP_LEDIR = 1;  // allume les leds IR
    EtatIRDroite++;
    if (EtatIRDroite==0) {
      SENSOR_D_IN = 0;  //on recharge le condensateur en utilisant l'entrée comme sortie
      SENSOR_D = 1;     // qu'on met à 1
    }
    else {
      SENSOR_D_IN = 1;
      if ((SENSOR_D==0) || (EtatIRDroite ==255)) {
         // si la sortie à passé à 0, le capteur a laisser passé assez de courant pour décharger le condo
         // le temps pris est une estimation de la distance
         // si on a mis 255 états, on met aussi la distance à 255, cela se sert plus a rien d'attendre (trop loin)
        DistDroite = EtatIRDroite;
        EtatIRDroite=255; // on recommance le cycle
      }
    }
    
    EtatIRGauche++;
    if (EtatIRGauche==0) {
      SENSOR_G_IN = 0;  //on recharge le condensateur en utilisant l'entrée comme sortie
      SENSOR_G = 1;     // qu'on met à 1
    }
    else {
      SENSOR_G_IN = 1;
      if ((SENSOR_G==0) || (EtatIRGauche ==255)) {
         // si la sortie à passé à 0, le capteur a laisser passé assez de courant pour décharger le condo
         // le temps pris est une estimation de la distance
         // si on a mis 255 états, on met aussi la distance à 255, cela se sert plus a rien d'attendre (trop loin)
        DistGauche = EtatIRGauche;
        EtatIRGauche=255; // on recommance le cycle
        LED_SW = !LED_SW;
      }
    }
  }

  int max=50;
  int VG=256;
  int VD=256;
  void Loop(void) {
    int i,n;
    
    GererCapteursIR();
    if ((DistDroite <= 50) && (DistGauche <= 50)) {
      //on est proche d'un mur à gauche et à droite donc coincé
      //le mieux est de tourner sur place pour débloquer la situation
      GererMoteur(100,-100);
    }
    else {
      // On avance avec la roue droite proportionnellement à la distance vue avec l'œil Gauche et inversement
      // plus on a de place a gauche, plus la route droite va vite (donc on tourne à gauche)
      // évidemment si on est loin tant à gauche qu’à droite, on va à vitesse max des deux côtés, donc tout droit
      GererMoteur(DistDroite,DistGauche);
    }
    for (i=0;i<=max;i++) {}
  }

  void main(void) {
    Setup();
    while (1) {
      Loop();
    }
  }

Autres Liens

modifier

Voici les liens vers les documents originaux de Didel, qui ne sont pas toujours très facile à trouver.

  • Architecture des PICS [3]
  • Tout sur les PIC donne accès à plein de liens où l’on trouve de l'information
  • Apprendre à programmer avec le 16F877A [4] C'est un document pas à pas, expliquant le PIC, les instructions en CALM, mais pas fait explicitement pour le WellBot, mais plutôt pour d’autre kits.
  • CALM pour PIC [5]
  • Utiliser les PIC 16F et 18F