ModelleisenbahN

Accueil > La technologie > Arduino > Manœuvre des aiguilles avec des servo-moteurs > Témoins de positions : la mise en œuvre

Manœuvre des aiguilles en analogique avec des servo-moteurs

Témoins de positions : la mise en œuvre

publié par Jean-Luc, le mardi 3 décembre 2013

Tags arduino - led

Nous avons vu la technique du Charlieplexing dans « Témoins de positions : le Charlieplexing », nous allons maintenant l’appliquer à un système à 5 broches de pilotage et 16 LED puis l’intégrer dans notre application.

Charlieplexing des 16 LED témoins [1]

Le schéma pour allumer 16 LED est le suivant.

PNG - 60.5 ko
Charlieplexing avec 5 broches et 16 LED

On peut noter que le schéma est incomplet. En effet, avec 5 broches, il est possible de piloter 20 LED. Ici les couples de broches 0-3 et 1-4 sont manquants et nous n’allons donc pas les placer dans notre table d’état des broches.

Voici donc la table d’état des broches pour chaque LED

  broche 0 broche 1 broche 2 broche 3 broche 4
D0 0 1 Z Z Z
D1 1 0 Z Z Z
D2 Z 0 1 Z Z
D3 Z 1 0 Z Z
D4 Z Z 0 1 Z
D5 Z Z 1 0 Z
D6 Z Z Z 0 1
D7 Z Z Z 1 0
D8 0 Z 1 Z Z
D9 1 Z 0 Z Z
D10 Z Z 0 Z 1
D11 Z Z 1 Z 0
D12 Z 0 Z 1 Z
D13 Z 1 Z 0 Z
D14 0 Z Z Z 1
D15 1 Z Z Z 0

Nous allons donc construire cette table en C comme nous l’avons fait pour la Charlieplexing avec 3 broches de commande.

  1. const byte etatSortiePourLED[16][5] = {
  2. { OUT0, OUT1, INZ, INZ, INZ }, /* D0 */
  3. { OUT1, OUT0, INZ, INZ, INZ }, /* D1 */
  4. { INZ, OUT0, OUT1, INZ, INZ }, /* D2 */
  5. { INZ, OUT1, OUT0, INZ, INZ }, /* D3 */
  6. { INZ, INZ, OUT0, OUT1, INZ }, /* D4 */
  7. { INZ, INZ, OUT1, OUT0, INZ }, /* D5 */
  8. { INZ, INZ, INZ, OUT0, OUT1 }, /* D6 */
  9. { INZ, INZ, INZ, OUT1, OUT0 }, /* D7 */
  10. { OUT0, INZ, OUT1, INZ, INZ }, /* D8 */
  11. { OUT1, INZ, OUT0, INZ, INZ }, /* D9 */
  12. { INZ, INZ, OUT0, INZ, OUT1 }, /* D10 */
  13. { INZ, INZ, OUT1, INZ, OUT0 }, /* D11 */
  14. { INZ, OUT0, INZ, OUT1, INZ }, /* D12 */
  15. { INZ, OUT1, INZ, OUT0, INZ }, /* D13 */
  16. { OUT0, INZ, INZ, INZ, OUT1 }, /* D14 */
  17. { OUT1, INZ, INZ, INZ, OUT0 } /* D15 */
  18. };

Télécharger

La fonction programmeBroche(...) reste la même par contre la fonction gereLED(...) doit être modifiée puisque l’on passe de 3 à 5 broches de commande.

  1. void gereLED(int num)
  2. {
  3. if (etatLED[num] == ALLUME) {
  4. programmeBroche(8,etatSortiePourLED[num][0]);
  5. programmeBroche(9,etatSortiePourLED[num][1]);
  6. programmeBroche(10,etatSortiePourLED[num][2]);
  7. programmeBroche(11,etatSortiePourLED[num][3]);
  8. programmeBroche(12,etatSortiePourLED[num][4]);
  9. }
  10. else {
  11. programmeBroche(8,INZ);
  12. programmeBroche(9,INZ);
  13. programmeBroche(10,INZ);
  14. programmeBroche(11,INZ);
  15. programmeBroche(12,INZ);
  16. }
  17. }

Télécharger

Et le tableau etatLED doit être agrandi pour contenir 16 éléments.

Intégration dans l’application

Pour intégrer l’allumage des témoins dans l’application il faut tout d’abord insérer l’appel à gereLED() dans loop(). Nous faisons face à un premier problème. Pour que les servomoteurs pivotent suffisamment lentement, l’attente est de 5ms. Cela conduit à un balayage des 16 LED en 80ms ce qui est trop lent pour que la persistance rétinienne opère. Il faudrait balayer au moins 4 fois plus souvent. Par conséquent, le délai dans loop() va être réduit à 1ms et la gestion des poussoirs et des servomoteurs sera appelée toutes les 5 fois alors que la gestion des LED sera appelée toutes les fois. Nous allons donc ajouter un compteur compteurGestionServos initialisé à 0. Comme ceci.

  1. void loop()
  2. {
  3. compteurGestionServos++;
  4.  
  5. if (compteurGestionServos == 5) {
  6.  
  7. compteurGestionServos = 0;
  8.  
  9. ...
  10. /* code de gestion des servos et des poussoir à l'identique */
  11. ...
  12. }
  13.  
  14. gereLED(numLED);
  15.  
  16. numLED++;
  17. if (numLED == 16)
  18. numLED = 0;
  19.  
  20. delay(1);
  21. }

Télécharger

Il suffit ensuite de changer l’état des LED en ALLUME ou ETEINT dans le tableau etatLED en fonction des événements. Deux fonctions membre de la classe DescripteurServo sont concernées : evenementServo(...) où on va éteindre la LED de la position que l’on quitte et gereServo() où on va allumer la LED de la position que l’on atteint. Dans le tableau etatLED, les LED sont alternativement rouges et vertes et par conséquent la paire de LED correspondant à un servomoteur est à la position numéro de servo × 2 (angle minimum) et numéro de servo × 2 + 1 (angle maximum).

  1. void evenementServo()
  2. {
  3. cptArret = -1;
  4. switch (etatServo) {
  5. case SERVO_A_ANGLE_MIN:
  6. etatLED[numServo * 2] = ETEINT;
  7. objetServo.attach(pin);
  8. case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
  9. vitesse = 1;
  10. etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
  11. break;
  12. case SERVO_A_ANGLE_MAX:
  13. etatLED[numServo * 2 + 1] = ETEINT;
  14. objetServo.attach(pin);
  15. case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
  16. vitesse = -1;
  17. etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
  18. break;
  19. }
  20. }

Télécharger

Dans la fonction membre gereServo(), la partie qui s’occupe du passage de la vitesse à 0 quand les angles minimum ou maximum sont atteint est modifiée comme suit :

  1. if (! reglageEnCours ||
  2. etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN ||
  3. etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) {
  4. if (angle > angleMax) {
  5. angle = angleMax;
  6. arreteServo();
  7. etatServo = SERVO_A_ANGLE_MAX;
  8. etatLED[numServo * 2 + 1] = ALLUME;
  9. }
  10. else if (angle < angleMin) {
  11. angle = angleMin;
  12. arreteServo();
  13. etatServo = SERVO_A_ANGLE_MIN;
  14. etatLED[numServo * 2] = ALLUME;
  15. }
  16. }

Télécharger

Il ne faut pas oublier d’allumer la LED correspondant à l’angle minimum dans la fonction membre connecte(...)

  1. /* allume la LED correspondante */
  2. etatLED[numServo * 2] = ALLUME;

Télécharger

Nous sommes parvenus au bout de ce développement. Voici le sketch de l’application complète à télécharger.

Zip - 4.4 ko
Sketch de l’application complète
(clic sur l'image pour agrandir ou télécharger)
mis à jour en version 1.1. La position des servos est désormais mémorisée dans l’EEPROM.
PNG - 599 ko
Dessin du montage complet
(clic sur l'image pour agrandir ou télécharger)
Attention : le montage montre les 8 servomoteurs alimentés par l’Arduino. Ce n’est pas possible en pratique et il est nécessaire d’avoir une alimentation 5V séparée pour les servomoteurs
PDF - 2.4 Mo
Dessin du montage complet à télécharger en PDF
(clic sur l'image pour agrandir ou télécharger)
Attention : le montage montre les 8 servomoteurs alimentés par l’Arduino. Ce n’est pas possible en pratique et il est nécessaire d’avoir une alimentation 5V séparée pour les servomoteurs

Ainsi qu’une vidéo de démonstration.

Démonstration de l’application complète et terminée

Notes

[1On peut noter que plus le nombre de LED est important, plus le temps d’allumage sur un cycle de balayage devient faible. En pratique, la luminosité n’est pas beaucoup plus faible avec 16 LED. Pour un plus grand nombre de LED, il peut être nécessaire de diminuer la valeur des résistances sans toutefois dépasser les capacités des entrées/sorties du micro-contrôleur

4 Messages

  • Témoins de positions : la mise en œuvre 22 janvier 2014 16:58, par christian

    Bonjour Jean-Luc,
    Vraiment très bien faite votre application.
    Je viens de l’utiliser pour piloter les barrières d’un passage à niveau. L’utilisation est similaire et cela fonctionne de façon très réaliste.
    Néanmoins, l’asservissement des servo n’est pas coupé dans leur position MIN et MAX. Quand je force un peu les servo, je sens de la résistance, donc ils sont encore asservis.
    J’ai utilisé votre dernier sketch complet avec les leds.
    Comme je suis un piètre programmeur, sur quoi faut-il agir pour couper réellement l’asservissement ?
    Merci par avance.
    Bien cordialement
    Christian

    repondre message

    • Témoins de positions : la mise en œuvre 22 janvier 2014 17:22, par Jean-Luc

      Bonjour Christian

      Merci pour le compliment :)

      Pour couper la PWM et stopper l’asservissement du servo, il faut détacher le servo. Il s’agit de la méthode detach() de la bibliothèque Servo

      Pour de nouveau l’asservir, il faut rappeler attach()

      Bien cordialement.

      repondre message

      • Merci pour cette réponse rapide.
        J’ai bien lu dans vos documents la fonction detach() mais j’ai essayé de la placer dans votre dernier sketch mais je ne suis pas parvenu à un résultat qui fonctionne.
        Je reprends votre dernier sketch (ci dessous), il y a bien la fonction detach(), peut-être y a-t-il une valeur à changer en fonction des servos, j’avoue être un peu perdu...

        /*
        * Ajoute la vitesse à l’angle. Stoppe le servo quand l’angle min ou max
        * est atteint. Stoppe son asservissement
        * Doit etre appelé péridioquement à un intervalle de temps fixe
        */
        void gereServo()

        objetServo.writeMicroseconds(angle) ;

        if (vitesse == 0)
        if (cptArret == 0)
        objetServo.detach() ;
        if (cptArret >= 0)
        cptArret— ;

        Pourriez-vous m’indiquer où il faut placer les fonctions detach() et attach(), sans vouloir vous faire perdre votre temps...
        Merci par avance.
        Cordialement.
        Christian

        repondre message

Répondre à cet article

Les thèmes

Archives

Informations

ModelleisenbahN | publié sous licence Creative Commons by-nc-nd 2.0 fr | généré dynamiquement par SPIP & Blog'n Glop