Hâte-toi de bien vivre et pense
que chaque jour nouveau
est à lui seul une vie. 
 (Sénèque)
  

Icones/3_icones.pngPont tournant - 06-Sketch ARDUINO

Emoticone_chantier.jpg

Pont tournant

Sketch pour l'ARDUINO N°1

 

Le texte du sketch « ARDUINO_PONT_KEYPAD_LCD_V23k » comporte environ 940 lignes, dont une bonne partie est constituée de commentaires.

Téléchargement ICI.


En fait ce sketch n'est impressionnant que par sa taille mais pas par sa complexité.

J'ai évité le plus possible de recourir à une programmation alambiquée, qui aurait été sans doute plus élégante mais moins facilement compréhensible et moins facilement modifiable.

 


Les commentaires intégrés
 

Ils me servent de pense-bête personnel.

Je n'irais pas jusqu'à dire que tout est expliqué dans ces commentaires, mais presque.

La ligne de commentaire ci-dessous sur fond rouge (aux environs de la ligne 90)...

/*  NOTE SUR LA CONNEXION ENTRE LES DEUX ARDUINO :
 *  ARDUINO n°1 Tx --> ARDUINO n°2 Rx. (La liaison ARDUINO n°1 Rx --> ARDUINO n°2 Tx n'est pas nécessaire) ;
 *  Les masses doivent être reliées ensemble, sinon les deux ARDUINOS doivent être sur la même alimentation ;

 *  !!! IMPERATIF : COUPER LA LIAISON Tx --> Rx AVANT LE TELEVERSEMENT (sinon blocage du téléversement)
*/

... est certainement une des plus importante à garder en mémoire.

 

J'ai même pris la précaution de l'écrire sur un petit carton posé près de mes deux ARDUINO.

En effet, si on oublie de débrancher cette liaison, l'IDE affiche un message d'erreur, mais sans expliquer clairement le problème !

 

 

Les bibliothèques additionnelles

L'IDE ARDUINO propose plusieurs bibliothèques, mais elles ne couvrent pas tous les besoins, ou alors elles n'ont pas l'efficacité voulue.

On trouve sur le net de nombreuses bibliothèques complémentaires.

Il est indispensable de télécharger et d'installer les bibliothèques ci-dessous pour que l'écriture et la compilation du sketch puisse se faire.

 

Il s'agit des bibliothèques :

StepperLab3.h

LiquidCrystal.h

LiquidCrystal_I2C.h

Keypad.h

 

 

Datasheet du clavier : ICI

 

 

 

Table de correspondance « n° voie ⇔ n° du pas du moteur pas-à-pas »

Entre les lignes 320 et 520 (environ) se trouve une des plus importantes fonction :

int traitementNumeroVoie(int num_Voie)

 

La table «switch (num_Voie) ... case xx : » contient la correspondance entre le numéro de voie sélectionné et le numéro du pas pour le moteur pas-à-pas.

switch (num_Voie) // "num_Voie" est une variable locale
    {     
    case 0:
      positionVoie = 0 ;
      initialisationPositionPont() ;
      break ;  
    case 1:
      positionVoie = 274 ;      
      break;
    case 2:
      positionVoie = 725 ;
      break;
    case 3:
      positionVoie = 1217 ;
      break ;  
    case 4:

...

 case 113:
      positionVoie = 13383 ;
      break ;  
    case 114:
      positionVoie = 4102 ;
      break;
    case 115:
      positionVoie = 5170 ;
      break;
    case 116:
      positionVoie = 5543 ;
      break ;
    case 117:
      positionVoie = 6076 ;
      break ;

...

 

Non, il n'y a pas 117 voies !

  • les voies sont codées de 1 à 17 quand le pont y accède par son extrémité « directe ».
  • elles sont codées de 101 à 117 quand c'est l'extrémité « opposée» qui se présente en face de la voie.

(voir les commentaires intégrés dans le sketch).

 

Mais ce n'est pas tout !

 

... accès à quelques commandes

 

Un certain nombre de codes « exotiques » correspondent à des commandes et non à des numéros de voies :

 

if (num_Voie == 222) // Ce code commande le retournement du pont
      {
      if (voieEnCours <= 17) {num_Voie = voieEnCours + 100 ; }

...

 

    case 60:
      vitessePont = 600 ;       
      codeVoie = voieEnCours ;
      Message_LCD1602_VitesseDuPont() ;

...

 

    case 255:           // Détermination manuelle de la position des voies
      vitessePont = 1000 ;
      codeVoie = 0 ;
      Message_LCD1602("MENU 255", "POSITION VOIES", 4000) ;
      determinationPositionsVoies() ;
      break ;

...

    case 253:
      hotReset() ;
      break ;
    case 254:           // Modification de l'offset
      vitessePont = 1000 ;
      codeVoie = 0 ;
      Message_LCD1602("MENU 254", "Modif. OFFSET", 2000) ;
      determinationOffset() ;
      hotReset() ;      // Reset à chaud du programme
      break ;

C'est certainement moins élégant que la mise en place de menus hiérarchisés, mais vu le petit nombre d'options (7 au total) c'était plus simple et cela allège grandement l'écriture du sketch.

L'utilisation de ces codes est expliquée dans l'article « 08-Mode d'emploi ».

 

Note 1 :

Au départ de mon projet, la fonction « determinationPositionsVoies() » faisait partie d'un programme indépendant. Ce programme ne sert qu'une seule fois puisque, quand les positions des voies sont connues et reportées dans le programme principal, il n'a plus d'utilité.

Or il était très très peu différent du programme principal.

Pour m'amuser, je l'ai donc intégré dans le programme principal, sous forme d'une fonction.

En fait, l'accès à ce menu « 255 » n'est utile que si on doit ajouter une 18ème voie (ou plus), ou si on doit déplacer une voie existante.

 

Note 2:

L'instruction « hotReset() ; », utilisée dans « case 253: » et « case 254: », fait appel à la procédure :

void(*hotReset) (void) = 0 ;          // Déclare la fonction Reset @ adresse 0
... qui est insérée juste avant « void setup() ».

J'ai utilisé le nom « hotReset » pour faire celui qui connaît 2 mots d'anglais...

 

En réalité c'est plus court que « redemarrage_a_chaud ».

On peut choisir le nom qu'on veut du moment qu'il est explicite.

MDR2.gifoui, bon, ça va...

 

   

 

 

 

 

 

 

 

 

void saisieNumeroVoie()
 

Cette fonction traite à la fois les ordres en provenance du clavier et ceux en provenance de l'application ANDROÏD.

Dans les deux cas, le numéro de la voie sélectionnée est affiché sur l'écran LCD de la petite console.

 

 

Arrêt d'urgence

int arretUrgence()
{
  char emergency = '0' ;                         // Effacement du dernier caractère saisi avant nouvelle saisie

    emergency = kpd.getKey();                    // scrutation du clavier   
    if (emergency == '#' || emergency == '*' || (char) (HC_05_Pont.read()) == '#' )   // ... si une touche '#' ou '*' est reçue
       {
       return(1) ;       
       }
    else
       {
       return(0) ;
       }  // Fin de "if (emergency...)"
}         // Fin de void arretUrgence()

 

Si le clavier ou l'application ANDROÏD envoie un des deux codes « # » ou « * » seul, alors ce code est interprété comme un ordre d'arrêt d'urgence.

Cet arrêt d'urgence permet d'éviter ceci (par exemple) :

turntable_accident.jpg          emoticone_punition.png

 

Jusqu'à maintenant je n'ai jamais eu besoin  d'utiliser ce code mais mes petits enfants trouvent ça très amusant !

 

Après un arrêt d'urgence, il est recommandé d'utiliser le code « 253 » (voir ci-dessous) pour recaler le pont.

 

 

 

void arretMoteur()

void arretMoteur()
{
    digitalWrite(2,HIGH);
    digitalWrite(3,HIGH);
    digitalWrite(4,HIGH);
    digitalWrite(5,HIGH);  
}
/* Coupe la consommation du moteur lorsqu'il n'est plus en mouvement.
// ATTENTION ! dans ces conditions le moteur est libre et tourne facilement à la main.
// Malgré tout il est utile de couper l'alimentation du moteur,
// sinon il chauffe : environ 4 Watts sous 5 volts et plus de 12 Watts sous 12 volts !
// Dans ce dernier cas le moteur devient vite brûlant.

 

Cette procédure est indispensable pour les raisons ci-dessus (commentaire).

Bien entendu il faut veiller à ne pas bousculer le pont quand il est à l'arrêt.

Au cas où cela se produirait, ou en cas de doute, il suffit d'utiliser le code « 253 » pour recaler le pont.

 

 

 

Transmission vers ARDUINO N°2

 

void transmissionVersARDUINO_2()  // transmet le numero de voie à l'ARDUINO n° 2 sous forme int  
    {
    if (codeVoie > 100) {Serial.write(codeVoie - 100) ; }
    else {Serial.write(codeVoie) ; }

    Serial.print("codeVoie =  ") ;     // pour controle sur moniteur
    Serial.println(codeVoie) ;

    }   
 

Très simple.

C'est la dernière instruction de la boucle principale « void loop ».

C'est donc seulement quand le pont a atteint sa destination que l'ARDUINO n°2 reçoit l'ordre de commutation des voies.

 

 

void setup ()

 

void setup()
{   
  pinMode(StopSwitch, INPUT_PULLUP) ;
  pinMode(SlowSwitch, INPUT_PULLUP) ;
 

...


  initialisationPositionPont() ; // (une seule fois à l'allumage de l'ARDUINO)
            // utilise Message_LCD1602("CALAGE DU ZERO", "EN COURS...", 3000) ;
            // utilise Message_LCD1602("PONT TOURNANT OK", "Numero voie ?", 3000) ;


} // Fin de "void setup"

 

Si l'ARDUINO a été éteint « à l'arrache », ou s'il y a eu une coupure de courant... le pont est stoppé dans une position qui n'est pas connue de l'ARDUINO.

Le rôle de l'instruction surlignée en vert initialisationPositionPont() ; est de réaliser le calage du pont à chaque démarrage de l'ARDUINO.

Ainsi tout le système est remis dans un état « propre ».

Cette instruction figure dans « void setup() ». Elle n'est donc exécutée qu'une fois.

 

Note :

J'aurais pu programmer une mémorisation « à la volée » de la position du pont en EPROM, et ainsi connaître la position exacte qu'il occupait au moment de l'arrêt du système.

Pas si exacte que ça !

  • les phénomènes transitoires, lors de la coupure des alimentations du système, ne garantissent pas que la position exacte du pont ait eu le temps d'être mémorisée ;
  • à l'arrêt (tension coupée) le moteur pas-à-pas n'est pas verrouillé en position : son axe tourne très facilement.
    Si on touche le pont lui-même, on peut être assuré que sa position aura changé, ne serait-ce que de quelques fractions de mm.
    La mémorisation de la position n'aura donc servi à rien ;
  • d'autre part, la mémorisation « à la volée » mobilise le processeur à chaque pas du moteur ! Un ralentissement important du programme en découle.
     

emoticon_sueur.jpg

 

 

Sketch pour l'ARDUINO N°2

 

Difficile de faire plus simple.

 

void loop ()

void loop()
{
receptionNumVoie() ;
 
commutationRelaisVoies() ;         
}

 

On peut se passer d'explications pour cette boucle principale.

 

 

 

Définition des sorties

Stroumpf_bricoleur.png

(partie en cours de vérification)

 

#define relaiVcc_1 2   // relai n°1 sur sortie n°2, etc.
#define relaiVcc_2 3
#define relaiVcc_3 4
#define relaiVcc_4 5
#define relaiVcc_5 6   // x5 relais pour commuter le Vcc
#define relaiGND_6 7   // et x4 relais pour commuter la masse
#define relaiGND_7 8
#define relaiGND_8 9
#define relaiGND_9 10

 

Oui. C'est la seule originalité .

Au lieu d'utiliser 17 relais (en réalité 5 modules de 4 relais, soit 20 relais), on n'en utilise que 9. Ils commutent les voies de façon matricielle :

4 lignes x 5 colonnes (4x5 = 20, suffisant pour 17 voies).

Le véritable intérêt de cette matrice de relais n'est pas l'économie de prix, mais l'allègement du câblage.

 

 

 

void commutationRelaisVoies()

Cette procédure (fonction) fait appel à « RAZ_relais() », tellement simple que je ne la détaillerai même pas ici.

Remarque : il y a une 18ème voie programmée, au cas où...


void commutationRelaisVoies()
{
     RAZ_relais() ;
 
     if (voieAlimentee == 1) { digitalWrite (relaiVcc_1, HIGH) ; digitalWrite (relaiGND_6, HIGH) ; }
else if (voieAlimentee == 2) { digitalWrite (relaiVcc_2, HIGH) ; digitalWrite (relaiGND_6, HIGH) ; }
else if (voieAlimentee == 3) { digitalWrite (relaiVcc_3, HIGH) ; digitalWrite (relaiGND_6, HIGH) ; }
else if (voieAlimentee == 4) { digitalWrite (relaiVcc_4, HIGH) ; digitalWrite (relaiGND_6, HIGH) ; }
else if (voieAlimentee == 5) { digitalWrite (relaiVcc_5, HIGH) ; digitalWrite (relaiGND_6, HIGH) ; }
else if (voieAlimentee == 6) { digitalWrite (relaiVcc_1, HIGH) ; digitalWrite (relaiGND_7, HIGH) ; }
else if (voieAlimentee == 7) { digitalWrite (relaiVcc_2, HIGH) ; digitalWrite (relaiGND_7, HIGH) ; }
else if (voieAlimentee == 8) { digitalWrite (relaiVcc_3, HIGH) ; digitalWrite (relaiGND_7, HIGH) ; }
else if (voieAlimentee == 9) { digitalWrite (relaiVcc_4, HIGH) ; digitalWrite (relaiGND_7, HIGH) ; }
else if (voieAlimentee == 10) { digitalWrite (relaiVcc_5, HIGH) ; digitalWrite (relaiGND_7, HIGH) ; }
else if (voieAlimentee == 11) { digitalWrite (relaiVcc_1, HIGH) ; digitalWrite (relaiGND_8, HIGH) ; }
else if (voieAlimentee == 12) { digitalWrite (relaiVcc_2, HIGH) ; digitalWrite (relaiGND_8, HIGH) ; }
else if (voieAlimentee == 13) { digitalWrite (relaiVcc_3, HIGH) ; digitalWrite (relaiGND_8, HIGH) ; }
else if (voieAlimentee == 14) { digitalWrite (relaiVcc_4, HIGH) ; digitalWrite (relaiGND_8, HIGH) ; }
else if (voieAlimentee == 15) { digitalWrite (relaiVcc_5, HIGH) ; digitalWrite (relaiGND_8, HIGH) ; }
else if (voieAlimentee == 16) { digitalWrite (relaiVcc_1, HIGH) ; digitalWrite (relaiGND_9, HIGH) ; }
else if (voieAlimentee == 17) { digitalWrite (relaiVcc_2, HIGH) ; digitalWrite (relaiGND_9, HIGH) ; }
else if (voieAlimentee == 18) { digitalWrite (relaiVcc_3, HIGH) ; digitalWrite (relaiGND_9, HIGH) ; }
}

 

Sur l'ARDUINO N°2, pour commuter ces 18 voies, on utilise les sorties 2 à 10 (soit 9 sorties).
La table de commutation ci-dessus traduit le fonctionnement de la matrice des 9 relais.

 

En fait, le matriçage « 4 x 5 » à 9 relais permet de commuter 4 x 5 = 20 voies.

Or l'ARDUINO N°2 dispose de 18 sorties (puisque 2 broches sont mobilisées pour la liaison série avec l'ARDUINO N°1).

Avec 18 sorties qui commandent 18 relais on pourrait donc commander :

  • 80 relais (donc 80 voies) avec une matrice 8 x 10 ;
  • 81 relais (donc 81 voies) avec une matrice 9 x 9 ;

Ouch ! voilà qui ouvre des perspectives si 18 voies ne suffisent pas à votre bonheur !

 

 

 

 

 

Schéma de câblage des relais commandés par l'ARDUINO N°2

 

Schema_relais_ARDUINO_2.png

Chaque nœud de la matrice correspond au branchement d'une des voies, le fil rouge sur le rail gauche, le fil noir sur le rail droit.

L'inversion de sens de marche est assurée par un inverseur à 2 relais situé en amont et commandé par l'ARDUINO N°1.

 

Remarque :

Dans le sketch ARDUINO j'ai appelé les sorties pour les relais « relaiVcc_xx » et « relaiGND_xx » pour qu'il soit plus facile de comprendre le principe de la matrice de commutation : x5 relais commutent le « Vcc » et 4 relais commutent « Gnd » de la tension de traction.

Bien entendu, si on veut pouvoir changer le sens de marche il faut installer un inverseur à relais en amont de la matrice de commutation.

Ces relais inversent « + » et « - », c'est à dire « Vcc » et « Gnd » de la tension de traction.

La terminologie utilisée dans la procédure « void commutationRelaisVoies() » pour désigner les sorties qui commandent des relais de commutation des voies — « relaiVcc_xx » et « relaiGnd_yy » — n'est donc rigoureusement exacte que quand les relais d'inversion de marche sont au repos, mais il faut bien « baptiser » les sorties en question d'une façon explicite.

Sur le schéma ci-dessus, les désignations « Vcc » et « Gnd » sont remplacées par :
« TRACTION RAIL DROIT » et « TRACTION RAIL GAUCHE ».

Ça colle plus à la réalité mais c'est moins parlant du point de vue électrique.

 

 

 

 

 

 

 

 


Date de création : 24/10/2017 - 21:29
Dernière modification : 03/10/2018 - 10:32
Catégorie :
Page lue 385 fois


Imprimer l'article Imprimer l'article

^ Haut ^