Capteur infra-rouge : utilisation d’une table

Dans le programme précédent, on avait utilisé une fonction pour convertir la valeur mesurée en une distance en cm. Cette fonction, faut déjà la trouver et, en plus, elle ne fonctionne que dans une plage de distances assez serrée…

Voici une autre solution, qui fonctionne avec de nombreux capteurs, où l’on va créer une table de correspondance de façon expérimentale, en notant pour 3 cm la valeur mesurée entre 0 et 1023, on refait ensuite une mesure pour 4 cm on note la valeur, et ainsi de suite…

Une fois que la table est faite on l’inclut dans le programme et on s’en sert pour convertir les mesures entre 0 et 1023 en distances en cm.

Voici le programme correspondant dans lequel on a rempli la table après avoir effectué les mesures nécessaires. Bien sûr chaque type de capteur aura sa propre table, le tableau de ce programme est donc à faire si vous avez un autre modèle de capteur que celui utilisé (Sharp GP2D120XJ00F).

// Arduino IR8

// On va connecter un capteur IR en entrée sur l'Arduino

// Le capteur est un Sharp GP2D120XJ00F

// on va afficher sur l'écran du moniteur serie 
// les différentes valeurs lues en entrée suivant
// la distance entre le capteur et un objet placé en face
// il faut que la cable USB soit branché


// sur la broche A0  on connecte le signal (0 à 5v)
// une autre broche du potentiomètre est reliée au 5v
// la dernière broche est reliée à la masse (GND)

const int Pin_input=0; 


// on fait un certain nb de mesures dont on fera la moyenne
// car le signal fluctue, meme pour une distance fixe

const int nb_mesures=5;

int mesure;

// On a établi expérimentalement un tableau de correspondance
// entre mesure (entre 0 et 1023) et distance (entre 20 et 3 cm)
// on vise une précision au centimètre

// nombre maxi d'éléments du tableau 

#define NBEL 18

/*
mesure  distance indice tableau
81	20       0
90	19       1
105	18       2
118	17       3
130	16       4
144	15       5
156	14       6
172	13       7
188	12       8
205	11       9
232	10      10
257	9       11
294	8       12
339	7       13
394	6       14
459	5       15
544	4       16
635	3       17

*/

// Attention, pour ce capteur, en dessous de 3 cm
// les valeurs mesurées chutent

int tab [NBEL]= {81,90,105,118,130,144,156,172,188,205,232,257,294,339,394,459,544,635} ;


void setup()   { 

// initialise connexion série à 115200 bauds

Serial.begin(115200); 

} // setup


void loop(){ 

// La tension produite par le capteur
// est traduite en une mesure entre 0 et 1023

mesure=mesurer(Pin_input);

// on affiche cette valeur sur le moniteur série
// (écran du PC)

Serial.println(mesure); 


// On vérifie que la valeur mesurée est dans 
// un intervalle qui est celui des limites 
// du tableau légèrement assouplies

if ( (mesure > 650) || (mesure < 75)){
  
    Serial.println ("Valeur mesurée hors bornes");
    
} else {    

Serial.print("distance en cm : "); 

Serial.println(convertir(mesure) );

} // else hors bornes

} // loop


// Fonction mesurer //////////////

int mesurer(int pin) { 
  
// Variable qui va contenir une valeur entre 0 et 1023
// suivant la distance capteur - objet

int mesure=0;

// accumulateur pour calculer la moyenne des mesures
// on fait la moyenne car les valeurs fluctuent un peu
// meme pour une distance fixe

long acc=0;

// indice de boucle

int i=0;
   
// Sur l'entree analogique, la mesure de la tension
// délivrée par le capteur est convertie en un nombre
// compris entre 0 et 1023 

for (i=0; i < nb_mesures ; i++) {
  
  acc=acc + analogRead(pin); 
  
   // On attend un peu avant la prochaine mesure
   // il faut au moins 38ms entre deux mesures
   // sur ce capteur

   delay(40); 
}

// on fait la moyenne des mesures

mesure=acc/nb_mesures;

return(mesure);

} // mesurer


// Fonction convertir  //////////////

int convertir(int mesure) { 
  
  // fonction de conversion mesure -> distance
  // Si on ne trouve pas la valeur exacte ce n'est pas
  // grave on prendra la valeur du tableau la plus
  // proche
  
  // on initialise l'indice qui limite à droite 
  // le tableau de recherche   // et l'indice qui limite 
  // à gauche le tableau de recherche
  // ce type de recherche est très performant
  
// nb éléments du tableau  

int N=NBEL;

// indices borne de gauche, borne de droite, milieu tableau

int g,d,m; 

int i=0;

g=0;

d=N-1;

while ( g<=d) {
       m = (g+d) / 2;
       if ( tab[m] < mesure)
           g = m + 1;
       else
           d = m - 1;
}

// de quelle borne est-on le plus proche ?

if ( abs(mesure - tab[g]) <   abs(mesure - tab[d]) ) {
  i = g ;
} else {
  i = d;
}

// l'indice 0 du tableau correspond à 20 cm
// l'indice 1 du tableau correspond à 19 cm ...

return(20-i);

} // convertir

arduino lookup table

Capteur infrarouge (banc de mesure)

Pour apprivoiser un nouveau type de capteur, voici un banc de mesure rudimentaire.

A la place du potentiomètre des montages précédents, j’ai monté un capteur infra-rouge Sharp GP2D120XJ00F. (On peut utiliser sur un Dfrduino le cable analogique qui reliait le potentiomètre dans les montages précédents).

En étudiant la fiche technique, on peut trouver une relation entre la valeur entre 0 et 1023 donnée par AnalogRead et la distance à laquelle un objet se trouve du capteur.

Fichier hébergé par Archive-Host.com

Voici le programme pour le Sharp GP2D120XJ00F ; il en existe toute une gamme, le programme n’est étalonné que pour ce modèle, il faudra donc le modifier si on a un autre type de capteur infra-rouge.


// Arduino IR5

// On va connecter un capteur IR en entrée sur l'Arduino

// on va afficher sur l'écran du moniteur serie 
// les différentes valeurs lues en entrée suivant
// la distance entre le capteur et un objet placé en face
// il faut que la cable USB soit branché


// sur la broche A0  on connecte le signal (0 à 5v)
// une autre broche du potentiomètre est reliée au 5v
// la dernière broche est reliée à la masse (GND)

const int Pin_input=0; 

// Variable qui va contenir une valeur entre 0 et 1023
// suivant la distance capteur - objet

int mesure=0;

// accumulateur pour calculer la moyenne des mesures

long acc=0;

// mesure distance

float distance=0;

// indice de boucle

int i=0;

// on fait un certain nb de mesures dont on fera la moyenne

int nb_mesures=4;


void setup()   { 

// initialise connexion série à 115200 bauds

Serial.begin(115200); 

} 


void loop(){ 

// Sur l'entree analogique la mesure de la tension
// est convertie en un nombre compris entre 0 et 1023 


acc=0;

for (i=0; i < nb_mesures ; i++) {
  
  acc=acc + analogRead(Pin_input); 
  
   // On attend un peu avant la prochaine mesure
   // il faut au moins 38ms entre deux mesures
   // sur ce capteur

   delay(40); 
}

// on fait la moyenne des mesures

mesure=acc/nb_mesures;

// on affiche cette valeur sur le moniteur série
// (écran du PC)

Serial.println(mesure); 

// En étudiant la Datasheet du Sharp GP2D120XJ00F
// on peut calculer la distance en fonction
// de la valeur mesurée


// Entre 3 et 10 cm la relation ci-dessous
// donne de bons résultats

// distance en cm

distance=2500/mesure;

Serial.print("distance en cm : "); 

Serial.println(int(distance));
} 

Oscilloscope avec un Arduino (partie 2)

Pour attaquer cette partie, il y a d’abord deux petites modifs à faire dans le programme publié dans la partie 1 :

– augmenter la vitesse de transmission (19200 -> 115200)
– réduire le délai entre deux mesures (100 -> 10 ms)

Voilà le programme modifié :


// Oscillo_potar_arduino V2

// On va connecter un potentiomètre en entrée sur l'Arduino

// on va afficher sur l'écran du moniteur serie 
// les différentes valeurs lues en entrée suivant
// la position du potentiomètre
// il faut que la cable USB soit branché


// sur la broche A0  on connecte le signal (0 à 5v)
// une autre broche du potentiomètre est reliée au 5v
// la dernière broche est reliée à la masse (GND)

const int Pin_input=0; 

// Variable qui va contenir une valeur entre 0 et 1024
// suivant la position du potentiomètre

int mesure=0;


void setup()   { 

// initialise connexion série à 115200 bauds

Serial.begin(115200); 

} 

void loop(){ 

// Sur l'entree analogique la mesure de la tension
// est convertie en un nombre compris entre 0 et 1024 

mesure=analogRead(Pin_input); 

// affiche de cette valeur sur le moniteur série
// (écran du PC)

Serial.println(mesure); 

// On attend un peu avant la prochaine mesure

delay(1<strong>0); 

} 

Dans la partie précédente, on avait affiché dans le moniteur série, sur l’écran du PC une suite de nombres entre 0 et 1023 décrivant la position du potentiomètre. Cette suite de nombres, on va maintenant la présenter autrement, de façon graphique.

[Edit le programme n’est plus dispo, il faut trouver une alternative]
Pour cela, il faut aller sur le site « mon-club-elec », où on trouve un superbe outil écrit par Xavier HINAULT.

Il suffit de le télécharger ; on trouve une version pour Linux et une pour Windows. Ici c’est une version pour Linux mais je pense que le résultat est le même sous Windows. Voilà ce que ça donne quand on fait bouger le potentiomètre :

Fichier hébergé par Archive-Host.com

On va bientôt se servir de cet outil pour visualiser l’allure du signal délivré par des capteurs plus élaborés que ce simple potentiomètre. A suivre …

Oscilloscope avec un Arduino (partie 1)

Une petite série d’articles pour arriver à utiliser un Arduino comme un oscilloscope et donc visualiser sur un écran l’allure d’un signal connecté à une broche de l’Arduino en entrée.

Nous allons commencer très simple avec un potentiomètre en entrée connecté à l’entrée analogique A0 et au lieu de visualiser une belle courbe sur un écran graphique nous allons commencer par visualiser sur le moniteur série une série de chiffres. Le potentiomètre vient de DFRobot (trouvé chez Zartronic), il est livré avec son cordon prêt à connecter sur un Dfrduino. On peut le connecter simplement sur un Arduino en utilisant quelques fils (jumper wires) utilisés sur les breadboards.

En fait ce potentiomètre est un modèle très simple de capteur ; nous verrons qu’il en existe de toutes sortes connectables à un Arduino.

Fichier hébergé par Archive-Host.com

Le programme, le voici :


/ Oscillo_potar_arduino

// On va connecter un potentiomètre en entrée sur l'Arduino

// on va afficher sur l'écran du moniteur serie 
// les différentes valeurs lues en entrée suivant
// la position du potentiomètre
// il faut que la cable USB soit branché


// sur la broche A0  on connecte le signal (0 à 5v)
// une autre broche du potentiomètre est reliée au 5v
// la dernière broche est reliée à la masse (GND)

const int Pin_input=0; 

// Variable qui va contenir une valeur entre 0 et 1024
// suivant la position du potentiomètre

int mesure=0;




void setup()   { 

// initialise connexion série à 19200 bauds

Serial.begin(19200); 

} 


void loop(){ 

// Sur l'entree analogique la mesure de la tension
// est convertie en un nombre compris entre 0 et 1024 

mesure=analogRead(Pin_input); 

// affiche de cette valeur sur le moniteur série
// (écran du PC)

Serial.println(mesure); 

// On attend un peu avant la prochaine mesure

delay(100); 

} 

Voilà ce que cela donne quand on bouge le potentiomètre :

Fichier hébergé par Archive-Host.com

Si vous avez un DFrduino, le programme est exactement le même, les connexions diffèrent un peu.

Première façon de réaliser les connexions sur un DFRduino :

Fichier hébergé par Archive-Host.com

Seconde façon qui utilise les connecteurs tout prêts du DFRduino ; attention à la numérotation des entrées, pas évidente à voir et avec un ordre pas évident non plus.

Fichier hébergé par Archive-Host.com

A suivre …

Train épicycloïdal

Fichier hébergé par Archive-Host.com

J’ai essayé de soigner le montage planétaire 19 dents + satellite de 38 tournant dans une couronne 95 dents. l’entr’axe est non standard, j’ai bricolé quelque chose avec des ref 63 c (accouplements taraudés), l’entr’axe se réglant avec des rondelles (minces).

Le montage n’est pas équilibré car il n’y a qu’un satellite, il faudrait rajouter un peu de poids du côté opposé à la 38 dents. J’ai essayé avec deux satellites, c’est plus beau mais je trouve que ça tourne moins bien.

Remarque : on obtient un rapport de 6 alors que les pignons (19 et 38) sont dans un rapport de 2, rigolo non ?

Le rapport 6 est donné par le calcul 1+ 95/19 (on remarque que le nb de dents du satellite ne figure pas directement dans la relation, on peut uniquement s’occuper de la couronne et du planétaire).

Comment connaître les combinaisons qui fonctionnent ?

Si le planétaire est de 19 dents et qu’on ajoute deux satellites de 38 dents, l’encombrement sera de 19 + 2 x 38 = 95 ; cela tient donc dans une couronne de 95 dents (raisonner sur les diamètres ou le nombre de dents, c’est pareil puisqu’ils sont proportionnels).

Wagon sur une voie (Partie 2)

La deuxième version …


//Chap 6 P9 wagon + opto coupleur + feux + barrière + sonnerie

// recap Pin utilisées

// 2  : Fin de course droit
// 3  : Opto droit
// 4  : Moteur 1 controle sens
// 5  : Moteur 1 controle vitesse PWM (entrainement wagon)
// 6  : Moteur 2 controle sens
// 7  : Moteur 2 controle vitesse PWM  (bobine barrière)
// 8  : Fin de course gauche
// 9  : Opto gauche
// 10 : feu (led) avant
// 11 : sonnerie piezo
// 12 : libre
// 13 : occupé par Led carte Arduino



//Controles moteur 

int E1 = 5; // Moteur 1 Controle vitesse PWM

int M1 = 4; // Moteur 1 Controle sens rotation


int M2 = 7 ; // Moteur 2 Controle vitesse PWM

int E2 = 6; // Moteur 2 Controle sens de rotation


// Les fins de course

int FDC_droit=2; // le fin de course droit est relié à la Pin 2

int FDC_gauche=8; // le fin de course gauche est relié à la Pin 8

int APPUI=0; // quand on appuie sur le bouton la Pin passe à l'état bas

int SENS=0 ; // sens de marche du wagon 0 : de gauche à droite, 1 : de droite à gauche

// les opto-coupleurs

int OPT_droit = 3 ;

int OPT_gauche = 9;

int etat_OPT_droit = 0;

int etat_OPT_gauche = 0;

int anc_etat_OPT_droit = 0;

int anc_etat_OPT_gauche = 0;

// gestion des feux clignotants 

int pin_led_av = 10;

boolean CLIGNOTE = false ; // si clignote est vrai, il faut faire clignoter les feux

boolean LED_ON = false ; // si LED_ON est vrai, les led sont allumées

int compteur = 0; // compteur de boucle

// Piezo - sonnerie

int pin_son = 11;

int LA= 440;


// fonctions /////////////////////////////////////////////

void sonnette_on () {
  
  tone (pin_son,LA);
}

void sonnette_off () {
  
  noTone (pin_son);
}


void allumer_feux () {

  digitalWrite(pin_led_av,HIGH);
  
  LED_ON = true;
}

void eteindre_feux () {

  digitalWrite(pin_led_av,LOW);

  LED_ON = false;
}

void baisse_barriere (int a) // on alimente la bobine
{
  analogWrite (E2,a);
  digitalWrite(M2,HIGH);
   
} 

void leve_barriere () // on stope l'alime de la bobine
{
  digitalWrite(E2,LOW);
}


void advance(int a) // marche avant
{
  analogWrite (E1,a);
  digitalWrite(M1,HIGH);
  
} 

void back_off (int a) //marche arriere
{
  analogWrite (E1,a);
  digitalWrite(M1,LOW);

}

 
void stop_moteur(int a) //stop
{
  digitalWrite(E1,LOW);
  delay(a);
  
}  

boolean test_FDC (int FDC) // fonction qui retourne "vrai" si le fin de course testé est actionné et "faux" sinon
{
   
  if (digitalRead(FDC) == APPUI) {
    
    delay(50);
    
    if (digitalRead(FDC) == APPUI) // on effectue une seconde lecture de confirmation pour s'affranchir des rebonds
    
       { 
         Serial.println ("True");
         return (true);
       }  
   }  

Serial.println ("False");
return (false);
}

void entre_dans_passage() { // le wagon entre dans le passage par la droite ou la gauche
 
      CLIGNOTE = true ;
      allumer_feux() ;
      baisse_barriere(255) ;
      sonnette_on ();
}

void sort_de_passage() { // le wagon sort du passage par la droite ou la gauche
  
      CLIGNOTE  = false ;
      eteindre_feux();
      leve_barriere() ;
      sonnette_off();
}  


// setup ///////////////////////////////

void setup() {
  
  pinMode(E1,OUTPUT);
  
  pinMode(M1, OUTPUT);
  
  pinMode(E2,OUTPUT);
  
  pinMode(M2, OUTPUT);
  
  Serial.begin(19200); // on initialise la communication en fait USB
  
  pinMode(FDC_droit,INPUT); // la broche reliée au fin de course droit est en mode INPUT
  
  
  pinMode(FDC_gauche,INPUT); // la broche reliée au fin de course gauche est en mode INPUT
  
  
  digitalWrite(FDC_droit,HIGH) ; // on active la resistance interne à l'Arduino qui va ramener au + la Pin quand on cesse d'appuyer sur le FDC
                           // une sorte de "ressort de rappel" ; la resistance est dite pull-up (on tire vers le haut).
                           // du coup on retire du montage la resistance 10 k ohms qui faisait le meme travail
                           
 digitalWrite(FDC_gauche,HIGH) ; // on active la resistance interne à l'Arduino qui va ramener au + la Pin quand on cesse d'appuyer sur le FDC
 
 
  pinMode(OPT_droit,INPUT);
  
  pinMode (OPT_gauche, INPUT);
  
  pinMode (pin_led_av, OUTPUT);

  pinMode (pin_son, OUTPUT);
  
}

// loop ///////////////////////////////

void loop() {
  
       
  // tests opto-coupleurs
  
    etat_OPT_droit = digitalRead(OPT_droit);
    
    if (etat_OPT_droit == 1 && anc_etat_OPT_droit == 0) { // on vient de laisser passer le wagon
    
    Serial.println ("Opt_droit : j'ai vu passer le wagon !");
    
    if (SENS == 0)
        sort_de_passage();            
    else
        entre_dans_passage();   
    }
    
    etat_OPT_gauche = digitalRead(OPT_gauche);
    
    if (etat_OPT_gauche == 1 && anc_etat_OPT_gauche == 0) { // on vient de laisser passer le wagon
         
        Serial.println ("Opt_gauche : j'ai vu passer le wagon !");
        
        if (SENS == 0)
           entre_dans_passage();
        else
           sort_de_passage();              
    }
   
      
    // tests fin de course
    
      
    if (test_FDC (FDC_droit)) { // le wagon appuie sur le fin de course droit
      
        Serial.println ("Appui droit !");
      
        stop_moteur(2000); // arret moteur 2s
        
        Serial.println ("fin 2s stop moteur");
                 
        back_off(120) ; // marche arriete
        
        delay(1000); // on se dégage de la zone fin de course
   
        Serial.println ("fin dégagement en marche arrière");
     
         SENS=1 ; // marche arrière
    }
    
           
     if (test_FDC (FDC_gauche)) { // le wagon appuie sur le fin de course gauche
          
           Serial.println ("Appui gauche!");
          
           stop_moteur(2000); // arret moteur 2s
            
           Serial.println ("fin 2s stop moteur");
         
           advance(120) ; //
        
           delay(1000); // on se dégage de la zone fin de course
     
           Serial.println ("fin dégagement en marche avant");
       
           SENS=0; // marche avant
    }
        
   
 if (! test_FDC(FDC_gauche) && ! test_FDC(FDC_gauche) ) // on est soit en marche avant soit en marche arrière mais on ne presse pas un fin de course
  
    {
          if (SENS == 0 ) {
          
          advance(160); // avance "vitesse 160"
          Serial.println ("marche avant > > > > ");
      
           } else {
    
          back_off(160); // recule "vitesse 160"
          Serial.println ("marche arrière < < < < ");
    
      }
    }     

compteur= compteur +1; // on compte le nombre de boucles ; cela sert juste à régler la fréquence de clignotement

    
if (CLIGNOTE && ( compteur > 5)) { // on attendu assez longtemps, on va changer d'état les led si elles etaient allumées on les eteint, si elles étaient éteintes on les allume

    compteur=0;
   
    if (LED_ON) // si les led sont allumées on les éteint
        eteindre_feux();
    else
       allumer_feux();             // si les led sont éteintes on les allume
}  
      
anc_etat_OPT_droit  = etat_OPT_droit ;
    
anc_etat_OPT_gauche = etat_OPT_gauche ;
  
} // fin loop

Wagon sur une voie (Partie 1)

Voici le début d’un modèle :

un wagon se déplace sur une voie horizontale deux micro-contacteurs (origine metallus) sont placés aux extrémités. Une fois l’extrémité atteinte, le wagon est immobile avant de repartir dans l’autre sens.

Une occasion de se familiariser avec l’Arduino.

Voici le programme, il est émaillé de nombreux commentaires et affichages pour faciliter la compréhension. Pendant la mise au point il est indispensable de surveiller ces affichages dans le moniteur série pour voir si ce qui se passe est bien conforme aux attentes. Il faut s’habituer en particulier au fait que l’Arduino décrit sa boucle loop() à toute allure et qu’il peut passer des dizaines de fois sur évènement qui est dans « notre tête » ponctuel : le programme doit être écrit en conséquence et la surveillance des affichages est un atout précieux.

D’ailleurs la mise au point peut se faire sans mettre le moteur en marche, juste en actionnant à la main les fin de course et en surveillant les affichages.


// 6 P4 wagon 


//Controle moteur PWM DC 

int E1 = 5; //M1 Controle vitesse

int M1 = 4; //M1 Controle sens rotation

// Les fins de course

 int FDC_droit=2; // le fin de course droit est relié à la Pin 2

int FDC_gauche=8; // le fin de course gauche est relié à la Pin 8


int APPUI=0; // quand on appuie sur le bouton la Pin passe à l'état bas

int SENS=0 ; // sens de marche du wagon 0 : de gauche à droite, 1 : de droite à gauche


void advance(int a) // marche avant
{
  analogWrite (E1,a);
  digitalWrite(M1,HIGH);
 } 

void back_off (int a) //marche arriere
{
  analogWrite (E1,a);
  digitalWrite(M1,LOW);
}

 
void stop_moteur(int a) //stop
{
  digitalWrite(E1,LOW);
  delay(a);
}  

boolean test_FDC (int FDC) // fonction qui retourne "vrai" si le fin de course testé est actionné et "faux" sinon
{
   
  if (digitalRead(FDC) == APPUI) {
    
    delay(50);
    
    if (digitalRead(FDC) == APPUI) // on effectue une seconde lecture de confirmation pour s'affrénchir des rebonds
    
       { 
         Serial.println ("True");
         return (true);
       }  
   }  

Serial.println ("False");
return (false);
}


void setup() {
  
  pinMode(E1,OUTPUT);
  
  pinMode(M1, OUTPUT);
  
  Serial.begin(19200); // on initialise la communication en fait USB
  
  pinMode(FDC_droit,INPUT); // la broche reliée au fin de course droit est en mode INPUT
  
  
  pinMode(FDC_gauche,INPUT); // la broche reliée au fin de course gauche est en mode INPUT
  
  
  digitalWrite(FDC_droit,HIGH) ; // on active la resistance interne à l'Arduino qui va ramener au + la Pin quand on cesse d'appuyer sur le FDC
                           // une sorte de "ressort de rappel" ; la resistance est dite pull-up (on tire vers le haut).
                           // du coup on retire du montage la resistance 10 k ohms qui faisait le meme travail
                           
 digitalWrite(FDC_gauche,HIGH) ; // on active la resistance interne à l'Arduino qui va ramener au + la Pin quand on cesse d'appuyer sur le FDC
                         
}

void loop() {
  
      
    if (test_FDC (FDC_droit)) { // le wagon appuie sur le fin de course droit
      
        Serial.println ("Appui droit !");
      
        stop_moteur(2000); // arret moteur 2s
        
        Serial.println ("fin 2s stop moteur");
                 
        back_off(120) ; //
        
        delay(1000); // on se dégage de la zone fin de course
   
        Serial.println ("fin dégagement en marche arrière");
     
        SENS=1 ; // marche arrière
    }
    
           
     if (test_FDC (FDC_gauche)) { // le wagon appuie sur le fin de course gauche
          
           Serial.println ("Appui gauche!");
          
           stop_moteur(2000); // arret moteur 2s
            
           Serial.println ("fin 2s stop moteur");
         
           advance(100) ; //
        
           delay(1000); // on se dégage de la zone fin de course
     
           Serial.println ("fin dégagement en marche avant");
       
           SENS=0; // marche avant
    }
       
 if (! test_FDC(FDC_gauche) && ! test_FDC(FDC_gauche) ) // on est soit en marche avant soit en marche arrière mais on ne presse pas un fin de course
  
    {
          if (SENS == 0 ) {
          
          advance(110); // avance "vitesse 110"
          Serial.println ("marche avant > > > > ");
      
           } else {
    
          back_off(160); // recule "vitesse 160"
          Serial.println ("marche arrière < < < < ");
    
      }
    }     
  
} // fin loop

Fichier hébergé par Archive-Host.com

Le montage est très semblable à ce qui a été vu dans les chapitres « Arduino introduction » sur ce forum concernant les boutons poussoirs. On utilise les résistances pull-up internes à l’Arduino et deux résistances de protection de 220 ohms « au cas où » on se tromperait et déclarerait une Pin en OUTPUT au lieu d’INPUT souhaité dans ce montage.

On utilise une mini-breadboard, très pratique, du fil de portier 0,6 mm monobrin, des connecteurs et des micro-rupteurs venant de metallus.

A noter : les micro-rupteurs laissent passer une très faible intensité, ils ne sont pas traversés par le même courant que le moteur. La partie « logique » et la partie « puissance » sont complètement distinctes.

Des améliorations vont venir avec un passage à niveau et un éclairage clignotant.

Servo-moteur 1ere réalisation

Grâce au logiciel Fritzing (gratuit et libre), on peut très facilement faire de beaux schémas. Une fois n’est pas coutume, je commence par le schéma.

Fichier hébergé par Archive-Host.com

Un servo c’est un dispositif qui comporte un moteur, des engrenages de réduction et une logique de contrôle. Il existe de très nombreux modèles, les modèles les plus simples peuvent faire tourner un axe de 0 à 180 °. Le servo est alimenté en 5v par trois fils : le +, le – et le fil de contrôle souvent blanc ou jaune. J’ai choisi un modèle courant et solide le futaba S3003. (environ 10 euros)

Comme le montre le schéma, ça se connecte très facilement sur un Arduino. Il est important que le servo ait sa propre alim en 5v et que la masse de l’Arduino soit connectée à la masse de l’alimentation 5v du servo. Le fil de contrôle, jaune, laisse passer une très faible intensité, on ne risque pas d’endommager l’Arduino. La puissance nécessaire pour alimenter le servo n’est pas fournie par l’Arduino mais par l’alim extérieure.

Dans ce modèle de démo, j’ai chargé le servo de déplacer un axe, ce qui peut servir dans quantité de modèles meccano (embrayages, boites de vitesses …).

Voilà le montage. Il faut alimenter l’Arduino soit par le port USB soit par un jack ; le servo a son alim indépendante (attention à bien relier la terre de l’alim du servo à la broche GND de l’Arduino).
Le moteur tourne en permanence ; le servo fait coulisser l’arbe horizontal qui porte les deux bagues d’arrêt. On va donc pouvoir entraîner l’un ou l’autre des deux arbres de sortie qui portent des roues de chaîne à droite. Bien sûr, pas besoin d’electronique pour faire ça, avec une vis sans fin on réalise sans peine un montage similaire. La différence c’est que l’on va pouvoir exprimer dans le programme exactement ce qu’on veut faire ( à quelle vitesse on déplace l’arbre, dans quel sens, avec quels arrêts…) et que les modifications, mises au point sont très rapides (il suffit de modifier quelques valeurs dans le programme).

Le servo porte un arbre comportant des canelures, le levier aussi, si bien qu’on peut ajuster la position du levier correspondant à zéro degré suivant les besoins.

Fichier hébergé par Archive-Host.com

Le programme est volontairement « brut de fonderie » ; on pourrait faire beaucoup plus court mais un peu moins facile à comprendre. On demande au servo de déplacer l’arbre progressivement, par pas de 1 degré en attendant 300 ms entre chaque changement de position. Une fois qu’une position cible est atteinte on attend 5000 ms avant de commencer le mouvement suivant.

On peut imaginer une boîte de vitesse pilotée en utilisant le même principe.


// 
// controle d'un servo moteur


#include <Servo.h>
  
 Servo myservo; // un objet de type servo est crée (max 8 objets servo)
                 
  
int pos = 0; // variable ou sera stockée la position (de 0 à 180).
  
void setup()
{ 
   myservo.attach(9); // attache le servo à la pin 9
} 
  
  
void loop()
{ 
    
  // le levier est vertical quand il est en position 8 °
  // à 0 ° l'extrémité portant la vis entre les deux bagues d'arret est à gauche
  // à 18° l'extrémité portant la vis entre les deux bagues d'arret est à droite
  // il est préférable d'arreter le mecanisme quand il est arrivé en position 0° (car c'est de là qu'il repartira à la mise sous tension)
  
  
   for(pos = 0; pos < 8; pos += 1) // aller de 0 degres à 8 degres par pas de 1 degre
    { 
     myservo.write(pos);
     delay(300); // attendre 300 ms après chaque changement
    } 
            
  delay(5000);
  
   for(pos = 8; pos < 18; pos += 1)
   {                                  
     myservo.write(pos);
     delay(300);
   } 
   
   delay(5000);
        
  for(pos = 18 ; pos > 8; pos -= 1)
   {                                  
     myservo.write(pos);
     delay(300);
   } 
       
  delay(5000);
  
  for(pos = 8; pos > 0; pos -= 1)
   {                                  
     myservo.write(pos);
     delay(300);
   }       
      
  delay(5000);
   
}

On peut connecter directement un servo sur le DFrduino

Fichier hébergé par Archive-Host.com

Les points importants :

– fournir une alim extérieure 5v (marquage Servo_PWR sur la carte), comme d’habitude bien vérifier le + et le –

– ensuite on peut brancher directement le servo sur la carte, aucun adaptateur nécessaire (attention à brancher comme sur la photo, il n’y a pas de détrompeur et on peut se planter de sens)

– attention la numérotation des contacts n’est pas évidente, les prises servo ont leur propre numérotation, difficile à voir (regarder sur la carte du côté du fil blanc du connecteur servo)

– le programme ci-dessus fonctionne, sans aucune modification

Le câble d’origine connectant le servo à la carte est court ; on trouve des rallonges de câble servo (30 cm) très pratiques par exemple chez Zartronic.

Monte-Charge (Partie 3)

Dernière version de cette série, le monte-charge est désormais commandé par une série de boutons poussoirs (un pour chaque niveau).

Le montages des boutons est expliqué au chapitre 4

Une petite amélioration : on a monté aux bornes de chaque bouton un condensateur de 100 microF qui supprime les problèmes de rebond et permet donc de ne pas les traiter par logiciel. (La méthode logicielle ne fonctionne pas de manière pas totalement satisfaisante, quelques appuis sont ignorés, la méthode « condensateur » me parait très fiable.)

Fichier hébergé par Archive-Host.com


/*

Monte-charge moteur pas à pas ;  ok pour dfrduino M1 : vert (-) rouge, M2 : jaune (-), bleu

Le moteur pas à pas bipolaire utilise les deux sorties moteur M1 et M2

On utilise 4 boutons pour demander l'étage souhaité ; le traitement des rebonds est effectue par des condensateurs

*/

#include <Stepper.h>

#define motorSteps 200     // 200 pas par tour
                           
#define motorPin1 4        // correspond à M1
#define motorPin2 7        // correspond à M2

//construction d'un objet de type stepper (pas à pas)

Stepper myStepper(motorSteps, motorPin1,motorPin2);

// E1 et E2 servent à activer les sorties M1 et M2

int E1=5; // enable M1
int E2=6; // enable M2

// Pin correspondants aux boutons

int Bzero= 8; // la Pin 8 correspond au bouton demandant l'étage 0

int Bun=9 ; // la Pin 9 correspond au bouton demandant l'étage 1

int Bdeux=10 ; // la Pin 8 correspond au bouton demandant l'étage 2

int Btrois=11 ; // la Pin 8 correspond au bouton demandant l'étage 3

/////////////////////////

int hauteur[3]={1160,890,680} ; // on range dans un tableau le nb de pas pour passer du rdc au 1er, du 1er au 2 eme, du 2 eme au 3 eme

int i=0; // indice servant a parcourir le tableau ; le premier élément du tableau a l'indice 0

int etage_voulu=0; // Ce que l'on tape sur le clavier du PC

int etage_courant=0; // Pour simplifier, on se débrouille pour qu'au démarrage du programme le monte-charge soit au RDC (niveau 0)

int hauteur_cumulee=0; // le nb de pas requis pour aller à l'étage concerné

////////////////////////////////////////

 int lire_boutons () { // on ne traite pas le pb du rebond par logiciel mais en montant en parallele des contacts de chaque bouton un condensateur de 100 microF
   
   int appui = 0;
   
   while (1) { // boucle infinie, on en sort par l'instruction return si lecture d'un appui
             
          if (digitalRead(Bzero) == appui) { return(0); }
          
          if (digitalRead(Bun) == appui) { return(1); }
          
          if (digitalRead(Bdeux) == appui) { return(2); }
         
          if (digitalRead(Btrois) == appui) { return(3); }
         
          
   } // while
          

} // lire_boutons

//////////////////////////

void setup() {
  
  
  Serial.begin(19200);
  
    
  // pour que le moteur soit actif il faut mettre à l'état haut E1 et E2

  pinMode (E1,OUTPUT);
  pinMode (E2,OUTPUT);
  digitalWrite (E1,HIGH);
  digitalWrite (E2, HIGH);
  
  // Les pin reliées aux boutons sont mises en mode INPUT
  
 pinMode(Bzero, INPUT); // Pin en mode entrée
 pinMode(Bun, INPUT); // Pin en mode entrée
 pinMode(Bdeux, INPUT); // Pin en mode entrée
 pinMode(Btrois, INPUT);// Pin en mode entrée
  
  
  // Activation de la resistance interne pull-up (rappel au plus) voir chapitre 4 pour plus d'explications
    
 
  digitalWrite(Bzero, HIGH); // Activation de la resistance interne pull-up (rappel au plus)
  digitalWrite(Bun, HIGH); // Activation de la resistance interne pull-up (rappel au plus)
  digitalWrite(Bdeux, HIGH); // Activation de la resistance interne pull-up (rappel au plus)
  digitalWrite(Btrois, HIGH);// Activation de la resistance interne pull-up (rappel au plus)
  
  
  
  
  myStepper.setSpeed(90); // on fixe la vitesse
  
  }
  
/////////////////////////////////

void loop() {
    
      
     etage_voulu = lire_boutons(); 
      
     hauteur_cumulee=0;
      
     if ( (etage_voulu >= 0) && (etage_voulu <=3) ) { // controle que la valeur demandee est raisonnable...
            
         Serial.print ("Etage courant : "); Serial.println(etage_courant);
             
         Serial.print ("Etage voulu : "); Serial.println(etage_voulu);
            
         if (etage_voulu-etage_courant > 0) { // il faut monter
            
            for (i=etage_courant ; i< etage_voulu ; i++) { // on calcule de combien de pas il faut monter
              
                hauteur_cumulee=hauteur_cumulee + hauteur[i];  
             
               }
                               
            Serial.print ("Il faut monter de :"); Serial.println (hauteur_cumulee);
                             
            myStepper.step(hauteur_cumulee);
                
            etage_courant=etage_voulu;    
          
            delay(2000);
          
            
         } // il faut monter
    
            
        if (etage_voulu-etage_courant < 0) { // il faut descendre
            
           for (i=etage_courant -1 ; i> etage_voulu -1 ; i--) { // on calcule de combien de pas il faut descendre
              
                hauteur_cumulee=hauteur_cumulee + hauteur[i];
                
           }              
                   
          Serial.print ("Il faut descendre de :"); Serial.println (hauteur_cumulee);
         
          myStepper.step(-hauteur_cumulee);
               
          etage_courant=etage_voulu;    

          delay(2000);
                           
       } // il faut descendre
    
    } // etage entre 0 et 3
                   
  
} // loop

L’ensemble fonctionne très bien et ne se décale pas.

A noter : pour simplifier le modèle, il n’y a pas de fin de course, pas de contrôle optique, tout repose sur le calcul des déplacements relatifs à partir d’une position initiale (plateau au rez-de-chaussée). On pourrait ajouter, au minimum, pour améliorer la sécurité de l’installation un fin de course en haut et un fin de course en bas.