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.
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.
Ainsi qu’une vidéo de démonstration.
Messages
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
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 ServoPour de nouveau l’asservir, il faut rappeler
attach()
Bien cordialement.
23 janvier 2014, 13:41
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
23 janvier 2014, 13:46, par Jean-Luc
Je vous propose de continuer par mail. Envoyer moi votre adresse email via le formulaire de contact : Jean-Luc
31 janvier 2018, 16:43, par Beersaerts Hervé
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 .
1er février 2018, 09:58, par Jean-Luc
Bonjour.
Oui c’est possible mais pas sur un Uno en conservant 8 servos car il n’y a plus de broches disponibles. Soit il faut passer sur un Mega, soit il fait mettre une paire d’interrupteurs de fin de course comme ici « Actionneurs à servo-moteurs, Conception et mise en œuvre ».
14 mai 2019, 18:40, par goupil_3651
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
15 mai 2019, 08:33, par Jean-Luc
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.
17 mai 2019, 18:00, par goupil_3651
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
6 avril 2020, 12:35, par Eric
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.
6 avril 2020, 15:51, par Jean-Luc
Bonjour,
Il s’agit d’un DIP-switch, exemple : https://www.gotronic.fr/art-dip-switch-ds04-4346.htm
Cordialement