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

mardi 3 décembre 2013, par Jean-Luc

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.

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.

const byte etatSortiePourLED[16][5] = {
  { OUT0, OUT1, INZ, INZ, INZ }, /* D0 */
  { OUT1, OUT0, INZ, INZ, INZ }, /* D1 */
  { INZ, OUT0, OUT1, INZ, INZ }, /* D2 */
  { INZ, OUT1, OUT0, INZ, INZ }, /* D3 */
  { INZ, INZ, OUT0, OUT1, INZ }, /* D4 */
  { INZ, INZ, OUT1, OUT0, INZ }, /* D5 */
  { INZ, INZ, INZ, OUT0, OUT1 }, /* D6 */
  { INZ, INZ, INZ, OUT1, OUT0 }, /* D7 */
  { OUT0, INZ, OUT1, INZ, INZ }, /* D8 */
  { OUT1, INZ, OUT0, INZ, INZ }, /* D9 */
  { INZ, INZ, OUT0, INZ, OUT1 }, /* D10 */
  { INZ, INZ, OUT1, INZ, OUT0 }, /* D11 */
  { INZ, OUT0, INZ, OUT1, INZ }, /* D12 */
  { INZ, OUT1, INZ, OUT0, INZ }, /* D13 */
  { OUT0, INZ, INZ, INZ, OUT1 }, /* D14 */
  { OUT1, INZ, INZ, INZ, OUT0 }  /* D15 */
};

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.

void gereLED(int num)
{
    if (etatLED[num] == ALLUME) {
        programmeBroche(8,etatSortiePourLED[num][0]);
        programmeBroche(9,etatSortiePourLED[num][1]);
        programmeBroche(10,etatSortiePourLED[num][2]);
        programmeBroche(11,etatSortiePourLED[num][3]);
        programmeBroche(12,etatSortiePourLED[num][4]);
    }
    else {
        programmeBroche(8,INZ);
        programmeBroche(9,INZ);
        programmeBroche(10,INZ);
        programmeBroche(11,INZ);
        programmeBroche(12,INZ);
    }
}

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.

void loop()
{
    compteurGestionServos++;
    
    if (compteurGestionServos == 5) {
        
        compteurGestionServos = 0;

        ...
        /* code de gestion des servos et des poussoir à l'identique */
        ...      
    }
  
    gereLED(numLED);
 
    numLED++;
    if (numLED == 16)
        numLED = 0;
  
    delay(1);
}

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).

void evenementServo()
{
    cptArret = -1;
    switch (etatServo) {
      case SERVO_A_ANGLE_MIN:
        etatLED[numServo * 2] = ETEINT;
        objetServo.attach(pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
        vitesse =  1;
        etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
        break;
      case SERVO_A_ANGLE_MAX:
        etatLED[numServo * 2 + 1] = ETEINT;
        objetServo.attach(pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
        vitesse = -1;
        etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
        break;
    }
}

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 :

if (! reglageEnCours ||
    etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN ||
    etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) {
    if (angle > angleMax) {
        angle = angleMax;
        arreteServo();
        etatServo = SERVO_A_ANGLE_MAX;
        etatLED[numServo * 2 + 1] = ALLUME;
    }
    else if (angle < angleMin) {
        angle = angleMin;
        arreteServo();
        etatServo = SERVO_A_ANGLE_MIN;
        etatLED[numServo * 2] = ALLUME;
    }
}

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

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

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

Sketch de l’application complète
mis à jour en version 1.1. La position des servos est désormais mémorisée dans l’EEPROM.
Dessin du montage complet
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
Dessin du montage complet à télécharger en PDF
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

[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

Messages

  • 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

    • 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.

    • 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

    • Je vous propose de continuer par mail. Envoyer moi votre adresse email via le formulaire de contact : Jean-Luc

  • Bonjour et un grand bravo pour votre page, je débute avec l’arduino j’ai une question , est t’il possible de rajouter en plus une commande pour des relais , afin de changer le pole sur les cœurs de pointe .

    et encore un grand merci a vous .

  • bonjour jean-luc.

    je suis un Papi de 73 ans qui remonte un réseau pour se petits enfants et pour mon plaisir aussi.
    Je vous écrit pour vous demander ou des conseils ou un coup de main.J’ai une quinzaine d’aiguillages à faire fonctionner à partir d’un TCO et- votre article m’a interpellé à tel point que j’ai modifié toutes les aiguilles Jouef en supprimant les moteurs de façon à aller jusqu’au bout.
    J’ai reproduit le montage que vous avez mis en ligne "8 servomoteurs commandés par ARDUINO."
    Je pense avoir calqué l’image FRITZING convenablement en mettant le bon matos, les bonnes résistances dans la mesure où la résolution me permettait de lire convenablement les couleurs,-toutes à 5%_, j’ai lancé le programme qui se téléverse très bien, mais..........
    Rien ne fonctionne.
    Pour les diodes, c’est Noël tout est allumé et si j’appuie sur les BP, rien ne se passe.
    J’ai démonté, remonté plusieurs fois, rien à faire c’est toujours pareil. Rien, oualou, nada, bernique ! C’a m’énerve.........
    Je suis mécanicien, ne suis ni électronicien et encore moins informaticien programmeur. alors, comme les Shadok,, je pompe, je soude et c’est tout. Ca marche ou ça marche pas . Là, ça veut pas marcher.
    S’il vous plait, si vous pouviez m’expliquer où ça pèche, je bien voudrai voir avancer ce projet. je ne peut rien faire d’autre sans avoir installé les ARDUINO et le PCB sous la table.
    J’ai pris le schéma FRITZING sur le site "etrain.fr" :
    http://forum.e-train.fr/viewtopic.php?f=63&t=74560&start=45
    Merci d’avance

    Bernard Francis

    Voir en ligne : Manœuvre des aiguilles en analogique avec des servo-moteurs

    • Bonjour,

      Difficile de répondre à distance.

      Toutefois, pour comprendre et être à même de détecter les erreurs je ne saurais que trop vous conseiller de prendre la série d’articles à partir du début et de cheminer du moins complexe au plus complexe. Mon but n’a jamais été de proposer une solution clé en main mais au contraire d’exposer le plus pédagogiquement possible le processus de développement de cette application. À la fin vous aurez appris des choses, ce qui est l’activité la plus satisfaisante au monde (ou qui devrait l’être).

      Cordialement.

    • Bonsoir,

      Merci pour votre réponse. je vais faire ce que vous me conseillez et je verrai bien ce dont je serai capable.

      Bonne soirée

      BFC

  • Bonjour, mon fils, passionné de modelisme ferroviaire et de train, voudrait faire un réseau(petit). J’aimerais utiliser votre montage à 8 servo. Dans le schema que vous donnez je ne reconnais pas le composé branche sur les pin A2 A3 A4 A5. Pourriez vous m’éclairer svp ? Merci beaucoup d’avance. Cordialement.

Un message, un commentaire ?

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)