1/160 - Echelle N

Le Forum consacré à l'Echelle N
 
AccueilAccueil  PortailPortail  ÉvènementsÉvènements  Dernières imagesDernières images  S'enregistrerS'enregistrer  Connexion  
N'hésitez pas à consulter le calendrier et les événements du forum pour voir les manifestations près de chez vous !
Le Deal du moment :
Cdiscount : -30€ dès 300€ ...
Voir le deal
Le Deal du moment :
Cdiscount : -30€ dès 300€ ...
Voir le deal

 

 Décodeur accessoire DCC/analogique universel

Aller en bas 
+3
jlb
pilate68
Trusty
7 participants
Aller à la page : 1, 2, 3, 4, 5, 6, 7  Suivant
AuteurMessage
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 12:59

Le titre est accrocheur, parce que même si la volonté y est, le projet est ambitieux Smile ! Malgré tout, je vais tenter de vous expliquer à quoi je suis arrivé pour le moment.

Je vous propose un montage matériel/logiciel basé sur l'Arduino pour fabriquer un décodeur universel d'accessoires. Etant moi même une bille en électronique, je n'ai fait qu'agglomérer les circuits et développements faits par d'autres ! L'avantage de la méthode Arduino est le coût, moins élevé que les décodeurs du commerce... Mais il faut quand même y passer un peu de temps. Je vous expose ici le fruit de mes réflexions, recherches sur le net et discussions menées ici même, mais je peux me tromper, et je ne demande pas mieux que d'apprendre, alors si quelque chose vous choque, n'hésitez pas à me le faire savoir.

Il y a deux parties pour mon projet : le décodage du DCC et l'activation des accessoires. Chaque partie comporte un volet matériel essentiellement électronique, et un volet logiciel sur l'Arduino.

La première chose à avoir est bien sûr un Arduino. Pour ma part, j'ai trouvé un Arduino Mega2560 autour de 10€ sur la toile. C'est un compatible asiatique (rappellons que ce n'est pas interdit puisque l'Arduino est Open Source...), mais il marche bien...

1) Décodage
1.1) Logiciel

Je commence par le logiciel parce que c'est ce qui va conditionner le côté matériel ensuite. J'ai utilisé la librairie écrite par Kevin Snow et mise à disposition sur son site Mynabay.com . C'est gratuit et libre de droits.

1.2) Matériel

Mynabay aussi fournit le schéma d'un petit circuit électronique basé sur un Opto coupleur qui permet, si j'ai bien tout compris, de séparer physiquement le courant venant des rails de la partie Arduino. Une sécurité quoi... Je l'ai réalisé pour moins de 10€.

2) Accessoires
2.1) Matériel

Là, c'est plutôt le matériel qui va conditionner le logiciel. En effet, selon ce que vous voulez commander, il faudra trouver une compensation au manque de puissance de l'Arduino, même Méga. S'il n'y a que quelques diodes basse puissance ou de petits servos à alimenter, l'Arduino peut suffire. Il faut malgré tout bien calculer son coup, sous peine de voir le Micro-contrôleur partir en fumée ! Si plus de puissance est nécessaire, il y a plusieurs possibilités. Le principe de base reste le même, une alimentation extérieure assez puissante est dirigée vers les appareils à piloter via un dispositif dont la commutation est commandée par l'Arduino. On peut utiliser des relais, des transistors, ou des H Bridges qui ne sont que des assemblages de transistors.
Il faut aussi faire avec la variété de dispositifs à contrôler. Courant en continu comme une led ou un moteur tournant, courant intermittent comme un dételeur ou un aiguillage à solénoïde... Avec un peu de puissance pour une diode, un petit servo, un petit moteur, ou avec beaucoup de puissance pour un gros moteur, un aiguillage imposant comme le cross boarding de Kato qui comprend quatre solénoïdes... Il y a aussi les moteurs d'aiguillage trois fils, et les moteurs type Kato qui réclament deux fils alimentés un coup en + / -, et l'autre coup en - / + ! C'est ce que permet le H-bridge. Comme j'ai prévu d'équiper un module T-Trak avec entre-autres des aiguillages Kato, c'est ce que j'ai utilisé.

J'ai identifié cinq méthodes différentes pour alimenter mes accessoires:

- A tout seigneur, tout honneur, par l'Arduino! C'est le plus simple, et il n'y pas de matériel complémentaire, mais le nombre et la puissance sont limités.

- Avec un shield 293D. C'est disponible sur la toile pour moins de dix euros, ça peut commander quatres moteurs DC en PWM, ou deux servos et quatres moteurs DC. La puissance est limitée à 0,6A par canal, et ce n'est pas chainable. Sur un Arduino classique, c'est donc limité définitivement à quatre actionneurs. De plus, le shield ne renvoie pas de place disponible pour d'autres dispositifs, il n'y a pas de connecteurs pour un autre shield au dessus. Enfin tous les canaux PWM sont pris par le shield...
Sur le Méga, seuls des pins analogiques et digitales restent dispos pour d'autres applications.

- Avec un montage à base de L298N. C'est un petit circuit trouvé sur la toile à moins de 8 euros. Deux moteurs DC sont pilotables, avec 2A Maxi pour chacun. Chaque moteur réclame deux pins digitales pour se mettre en route. Ce qui fait un vingtaine de moteurs pilotables sur un Méga !

- Avec des relais. Les barres de relais sont disponibles par un, deux, quatre ou huit et tout à moins de dix euros !
Le relais est bruyant, mais il assure une transmission de puissance bien supérieure à ce que permettent les H Bridges...

- Avec des transistors. Un transistor n'est rien d'autre qu'un relais dans un petit boitier électronique. Si le fonctionnement est un petit peu différent, le principe est le même. L'inconvénient majeur du transistor, c'est son manque de puissance pour un prix raisonnable... N'ayant pas de transistor sous la main, je n'ai pas testé/codé cette partie.

La vraie alimentation externe dont je me suis servi est issue de récupération d'alimentations de vieux portables qui délivrent 12 à 24v sous 1 à 12A selon le modèle. Il y en a même dont le voltage est réglable !

2.2) Le logiciel

2.2.a) Le Cahier des charges

- Simplicité de programmation. Le but est qu'un utilisateur de ma librairie n'ai pas besoin d'y toucher. Il lui suffit d'une partie déclarative pour décrire ses accessoires, d'une partie setup pour initialiser tout ça, et d'une loop() la plus réduite possible.

- Compacité. Autant que faire se peut, il doit être possible d'utiliser de petits Arduino dotés de 32Ko de mémoire programme.

- Facilité de maintenance. La librairie doit intégrer tout le nécessaire pour débugguer aussi facilement que possible.

- Extensibilité. Bien sûr, je n'ai codé que les classes que je pouvais tester. Il y a sans doute d'autres accessoires auquel je n'ai pas pensé, et d'autre alimentations possibles. Il faut que l'utilisateur puisse se coder cela.

2.2.b) Les moyens

Coder un projet un peu important avec l'outil Arduino ne m'a pas paru possible. Bien sûr, dans mon jeune temps, faute d'outil évolué et comme tout le monde à l'époque, j'ai développé sur un simple éditeur de texte et compilé via la ligne de commande. Mais les outils modernes nous ont donné d'autres habitudes et d'autres exigences. Comme je dispose de Visual Studio 2012, j'ai trouvé un addin adapté à l'Arduino, Visual Micro, gratuit en essai. Il permet aussi de débugguer, mais je n'ai pas réussi à le faire fonctionner pour ça... Parmi les autres outils que j'avais évalué, seul MariaMole se détachait du lot et permettait vraiment de travailler.
D'autres n'ont pas réussi à générer quelque chose de correct, comme CodeBlocks ou Xamarin...
Bref, j'ai utilisé Visual Studio 2012 avec Visual Micro. Peut être que c'est possible d'utiliser Visual Studio Express qui est gratuit, mais je n'ai pas essayé...
Pour ceux qui voudraient lire mon code, je m'excuse par avance de l'usage immodéré et exclusif de l'anglais. C'est une habitude professionnelle, et une simplification pour moi. Au revoir les accents, les longues descriptions, les noms à rallonge. L'anglais est concis, sans fioriture, efficace. Amis poêtes, passez votre chemin !

2.2.c) Le modèle objet

Le programme principal et les libraries sont codés en C et C++ . J'ai utilisé abondamment le C++ pour hiérarchiser mes classes et décrire le monde... Pour ceux qui ne le savent pas, le C++ permet de créer des objets qui vont interragir entre eux via des fonctions. Il y a une partie déclarative, qui décrit à quoi ressemble un objet et ce qu'il est capable de faire, et une partie executive qui décrit les comportements voulus pour cet objet.

La première étape c'est l'abstraction.

2.2.c.1) Les accessoires

Accessory
AccessoryLight
AccessoryLightDriver
AccessoryMotor
AccessoryMotorOneWay
AccessoryMotorTwoWays

Un Accessory, c'est au sens large un accessoire. C'est divisé pour l'instant en deux groupes: les éclairages (AccessoryLight) et les actionneurs (AccessoryMotor).
Dans le cas des éclairages, fixes ou clignotants, il y a qu'une version simple commandée par ce que j'ai appelé des Drivers, c'est à dire des commutateurs d'alimentation, comme cité plus haut.
Du côté des moteurs, j'ai pour l'instant découpé le monde est deux groupes : les moteurs qui ne tournent que dans un sens, comme un moteur d'un moulin à vent ou à eau, ou un dételeur... Les moteurs bi-directionnels, c'est à dire tout les autres ! Cela inclus les aiguillages, les plaques tournantes, et j'en oublie sans doute... Il y a aussi les servos, mais pour l'instant, je n'ai pas créé la classe. Sans doute une dérivation supplémentaire du moteur bi-directionnel.

2.2.c.2) Les drivers

Driver
DriverArduino
DriverL293n
DriverL298d
DriverRelay
DriverPort
DriverPortArduino
DriverPortL293n
DriverPortL298d
DriverPortRelay

Le driver est l'interface, le shield, l'Arduino ou le composant de circuit électronique qui va piloter un ou plusieurs accessoires. Il est doté de ports, c'est à dire d'endroits possibles où brancher un moteur ou une lumière. Par exemple sur le shield L293d, il y a quatres ports disponibles. Sur la carte L298d, il n'y en a que deux. Tandis que les cartes de relais vont de un à huit, et peut être plus... C'est aussi le driver qui recevra l'alimentation extérieure qui va donner la puissance aux accessoires. Comme je l'ai dit plus haut, il y a d'autre types de drivers possibles que je n'ai pas encore codé, comme les transistors, et aussi d'autres H bridges peut être plus puissants... C'est ouvert. Il suffit de dériver Driver, puis de dériver DriverPort, et d'associer les deux grâce au constructeur du driver.

2.2.c.3) Les groupes

L'idée du groupe (AccessoryGroup), c'est de rassembler plusieurs accessoires et de les piloter ensembles. Il y a deux cas que me viennent à l'esprit.
Le premier est un feu de signalisation simple avec juste rouge et vert. Chaque led est un accessoire (AccessoryLightDriver) piloté par une broche de l'Arduino (DriverArduino, pin 52 et 54 par exemple), et la combinaison des leds pour former un motif précis (rouge fixe + vert clignotant par exemple) constitue un état du groupe. Un autre état serait le rouge seul, un autre le vert seul... La somme des états forme le groupe. Le programme n'a plus qu'à demander de passer à un état particulier, le groupe va se charger d'activer ce qui doit l'être, et d'éteindre le reste.
Le second exemple est le double crossing de Kato, un gros croisement formé par quatre aiguillages. Il y a donc quatre moteur à piloter, environ 2A, ce que tous les Driver à base de transistor ou de H bridge ne peuvent pas faire. Il faut donc séparer les moteurs et les cabler deux par deux. Ainsi un Driver L293d pourra les actionner séquentiellement. Pas ensemble, sinon l'appel de puissance sera trop important. On a donc deux accessoires (AccessoryMotorTwoWays, chacun pilotant deux moteurs, mais c'est le cablage qui s'en occupe), pilotés par un DriverL293d. Le groupe comprend deux états, un pour la position droite des aiguillages, l'autre pour la position déviée. Lors du changement d'état, le groupe doit d'abord activer un accessoire, puis lorsqu'il a fini, activer l'autre. Ainsi pas trop de dépense d'énergie.

La suite au prochain épisode !
Revenir en haut Aller en bas
http://www.lapajaparis.net
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 15:32

Le code Arduino est .
Revenir en haut Aller en bas
http://www.lapajaparis.net
pilate68
Membre
Membre
pilate68


Masculin Age : 66
Localisation : Campagnan (34)
Nombre de messages : 270
Date d'inscription : 14/07/2013

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 15:44

Salut Trusty

Ton lien ne fonctionne pas.
Revenir en haut Aller en bas
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 16:08

Bonjour Trusty,

Projet intéressant. Je vais regarder plus en détails plus tard.

Une petite question : dans l'archive, il y a un dossier UAD avec, entre autres, deux fichiers à l'intérieur : arduino.h et Arduino.cpp

Quel est leur rôle ?
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 16:53

UAD (la version courte de Universal Accessory Decoder), c'est le projet Visual Studio qui me permet de tester le code sans l'envoyer à l'Arduino ! Les deux fichiers que tu cites sont là juste pour que le code se compile. Il suffit ensuite d'avoir un main UAD.cpp qui fait grosso modo ce que fait un .ino .
Revenir en haut Aller en bas
http://www.lapajaparis.net
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 20 Avr 2014 - 17:06

Ok, compris Smile Je me demandais pourquoi tu dupliquais des entêtes
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
sam95
Membre
Membre



Masculin Age : 43
Localisation : Ermont, 95
Nombre de messages : 1396
Date d'inscription : 29/11/2009

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeSam 26 Avr 2014 - 14:21

Hélas je n'ais pas compris grand chose mais ça me semble super intéressant. J'attend la suite !
Revenir en haut Aller en bas
http://sam95.fr/
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 12:33

Ce qu'il faut retenir à cette étape, est que si tu te sers des drivers que j'ai déjà codé, le L293D, Le L298N , les relais ou l'Arduino lui même, tu n'a rien d'autre à faire que créer un .ino adapté à ce que tu veux piloter, sur le modèle de celui fournit dans le zip.
Revenir en haut Aller en bas
http://www.lapajaparis.net
sam95
Membre
Membre



Masculin Age : 43
Localisation : Ermont, 95
Nombre de messages : 1396
Date d'inscription : 29/11/2009

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 15:37

Les infos DCC venant du bus (ou des rails) entrent directement dans l'arduino et celui ci gère ensuite les ordre vers les moteurs d'aiguillages ?
Revenir en haut Aller en bas
http://sam95.fr/
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 16:03

Non, ce n'est pas aussi simple. Il faut réaliser le petit montage très simple proposé par l'auteur de la librairie Dcc que j'ai utilisé sur mynabay.com. C'est lui qui assure la remontée d'information, sans risque pour l'Arduino.
Revenir en haut Aller en bas
http://www.lapajaparis.net
sam95
Membre
Membre



Masculin Age : 43
Localisation : Ermont, 95
Nombre de messages : 1396
Date d'inscription : 29/11/2009

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 17:09

Ok merci ce montage je l'ai compris !!

Par contre pourquoi faut il impérativement un shield pour piloter des servos ? En effet j'ai vue ça sur le net:
http://modelleisenbahn.triskell.org/spip.php?article60

Et les servo sont directement sur des sorties de l'arduino
Revenir en haut Aller en bas
http://sam95.fr/
pilate68
Membre
Membre
pilate68


Masculin Age : 66
Localisation : Campagnan (34)
Nombre de messages : 270
Date d'inscription : 14/07/2013

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 17:23

Si tu veux alimenter 4 ou 5 servos, l'alimentation de l'arduino devrait tenir le choc. Au-delà, rien n'est moins sur.
Revenir en haut Aller en bas
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 17:25

Comme je le disais,
Trusty a écrit:
des drivers que j'ai déjà codé, le L293D, Le L298N , les relais ou l'Arduino lui même ...
, L'Arduino lui même peut être un driver. Un shield n'est pas nécessaire. Par contre la puissance est très limitée. D’ailleurs il le dit dans sa vidéo, son régulateur de tension a sauté par la faute d'une consommation excessive... D'autre part, je n'ai pas encore codé la partie Servo. Je m'inspirerais peut être de ton lien pour le faire...
Revenir en haut Aller en bas
http://www.lapajaparis.net
sam95
Membre
Membre



Masculin Age : 43
Localisation : Ermont, 95
Nombre de messages : 1396
Date d'inscription : 29/11/2009

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 17:32

ok c'est dur dur de ne rien connaitre en programmation et électronique et pourtant de vouloir s'y mettre.
Revenir en haut Aller en bas
http://sam95.fr/
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 18:22

Oui mais justement, on est tous là pour aider les autres, chacun à l'aune de ses capacités ! Je suis une quiche en décor, d'ailleurs aucun de mes modules n'est décoré, mais je compte sur vous pour m'aider quand je me lancerais ! En attendant, je peux aider ceux qui le souhaitent à réaliser leur décodeur Dcc par Arduino.
Revenir en haut Aller en bas
http://www.lapajaparis.net
sam95
Membre
Membre



Masculin Age : 43
Localisation : Ermont, 95
Nombre de messages : 1396
Date d'inscription : 29/11/2009

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 19:06

Je vais chercher un arduino mega pour commencer alors.
Revenir en haut Aller en bas
http://sam95.fr/
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeDim 27 Avr 2014 - 19:36

Bonsoir,

Effectivement on peut alimenter quelques servos directement avec l'Arduino à condition que ce soit des micro-servos qui consomment peu. Le régulateur de tension est protégé contre une consommation excessive et coupe en cas de surcharge. Il n'y donc a pas de risque.

@Trusty :

Concernant le code de pilotage des servos que j'ai publié, il n'y aucun problème à le réutiliser. C'est une conception objet. Il est publié sous licence GPL v2
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 8:40

Bonjour Trusty

J'ai survolé ton code et il ne me semble pas que tu aies prévu d'appeler à intervalles de temps réguliers un accessoire entre le moment où tu le démarres et le moment où tu l'arrêtes (ou alors j'ai pas vu). Si on veut permettre piloter un servo-moteur avec un mouvement lent, il faut prévoir cela.


Dernière édition par jlb le Lun 28 Avr 2014 - 8:54, édité 1 fois
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 8:47

Je pense plutôt déléguer ce travail à la classe servo elle même. Je ne suis pas sûr qu'il y ai un gros besoin pour les autres types d'accessoires... Mais si le besoin s'en fait sentir pourquoi pas ?
Revenir en haut Aller en bas
http://www.lapajaparis.net
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 8:53

Tu veux dire gérer cela dans ActionEnded() ?
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 9:02

Non. Comme on ne peut pas interrompre tout le monde juste pour faire bouger un servo, il faut gérer le temps. Je vois deux solutions, soit via Loop() en vérifiant à chaque passage si on doit faire quelque chose ou pas sur le servo, mais si il y a d'autres accessoires en cours d'activation eux aussi, on va avoir des intervalles de temps irréguliers, et le mouvement ne sera pas fluide. L'autre solution serait d'utiliser un timer unique pour tous les servos, et à chaque tick activer ceux qui le veulent.
C'est pour ça que je n'avais pas encore fait cette partie là, je ne suis pas familier des timers sur l'Arduino...
Revenir en haut Aller en bas
http://www.lapajaparis.net
jlb
Membre
Membre
jlb


Masculin Age : 60
Localisation : Ici
Nombre de messages : 1543
Date d'inscription : 31/12/2011

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 9:12

C'est pas forcément simple d'utiliser les timers de l'Arduino qui sont employés pour d'autres tâches (comptage du temps, PWM, librairie Servo).
Revenir en haut Aller en bas
http://modelleisenbahn.triskell.org
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 11:43

Deuxième partie : explications de texte sur le .ino dont je me sers pour tester et qui est inclus dans le zip... Il y a beaucoup de code superflu, destiné uniquement aux tests, mais le principe reste le même.

J'ai mis en place une petite astuce pour réduire au maximum l'empreinte mémoire du programme final. Selon l'utilisation qui va être faite de la librairie, tous les drivers ne sont pas forcément nécessaires, tous les types d'accessoires non plus. Il y a donc un fichier UniversalAccessoryDecoder.h avec le moyen d'exclure ce qui ne sera pas utilisé. Il suffit de décommenter par exemple la ligne '#define NO_L293D' pour renoncer à ce type de driver et libérer la mémoire programme d'autant.

L'entête réglementaire...
Code:
/*************************************************************
project: <DCC Accessory Decoder>
author: <Thierry PARIS>
description: <Demo and test for library>
*************************************************************/

Ça va me servir à voir la mémoire occupée après setup...
Code:
#include <MemoryFree.h>

Include principal de la librairie
Code:
#include "Accessories.h"

Include de la bibliothèque nécessaire pour le shield L293D. En réalité, je n'en ai pas besoin dans ce source, mais il faut le mettre là si on veut pouvoir l'utiliser ailleurs... On teste sur le define vu plus haut pour savoir s'il faut référencer cette bibliothèque.
Code:
#ifndef NO_L293D
#include <AFMotor.h>
#endif

Idem pour la partie DCC optionnelle.
Code:
#ifndef NO_DCC
#include <DCC_Decoder.h>
#endif

Includes pour les types d'accessoires et de driver dont j'ai besoin ici...
Code:
#include "AccessoryGroup.h"
#include "AccessoryMotorOneWay.h"
#include "AccessoryMotorTwoWays.h"
#include "AccessoryLightDriver.h"
#include "DriverL293d.h"
#include "DriverL298n.h"
#include "DriverRelay.h"

Celui là ne fait pas strictement partie de la librairie, c'est juste un petit codage simple de bouton, pour ne pas réinventer
la poudre à chaque fois...
Code:
#include "PushButton.h"

L'interruption utilisée de base par le decodeur Dcc utilise la pin 2 de l'Arduino, mais cette pin est cachée par le shield L293D que j'utilise pour les tests. Il me faut donc utiliser une spécificité du Mega, et prendre l'interruption 5 qui va utiliser la pin 18.
Code:
#define kDCC_INTERRUPT            5

Là on entre dans la partie déclaration des accessoires.
Code:
// total number of pushbuttons / accessories.
#define AccessoryNumber 9

Numéros des accessoires dans la liste, avec un nom expressif.
Code:
#define TURNOUT_ARNOLD 0
#define DETELEUR 1
#define LIGHT 2
#define TURNOUT1 3
#define TURNOUT2 4
#define TURNOUT_FLEI_RAIL 5
#define DETELEUR2 6
#define TURNOUT3_LEFT 7
#define TURNOUT3_RIGHT 8

Une astuce locale de test. Une matrice de boutons, avec un bouton par accessoire, qui me permet d'activer manuellement l'accessoire et de me passer du Dcc pour tester.
Code:
PushButton buttons[AccessoryNumber];

La liste d'accessoires:
Code:
// Accessories

Accessories accessories;

Un groupe de test
Code:
AccessoryGroup mainGroup;

Deux états d'un groupe d'aiguillages : tous droits, ou tous déviés... Le premier argument est un Id Dcc qui pourrait mettre tous les aiguillages droits ou tous déviés ! Ce n'est pas complètement codé, et pour bien faire il faudrait y associer un état. Le Dcc demande un 'enable' à vrai ou faux pour une adresse donnée, et ici comme je n'ai que l'adresse, je serais obligé d'en utiliser une seconde pour activer le côté dévié. Ce n'est pas trop correct. C'est pourquoi j'ai mis zéro qui dit que le Dcc ne pilote pas ces états. Le second argument dit si l'activation des accessoires contenus dans l'état doit se faire simultanément (true), ou en séquence (false). Pour les besoins du test, j'ai voulu activer les trois aiguillages l'un après l'autre.
Code:
GroupState Straight(0, false);
GroupState Curve(0, false);

Passons maintenant à la déclaration des matériels qui vont alimenter les accessoires : un shield L293D, un petit circuit L298N, et une barre de 4 relais.
Code:
// Drivers

DriverL293d *l293d;
DriverL298n *l298n;
DriverRelay *relay;

Déclaration de la fonction qui va être appelée lorsqu'un signal accessoire Dcc sera détecté.
Code:
void AccessoryDecoderPacket_Handler(int address, boolean activate, byte data);

Prochaine étape, le Setup .


Dernière édition par Trusty le Lun 28 Avr 2014 - 13:23, édité 2 fois
Revenir en haut Aller en bas
http://www.lapajaparis.net
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 12:32

Troisième partie : le setup. C'est le lieu de toutes les déclarations, de tous les démarrages. Ici on va créer les objets, associer les accessoires avec leur driver, donner les éléments au drivers pour savoir comment piloter chaque accessoire.

Voilà la début. Jusque là c'est simple...  Very Happy 
Code:
void setup()
{

Pour commencer, on va mémoriser la mémoire utilisée au départ.
Code:
int mem = freeMemory();

On initialise la liaison série à 9600 bauds pour renvoyer du texte au PC et permettre de debugguer un peu. On initialise aussi le port 13 qui commande une petite diode déjà câblée sur l'Arduino. Toujours pour debugguer, elle peut servir à visualiser l'appui sur un bouton ou l'activation d'un accessoire...
Code:
// Arduino setup
 
Serial.begin(9600);

 pinMode(13, OUTPUT);

Dans la deuxième partie, j'expliquais que l'on pouvait activer ou désactiver certaines parties du code. Cela concerne aussi la partie débugage. Ce mode debug permet deux choses : tester la validité des arguments passés aux fonctions, comme la vérification du numéro de l'accessoire ou du numéro du port demandé, et l'envoi d'informations au PC au fur et à mesure de l'exécution. Comme on peut le comprendre aisément tout ça utilise beaucoup de mémoire programme pour stocker les nombreuses chaines de caractères. D'autre part, le traitement est fortement ralenti par la liaison série qui est lente par nature. J'aurai pu utiliser 115200 bauds au lieu de 9600, mais je ne voulais pas devoir reconfigurer ma fenêtre de réception de Visual à chaque exécution... En effet Visual Micro, qui assure cette partie moniteur série, se remet systématiquement à 9600... Je vous conseille fortement d'activer le mode Debug tant que la vitesse n'est pas un problème, et tant que vous n'êtes pas en production. C'est un moyen simple de comprendre ce qui se passe et éviter les mauvaises surprises.
Code:
#ifdef DEBUG_MODE
 Serial.println(F("Setup started."));
#endif

Voici l'initialisation des drivers. Chaque driver possède un nombre de port qui lui est propre, souvent fixe. L'appel au Setup du driver va créer les ports nécessaires et les mettre dans une liste. Le cas du relais est différent, parce que je n'ai pas fait une dérivation pour des barres avec plus ou moins de relais, j'ai juste ajouté un argument au setup pour fixer le nombre de ports. Le mien en comprend quatre, mais j'en ai vu de 1 à 16... Ensuite il faut initialiser chaque port individuellement. Les arguments sont différents selon le driver. Ainsi un L293D va réclamer une fréquence liée à la librairie AFMotor que l'on a référencé plus haut, le L298N a besoin de deux pins Arduino, tandis qu'un port relais n'en a besoin que d'un.
Code:
// Drivers setups

 l293d = new DriverL293d();
 l293d->Setup();
 l293d->SetupPort(L293D_PORT_M1, MOTOR12_1KHZ); //TURNOUT_ARNOLD
 l293d->SetupPort(L293D_PORT_M2, MOTOR12_1KHZ); //DETELEUR
 l293d->SetupPort(L293D_PORT_M3, MOTOR34_1KHZ); //
 l293d->SetupPort(L293D_PORT_M4, MOTOR34_1KHZ); //TURNOUT1
 
l298n = new DriverL298n();
 l298n->Setup();
 l298n->SetupPort(L298N_PORT_OUT1, 24, 25); //TURNOUT2
 l298n->SetupPort(L298N_PORT_OUT2, 32, 33); //TURNOUT_FLEI_RAIL

 relay = new DriverRelay(4);
 relay->Setup();
 relay->SetupPort(0, 52);
 relay->SetupPort(1, 51);
 relay->SetupPort(2, 53);
 relay->SetupPort(3, 49);

Comme je l'ai dit dans la deuxième partie, j'ai ajouté une liste de boutons, un par accessoire, pour pouvoir les piloter manuellement. L'indice est le même, ce qui signifie par exemple que l'activation du bouton 3 activera l'accessoire 3... Il faut assigner un pin à chaque bouton. Notez l'usage des define vus plus tôt, plutôt que de simples numéros toujours confusants et dangereux...
Code:
// Buttons setups

 buttons[TURNOUT_ARNOLD].Setup(40);
 buttons[DETELEUR].Setup(42);
 buttons[LIGHT].Setup(44);
 buttons[TURNOUT1].Setup(46);
 buttons[TURNOUT2].Setup(48);
 buttons[TURNOUT_FLEI_RAIL].Setup(50);
 buttons[DETELEUR2].Setup(36);
 buttons[TURNOUT3_LEFT].Setup(37);
 buttons[TURNOUT3_RIGHT].Setup(38);

Enfin, la déclaration des accessoires. On va définir le fonctionnement, les durées, les options éventuelles de chacun. Attention, il est important de pousser les accessoires dans la liste principale dans le bon ordre ! D'où le commentaire à la fin de chaque ligne qui n'est là que pour s'assurer du bon placement de chacun. Les constructeurs d'accessoires appelés ici ont tous les mêmes arguments. On commence par l'identifiant Dcc, puis vient la durée de fonctionnement en millisecondes. AccessoryLightDriver utilise un peu différemment l'argument de durée. S'il est à zéro, sa valeur par défaut, la lumière sera allumée en permanence. Si ce n'est pas zéro, alors c'est la durée d'un clignotement !
Code:
// Accessories setups

 accessories.Setup(AccessoryNumber);
 accessories.Add(new AccessoryMotorTwoWays(20, 50)); //TURNOUT_ARNOLD
accessories.Add(new AccessoryMotorOneWay(21, 500)); //DETELEUR
 accessories.Add(new AccessoryLightDriver(22, 1000)); //LIGHT
 accessories.Add(new AccessoryMotorTwoWays(23, 300)); //TURNOUT1
 accessories.Add(new AccessoryMotorTwoWays(24, 300)); //TURNOUT2
 accessories.Add(new AccessoryMotorTwoWays(25, 300)); //TURNOUT_FLEI_RAIL
 accessories.Add(new AccessoryMotorOneWay(51, 500)); //DETELEUR2
 accessories.Add(new AccessoryMotorOneWay(49, 300)); //TURNOUT3_LEFT
 accessories.Add(new AccessoryMotorOneWay(52, 300)); //TURNOUT3_RIGHT

Chaque accessoire est 'piloté' par un port d'un driver. On doit donc les associer. La syntaxe 'MOTOR2WAYS(accessories, TURNOUT_ARNOLD)' est une tentative de simplifier l'écriture de l'accès à un accessoire de la liste. Sans cet bidouille, vous auriez dû (et vous pourriez toujours !) écrire '((AccessoryMotorTwoWays *) accessories[TURNOUT_ARNOLD])'  , que je trouve quand même moins clair... A vous de voir. On dit à chaque accessoire le driver concerné, le numéro du port dans le driver, et la puissance délivrée pour le fonctionnement, entre 0 et 255.
Code:
MOTOR2WAYS(accessories, TURNOUT_ARNOLD)->Setup(l293d, L293D_PORT_M1, 150);
 MOTOR1WAY(accessories, DETELEUR)->Setup(l293d, L293D_PORT_M2, 150);
 LIGHTDRIVER(accessories, LIGHT)->Setup(l293d, L293D_PORT_M3, 255);
 MOTOR2WAYS(accessories, TURNOUT1)->Setup(l293d, L293D_PORT_M4, 150);
 MOTOR2WAYS(accessories, TURNOUT2)->Setup(l298n, L298N_PORT_OUT1, 150);
 MOTOR2WAYS(accessories, TURNOUT_FLEI_RAIL)->Setup(l298n, L298N_PORT_OUT2, 150);
 MOTOR1WAY(accessories, DETELEUR2)->Setup(relay, 1, 255);
 MOTOR1WAY(accessories, TURNOUT3_LEFT)->Setup(relay, 2, 255);
 MOTOR1WAY(accessories, TURNOUT3_RIGHT)->Setup(relay, 3, 255);

Là on va déclarer que le groupe mainGroup comprend deux états Straight et Curve, et que chacun utilise trois accessoires, dans un état déterminé : left pour Straight, right pour Curve. C'est une convention que j'ai prise dès le départ, mais chacun fait comme il veut.
Code:
Straight.Setup(3);
Straight.Add(accessories[TURNOUT1], LEFT);
Straight.Add(accessories[TURNOUT2], LEFT);
Straight.Add(accessories[TURNOUT_FLEI_RAIL], LEFT);

Curve.Setup(3);
Curve.Add(accessories[TURNOUT1], RIGHT);
Curve.Add(accessories[TURNOUT2], RIGHT);
Curve.Add(accessories[TURNOUT_FLEI_RAIL], RIGHT);

mainGroup.Setup(2);
mainGroup.Add(&Straight);
mainGroup.Add(&Curve);

Si le Dcc est activé, alors il faut associer la fonction déclarée plus haut avec la bonne interruption...
Code:
#ifndef NO_DCC
 // DCC Decoder setup
 
DCC.SetBasicAccessoryDecoderPacketHandler(AccessoryDecoderPacket_Handler, true);
 
/* kDCC_INTERRUPT values :
 Board int.0 int.1 int.2 int.3 int.4 int.5
 Uno, Ethernet 2 3
Mega2560 2 3 21 20 19 18
 Leonardo 3 2 0 1 7
 */
 DCC.SetupDecoder(0x00, 0x00, kDCC_INTERRUPT);
#endif

Le setup est terminé. On va le dire au PC, et en même temps lui faire afficher la mémoire consommée. A noter que cela n'inclut pas les déclarations vues à l'étape précédente. Cela ne concerne que les allocations faites pendant le setup...
Code:
#ifdef DEBUG_MODE
 Serial.print(F("Setup Finished. Mem free after :"));
 Serial.println(mem - freeMemory());
#endif
}
Revenir en haut Aller en bas
http://www.lapajaparis.net
Trusty
Membre
Membre
Trusty


Masculin Age : 61
Localisation : Melun
Nombre de messages : 942
Date d'inscription : 08/10/2012

Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitimeLun 28 Avr 2014 - 13:12

Quatrième partie, la fonction Loop(). Tout a été simplifié pour diminuer au maximum le besoin de codage. La grosse partie concerne surtout la gestion des boutons et leur effet.

Code:

void loop()
{

On va maintenant regarder si l'état d'un bouton poussoir a changé, et si c'est le cas activer l'accessoire correspondant.
Code:

for (int i = 0; i < AccessoryNumber; i++)
{
if (buttons[i].Loop())
{
if (buttons[i].GetState() == LOW)
{

Ça a changé ! On affiche une notification sur le moniteur série et on fait le boulot... Ce boulot est différent selon l'accessoire. Pour un moteur à deux directions (TwoWays) on va changer le sens et le mettre en route (MoveToggle). Si c'est un moteur à une seule direction (OneWay) on va faire pareil, sachant que le Left et le Right feront la même chose, c'est à dire activer le moteur pour la durée prévue. En clair sur le dételeur, on va l'activer pendant une seconde à chaque appui sur son bouton. Enfin pour les lumières, l'appui va changer l'état, c'est à dire allumer ou éteindre (Toggle).
Code:

#ifdef DEBUG_MODE
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
Serial.print(F("Accessory nb "));
Serial.print(i);
Serial.println(F(" moved by its button !"));
#endif
#ifndef NO_MOTOR
if (accessories[i]->GetType() == ACCESSORYMOTOR)
((AccessoryMotor *)(accessories[i]))->MoveToggle();
#endif
#ifndef NO_LIGHT
if (accessories[i]->GetType() == ACCESSORYLIGHT)
((AccessoryLight *)(accessories[i]))->Toggle();
#endif

Là le codage pour l'action des boutons sur le groupe d'accessoire. Cette partie du codage n'est activée qu'à l'occasion. Comme elle ne peut cohabiter avec l'activation d'accessoires simples, elle est commentée.
Code:
/* if(!mainGroup.IsActionPending())
 mainGroup.CurrentState = 0;
 else
 {
 mainGroup.CurrentState ++;
 if( mainGroup.CurrentState > 1)
 mainGroup.CurrentState = 0;
 }
 mainGroup.StartAction(mainGroup.CurrentState);
*/ }
 }
 }

Si du Dcc est utilisé, faire sa loop !
Code:
#ifndef NO_DCC
 DCC.loop();
#endif

Le mode démo est une activation brutale et séquentielle de tous les accessoires raccordés... En remarque ici.
Code:
//ModeDemo();

Enfin les loop des accessoires et du groupe. Ces boucles vont se débrouiller pour gérer ce qu'il y a à gérer.
Code:

 accessories.Loop();

 mainGroup.Loop();
}

On a là la fonction d'interruption Dcc, qui est appelée lorsqu'un signal Dcc accessoire est reçu. Elle est presque conforme à ce que fournit mynabay dans son exemple. J'ai juste expédié l'interprétation de l'adresse et du type d'activation dans sa lirairie plutôt que de laisser ce calcul abscons ici... La version modifiée de la librairie est . Hormis ce détail, on compare juste l'adresse avec celle des accessoires dans la liste, et si on la trouve, on fait le taf ! La petite différence avec la gestion des boutons est que là je respecte ce que demande la centrale via 'enable'.
Code:

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

//////
//
// Basic accessory packet handler
//
#ifndef NO_DCC
void AccessoryDecoderPacket_Handler(int address, boolean activate, byte data)
{
 address = DCC_Decoder::GetAddress(address, data);
 boolean enable = DCC_Decoder::IsEnabled(data);

#ifdef DEBUG_MODE
 Serial.print(F("Basic addr: "));
 Serial.print(address);
 Serial.print(F("   activate: "));
 Serial.println(enable, DEC);
#endif

 for (int i = 0; i < AccessoryNumber; i++)
 if (accessories[i]->GetId() == address)
 {
#ifdef DEBUG_MODE
 Serial.print(F("Accessory "));
 Serial.print(i);
 Serial.print(F(" activated "));
 Serial.println(enable, DEC);
#endif
#ifndef NO_MOTOR
 if (accessories[i]->GetType() == ACCESSORYMOTOR)
 {
 if (enable)
 ((AccessoryMotor *)(accessories[i]))->MoveLeft();
 else
 ((AccessoryMotor *)(accessories[i]))->MoveRight();
 }
#endif
#ifndef NO_LIGHT
 if (accessories[i]->GetType() == ACCESSORYLIGHT)
 {
 ((AccessoryLight *)(accessories[i]))->SetState(enable ? LIGHTON : LIGHTOFF);
 }
#endif
 }
}
#endif

Et pour finir, la fonction brutale de demo, qui balaie les accessoires et change leur état toutes les trois secondes. Notez juste que j'aurais pu utiliser ma notation 'simplifiée' d'accès aux accessoires, mais comme je l'ai codé avant, je n'ai pas fait le changement !
Code:
int counterDemo = 0;
unsigned long timerDemo = 0;

void ModeDemo()
{
 // if last action not finished
 if (millis() - timerDemo < 3000)
 return;

 // restart from begginning if necessary
 if (counterDemo >= AccessoryNumber)
 counterDemo = 0;

 switch(accessories[counterDemo]->GetType())
 {
 case ACCESSORYMOTOR:
 ((AccessoryMotor *)(accessories[counterDemo]))->MoveToggle();
 break;

 case ACCESSORYLIGHT:
 ((AccessoryLight *)(accessories[counterDemo]))->Toggle();
 break;
 }

 timerDemo = millis();
 counterDemo++;
}

Voilà pour la partie utile du programme. J'espère ne pas vous avoir trop barbés, et si vous avez des questions, le post est là pour ça ! Un prochain post (mais pas aujourd'hui, j'ai le bout des doigts qui brulent...) vous décrira un .ino beaucoup plus simple : celui que je vais utiliser sur mon module triple (voir ma signature).
Revenir en haut Aller en bas
http://www.lapajaparis.net
Contenu sponsorisé





Décodeur accessoire DCC/analogique universel Empty
MessageSujet: Re: Décodeur accessoire DCC/analogique universel   Décodeur accessoire DCC/analogique universel Icon_minitime

Revenir en haut Aller en bas
 
Décodeur accessoire DCC/analogique universel
Revenir en haut 
Page 1 sur 7Aller à la page : 1, 2, 3, 4, 5, 6, 7  Suivant
 Sujets similaires
-
» Bloc-système universel : Intégral
» [Digikeis] - Décodeur d'accessoire DK50018
» Projet : Décodeur d'accessoires universel DCC
» Test du nouveau décodeur d'accessoire DIGIKEIS DK 50 018
» Produit presque universel

Permission de ce forum:Vous ne pouvez pas répondre aux sujets dans ce forum
1/160 - Echelle N :: Modèles réduits à l'echelle N :: Electricité / Electronique-
Sauter vers: