LOCODUINO

Parlons Arduino => Le logiciel DCC++ => Discussion démarrée par: Thierry le mars 03, 2016, 02:31:09 pm

Titre: DCC++ BaseStation
Posté par: Thierry le mars 03, 2016, 02:31:09 pm
Denis nous a signalé il y a peu de temps l'existence d'une bibliothèque très intéressante pour créer un module de pilotage DCC à partir d'un Arduino: https://github.com/DccPlusPlus/BaseStation . Il faut que tout le monde en profite, alors je porte la discussion sur le Forum.

Ce projet couvre plusieurs domaines:

un générateur de signaux DCC comme le cmdrArduino largement utilisé ici, mais maison, qui traite aussi bien les locos que les accessoires.
un module de commande série permettant d'envoyer des commandes de pilotage via la console série
une extension de tout ça pour gérer aussi des aiguillages en conservant les dernières positions, et des capteurs de toutes sortes.

A noter les vidéos (https://www.youtube.com/channel/UCJmvQx-fe0OMAIH-_g-_rZw (https://www.youtube.com/channel/UCJmvQx-fe0OMAIH-_g-_rZw)) très bien faites (si on comprend l'anglais) sur le DCC en général, et le projet en particulier.

Vu la qualité du discours et des commentaires sur les videos, c'est dommage que le gars soit anglo-saxon, sinon on aurait fait le forcing pour le fairer venir sur Locoduino !
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 03, 2016, 10:32:46 pm
C'est vrai que j'ai eu un choc en voyant ça pour la première fois.
Et je n'avais pas tout vu, juste la partie github...(du 10/01/2016)

Je pense vraiment qu'on a intérêt à creuser, ça paraît prometteur.  ;D
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 04, 2016, 11:39:18 am
Je viens de regarder les premières vidéos (je conseille fortement de les regarder dans l'ordre).
Elles sont extrêmement bien faites (pour qui comprend l'américain, malheureusement).

Disons qu'on se rapproche vraiment de productions commerciales ("gold", pour ne pas citer de marque) :

La première vidéo est assez impressionnante : conduite aléatoire de 6 trains qui ne font donc pas toujours la même chose, ni dans le même ordre.
Et, pour autant, un vrai décor, typiquement américain.
Décor qui fait souvent cruellement défaut à ceux qui s'intéressent à la technique et qui le feront "plus tard"  ;D ;D ;D

1°) On a besoin d'un ordi, souris, clavier pour commander les trains

2°) Suit le programme en processing, assez costaud, pour commander le réseau, les CV sur la voie de programmation, les aiguilles, les circuits pré-enregistrés, ...
C'est bien fait.
Je ne l'ai pas implémenté complètement car il faut implanter d'abord certaines autres bibliothèques java avant. Mais je le ferai, maintenant que je commence à tâter de processing  ;)
Il y a aussi un certain ordre à suivre pour les ouvrir.

3°) Des bibliothèques Arduino pour gérer le DCC. Là, je ne connais pas. Mais tout y est (28 (!) fonctions par loco, 128 crans, ...) et assez costaud pour 6 trains simultanés.

On a même une fonction que je n'avais jamais vu (mais je ne suis pas spécialiste) : affichage, avec graphique historique (!) du courant consommé  :-*

Vraiment un sacré projet, complet. Chapeau l'artiste !
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 05, 2016, 11:48:41 am
J'ai vu toutes les vidéos.
Encore une fonction vraiment pas courante : à l'écran, on choisit la couleur de l'éclairage du réseau, sur un cercle coloré (16 millions de couleurs !)
Et donc, faire le jour, la nuit, les éclairs, l'orage, etc,... n'est qu'un jeu d'enfant.

Il a vraiment pensé à tout !  :-*
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 08, 2016, 10:32:04 pm
En fait ce n'est pas une bibliothèque, c'est carrément un système de pilotage de trains et accessoires en DCC.

Le premier document d'introduction (en anglais) est ici ->https://sites.google.com/site/dccppsite/ (https://sites.google.com/site/dccppsite/)

Sur le plan matériel, on a deux sous-ensemble :

On a donc 2 programmes :

Les liens de téléchargement sont là :

J'avoue que j'ai tout de suite installé le programme DCCpp_UNO sur un MEGA (oui le nom du programme est plutôt mal choisi!!), compilé (il y a juste quelques Warnings sur lesquels on reviendra plus tard), le téléversement se passe bien et un message s'affiche sur le moniteur :

<iDCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD: V-1.2.1+ / Mar  8 2016 21:43:55><N0: SERIAL>

D'après la documentation très complète qui est intégrée au programme, je vois que c'est la pin 12 du MEGA qui délivre le signal DCC. Je branche mon petit oscillo de poche et je vois ce signal immédiatement, avec des créneaux de 50 et 100 microsecondes environ (mon oscillo n'est pas très précis, mais cela suffit).

Donc ça marche !

A suivre...
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 08, 2016, 10:44:24 pm
L'architecture a de quoi intéresser pas mal de monde :



Le code est assez difficile à lire, il faut du temps. Le développeur doit être un expert. Il y a des tonnes de commentaires donc c'est bien ! Mais ses classes C++ ne sont que des structs ! Il perd le bénéfice des données et fonctions protégées.

La génération du DCC est du même type que celui de la première version présentée dans mon premier articles : http://www.locoduino.org/spip.php?article17 (http://www.locoduino.org/spip.php?article17).
Un ensemble de 12 tableaux de bits (sur 10 octets) contiennent des trames prêtes à émettre et une routine sous interruption émet les bits avec des timers. C'est différent de CMDRArduino.
A coté de cela il y a un module de préparation des trames (registres), gestionnaire des "files à émettre", à partir des commandes reçues par la liaison série.

Ce qui est assez simple, c'est que les commandes reçues sous forme de message texte sont directement traduites en série de bits placés dans un registre (le numéro de registre est même dans la commande, il faut donc faire attention !).

Ce qui fait que le programme LOOP ne fait pas grand chose d'autre que :

void loop(){
 
  SerialCommand::process();              // check for, and process, and new serial commands
 
  if(CurrentMonitor::checkTime()){      // if sufficient time has elapsed since last update, check current draw on Main and Program Tracks
    mainMonitor.check();
    progMonitor.check();
  }

  Sensor::check();    // check sensors for activate/de-activate
 
} // loop

Le logiciel semble couvrir toutes les fonctions de la NMRA (du moins c'est à vérifier)

Il y a un beau "parser" de commandes pour piloter la bête.

Il y a surtout, pour les anglophiles, un blog de 46 pages qui commence là :

http://www.trainboard.com/highball/index.php?threads/introducing-dcc-a-complete-open-source-dcc-station-and-interface.84800/ (http://www.trainboard.com/highball/index.php?threads/introducing-dcc-a-complete-open-source-dcc-station-and-interface.84800/)

On y trouve des discussions sur tout un tas d'interfaces de puissances (sauf le LMD18200 mais y compris l'IBT2 à base de double BTS7960 pouvant délivrer 43 ampères). Apparemment on peut faire du DCC de 2 à 5 A avec plein de cartes (shield Arduino pour 2 moteurs, cartes Polulu, etc.. qui coûtent néanmoins plus cher que le LMD18200.

Il y a aussi des tas de discussions sur le logiciel (open source) et les interfaces avec JMRI et autres gestionnaires. C'est très riche.
On a l'impression que ça marche, vu les commentaires des internautes qui l'on mis en oeuvre.

a suivre ....
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 08, 2016, 10:51:55 pm
Je n'ai pas résisté non plus à télécharger et essayer le "Controller" écrit en Processing, dont voici une image ci-dessous.

Mais Denis nous en dira plus sur cette partie ...
Titre: Re : DCC++ BaseStation
Posté par: Thierry le mars 09, 2016, 09:08:30 am
Au delà de la bonne utilisation ou non des structures, j'ai moi aussi jeté un oeil sur le code et je dois dire que c'est bien écrit, clair et très documenté. Il y a de très bonnes idées, mais il reste une syntaxe dans DCCpp_Uno.ino que je n'ai pas comprise (ligne 443) :

  if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8]){
    OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N;
    OCR ## N ## B=DCC_ONE_BIT_PULSE_DURATION_TIMER ## N;
  } else{ /* ELSE it is a ZERO */
    OCR ## N ## A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER ## N;
    OCR ## N ## B=DCC_ZERO_BIT_PULSE_DURATION_TIMER ## N;
} /* END-ELSE */

est-ce que ## est un opérateur ?? J'avoue que je sèche.
A part ça, j'ai commencé à extraire la partie DCC de son code et je vais tenter (à mon rythme, donc pas trop vite...) de le comparer en terme de mémoire consommée à cmrdArduino.
La partie reconnaissance du ACK est aussi très intéressante. Il semble que le LMD18200 ait sa broche 8 qui permette de vérifier la consommation de courant instantanée, comme les broches 1 et 15 du L298N qu'emploie Greg . A creuser.
Pour ce qui est du prix de son montage, il faut voir les contraintes qu'il s'est imposé, c'est à dire aucune soudure, aucun composant autre que l'Arduino et le shield L298N (plutôt coûteux) au dessus... Pour le prix de ce shield, on peut utiliser deux LMD18200 qui rempliront le même rôle !
Titre: Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 09:18:11 am
Citer
mais il reste une syntaxe dans DCCpp_Uno.ino que je n'ai pas comprise (ligne 443) :

if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8]){
  OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N;
  OCR ## N ## B=DCC_ONE_BIT_PULSE_DURATION_TIMER ## N;
} else{ /* ELSE it is a ZERO */
  OCR ## N ## A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER ## N;
  OCR ## N ## B=DCC_ZERO_BIT_PULSE_DURATION_TIMER ## N;
} /* END-ELSE */

est-ce que ## est un opérateur ?? J'avoue que je sèche.

C'est le token de concaténation de macros :

https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html#Concatenation

Donc là, OCR, N, A sont des macros qui sont respectivement expansées et concaténées

DCC_ONE_BIT_TOTAL_DURATION_TIMER (ou DCC_ONE_BIT_PULSE_DURATION_TIMER) et N sont également expansées et concaténées

Le résultat repasse par le préprocesseur pour traitement et éventuelle réexpansion.
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 09, 2016, 11:53:19 am
Moi, j'ai regardé la partie Processing. On est complémentaires.

Le résultat est assez impressionnant, la programmation est propre, très bien documentée.
Cela donne une bonne idée de ce que l'on peut faire avec Processing.

Mais il y a quand même une ombre au tableau.

Analyse de la partie Processing (appellée DCCpp_Controller) :

J'ai trouvé où était décrit le réseau qu'on voit en jaune.   ;D

C'est dans "controllerConfig" (le deuxième onglet) des lignes 371-481 pour le réseau principal.
C'est le tracé en jaune.

Un supplément est fait pour déplacer la partie aérienne (la boucle supérieure) lignes 483-494 parce qu'elle a deux positions (voir les vidéos)
C'est le petit tracé en jaune.

Puis sont décrits les aiguilles (lignes 513-587), avec les différentes positions possibles :
- couleurs jaune (libre)
- vert                  (fait partie d'un circuit)
- rouge               (en mauvaise position pour le circuit considéré)

Puis les circuits pré-enregistrés (lignes 589-1037), avec les boutons elliptiques en bleu en bas à droite

Dit autrement, vous aurez à refaire toutes ces lignes (de 371 à 1037 !!) pour votre propre réseau.
Pas insurmontable, puisqu'on a des modèles, mais assez fastidieux.    :( :(

Il faudrait que je voie comment adapter mon "TCO en Processing" (qui, lui, a un éditeur intégré : tout se fait avec la souris et quelques touches) pour que cette partie soit plus simple à faire. Parce que, là, c'est "en dur" dans le programme !

Il y aurait du travail, mais ça me paraît faisable.  :D

La question est : y-a-t-il un "marché" ?
Dit autrement, qui voudrait que cette interface soit plus facile à adapter à son réseau ?
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 01:39:57 pm
Citer
mais il reste une syntaxe dans DCCpp_Uno.ino que je n'ai pas comprise (ligne 443) :

if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8]){
  OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N;
  OCR ## N ## B=DCC_ONE_BIT_PULSE_DURATION_TIMER ## N;
} else{ /* ELSE it is a ZERO */
  OCR ## N ## A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER ## N;
  OCR ## N ## B=DCC_ZERO_BIT_PULSE_DURATION_TIMER ## N;
} /* END-ELSE */

est-ce que ## est un opérateur ?? J'avoue que je sèche.

C'est le token de concaténation de macros :

https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html#Concatenation

Donc là, OCR, N, A sont des macros qui sont respectivement expansées et concaténées

DCC_ONE_BIT_TOTAL_DURATION_TIMER (ou DCC_ONE_BIT_PULSE_DURATION_TIMER) et N sont également expansées et concaténées

Le résultat repasse par le préprocesseur pour traitement et éventuelle réexpansion.

Comme je ne suis pas encore familier avec ce type de Macros concatenées ou expansées, j'aimerai bien comparer cette écriture au langage C classique sans Macros.

D'ailleurs, dans ce cas, qu'est-ce qu'on gagne avec les Macros ? (Au vin blanc ou à la moutarde ?)

Titre: Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 01:45:45 pm
Si je voulais être caustique, je dirais « le droit de concourir à The International Obfuscated C Code Contest »  http://www.ioccc.org ;D

Plus sérieusement, bien fait ça donne un code (légèrement) plus efficace tout en restant concis. Personnellement je n'aime pas. Il y a tellement de possibilités de se faire avoir par le préprocesseur qu'il ne vaut mieux pas s'y frotter de cette manière :)
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 01:57:52 pm
Si je voulais être caustique, je dirais « le droit de concourir à The International Obfuscated C Code Contest »  http://www.ioccc.org ;D

Plus sérieusement, bien fait ça donne un code (légèrement) plus efficace tout en restant concis. Personnellement je n'aime pas. Il y a tellement de possibilités de se faire avoir par le préprocesseur qu'il ne vaut mieux pas s'y frotter de cette manière :)

Donc, qu'est-ce ça donne en clair ?
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 02:19:38 pm
Au delà de la bonne utilisation ou non des structures, j'ai moi aussi jeté un oeil sur le code et je dois dire que c'est bien écrit, clair et très documenté. Il y a de très bonnes idées, mais il reste une syntaxe dans DCCpp_Uno.ino que je n'ai pas comprise (ligne 443) :

  if(R.currentReg->activePacket->buf[R.currentBit/8] & R.bitMask[R.currentBit%8]){
    OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N;
    OCR ## N ## B=DCC_ONE_BIT_PULSE_DURATION_TIMER ## N;
  } else{ /* ELSE it is a ZERO */
    OCR ## N ## A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER ## N;
    OCR ## N ## B=DCC_ZERO_BIT_PULSE_DURATION_TIMER ## N;
} /* END-ELSE */

est-ce que ## est un opérateur ?? J'avoue que je sèche.
A part ça, j'ai commencé à extraire la partie DCC de son code et je vais tenter (à mon rythme, donc pas trop vite...) de le comparer en terme de mémoire consommée à cmrdArduino.
La partie reconnaissance du ACK est aussi très intéressante. Il semble que le LMD18200 ait sa broche 8 qui permette de vérifier la consommation de courant instantannée, comme les broches 1 et 15 du L298N qu'emploie Gregg . A creuser.
Pour ce qui est du prix de son montage, il faut voir les contraintes qu'il s'est imposé, c'est à dire aucune sourude, auncun composant autre que l'Arduino et le shield L298N (plutôt couteux) au dessus... Pour le prix de ce shield, on peut utiliser deux LMD18200 qui rempliront le même rôle !

J'ai toujours trouvé mystérieuse cette mesure de courant dans les hacheurs 4Q. Qu'est-ce qu'on mesure quand la tension s'inverse toutes les 1/2 périodes ? Surtout quand la mesure est prise n'importe quand !

J'ai tenté d'utiliser la mesure du courant du LMD18200 en reliant la sortie C/S sur une entrée analogique de l'Arduino, en moyennant des dizaines voire des centaines de mesures et j'avoue que ce n'est pas convainquant !
Là dans DCC++, il fait une mesure de courant toutes les 10 ms (pourquoi pas à chaque loop ?), puis il pratique un "lissage exponentiel" qui prend du temps calcul, c'est le moins qu'on puisse dire.

Je ne suis toujours pas convaincu !

Finalement la solution fiable que j'ai trouvée est extrêmement simple et peu couteuse :

(http://www.locoduino.org/local/cache-vignettes/L500xH219/ponth_dcc-50411.jpg)

Un MAX471 que l'on trouve sous forme de petit BoB sur eBay est monté en série avec l'alim 12/15v du LMD18200.
Ce Max 471 peut mesurer des courants de 0 à 3 A avec une sortie en tension de 1 volt/ampère.

Pour de plus gros ampèrages, il y a l'ACS712T qui monte jusqu'à 5 A.

Là la mesure est très fiable avec un seul Analogwrite.
Je m'en sers évidemment pour la mesure de court-circuit et c'est une merveille !

Reste maintenant à l'appliquer au retour des commandes de programmation.


J'ai ajouté la recette à mon article Comment piloter trains et accessoires en DCC avec un Arduino (3)
http://www.locoduino.org/spip.php?article19 (http://www.locoduino.org/spip.php?article19).
Titre: Re : Re : Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 02:37:35 pm
Si je voulais être caustique, je dirais « le droit de concourir à The International Obfuscated C Code Contest »  http://www.ioccc.org ;D

Plus sérieusement, bien fait ça donne un code (légèrement) plus efficace tout en restant concis. Personnellement je n'aime pas. Il y a tellement de possibilités de se faire avoir par le préprocesseur qu'il ne vaut mieux pas s'y frotter de cette manière :)

Donc, qu'est-ce ça donne en clair ?

Prenons la ligne

OCR ## N ## A=DCC_ONE_BIT_TOTAL_DURATION_TIMER ## N

OCR n'est pas une macro
N est l'argument de la macro dans laquelle cette ligne apparaît
A n'est pas une macro
DCC_ONE_BIT_TOTAL_DURATION_TIMER n'est pas une macro

Donc première passe, N est remplacé par sa valeur, 0 ou 1. Prenons 1

OCR1A=DCC_ONE_BIT_TOTAL_DURATION_TIMER1

OCR1A est une macro de l'AVR, DCC_ONE_BIT_TOTAL_DURATION_TIMER1 est défini à 3199

2e passe

OCR1A est défini dans iom328p.h

#define OCR1A _SFR_MEM16(0x88)

Et donc

_SFR_MEM16(0x88)=3199

Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 03:07:24 pm
Donc, dans le code des interruptions, pour le Timer 1, par exemple, j'ai remplacé la Macro :
DCC_SIGNAL(mainRegs,1)
par son expansion et cela donne ça :

ISR(TIMER1_COMPB_vect){              // set interrupt service for OCR1B of TIMER-1
  if(mainRegs.currentBit==mainRegs.currentReg->activePacket->nBits){    /* IF no more bits in this DCC Packet */ \
    mainRegs.currentBit=0;                                              /*   reset current bit pointer and determine which Register and Packet to process next--- */ \   
    if(mainRegs.nRepeat>0 && mainRegs.currentReg==mainRegs.reg){        /*   IF current Register is first Register AND should be repeated */ \
      mainRegs.nRepeat--;                                               /*     decrement repeat count; result is this same Packet will be repeated */ \
    } else if(mainRegs.nextReg!=NULL){                                  /*   ELSE IF another Register has been updated */ \
      mainRegs.currentReg=mainRegs.nextReg;                             /*     update currentReg to nextReg */ \
      mainRegs.nextReg=NULL;                                            /*     reset nextReg to NULL */ \
      mainRegs.tempPacket=mainRegs.currentReg->activePacket;            /*     flip active and update Packets */ \       
      mainRegs.currentReg->activePacket=mainRegs.currentReg->updatePacket; \
      mainRegs.currentReg->updatePacket=mainRegs.tempPacket; \
    } else{                                                             /*   ELSE simply move to next Register */ \
      if(mainRegs.currentReg==mainRegs.maxLoadedReg)                    /*     BUT IF this is last Register loaded */ \
        mainRegs.currentReg=mainRegs.reg;                               /*       first reset currentReg to base Register, THEN */ \
      mainRegs.currentReg++;                                            /*     increment current Register (note this logic causes Register[0] to be skipped when simply cycling through all Registers) */ \
    }                                                                   /*   END-ELSE */ \
  }                                                                     /* END-IF: currentReg, activePacket, and currentBit should now be properly set to point to next DCC bit */ \
                                                          \
  if(mainRegs.currentReg->activePacket->buf[mainRegs.currentBit/8] & mainRegs.bitMask[mainRegs.currentBit%8]){     /* IF bit is a ONE */ \
    OCR1A=DCC_ONE_BIT_TOTAL_DURATION_TIMER1;                            /*   set OCRA for timer1 to full cycle duration of DCC ONE bit */ \
    OCR1B=DCC_ONE_BIT_PULSE_DURATION_TIMER1;                            /*   set OCRB for timer1 to half cycle duration of DCC ONE but */ \
  } else{                                                               /* ELSE it is a ZERO */ \
    OCR1A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER1;                           /*   set OCRA for timer1 to full cycle duration of DCC ZERO bit */ \
    OCR1B=DCC_ZERO_BIT_PULSE_DURATION_TIMER1;                           /*   set OCRB for timer1 to half cycle duration of DCC ZERO bit */ \
  }                                                                     /* END-ELSE */ \
                                                                                       \
  mainRegs.currentBit++;                                         /* point to next bit in current Packet */ 
}

Une dernière question : à quoi sert l'anti-slash en fin de ligne ?

J'ai recompilé et ça fonctionne encore !
Titre: Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 03:13:43 pm
Pour le préprocesseur, la fin de ligne termine la macro. Ici la macro est très grosse et donc c'est impossible de l'écrire sur une seule ligne. Le \ permet d'échapper le caractère qui suit. Ici le caractère qui suit est le retour à la ligne. Donc les fin de lignes ne sont pas vue par le préprocesseur et la macro est vue comme étant sur une seul ligne comma attendu. Du point de vue du formatage, c'est lisible.
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 03:17:14 pm
Pour le préprocesseur, la fin de ligne termine la macro. Ici la macro est très grosse et donc c'est impossible de l'écrire sur une seule ligne. Le \ permet d'échapper le caractère qui suit. Ici le caractère qui suit est le retour à la ligne. Donc les fin de lignes ne sont pas vue par le préprocesseur et la macro est vue comme étant sur une seul ligne comma attendu. Du point de vue du formatage, c'est lisible.

Donc je peux enlever l' \ dans la version expansée. Il n'a aucun effet sur le compilateur ?
Titre: Re : DCC++ BaseStation
Posté par: Thierry le mars 09, 2016, 03:18:31 pm
Merci Jean-Luc pour, littéralement, cette explication de texte.  :)

Le code est lisible et bien optimisé, c'est boooo.  8)

J'allais ajouter qu'effectivement ce test est lui même à l'intérieur d'une macro plus conséquente !

Une macro doit tenir sur une seule ligne, c'est une contrainte du langage. Mais parfois, et c'est le cas là, elle ne tient pas. Et dans ce cas, le '/' en fin de ligne signifie que la macro n'est pas terminée et qu'elle continue sur la ligne suivante !

Pourquoi faire une aussi grosse macro ?
L'autre solution de codage aurait été de faire une fonction avec les mêmes arguments R et N. Mais au moment de l'exécution la routine d'interruption aurait dû appeler cette fonction, et cela aurait généré un peu de code assembleur pour la mémorisation du pointeur d'exécution, le passage des arguments, la valeur de retour, etc... En procédant par une macro, plus de fonction appelée puisque le code de la macro est directement intégré à sa place dans le source. Le principal inconvénient de cette approche réside dans la taille mémoire programme qui augmenterait significativement à chaque appel de la macro puisque l'ensemble de son code est à nouveau compilé. Mais cela ne se pose pas ici puisque la macro n'est appelée qu'une seule fois selon le type d'Arduino... Donc une solution optimale, tout en conservant l'idée des arguments, et en réduisant l'empreinte mémoire mais aussi et surtout le temps passé dans la routine d'interruption.

Ps : flute, battu par Jean-Luc !
Titre: Re : Re : Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 04:10:21 pm
Donc je peux enlever l' \ dans la version expansée. Il n'a aucun effet sur le compilateur ?

Oui  :)
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 07:32:51 pm
Voici un oscillogramme du signal DCC sur la patte 12 du Mega.

Vous remarquerez la modernité de mon équipement de labos  :-\ :-\

La base de temps est réglée sur 50 microsecondes et les signaux ont l'air assez propres.
J'ai hate de faire bouger une loco avec ça !
Titre: Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 07:41:00 pm
GameBoy Pocket  :o
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le mars 09, 2016, 08:14:25 pm
GameBoy Pocket  :o

Pas jeune la bestiole (tu n'étais pas né  ???), mais marche encore. C'est bien une Game Boy Pocket, avec une cartouche ocscilloscope 2 voies. C'est peut-être même un montage Elektor ?

A coté de ça j'ai un oscillo analogique classique, mais pas à mémoire.
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 09, 2016, 10:31:16 pm
Je confirme : Elektor.
Ils l'ont même fait avec une GameBoy Color. ET bi-courbe, SVP !! ;)
Titre: Re : Re : Re : DCC++ BaseStation
Posté par: Jean-Luc le mars 09, 2016, 11:19:42 pm
GameBoy Pocket  :o

Pas jeune la bestiole (tu n'étais pas né  ???)

N'exagérons rien  :D. Elle est sortie en 1996 d'après Wikipedia et je n'ai plus 20 ans  ;)
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 25, 2016, 04:18:05 pm
Et une commande par mobile et DCC++

Et pour 10$, s'il vous plait !!  ;D ;D ;D

https://www.youtube.com/watch?v=aXOVNPRaMIo (https://www.youtube.com/watch?v=aXOVNPRaMIo)

Si j'ai bien compris, c'est WiThrottle sur l'App Store (Ipod pour la vidéo)
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 25, 2016, 06:12:58 pm
Oui c'est bien DCC++.
Un Uno et une carte moteurs pour 10$ c'est déjà à peine possible. Alors si tu ajoutes le PC, l'iPhone et le routeur, tu exploses ton budget.

Cela dit DCC++ est très attirant et je pense que ça peut apporter une expérience rapide et réussie du DCC.

Je vais me pencher sur la transformation de DCC++ pour en décliner diverses choses :
- la voie de programmation (j'en ai besoin)
- le va-et-vient (une petite centrale comme ça peut suffire largement)
- des suites logiques à mes articles.
- je ne vais pas utiliser le Uno, ni le L298 mais un Nano (je pense que les macros seront les même) et un LMD18200.
- au total, avec quelques boutons, voire un LCD 4x20, ça ne sera pas loin de 20 à 30 €
- j'ai acheté aussi la bestiole à 43A, mais ce sera pour la version "jardin" sur batterie de voiture.

De toute façon je dois tester ce logiciel qui peut être un bon successeur à CmdrArduino, mais testons avant de vendre la peau de l'ours ..

... après mes travaux de peinture et en partage de temps avec la maçonnerie que je me suis promis de faire :-[
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le mars 25, 2016, 07:00:16 pm
Tu vas faire un UNO en parpaings ?  ;D
Titre: Re : DCC++ BaseStation
Posté par: Dominique le mars 25, 2016, 07:37:49 pm
Non un mur de Nanos  8)
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 09, 2016, 02:32:44 pm
Juste pour dire à tout le monde que la discussion continue sur le Forum, ici : http://forum.locoduino.org/index.php?topic=203 (http://forum.locoduino.org/index.php?topic=203)

On y trouvera des tests, des exemples de mise en oeuvre et des adaptations à nos propres besoins.

Ca à l'air vraiment bien  :P :P
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 19, 2016, 12:56:04 pm
Bonjour à tous,

Nous avons 3 fils qui parlent de DCC++ :
Je propose que le coeur des discussions sur DCC++ se situe dans CE fil et que les 2 autres restent consacrés à ses applications.

Ce qui me gène aussi c'est que ce fil soit dans le sujet "bibliothèques". Je préfèrerai le voir dans la discussion générale soit dans "Bus DCC" soit en sujet à part entière car il présente pas mal de potentiel (j'y consacrerai une réflexion bientôt). Est-ce possible ?
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 20, 2016, 07:58:52 pm
Présentation de DCC++

Le projet DCC++ a pour auteur un américain : Gregg E. Berman, qui y a travaillé depuis 2013 et jusqu'en 2016, avec la livraison de sa dernière version sur GitHub : https://github.com/DccPlusPlus/BaseStation.

C'est un très bon programmeur C++ à qui je rend hommage pour cet excellent projet (s'il lit ce fil, ce qui ne manquera pas d'arriver).

Ce projet comprend deux parties :
- une centrale DCC dite "BaseStation" qui se charge de la génération du courant de traction selon la norme NMRA DCC. Cette centrale est construite sur la base d'un Arduino UNO ou d'un MEGA, augmenté d'une carte "Motor Shield" pour la partie puissance.
- une application "Processing" dite "Controller" qui se charge du pilotage de la "BaseStation" soit via l'interface USB entre le PC et l'Arduino, soit via l'interface TCP/IP (ethernet ou wifi sur Mega seulement).

(http://forum.locoduino.org/index.php?action=dlattach;topic=151.0;attach=395;image)

Présentée comme cela, la BaseStation semble ne pas pouvoir se passer du Controller, comme une centrale SPROG a besoin d'un logiciel comme JMRI ou RocRail.
En réalité, d'une part, c'est vrai et il est possible de piloter la BaseStation par JMRI à partir de la version 4.1.16 ou RocRail (récent avec la bibliothèque dccpp) qui contiennent donc une interface spécifique pour DCC++. D'autre part ce n'est pas vrai, la centrale peut fonctionner de façon autonome à condition d'en modifier la programmation, ce à quoi je m'emploie obstinément.

Car Gregg a réalisé un logiciel Open Source admirable en C++ avec force commentaires et explications, et un découpage des fonctions en plusieurs onglets qui rendent la compréhension du logiciel beaucoup plus facile.

Je n'ai pas pu résisté à la tentation et je vais avoir bientôt plusieurs versions personnelles en test pour mon réseau et celui du club, que je décrirai bientôt sur Locoduino (j'en imagine qui salivent déjà ….)

Pour ceux qui voudraient se documenter sur le Web, en langue américaine, voici les liens utiles qui vous diront tout :


Il faut reconnaitre que Gregg à voulu particulièrement respecter la norme NMRA pour que sa centrale fournisse les meilleures caractéristiques :

La centrale peut donc se connecter à la voie principale ET à la voie de programmation. C'est une configuration qui ressemble assez bien à la SPROG (sans vouloir les comparer).

J'ai rapidement découvert qu'on pouvait ajouter d'autres fonctions facilement comme expliqué dans le fil http://forum.locoduino.org/index.php?topic=46.msg1853#msg1853 (http://forum.locoduino.org/index.php?topic=46.msg1853#msg1853) : DCC++ est plein de promesses  :P

Dans la suite de cet exposé, je vais détailler d'abord le logiciel de la BaseStation en montrant comment on pourrait tirer partie des différents mécanismes qui le composent.

Il s'agit du sketch DCpp_Uno.

Ce sketch est accompagné de 17 onglets, certains toujours nécessaires, d'autres optionnels (ce qui ne veut pas dire que si on les enlève, ça va encore compiler, mais l'adaptation est facile à faire) :

D'abord les onglets nécessaires :

Ensuite les onglets dont on peut se passer éventuellement :

Je fais une petite pause pour vous laisser digérer cette intro et je détaillerai ensuite :

A suivre ...
Titre: Re : DCC++ BaseStation
Posté par: Thierry le août 21, 2016, 10:23:02 am
Tout ça est très clair. Hâte de lire la suite !
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 21, 2016, 06:43:16 pm
La génération du signal DCC

C'est là où réside l'intérêt de ce logiciel :

Comme je l'ai indiqué auparavant, DCC++ utilise des tableaux d'octets dits "Packet" organisés en "Register" qui sont gérés dans une liste "RegisterList". Ceci est décrit dans l'onglet PacketRegister.h. Les définitions de base sont :

struct Packet{
  byte buf[10];
  byte nBits;
}; // Packet

struct Register{
  Packet packet[2];
  Packet *activePacket;
  Packet *updatePacket;
  void initPackets();
}; // Register

struct RegisterList{ 
  int maxNumRegs;
  Register *reg;
  Register **regMap;
  Register *currentReg;
  Register *maxLoadedReg;
  Register *nextReg;
  Packet  *tempPacket;
  byte currentBit;
  byte nRepeat;
  int *speedTable;
  int addressDccToDiscover;      // ajout Dominique
  static byte idlePacket[];
  static byte resetPacket[];
  static byte bitMask[];
  RegisterList(int);
  void loadPacket(int, byte *, int, int, int=0) volatile;
  void setThrottle(char *) volatile;
  void setFunction(char *) volatile; 
  void setAccessory(char *) volatile;
  void writeTextPacket(char *) volatile;
  void readCV(char *) volatile;
  void readCV_Main(char *s) volatile;      // ajout Dominique
  void writeCVByte(char *) volatile;
  void writeCVBit(char *) volatile;
  void writeCVByteMain(char *) volatile;
  void writeCVBitMain(char *s) volatile; 
  void printPacket(int, byte *, int, int) volatile;
};

Au passage, on voit dans RegisterList les méthodes disponibles dans CPP++, ainsi que celle que j'ai osé ajouter. Mais nous y reviendrons plus loin.

Il peut y avoir 12 registres dans un Uno et probablement jusqu'à 50 dans un Mega. En tout cas c'est réglable dans la configuration.
Le registre N°0 est réservé pour les commandes à envoyer une seule fois (paquets Idle et Reset, commandes de programmation, commandes de fonctions, commandes d'accessoires). Les registres N° 1 au maximum sont réservés chacun à une machine sur le réseau. Il ne doit pas y avoir plusieurs registres affectés à une même machine, on verra pourquoi bientôt.

Il y a un jeu de registres pour la voie principale et un autre, plus petit pour la voie de programmation car elles peuvent être commandées simultanément.

L'ensemble de ces Registres constitue donc un grand tableau de bits 0 et de bits 1 où chaque ligne est une trame DCC conforme à la norme NMRA et où chaque bit se traduit par une alternance de 200 microsecondes pour un bit ZERO ou 116 microsecondes pour un bit UN.

On se reportera à l'article "L’Arduino et le système de commande numérique DCC" http://www.locoduino.org/spip.php?article14 (http://www.locoduino.org/spip.php?article14) pour se remémorer le principe de fonctionnement du bus DCC.

Pour produire le signal DCC automatiquement il faut une routine sous interruption pilotée par les 2 compteurs OCR1A (pour les 2 alternances du bit) et OCR1B (pour chaque alternance, donc la moitié de la durée du bit) de l'ATMega.  Il est évident que cette mécanique dépend du processeur utilisé et DCC++ ne s'applique dans son état actuel qu'au UNO et au MEGA. On peut le modifier légèrement pour qu'il fonctionne sur NANO et MINI car ils utilisent le même processeur que le UNO, un ATMega328.

Les 2 routines d'interruption, l'une pour la voie principale et l'autre pour la voie de programmation sont déclarées dans le programme principal DCCpp_Uno

ISR(TIMER1_COMPB_vect){              // set interrupt service for OCR1B of TIMER-1 which flips direction bit of Motor Shield Channel A controlling Main Track
  DCC_SIGNAL(mainRegs,1)
}

#ifdef ARDUINO_AVR_UNO      // Configuration for UNO

ISR(TIMER0_COMPB_vect){              // set interrupt service for OCR1B of TIMER-0 which flips direction bit of Motor Shield Channel B controlling Prog Track
  DCC_SIGNAL(progRegs,0)
}

#else      // Configuration for MEGA

ISR(TIMER3_COMPB_vect){              // set interrupt service for OCR3B of TIMER-3 which flips direction bit of Motor Shield Channel B controlling Prog Track
  DCC_SIGNAL(progRegs,3)
}

#endif

Cette écriture simplifiée vient du fait que Gregg utilise une "Macro" qui évite d'écrite 3 fois à peu prês la même chose. J'avoue que je me suis gratté la tête en tombant là dessus, mais Thierry et Jean-Luc m'ont éclairé à temps.

Dans mon adaptation à un prochain va et vient, j'ai limité le fonctionnement à la seule voie de programmation et à un ATMega328 (Uno ou Nano ou Mini)

Dans le code qui suit, j'ai "dé-macro-isé" la routine pour la voie principale :


ISR(TIMER1_COMPB_vect){              // set interrupt service for OCR1B of TIMER-1 which flips direction bit of Motor Shield Channel A controlling Main Track
  //DCC_SIGNAL(mainRegs,1)
  if(mainRegs.currentBit==mainRegs.currentReg->activePacket->nBits){  /* IF no more bits in this DCC Packet */
    mainRegs.currentBit=0;                                            /*   reset current bit pointer and determine which Register and Packet to process next--- */   
    if(mainRegs.nRepeat>0 && mainRegs.currentReg==mainRegs.reg){      /*   IF current Register is first Register AND should be repeated */
      mainRegs.nRepeat--;                                             /*     decrement repeat count; result is this same Packet will be repeated */
    } else if(mainRegs.nextReg!=NULL){                                /*   ELSE IF another Register has been updated */
      mainRegs.currentReg=mainRegs.nextReg;                           /*     update currentReg to nextReg */
      mainRegs.nextReg=NULL;                                          /*     reset nextReg to NULL */
      mainRegs.tempPacket=mainRegs.currentReg->activePacket;          /*     flip active and update Packets */         
      mainRegs.currentReg->activePacket=mainRegs.currentReg->updatePacket;
      mainRegs.currentReg->updatePacket=mainRegs.tempPacket;         
    } else{                                                           /*   ELSE simply move to next Register */
      if(mainRegs.currentReg==mainRegs.maxLoadedReg)                  /*     BUT IF this is last Register loaded */
        mainRegs.currentReg=mainRegs.reg;                             /*       first reset currentReg to base Register, THEN */
      mainRegs.currentReg++;                                          /*     increment current Register (note this logic causes Register[0] to be skipped when simply cycling through all Registers) */
    }                                                                 /*   END-ELSE */
  }                                                                   /* END-IF: currentReg, activePacket, and currentBit should now be properly set to point to next DCC bit */
                                                                     
  if(mainRegs.currentReg->activePacket->buf[mainRegs.currentBit/8] & mainRegs.bitMask[mainRegs.currentBit%8]){     /* IF bit is a ONE */
    OCR1A=DCC_ONE_BIT_TOTAL_DURATION_TIMER1;                          /*   set OCRA for timer N to full cycle duration of DCC ONE bit */
    OCR1B=DCC_ONE_BIT_PULSE_DURATION_TIMER1;                          /*   set OCRB for timer N to half cycle duration of DCC ONE but */
  } else{                                                             /* ELSE it is a ZERO */
    OCR1A=DCC_ZERO_BIT_TOTAL_DURATION_TIMER1;                         /*   set OCRA for timer N to full cycle duration of DCC ZERO bit */
    OCR1B=DCC_ZERO_BIT_PULSE_DURATION_TIMER1;                         /*   set OCRB for timer N to half cycle duration of DCC ZERO bit */
  }                                                                   /* END-ELSE */ 
                                                                       
  mainRegs.currentBit++;                                              /* point to next bit in current Packet */ 
}

Rien qu'avec cette routine d'interruption, et après l'initialisation des variables qui doit être faite dans le Setup(), notre BaseStation est capable d'emblée de produire le signal d'alimentation DCC des voies.

Il reste à comprendre maintenant comment les Registres sont programmés (octets et bits), c'est à dire comment BaseStation peut envoyer des commandes DCC sur les rails.

Pour ce faire, il y a une méthode de RegisterList qui est très importante et qu'il ne faut absolument pas modifier :

// LOAD DCC PACKET INTO TEMPORARY REGISTER 0, OR PERMANENT REGISTERS 1 THROUGH DCC_PACKET_QUEUE_MAX (INCLUSIVE)
// CONVERTS 2, 3, 4, OR 5 BYTES INTO A DCC BIT STREAM WITH PREAMBLE, CHECKSUM, AND PROPER BYTE SEPARATORS
// BITSTREAM IS STORED IN UP TO A 10-BYTE ARRAY (USING AT MOST 76 OF 80 BITS)

void RegisterList::loadPacket(int nReg, byte *b, int nBytes, int nRepeat, int printFlag) volatile {
 
  nReg=nReg%((maxNumRegs+1));         // force nReg to be between 0 and maxNumRegs, inclusive

  while(nextReg!=NULL);               // pause while there is a Register already waiting to be updated -- nextReg will be reset to NULL by interrupt when prior Register updated fully processed
 
  if(regMap[nReg]==NULL)              // first time this Register Number has been called
   regMap[nReg]=maxLoadedReg+1;       // set Register Pointer for this Register Number to next available Register
 
  Register *r=regMap[nReg];           // set Register to be updated
  Packet *p=r->updatePacket;          // set Packet in the Register to be updated
  byte *buf=p->buf;                   // set byte buffer in the Packet to be updated
         
  b[nBytes]=b[0];                     // copy first byte into what will become the checksum byte 
  for(int i=1;i<nBytes;i++)           // XOR remaining bytes into checksum byte
    b[nBytes]^=b[i];
  nBytes++;                           // increment number of bytes in packet to include checksum byte
     
  buf[0]=0xFF;                        // first 8 bytes of 22-byte preamble
  buf[1]=0xFF;                        // second 8 bytes of 22-byte preamble
  buf[2]=0xFC + bitRead(b[0],7);      // last 6 bytes of 22-byte preamble + data start bit + b[0], bit 7
  buf[3]=b[0]<<1;                     // b[0], bits 6-0 + data start bit
  buf[4]=b[1];                        // b[1], all bits
  buf[5]=b[2]>>1;                     // b[2], bits 7-1
  buf[6]=b[2]<<7;                     // b[2], bit 0
 
  if(nBytes==3){
    p->nBits=49;
  } else{
    buf[6]+=b[3]>>2;                  // b[3], bits 7-2
    buf[7]=b[3]<<6;                   // b[3], bit 1-0
    if(nBytes==4){
      p->nBits=58;
    } else{
      buf[7]+=b[4]>>3;                // b[4], bits 7-3
      buf[8]=b[4]<<5;                 // b[4], bits 2-0
      if(nBytes==5){
        p->nBits=67;
      } else{
        buf[8]+=b[5]>>4;              // b[5], bits 7-4
        buf[9]=b[5]<<4;               // b[5], bits 3-0
        p->nBits=76;
      } // >5 bytes
    } // >4 bytes
  } // >3 bytes
 
  nextReg=r;
  this->nRepeat=nRepeat;
  maxLoadedReg=max(maxLoadedReg,nextReg);
 
  if(printFlag && SHOW_PACKETS)       // for debugging purposes
    printPacket(nReg,b,nBytes,nRepeat); 

} // RegisterList::loadPacket

C'est loadPacket qui va positionner les octets et les bits de chaque commande DCC dans un des registres.

LoadPacket contient aussi un mécanisme très important : une sorte de synchronisation avec la routine d'interruption ISR (pendant laquelle le programme principal est mis en attente) qui empêche la modification d'un registre tant que la fois précédente d'appel de loadPacket n'a pas complètement terminé sont travail et que la routine ISR n'a pas envoyé le paquet DCC sur les rails.

C'est la ligne suivant qui fait cela :

while(nextReg!=NULL);               // pause while there is a Register already waiting to be updated -- nextReg will be reset to NULL by interrupt when prior Register updated fully processed
Cette astuce permet de simplifier considérablement l'écriture du programme dans les niveaux plus hauts en faisant abstraction des contraintes précitées.

Par exemple, dans une autre fonction de RegisterList, on trouve :

loadPacket(0,resetPacket,2,3);          // NMRA recommends starting with 3 reset packets
loadPacket(0,bRead,3,5);                // NMRA recommends 5 verify packets
loadPacket(0,resetPacket,2,1);          // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
On est certain, grâce à ce mécanisme, que les paquets seront bien transmis intégralement sur les rails dans l'ordre indiqué. C'est génial, moi j'aime !

Avant de conclure sur cette partie, voici les autres fonctions présentes dans RegisterList. Leurs arguments sont contenus dans un tableau de caractères :

  void setThrottle(char *); // commande de vitesse (0..126) et directions (1=avant, 0=arriere)
  void setFunction(char *); // commande de fonction loco F0..F28
  void setAccessory(char *); // commande d'accessoire (0..2048)
  void writeTextPacket(char *); //envoi d'un paquet libre
  void readCV(char *); // lecture d'un CV sur voie de programation
  void readCV_Main(char *s); // lecture d'un CV sur voie principale (ajout perso de Dominique)
  void writeCVByte(char *); // écriture d'un octet entier de CV sur voie de programation
  void writeCVBit(char *); // écriture d'un bit de CV sur voie de programation
  void writeCVByteMain(char *); // écriture d'un octet entier de CV sur voie principale (sans réponse du décodeur)
  void writeCVBitMain(char *s);  // écriture d'un bit de CV sur voie principale (sans réponse du décodeur)

Si vous comparez avec le source original de BaseStation, vous trouverez que la fonction readCV_Main(char *s) n'existe pas. C'est un exemple de modification qui est facile à faire. Dans cet exemple, j'ai simplement adressé la commande aux registres de la voie principale et j'ai pris les mesures de courant sur la voie principale (en lieu et place de la voie de programmation). Il va de soi que cette fonction n'a d'intérêt que si une seule loco est présente sur la voie principale.

Dans la suite de cette série, nous regarderons la couche supérieure, c'est à dire l'interface entre RegisterList et la communication série ou ethernet.
Dans la série suivante nous regarderons les autres fonctions accessibles à la communication, qui sont les commandes des ports d'entrée et de sortie restant de l'Arduino, ce qui permet de commander des aiguilles directement sans passer par les commandes DCC d'accessoires et un peu de rétrosignalisation (détections de zones principalement).

A suivre …
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 21, 2016, 10:37:08 pm
L'interface avec le Contrôleur par liaison série ou ethernet

Nous avons vu dans l'épisode précédent comment la BaseStation fabrique ses paquets DCC à partir de commandes sous forme textuelle qui sont passées à des fonctions de l'objet RegisterList (qui n'est pas une classe mais une structure, mais bon..).

Les onglets SerialCommand.h et SerialCommand.cpp vont se charger d'assurer l'interface entre le canal de communication (série ou ethernet) et les fonctions de RegisterList.

SerialCommand.h déclare une structure SerialCommand :

struct SerialCommand{
  static char commandString[MAX_COMMAND_LENGTH+1];
  static volatile RegisterList *mRegs, *pRegs;
  static CurrentMonitor *mMonitor;
  static void init(volatile RegisterList *, volatile RegisterList *, CurrentMonitor *);
  static void parse(char *);
  static void process();
}; // SerialCommand

On y trouve pas mal de choses importantes :


Le code d'exécution se trouve donc dans l'onglet SerialCommand.cpp :

La fonction process ne fait pas grand chose d'autre que d'enregistrer les caractères compris entre "<" et ">" et de passer le résultat à parse.

La fonction parse analyse le 1er caractère de la commande pour envoyer le reste des caractères (sans cette 1ère lettre) vers la bonne fonction de RegisterList

"t" pour setThrottle (commande DCC)
"f" pour setFunction (commande DCC)
"a" pour setAccessory (commande DCC)
"T" pour une commande d'aiguille directe (commande non DCC)
"Z" pour une commande d'une pin de sortie de l'Arduino  (commande non DCC)
"S" pour lire l'état d'un capteur relié à une pin d'entrée de l'Arduino  (commande non DCC)
"Q" pour lire l'état de tous les capteurs à la fois  (commande non DCC)
"w" pour programmer un CV sur la voie principale en écriture seule sans vérification (commande DCC)
"b" pour programmer un bit particulier d'un CV sur la voie principale en écriture seule sans vérification (commande DCC)
"W" pour programmer un CV sur la voie de programmation avec vérification donc réponse du décodeur (commande DCC)
"B" pour programmer un bit particulier d'un CV sur la voie de programmation avec vérification donc réponse du décodeur (commande DCC)
"R" pour lire un CV sur la voie de programmation avec réponse du décodeur évidemment (commande DCC)
"1" pour appliquer le signal DCC sur les rails (power ON)
"0" pour couper le signal DCC sur les rails (power OFF)
"c" pour lire la valeur du courant sur la voie principale  (commande non DCC)
"s" pour envoyer sur la liaison un état du système  (commande non DCC)
"E" pour sauvegarder les valeurs des aiguilles et capteurs en EEPROM  (commande non DCC)
"e" pour effacer les valeurs enregistrées dans l'EEPROM  (commande non DCC)

A cela s'ajoute quelques utilitaires comme :
"M" pour envoyer un paquet DCC de 2 à 5 octets sur la voie principale (commande DCC)
"P" pour envoyer un paquet DCC de 2 à 5 octets sur la voie de programmation (commande DCC)

Si on s'arrête un instant pour regarder la loop() dans DCCp_Uno, on y lit :

///////////////////////////////////////////////////////////////////////////////
// MAIN ARDUINO LOOP
///////////////////////////////////////////////////////////////////////////////

void loop(){
 
  SerialCommand::process();              // check for, and process, and new serial commands
 
  if(CurrentMonitor::checkTime()){      // if sufficient time has elapsed since last update, check current draw on Main and Program Tracks
    mainMonitor.check();
    progMonitor.check();
  }

  Sensor::check();    // check sensors for activate/de-activate
 
} // loop

Ce qui veut dire que le programme BaseStation ne fait rien d'autre que de traiter les commandes ci-dessus venues de la liaison série ou ethernet, ainsi que de surveiller le courant en cas de court-circuit et de tester les capteurs, ce qui se traduit par l'envoi de messages vers la liaison série ou ethernet.

Il ne fait donc rien de lui-même, mais cela nous ouvre la voie vers des réalisations personnelles intéressantes et sophistiquées, avec une telle belle boite à outils.

Mais revenons à la fonction parse :

On constate qu'il y a deux familles de fonctions :
Les fonctions conformes à la norme DCC sont réalisées par RegisterList comme on l'a vu précédemment. Mais RegisterList ne s'occupe que des fonctions propres au DCC puisqu'il se charge de la gestion des paquets DCC envoyés aux rails.

Alors, pour les autres fonctions, il existe des onglets spécifiques qui traitent des fonctions non DCC :

Les onglets Accessories.h et Accessories.cpp s'occupent des aiguilles en commande directe par l'Arduino (et non en DCC via un décodeur d'accessoire, ce que BaseStation supporte aussi via la fonction setAccessory). Elles gèrent les structures :

struct TurnoutData {
  byte tStatus;
  byte subAddress;
  int id;
  int address; 
};

struct Turnout{
  static Turnout *firstTurnout;
  int num;
  struct TurnoutData data;
  Turnout *nextTurnout;
  void activate(int s);
  static void parse(char *c);
  static Turnout* get(int);
  static void remove(int);
  static void load();
  static void store();
  static Turnout *create(int, int, int, int=0);
  static void show(int=0);
}; // Turnout

On y retrouve la fonction parse qui fait le lien avec la fonction parse de SerialCommand, pour permettre au contrôleur de commander les aiguilles de cette façon.

Les onglets Outputs.h et Outputs.cpp s'occupent des pins disponibles de l'Arduino qui peuvent être programmées en sortie. Elles gère les structures :

struct OutputData {
  byte oStatus;
  int id;
  byte pin;
  byte iFlag;
};

struct Output{
  static Output *firstOutput;
  int num;
  struct OutputData data;
  Output *nextOutput;
  void activate(int s);
  static void parse(char *c);
  static Output* get(int);
  static void remove(int);
  static void load();
  static void store();
  static Output *create(int, int, int, int=0);
  static void show(int=0);
}; // Output

On y retrouve aussi la fonction parse qui fait le lien avec la fonction parse de SerialCommand, pour permettre au contrôleur de commander les pins de sortie de l'Arduino.

Les onglets Sensor.h et Sensor.cpp s'occupent des pins disponibles de l'Arduino qui peuvent être programmées en entrée pour lire des états de capteurs. Elles gèrent les structures :

struct SensorData {
  int snum;
  byte pin;
  byte pullUp;
};

struct Sensor{
  static Sensor *firstSensor;
  SensorData data;
  boolean active;
  float signal;
  Sensor *nextSensor;
  static void load();
  static void store();
  static Sensor *create(int, int, int, int=0);
  static Sensor* get(int); 
  static void remove(int); 
  static void show();
  static void status();
  static void parse(char *c);
  static void check();   
}; // Sensor

On y retrouve encore la fonction parse qui fait le lien avec la fonction parse de SerialCommand, pour permettre au contrôleur de lire les états des capteurs de rétrosignalisation.

De plus, la fonction check est scrutée par la loop de façon à informer le contrôleur au plus vite des changements d'état des capteurs.

Bien entendu je ne vais pas rentrer dans l'analyse des fonctions de ces 3 dernières familles, mais une série de conclusions d'imposent :

1) BaseStation est un logiciel très complet rédigé de façon propre et claire donc fiable (bien que je n'ai pas tout testé, loin s'en faut, mais cela fleure bon).

2) Sa modularité en fait un logiciel adaptable : on peut enlever et ajouter des fonctions, on peut réaliser certaines fonctions différemment, mais il convient de respecter le noyau principal qui est le moteur DCC.

3) BaseStation est principalement destiné à être piloté par un logiciel de contrôle sur PC. Gregg a écrit Controleur en Processing (version récente) : on peut l'apprécier ou pas. D'autres ont réalisé les adaptations dans JMRI (dernières versions seulement).
N'ayant pas pu installer de version récente dans mon MacBook, j'ai réalisé une petite manette perso que l'on peut voir en document joint.

4) Mais rien n'empêche d'ajouter d'autres fonctions, notamment un automate de gestion de circulation, une gestion de Bal, une gestion de signaux, etc..
Les modèles de programmation des onglets peuvent être une bonne base pour ces extensions. Un bel automate peut aussi trouver sa place dans la loop ou appelé depuis la loop.

Je vous invite maintenant à partager vos impressions et expériences sur DCC++.



Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 22, 2016, 01:34:23 pm
Bonjour à tous,

Je me suis moi même intéressé au DCC++ que j’ai testé avec succès. Ce programme est d’une simplicité d’utilisation déconcertante. J’ai bien dit d’utilisation car quand on regarde le code, c’est "chiadé", propre. Nul doute que Gregg Berman possède un don pour la programmation.

Mais je crois qu’il est moins doué pour le graphisme et l’esthétisme si j’en juge par son controller (DCCpp_Controller) ! Cela a déjà été précisé ailleurs mais il est important de rappeler que DCC++ peut fonctionner indépendamment de DCC++ Controller. Il y a là un côté génial car vous pouvez utiliser pratiquement tout sortes de moyens pour envoyer des ordres à votre Arduino sur laquelle vous avez recopié tel quel le code de DCC++ BasrStation et ça marche !

Vous pouvez utiliser JMRI ou RocRail par exemple, mais vous pouvez aussi (facilement) créer votre propre "controller".

A la base, c’est assez déconcertant, après avoir relié tout le hardware et alimenté l’ensemble, puis entré dans le moniteur série de l’IDE d’Arduino : <1> puis <t 1 3 10 1> de voir que la locomotive adresse 3 démarre bien à la vitesse 10 en avant. Entrez maintenant <t 1 3 10 0> et elle va partir en arrière toujours à la vitesse 10. Plus vite maintenant toujours en arrière <t 1 3 80 0>  à la vitesse 80. Voir aussi le premier post de Tanguy : http://forum.locoduino.org/index.php?topic=203.0

Tout a été fait pour que l’utilisation soit la plus simple possible. Certes, taper des <t 1 3 10 1> <t 1 3 10 0> ou autres <t 1 3 10 0> dans la fenêtre série pour piloter son réseau est un peu fastidieux mais beaucoup plus réaliste avec un petit programme simple qui saurait envoyer ces séquences d’ordres au port série ou à un shield Ethernet que vous auriez implanté sur votre Arduino Mega ! Eh oui, DCC++ ne peut communiquer par Ethernet qu’avec un Mega, avec son code actuel, il faut le préciser.

J’utilise l’Ethernet sur tout mon réseau et on m'a déjà demandé plusieurs fois d'expliciter la chose. Se servir de l’Ethernet n’est pas aussi compliqué qu’on le pense sans doute. Tout d’abord, on utilise son « bon vieux » réseau domestique, Free, Bouygues ou Orange et on peut concevoir de piloter son réseau avec son navigateur web ou son smartphone. A voir les vidéo sur le net, ça semble être le grand phantasme des amateurs de N ou de HO. Et pourquoi pas tous les smarthones de la famille car Ethernet permet le raccordement de terminaux multiples contrairement au port série. Mais cela peut être aussi un pilotage principal sur l’ordinateur, les commandes d'accessoires dont les aiguilles sur tablettes et pour le fun, une loco sur smarphone.

Voici un lien sur mon controller actuel : http://89.225.199.180/train_HO/locomotives/controller_demo.html

Cette version n’utilise pas encore DCC++ mais je suis en train de m’y consacrer.

Alors, je vous propose de rédiger un sujet sur la mise en œuvre de cette technologie et sur la réalisation des applications web à développer. Pour ce faire, j’aimerai que vous puissiez me remonter vos différentes attentes et questions sur le sujet afin que je puisse y répondre au mieux. A cet effet, j’ai ouvert un nouveau sujet dans la rubrique Modélisation, Architecture logicielles et matérielles : http://forum.locoduino.org/index.php?board=13.0

Je vous propose de nous retrouver sur ce tropic et merci par avances de vos contributions.

Bien à vous.

Christophe

Titre: Re : DCC++ BaseStation
Posté par: DDEFF le août 22, 2016, 09:04:26 pm
Finalement, avec DCC++, j'avais bien déniché une pépite... ;D ;D (premières vidéos il y a un an, quand même)

Bien content que Dominique et d'autres (dont Christophe et Tanguy) décortiquent la partie DCC. D'autant que je n'ai pas de locos DCC  :(

Je développe en ce moment une V3 de mon TCO qui sera en deux programmes :

Un éditeur graphique de TCO
Un gestionnaire de réseau en Processing.
La partie graphique avance bien et je corrige tous les bugs qui trainaient. Je veux faire un article qui fonctionne parfaitement. Et, des fois, c'est long  ::)

Développez bien, on se rejoindra à la fin.

Denis
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 23, 2016, 05:30:57 pm
La détection de courant de DCC++

Un des gros avantages de DCC++ par rapport aux autres logiciels connus qui génèrent du DCC est sa mesure de courant qui fonctionne bien sur divers matériels (shield Arduino Motor, ou Polulu ou LMD18200).

La mesure de courant se fait par la lecture d'un port analogique à chaque tour de loop() et l'intérêt de cette mesure est qu'elle intègre une moyenne glissante ou "lissage exponentiel" avec les dernières mesures, c'est une sorte de filtre passe-bas : on n'est pas tous capable d'inventer cela, donc profitons en  ;)

La formule utilisée est c_t = coeff x apin + c_t-1 x (1-coeff) où
- c_t est la valeur de courant calculée au tour t
- c_t-1 est la valeur de courant calculée au tour t-1 (précédent)
- apin est la valeur analogique lue sur la pin analogique utilisée pour la mesure
- coeff est le coefficient de pondération qui est ici de 1%

La valeur lue sur le port apin est donc réduite au 1/100 ème de sa valeur et ajoutée à 99/100 du résultat précédent (initialisé à 0 au départ). La valeur calculée converge donc progressivement vers une valeur moyenne du courant, avec un grande stabilité car les mesures affectent peu le résultat.

On trouve le code suivant dans l'onglet CurrentMonitor.cpp

void CurrentMonitor::check(){
#define  CURRENT_SAMPLE_SMOOTHING   0.01

  current=analogRead(pin)*CURRENT_SAMPLE_SMOOTHING+current*(1.0-CURRENT_SAMPLE_SMOOTHING);        // compute new exponentially-smoothed current
  if(current>CURRENT_SAMPLE_MAX && digitalRead(SIGNAL_ENABLE_PIN_PROG)==HIGH){                    // current overload and Prog Signal is on (or could have checked Main Signal, since both are always on or off together)
    digitalWrite(SIGNAL_ENABLE_PIN_PROG,LOW);                                                     // disable both Motor Shield Channels
    digitalWrite(SIGNAL_ENABLE_PIN_MAIN,LOW);                                                     // regardless of which caused current overload
    INTERFACE.print(msg);                                                                         // print corresponding error message
  }   
} // CurrentMonitor::check 

Ce code, appelé dans la loop permet de couper l'alimentation en cas de dépassement de seuil (ici 300), c'est à dire en cas de court-circuit.

La mesure de courant pour les commandes de programmation

C'est l'application la plus interessante de cette mesure de courant lissée.

Nous avons tous remarqué que lors de la programmation du décodeur d'une loco (on commence toujours par son adresse DCC), celle-ci se met à bouger  :-[
Cela vient du fait que le décodeur va provoquer des impulsions de consommation de courant sur les rails en activant le moteur pendant une fraction de seconde. Il répète plusieurs cycles de "consommation" pour transmettre une information qui est un bit 0 ou un bit 1.

Pour récupérer cette information, notre logiciel BaseStation va d'abord mesurer une valeur de repos du courant "base" c'est à dire quand la loco est au repos : ce courant n'est pas nul car le décodeur en consomme toujours un peu.
Puis quand la loco va transmettre ses "bits" le logiciel va mesurer la consommation en faisant une moyenne glissante pendant la durée du bit, puis comparer le résultat avec la valeur de repos. Si le résultat dépasse la valeur de repos d'un seuil ACK_SAMPLE_THRESHOLD alors le bit est un "1", sinon c'est un "0"

Ce mécanisme se répète 8 fois pour récupérer les 8 bits de l'octet de réponse de la loco.

Les constantes utilisées dans cette mesure se trouvent dans l'onglet PacketRegister.h :

// Define constants used for reading CVs from the Programming Track

#define  ACK_BASE_COUNT            100      // number of analogRead samples to take before each CV verify to establish a baseline current
#define  ACK_SAMPLE_COUNT          500      // number of analogRead samples to take when monitoring current after a CV verify (bit or byte) has been sent
#define  ACK_SAMPLE_SMOOTHING      0.2      // exponential smoothing to use in processing the analogRead samples after a CV verify (bit or byte) has been sent
#define  ACK_SAMPLE_THRESHOLD       30      // the threshold that the exponentially-smoothed analogRead samples (after subtracting the baseline current) must cross to establish ACKNOWLEDGEMENT

On constate que les paramètres de lissage ne sont pas tout à fait les même que pour la mesure dans la loop. Cela vient du fait que les mesures dans la loop se font en fonction du temps d’exécution de la loop toute entière, alors que dans la réponse lors d'une programmation, ce sont seulement quelques instructions qui s’exécutent.

Et le code de récupération de chaque bit se trouve dans l'onglet PacketRegister.cpp, à l'intérieur de chaque fonction de programmation avec réponse, comme readCV, writeCVByte, writeCVBit sur la voie de programmation :

    c=0;
    d=0;
    base=0;

    for(int j=0;j<ACK_BASE_COUNT;j++)
      base+=analogRead(CURRENT_MONITOR_PIN_PROG);
    base/=ACK_BASE_COUNT;

    bRead[2]=0xE8+i; 

    loadPacket(0,resetPacket,2,3);          // NMRA recommends starting with 3 reset packets
    loadPacket(0,bRead,3,5);                // NMRA recommends 5 verfy packets
    loadPacket(0,resetPacket,2,1);          // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)

    for(int j=0;j<ACK_SAMPLE_COUNT;j++){
      c=(analogRead(CURRENT_MONITOR_PIN_PROG)-base)*ACK_SAMPLE_SMOOTHING+c*(1.0-ACK_SAMPLE_SMOOTHING);
      if(c>ACK_SAMPLE_THRESHOLD)
        d=1;
    }


Il va de soi que ce code ne doit pas être modifié car il fonctionne bien : nous avons testé ce code sur plusieurs plateformes à base d'Uno, Nano et probablement Mega.

BaseStation confirme donc son universalité en permettant de commander la voie principale, et aussi la voie de programmation avec un compatibilité NMRA bien étudiée.

L'interface "textuelle" par le port série/usb ou par ethernet va permettre de développer diverses interfaces, en concurrence avec celle de Gregg, mais en s'appuyant sur la qualité de BaseStation. J'en suis convaincu.

J'espère que la présentation de cette partie du logiciel BaseStation ne vous a pas semblé trop ardue  ::)

Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 23, 2016, 06:39:17 pm
Alors là je dis chapeau parce que ça veut dire (si je ne trompe pas) que l'on doit pouvoir récupérer l'ensemble des cv's et leur valeur dès que l'on pose la loco sur la voie de programmation. On peut donc renseigner la base de données du controller automatiquement.

Ca devrait donc aussi vouloir dire que si la loco possède une adresse déjà attribuée (et stockée dans la base de données controller), il est possible de lui en affecter automatiquement une autre qui est libre.

Je suis certain que ce que tu nous soumets ouvre sur bien d'autres potentialités.
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le août 23, 2016, 06:53:10 pm
"Hardue", avec un "h", c'est voulu ? Moi, j'aime bien... ;D

A côté, la partie Processing est plus light, même si ces fonctionnalités sont étendues : on peut tout tester.

Mais côté Arduino, on est très loin de "cMDRarduino". Que de progrès.
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 23, 2016, 07:15:54 pm
Merci pour la détection d'erreur que j'ai quand même corrigée   :-[

J'étais en train de terminer quand toute la famille est rentrée et j'ai du être distrait !
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le août 23, 2016, 07:26:39 pm
Moi, je l'aurais laissée, mais avec des guillemets. C'est marrant.

Il ne faut pas focaliser sur ce détail. Le principal c'est l'énorme boulot que tu as abattu en décortiquant ce magnifique programme.
C'est ça qui est important et rafraichissant.

Bravo et merci.

Amicalement
Denis
Titre: Re : DCC++ BaseStation
Posté par: Thierry le août 23, 2016, 08:58:37 pm
Oui, c'est un gros boulot d'analyse et de compréhension qui va nous faciliter la vie à tous, en tout cas à ceux qui vont utiliser Dcc++ et dont je fais partie (ferais serait plus juste...) .
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 23, 2016, 09:00:51 pm
En fait j'avais envie de faire un article sur CmdrArduino mais l'inspiration tardait à venir. Et puis DCC++ est arrivé et tout est devenu évident parce que ce logiciel est bien foutu  8).

Christophe va bientôt nous éclairer sur Ethernet et ça vaudra le coup de faire un article complet dans la zone éditoriale à partir de toutes ces contributions.

Amicalement
dominique
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 29, 2016, 05:51:58 pm
Bonsoir à tous,

Je suis en train de tester la lecture des valeurs de CV's < R CV CALLBACKNUM CALLBACKSUB > mais impossible d'obtenir d'autre réponse que :  -1 étant "vérification impossible". Exemple : <r12|13|1 -1>.

Returns: **< r CALLBACKNUM|CALLBACKSUB|CV VALUE>
CV VALUE is a number from 0-255 as read from the requested CV, or -1 if read could not be verified.

Je suis sur Mega avec carte Pololu, j'ai fait le test en port série et en Ethernet. La voie de programmation est bien alimentée, diodes de la carte allumée et la loco a bien le comportement typique de la programmation (léger mouvement + phares allumés). J'ai ainsi testé dans une boucle les 200 premier CV's de deux locos avec des valeurs (non prises en compte par DCC++ de 12 et 13, puis 100 et 200). Exemple : <R 1 12 13> et c'est à chaque fois la même réponse.

Merci de votre aide, et bien cordialement

Christophe
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 29, 2016, 07:14:23 pm
Je viens de tester à l'instant la lecture du CV 1 (adresse DCC) et c'est bon, ma loco a bien l'adresse 18.

DCCpp-VV V0.10 du 9/08/2016

<iDCC++ BASE STATION FOR ARDUINO NANO / ARDUINO MOTOR SHIELD: V-1.2.1+ / Aug 15 2016 19:04:05>
<N0: SERIAL><p1><rm123|123|1 18><p0>
adresse DCC : 18

D'ailleurs j'ai ajouté cette lecture de l'adresse DCC dans le Setup : c'est donc automatique au démarrage

Mon matériel : Nano + LMD18200 + Max471

(http://forum.locoduino.org/index.php?action=dlattach;topic=203.0;attach=386;image)
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 29, 2016, 07:24:50 pm
Dominique,

C'est quoi "rm" au début du return ? Et tu as envoyé quoi comme texte ?

Merci
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 29, 2016, 08:46:22 pm
Ah oui, la réponse est dans le fil d'à coté :

http://forum.locoduino.org/index.php?topic=46.msg1862#msg1862 (http://forum.locoduino.org/index.php?topic=46.msg1862#msg1862)

Il y a le code de la version DCC++ que j'ai modifiée pour ajouter la fonction discover() qui fait une lecture de CV (le N°1 pour l'adresse DCC) sur la voie principale au moment du Setup().

Bonne "découverte"
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 30, 2016, 07:30:10 am
Bonjour Dominique,

Oui j'ai regardé ton code. Les seules différences sont que tu es sur la voie principale et moi sur la voie de programmation et que tu utilises un LMD18200 et moi un Pololu !

Je vais commencer par changer le booster pour tester. J'ai 16 V (en HO) à l'entrée du booster, cela est correct, non ?

Je fais de nouveaux tests ce matin et fais le retour.

Merci

Christophe
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le août 30, 2016, 08:45:22 am
Votre discussion est passionnante  ;D ;D

En tant que béotien du DCC, j'aimerais savoir si on peut tester le CV1 ... en roulant ?  :P
(Je sens que je viens de dire une grosse C.)

Denis
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 30, 2016, 08:59:06 am
Bonjour Denis,

Non pas en roulant, c'est ce que disait Dominique.

Par contre, il s'est "fabriqué" une méthode :

void SerialCommand::discover() {
  commandString[0] = '1';
  parse(commandString);
  commandString[0] = 'r';
  commandString[1] = ' ';
  commandString[2] = '1';
  commandString[3] = ' ';
  commandString[4] = '1';
  commandString[5] = '2';
  commandString[6] = '3';
  commandString[7] = ' ';
  commandString[8] = '1';
  commandString[9] = '2';
  commandString[10] = '3';
  parse(commandString);
  commandString[0] = '0';
  parse(commandString);
}

"r" dans commandString[0] = 'r'; est créé ad hoc (n'existe pas à l'origine) qu'il "parse" avec une méthode pour la voie principale (qui est similaire à la méthode pour la voie de programmation)

case 'r':     // <r CV CALLBACKNUM CALLBACKSUB>
/*   
 *    reads a Configuration Variable from the decoder of an engine on the main track
 *   
 *    CV: the number of the Configuration Variable memory location in the decoder to read from (1-1024)
 *    CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function
 *    CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function
 *   
 *    returns: <r CALLBACKNUM|CALLBACKSUB|CV VALUE)
 *    where VALUE is a number from 0-255 as read from the requested CV, or -1 if read could not be verified
*/   
      mRegs->readCV_Main(com+1);
      break;

On voit case 'r' au début et  mRegs-> en fin (pour la voie principale)

Le tout appelé dans le setup pour faire apparître l'adresse dans le moniteur série :

mainRegs.addressDccToDiscover = 3;
  SerialCommand::discover(); // dcc adress found is stored in readCV_Main()
  Serial.println();
  Serial.print("adresse DCC : ");Serial.println(mainRegs.addressDccToDiscover);

Voilà.

Christophe

Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 30, 2016, 09:25:57 am
Et d'ailleurs, je sais que ce n'est pas très élégant de programmer un string caractère par caractère :

  commandString[0] = 'r';
  commandString[1] = ' ';
  commandString[2] = '1';
  commandString[3] = ' ';
  commandString[4] = '1';
  commandString[5] = '2';
  commandString[6] = '3';
  commandString[7] = ' ';
  commandString[8] = '1';
  commandString[9] = '2';
  commandString[10] = '3';
  parse(commandString);

D'autres méthodes intégrant la chaîne complète ont été rejetées par le compilateur.

Avez-vous des suggestions ?
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le août 30, 2016, 09:39:15 am

En tant que béotien du DCC, j'aimerais savoir si on peut tester le CV1 ... en roulant ?  :P
(Je sens que je viens de dire une grosse C.)

Denis

Mais non, mais non ;)

Le principe de la lecture de la réponse d'un décodeur repose sur la mesure du différentiel de courant consommé. La loco doit être à l'arrêt (moteur arrêté), même si le décodeur consomme quelques dizaines de millis. Lors de la réponse, le décodeur commande le moteurs quelques millisecondes pour chaque bit, ce qui augmente la consommation de quelque 100mA (ou plus en HO) et la centrale voit bien ces bits.

Si la loco roule, il n'y aura plus de variation de consommation significative et je me demande même si le décodeur peut encore accepter la commande.

De même, cette mesure ne marche que s'il y a une seule loco sur les rails, sinon il y aurait des mélanges de bits différents et ça donnerait n'importe quoi.

Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 30, 2016, 06:06:27 pm
Bonjour à tous,

Je vous disais hier que j'avais des problèmes de lectures de CV's avec la fonction < R CV CALLBACKNUM CALLBACKSUB > (lecture des CV's d'une loco sur la voie de programmation). J'ai fait depuis toute une série de tests en utilisant, d'une part un UNO puis un MEGA et le LMD18200 et la carte POLOLU. Détail des mesures en PJ.

MEGA + LMD18200 : Aucune mesure possible, retourne -1 pour tous les CV's
MEGA + POLOLU : Mesures exactes sur 2 machines avec des décodeurs peu sophistiqués (MFX et l'autre n'a que la lumière et même pas le son). Toutes les autres machines avec des décodeurs sophistiqués (ZIMO XB 401, ESU V4.0) retournent -1, lecture impossible.

A préciser que la POLOLU se met en sécurité (sur la voie de prog) dès que l'on pose une loco gourmande en énergie !

UNO+POLOLU : Mêmes résultats qu'avec le MEGA, OK pour 2 machines avec des décodeurs peu sophistiqués, toutes les autres lecture impossible et les machines "énergivores" font disjoncter la carte.

Enfin, UNO+LMD18200, je n'ai aucune mesure cohérente, les valeurs retournées sont erronées !!!

Je ne dis pas que le problème soit universel (Dominique lit ses CV's, sur la voie principale certes, mais de façon correcte) avec un LMD18200.

J'ai aussi fait des tests en variant de 16 à 20 V (en HO) mais ça n'a rien donné.

Alors si quelqu'un à des idées  :) Merci d'avance.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 30, 2016, 06:44:43 pm
Je pense que si les résultats sont "incohérents" et, en tout cas pas = -1, cela veut dire que le soft a lu une valeur.

Si cette valeur n'est pas bonne, c'est que les bits lus ne sont pas bons.

La cause vient probablement de la mesure de courant qui doit être un peu en dessous de la limite de la lisibilité. Il faudrait regarder à l'oscillo quels sont les niveaux et les durées des bits.

Les seuls cas que j'ai testé et qui marchent sont :
Titre: Re : DCC++ BaseStation
Posté par: Tanguy le août 31, 2016, 11:25:49 am
Bonjour Christophe,

dans le montage UNO + LMD18200, quelle valeur de résistance utilisez-vous pour la mesure de courant ?
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 31, 2016, 01:34:03 pm
Bonjour Tanguy,

Merci pour votre aide.

En fait, j'utilise un MAX471 pour la lecture de courant. Il ne me semble pas qu'il soit nécessaire d'ajouter une résistance. Cependant, j'ai tout de même essayé puisque je me souviens que vous parliez d'une résistance dans un de vos post et j'ai donc mis 2,2 K. Mais la lecture est la même.

Comme je le disais, je fais des tests en "mélangeant" UNO et MEGA, LMD18200 et POLOLU.

Avec le LMD les résultats sont très incohérents. Avec le POLOLU plus réalistes

<r123|1|123 255>
<r123|1|123 255>
<r123|1|123 100>

Mais il n'empêche que pour la première lecture, la loco a le cv 9, pour la seconde 8 et pour la troisième 8 ???

Je n'arrive même plus à retrouver les "quelques" bons résultats que j'ai obtenus hier avec certaines configs et certaines locos.

Il y a sans doute un problème dans mon alimentation (trop fort en V ?, trop faible ?) Je suis en train d'analyser les bits pour la lecture des mesures de courant !

Amicalement

PS : Peut être pouvons nous nous tutoyer ?
Titre: Re : DCC++ BaseStation
Posté par: Tanguy le août 31, 2016, 02:06:04 pm
Dans mes tests, je n'utilise pas le MAX471 mais directement la sortie dédiée du LMD18200 (current sens output).
Comme cette sortie retourne 377 μA/A consommé, la résistance est nécessaire pour convertir ce courant en tension mesurable par arduino. En jouant sur la valeur de la résistance on peut donc également jouer sur la sensibilité de détection.

Je n'ai pas testé le MAX471 mais je comprend qu'il délivre directement 1V/A. Peut-être n'est ce pas assez sensible ?

As-tu essayé de modifier le seuil de détection dans le programme DCC++ (ACK_SAMPLE_THRESHOLD dans PacketRegister.h ?


Titre: Re : DCC++ BaseStation
Posté par: Tanguy le août 31, 2016, 02:22:40 pm
Les caractéristiques de "Arduino Motor Shield" annonce une sensibilité de 1,65V/A pour la mesure de courant.
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le août 31, 2016, 02:26:46 pm
J'attends avant de modifier le seuil de détection car je trouve les résultats tellement éloignés de ce qu'il devraient être que je cherche d'abord ailleurs.

J'ai pourtant tout re-re-re vérifié, les câbles les paramètres de DCC++ Base !!! C'est sans doute un truc tout bête mais bon...

Mais je suis preneur de toute proposition...
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 31, 2016, 03:15:31 pm
Complément sur la mesure de courant de DCC++

Devant les difficultés de BobyAndCo, je pense utile de partager ce petit bricolage qui permet d’y voir plus clair dans la mesure de courant de DCC++.

Ce « petit bricolage » est fait uniquement dans ma version DCCpp_VV que je joins au présent post, et uniquement dans la fonction ReadCV_Main (PacketRegister.cpp) que j’ai ajoutée pour lire un CV sur la voie principale.

Attention : c'est une version de tests, je vous conseille de la renommer autrement !

Cette lecture est faite dans le Setup en envoyant les 3 commandes :
<1><r 1 123 123><0>
On y voit la mise sous tension du réseau, puis la lecture du CV, puis la mise hors tension du réseau

Sur le moniteur de l’IDE, on doit lire :

DCCpp-VV V0.1.3 (c) Dominique Bultez

<DCC++ BASE STATION FOR ARDUINO NANO / LMD18200 MOTOR SHIELD + MAX471: V-1.2.1-DB / Aug 30 2016 21:56:33>
<N0: SERIAL><p1><rm123|123|1 18>5 0 36 0 0 31 0 0 0 6 33 1
<p0>
adresse DCC : 18

Si ça se passe mal, on peut avoir :
<N0: SERIAL><p1><rm123|123|1 -1>0 0 0 0 0 0 0 0 0 0 15 0
<p0>
adresse DCC : -1 >>> erreur adresse DCC !

Pour ce faire, j’ai ajouté un enregistrement des valeurs de mesure de courant dans toutes les phases de ReadCV_Main (PacketRegister.cpp) et un affichage à la fin de la fonction. Comme cela, ça ne perturbe pas trop les timings.

Je rappelle que la fonction ReadCV envoie 8 fois une commande de lecture pour lire les 8 bits du CV, puis une 9ème commande pour obtenir un bit de vérification.
Aussitôt après chaque commande, le sketch se met en lecture du courant dans une boucle de 500 lectures (ACK_SAMPLE_COUNT qui doit correspondre grosso modo à au moins 6 millisecondes, je n'ai pas mesuré), au cours de laquelle il recherche une valeur qui dépasse le seuil égal au courant de base + 30 (ACK_SAMPLE_THRESHOLD). Si ce seuil est dépassé c’est un bit 1 sinon 0.

Evidemment, il faut UNE SEULE LOCO sur la voie principale et il ne faut pas que la loco roule pour faire cette mesure, moteur arrêté, car c'est en activant le moteur 9 fois pendant 6 ms que le décodeur va "passer son message".

Ces valeurs sont déduites de la norme NMRA http://www.nmra.org/sites/default/files/s-9.2.3_2012_07.pdf (http://www.nmra.org/sites/default/files/s-9.2.3_2012_07.pdf)

Où il est écrit : Basic acknowledgment is defined by the Digital Decoder providing an increased load (positive-delta) on the programming track of at least 60 mA for 6 ms +/-1 ms. It is permissible to provide this increased load by applying power to the motor or other similar device controlled by the Digital Decoder.

La valeur du seuil (30 dans le soft) peut ou non correspondre à ces 60mA de delta consommation, c’est un truc à étalonner si ça ne marche pas du premier coup. De plus il est évident que c'est différent en N et en HO !?!

Voici l’explication des valeurs affichées à droite du « > », ici 5 0 36 0 0 31 0 0 0 6 33 1

5 =  courant de base mesuré avant lecture du premier bit (ou du dernier, c'est quasi pareil)
0 36 0 0 31 0 0 0 = courant lu - courant de base qui est ici supérieur au seuil de 30, pour 2 bits sur 8, ce qui correspond à 01001000, soit 12H donc 18 décimal.
6 = courant de base pour la verification
33 = courant lu pendant la vérification (>30)
1 = OK c’est bon (sinon 0)

Dans la fonction ReadCV_Main, on remarque qu’on a commenté cur[i+1]=d; et décommenté cur[i+1]=c;

Si on fait l’inverse, décommenter cur[i+1]=d; et commenter cur[i+1]=c; on obtient les bits de la réponse directement : 5 0 1 0 0 1 0 0 0 6 33 1

Conclusion : c’est raduc !!!

J'utilise le LMD18200 en série avec le Max471 qui fournit la mesure.
Le seuil étant de 30, on a de 31 à 36, mais c’est suffisant et reproductible

Quoi faire si ça ne marche pas :

Il y a au moins 2 pistes possibles :
1) En soft : réduire la valeur ACK_SAMPLE_THRESHOLD à 25, par exemple, en se basant sur les valeurs lues (si une valeur lue est négative, cela veut dire que la mesure est plus petite que le seuil)

On peut aussi répéter l'opération quelques fois en cas d'échec. Mais s'il y a trop d'échecs, c'est la solution suivante qu'il faut envisager.

2) en hard : augmenter la sensibilité de la mesure de courant. La solution, là est propre à chaque type d’interface choisie
Pour l’Arduino Shield et le Polulu Shield, ou le Max471 on ne peut que mettre un ampli extérieur.
Pour le LMD18200, il y a la résistance de conversion 377 μA/A en tension qui peut varier.

En tout cas c'est important de savoir ce qui se passe dans les entrailles de notre DCC++ façon Locoduino et j'espère que cela vous aidera, si nécessaire.

Titre: Re : DCC++ BaseStation
Posté par: Tanguy le août 31, 2016, 04:17:22 pm
Il me semble que le seuil de 60 mA est utilisé pour un  Basic acknowledgment uniquement.
Pour la lecture des CV c'est la section "Advanced Acknowledgment" qui me semble plus correspondre.

http://www.nmra.org/sites/default/files/s-9.3.2_2012_12_10.pdf :

2.2. RailCom – Transmitter in the Decoder
To transmit a “0”, the decoder must supply a current 1 of 30+4/-6 mA [...].
 To transmit a “1”, the current 1 must be at the most +/- 0.1mA.

2.3. The RailCom Detector
A detector must interpret a current of greater than 10mA during the middle 50% of the bit time as “0”
, a current smaller than 6 mA during the middle 50% of the bit time as “1”.
Titre: Re : DCC++ BaseStation
Posté par: Dominique le août 31, 2016, 04:29:15 pm
Merci Tanguy,

J'avoue que je ne connais pas bien cette partie de la norme qui tient compte aussi de Railcom (avec des schémas de détecteurs).

La norme appliquée par Gregg est peut-être mentionnée quelque part dans le forum TrainBoard, mais il faut se farcir les 46 pages ...

En tout cas, la commande DCC envoyée est du type 0111 10VV 0 VVVVVVVV 0 1110 1BBB où V est le CV et B le bit testé.
Le format d'un Configuration Variable Access Instruction - Long Form est 1110 CCVV 0 VVVVVVVV 0 BBBBBB, où CC = 01 pour verify bit. Cela ne correspond pas !

Je ne trouve pas l'instruction utilisée par DCC++. Je vais continuer à chercher.
En tout cas j'ai trouvé une machine qui ne répond pas mais qui marche quand même.
Il est certain qu'il y a des divergences entre les décodeurs.
Titre: Re : DCC++ BaseStation
Posté par: Dominique le septembre 03, 2016, 10:36:17 pm
Bonjour à tous,

Juste pour dire à la place de bobyAndCo que sa BaseStation dcc++ fonctionne maintenant correctement. Il a suffit de réinstaller tout tranquillement et maintenant les commandes fonctionnent.

Du coup il est en train (c'est le cas de le dire  ;D) de vous préparer un dossier très intéressant, dont je lui laisse le soin de vous faire la surprise  8) :P
Titre: Re : DCC++ BaseStation
Posté par: DDEFF le septembre 04, 2016, 10:54:45 am
Que de bonnes nouvelles!

Dominique : cela veut dire que ton système marche (ce dont je n'avais jamais douté, évidemment) et qu'il a été testé avec d'autres configurations.
C'est quand même une rétro-signalisation sans RailCom...
Bravo !

Christophe : on a un rédacteur supplémentaire. Bienvenue au Club !  ;D
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique le septembre 04, 2016, 12:21:51 pm
Que de bonnes nouvelles!

Dominique : cela veut dire que ton système marche (ce dont je n'avais jamais douté, évidemment) et qu'il a été testé avec d'autres configurations.
C'est quand même une rétro-signalisation sans RailCom...

Merci Denis,

Oui ça marche plutôt bien : j'ai un petit cercle dans mon bureau avec une centrale dcc++ en développement pour mon va et vient.

A tous les coups, quand je pose une loco inconnue sur la voie et que j'appuie sur le bouton de reset, elle démarre toute seule dans la seconde qui suit.

Le reste est maintenant une affaire d'automate que j'essaye d'intégrer avec le reste du logiciel dcc++ (et là, le c++ c'est puissant mais il faut l'apprendre un peu plus ...)

Cette solution de reconnaissance automatique peut être très utile aussi pour gérer des zones de ralentissement.
Mais apparemment Railcom a un avantage qui est qu'on peut récupérer des infos pendant que le train roule, alors qu'avec ma solution, le train doit être à l'arrêt.

Cela dit, du moment que la détection peut se faire à un endroit et un moment donné dans la circulation d'un train, la poursuite du train grâce au gestionnaire doit suffire à atteindre l'objectif qui n'est que de faire respecter la signalisation à la conduite des trains.

Peut-être arriverons-nous à intégrer la détection Railcom un de ces jours...

Suspense  :P :P
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le septembre 04, 2016, 05:39:35 pm
Bonjour à tous,

Il n’aura certainement pas échappé à ceux qui se sont intéressés à DCC++ que ce dernier permettait de communiquer par Ethernet en plus de la traditionnelle liaison série. L’un des nombreux points forts de DCC++ est qu’il fonctionne avec l’envoi de simples messages textuels structurés et ça fonctionne !

Dans ce post, je vais décrire comment paramétrer les réglages Ethernet et vous trouverez également en fin en téléchargement un petit "controller" pour piloter DCC++ avec un navigateur web ou pourquoi pas votre tablette ou votre smartphone en wifi  :)

(http://www.locoduino.org/IMG/jpg/image_1_2.jpg)


DCC++ Base Station utilise les mêmes messages en communication série ou Ethernet. Ces messages qui sont en fait des commandes, sont envoyés au programme et doivent être placés entre ‘<’ et ‘>’. Ce que vous mettrez avant ‘<’ ou après ‘>’ sera ignoré par DCC++. Pour plus de détails sur les commandes : https://github.com/DccPlusPlus/BaseStation/wiki/Commands-for-DCCpp-BaseStation (https://github.com/DccPlusPlus/BaseStation/wiki/Commands-for-DCCpp-BaseStation)

Cette précision est importante car en communication Ethernet avec le protocole HTTP on envoie plus que cela et ce sont les ‘<’ et ‘>’  qui vont permettre d’identifier la commande à l’intérieur de tout le texte des requêtes.

Pour utiliser Ethernet vous devrez bien sûr disposer d’un Arduino MEGA (les autres ne sont pas supportés) d’un shield Ethernet. Pour le reste vous n’avez pratiquement besoin que de votre ordinateur et d’un réseau Ethernet « domestique » qui est fourni par votre box.

Dans DCC++, c’est dans le fichier Config.h que l’on sélectionne la communication par Ethernet. Ligne 34 : #define COMM_INTERFACE   à 1,2 ou 3 selon votre shield.

// DEFINE COMMUNICATIONS INTERFACE
//
//  0 = Built-in Serial Port
//  1 = Arduino.cc Ethernet/SD-Card Shield
//  2 = Arduino.org Ethernet/SD-Card Shield
//  3 = Seeed Studio Ethernet/SD-Card Shield W5200

#define COMM_INTERFACE   1

Il faudra également décommenter la ligne 41 : #define IP_ADDRESS { 192, 168, 1, 200 }

// DEFINE STATIC IP ADDRESS *OR* COMMENT OUT TO USE DHCP
//

#define IP_ADDRESS { 192, 168, 1, 200 }

Mais auparavant on va tout de même s’assurer que cette adresse IP 192.168.1.200 peut « s’insérer » dans votre réseau domestique. Sur Mac, ces informations sont disponibles dans « Préférences Système » -> Réseau.

Sur mon ordinateur, l’adresse IP est 192.168.1.31 ce qui veut dire que toutes les adresse IP de mon réseau domestique vont de 192.168.1.1 à 192.168.1.254, et que mon Arduino + Ethernet devrait pouvoir trouver sa place à l’intérieur avec l'adresse IP 192.168.1.200.

Pour ceux qui maîtrisent un peu plus ces questions, faites un PING en Mac avec « Utilitaire de réseau »

(http://www.locoduino.org/IMG/jpg/image_2_2.jpg)

Sur PC, c'est  -> démarrer / exécuter / cmd/k ipconfig /all (je crois).

Dans le fichier confi.h, laissez le port HTTP tel qu’il est configuré à 2560. Voilà donc à quoi devrait ressembler notre code dans Config.h

Config.h
COPYRIGHT (c) 2013-2016 Gregg E. Berman

Part of DCC++ BASE STATION for the Arduino

**********************************************************************/

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE MOTOR_SHIELD_TYPE ACCORDING TO THE FOLLOWING TABLE:
//
//  0 = ARDUINO MOTOR SHIELD          (MAX 18V/2A PER CHANNEL)
//  1 = POLOLU MC33926 MOTOR SHIELD   (MAX 28V/3A PER CHANNEL)

#define MOTOR_SHIELD_TYPE   0

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE NUMBER OF MAIN TRACK REGISTER

#define MAX_MAIN_REGISTERS 12

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE COMMUNICATIONS INTERFACE
//
//  0 = Built-in Serial Port
//  1 = Arduino.cc Ethernet/SD-Card Shield
//  2 = Arduino.org Ethernet/SD-Card Shield
//  3 = Seeed Studio Ethernet/SD-Card Shield W5200

#define COMM_INTERFACE   1

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE STATIC IP ADDRESS *OR* COMMENT OUT TO USE DHCP
//

#define IP_ADDRESS { 192, 168, 1, 200 }

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE PORT TO USE FOR ETHERNET COMMUNICATIONS INTERFACE
//

#define ETHERNET_PORT 2560

/////////////////////////////////////////////////////////////////////////////////////
//
// DEFINE MAC ADDRESS ARRAY FOR ETHERNET COMMUNICATIONS INTERFACE
//

#define MAC_ADDRESS {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEF }

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

ATTENTION : Il manque quelques lignes de code dans DCC++ Base Station qui utilise la bibliothèque Ethernet de l’Arduino. Dans le fichier SerialCommand.cpp il faudra ajouter à la ligne 66 :

INTERFACE.println("HTTP/1.1 200 OK");
      INTERFACE.println("Content-Type: text/html");
      INTERFACE.println("Access-Control-Allow-Origin: *");
      INTERFACE.println("Connection: close");
      INTERFACE.println();

et entre les lignes 73 et 74 (qui seront devenues 80 et 81)

client.stop();

Code complet :

#elif COMM_TYPE == 1

    EthernetClient client=INTERFACE.available();

    if(client){

      INTERFACE.println("HTTP/1.1 200 OK");
      INTERFACE.println("Content-Type: text/html");
      INTERFACE.println("Access-Control-Allow-Origin: *");
      INTERFACE.println("Connection: close");
      INTERFACE.println();
     
      while(client.connected() && client.available()){        // while there is data on the network
      c=client.read();
      if(c=='<')                    // start of new command
        sprintf(commandString,"");
      else if(c=='>')               // end of new command
        parse(commandString);                   
      else if(strlen(commandString)<MAX_COMMAND_LENGTH)    // if comandString still has space, append character just read from network
        sprintf(commandString,"%s%c",commandString,c);     // otherwise, character is ignored (but continue to look for '<' or '>')
      } // while
     
      client.stop();
     
    }

  #endif

Le code étant le même pour COMM_TYPE == 0 (communication série) assurez vous que vous l’avez bien recopié dans #elif COMM_TYPE == 1

Voilà pour la programmation de la carte. Si vous uploadez, vous devez avoir un message de ce type dans le moniteur série de l’IDE avec l’adresse IP en fin :
<iDCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD: V-1.2.1+ / Aug 22 2016 15:52:06><N1: 192.168.1.200>

Une précision toute bête mais assurez-vous que votre shield Ethernet est bien relié à votre box par un câble RJ 45 ! Vous pourrez faire un nouveau ping toujours sur cette adresse 192.168.1.200 qui doit maintenant s’afficher.

Voilà pour la carte. Votre Arduino c’est transformé en petit serveur web qui va répondre aux requêtes HTTP sur son adresse IP.

La partie "client", c'est le Mini Controller DCC++ que vous allez trouver en fin de ce post. Mais pour que cette application fonctionne, il nous faut disposer d'un serveur web qui soit interne à notre réseau domestique et qui va héberger nos pages HTML, pages de programmation, feuilles de style et images.

Vous pouvez tout a fait utiliser votre box par exemple si elle fait serveur web ou si vous avez déjà un serveur web interne à votre domicile. Mais nous allons ici choisir d’installer ce serveur web sur notre propre ordinateur et pour cela, nous allons télécharger puis installer un logiciel gratuit mais très puissant qui est à la fois un serveur web, un serveur SQL et capable d’exécuter des scripts PHP (nous en aurons besoin assez rapidement quand notre application prendra de l’importance).

Ce logiciel s’appelle MAMP dans sa version Mac, WAMP dans sa version PC et XAMPP sous Linux. Choisissez la version gratuite largement suffisante. Voici les liens de téléchargement :

Mac : https://www.mamp.info/en/ (https://www.mamp.info/en/)
PC : http://www.wampserver.com/ (http://www.wampserver.com/)
Linux : https://www.apachefriends.org/fr/download.html (https://www.apachefriends.org/fr/download.html)

Normalement, l’installation ne doit vous poser aucun problème car elle est vraiment très simple. Au besoin, consultez le tuto sur  OpenClassrooms (https://openclassrooms.com/courses/concevez-votre-site-web-avec-php-et-mysql/preparer-son-ordinateur-2)

Sur votre ordinateur, vous devez déterminer un répertoire bien précis qui va être l’espace disque réservé pour votre serveur web. Choisissez par exemple de le « ranger » dans « Mes documents/mon_petit_train/dossier_web ».

Lancez maintenant l’application MAMP (ou WAMP, ou XAMPP) qui ouvre normalement automatiquement le serveur web et le serveur mySql, (cases en haut à droite de couleur verte).

(http://www.locoduino.org/IMG/jpg/image_3_2.jpg)

Clickez sur le bouton « Préférences » à gauche au milieu

Sur la première fenêtre, sélectionnez tout de suite le répertoire que vous avez créé précédemment et qui va devenir la racine de votre serveur web. Pour cela cliquez sur l’icone à droite de « Document Root » et naviguez jusqu’à trouver votre dossier :

(http://www.locoduino.org/IMG/jpg/image_4_2.jpg)
(http://www.locoduino.org/IMG/jpg/image_5_2.jpg)

Dossier racine qui pour l’instant ne contient rien. Concernant les autres onglets en haut de la fenêtre MAMP, ne changez rien.

(http://www.locoduino.org/IMG/jpg/image_6_2.jpg)

L’onglet Ports vous renseigne sur les paramétrages de ports que MAMP a programmés automatiquement. Ne changez rien. Par contre, notez que MAMP a attribué au Port Apache (c’est à dire au serveur web) le port 8888. Nous en aurons besoin par la suite.

Cliquez sur "annuler" pour sortir et vous vous retrouvez sur la fenêtre principale de MAMP que vous allez maintenant laisser travailler bien tranquillement en tâche de fond. Ne quittez pas MAMP car vous désactiveriez alors le serveur web.

Téléchargez le fichier joint : maPageTest.html.zip que vous allez dézipper et placer dans votre répertoire web, normalement « Mes documents/mon_petit_train/dossier_web ».

Dans votre navigateur, entrez l’url : http://localhost:8888/maPageTest.html (http://localhost:8888/maPageTest.html) et vous devriez voir apparaître dans la page : « Hello Locoduino ! »

Si oui, bravo, vous avez fini les paramétrages, sinon, retournez en arrière pour trouver où vous vous êtes probablement trompé.

Ca y est vous allez pouvoir maintenant piloter votre locomotive sur votre circuit. Téléchargez le fichier joint controller_mini_dccpp.zip et placez le contenu du dossier dans votre répertoire « Mes documents/mon_petit_train/dossier_web » puis clickez sur le lien http://localhost:8888/controller_mini_dccpp/controller.html (http://localhost:8888/controller_mini_dccpp/controller.html) ou tout simplement http://localhost:8888/ (http://localhost:8888/)

Attention : Si vous avez donné à votre Arduino MEGA une autre adresse IP que 192.168.1.200:2560 vous devrez modifier la ligne 14 du fichier « controller.js » qui se trouve dans le dossier « scripts » avec un éditeur de texte et entrer votre propre adresse IP.

Voilà un controller assez complet que vous allez personnaliser. En cliquant sur la petite flèche à droite de la fenêtre « paramétrages », vous allez entrer l’adresse de votre locomotive et valider. Profitez pour entrer son nom ainsi que les noms des fonctions pour votre loco. L’image de la loco est dans le dossier « image », vous pouvez placer votre propre image et entrer l’url « img/ma_belle_loco.jpg ». Vous pouvez même si vous le souhaitez trouver une image sur internet et entrer son url entière : http://www.leffondre.fr/_media/img/large/dsc-3385-rec.jpg (http://www.leffondre.fr/_media/img/large/dsc-3385-rec.jpg).

Tous les CV’s peuvent être modifiés dans autres réglages. Attention cependant à ne pas entrer n’importe quoi. Au besoin, le CV 8 auquel on affecte la valeur 8 permet de retrouver les réglages usine. N’oubliez pas modifier ensuite l’adresse sur votre controller puisque la valeur usine est 3 par défaut.

Avec ce Mini Controller, vous allez pouvoir tester DCC++ Base Station avec une locomotive. Par la suite, je développerai comment réaliser un controller pour tout un parc de locomotive en HTML 5 en utilisant le framework AngularJS. Vous verrez ainsi comment vous pourrez "jouer" à plusieurs en WIFI avec des tablettes ou des smartphones.

N’hésitez pas à me faire part de vos remarques et questions ou si vous avez besoin d'aide.

J'espère qu'avec DCC++ et votre controller web, vous connaitrez des expériences intéressantes.

Christophe.
Titre: Re : DCC++ BaseStation
Posté par: Dominique le septembre 04, 2016, 06:53:57 pm
Bravo  ;D

C'est super nickel et ça marche (j'ai monté un sandwich avec un Mega, une carte ethernet et une carte moteurs, toutes les 2 d'origine Arduino) et ça marche.

Voilà un nouveau pan entier de possibilités qui nous sont offertes grâce à DCC++

Dominique

Titre: Re : DCC++ BaseStation
Posté par: DDEFF le septembre 04, 2016, 08:05:19 pm
C'est vrai que ça ouvre des horizons !  ;D

Mais (je sais que je suis casse-pied) je l'aurais mis à la suite de ton post qui parlait déjà de l'Ethernet.
Parce que, là, il y en a maintenant à deux endroit ...

Mais ça ne retire rien à l'intérêt de ton post.
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le septembre 04, 2016, 08:11:46 pm
Oui mais ici, ça permet de tester DCC++ facilement, le controller est tout prêt !

Dans le fil sur Ethernet, je développerai la réalisation pas à pas d'un controller plus complet  dont on peut voir ici la version démo (http://89.225.199.180/locoduino/controller_dccpp/controller.html)
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le septembre 04, 2016, 09:18:52 pm
Pour le câblage entre l'ARDUINO (UNO ou MEGA) avec Arduino Motor Shield ou Pololu MC33926 voir :

https://github.com/DccPlusPlus/Documentation/blob/master/Motor%20Shield%20Pin%20Mappings.pdf (https://github.com/DccPlusPlus/Documentation/blob/master/Motor%20Shield%20Pin%20Mappings.pdf)

Ne pas oublier de couper 4, 10 et 12 sous la carte Pololu MC33926 pour éviter tout conflit (avec Ethernet en particulier) et Brake Disable et V-IN Connect sur Arduino Motor Shield. C'est bien illustré dans le document ci-dessus.

Pour le câblage entre l'ARDUINO (UNO ou MEGA) avec LMD18200 + MAX471, voir image jointe. Attention, si vous souhaitez que la voie Main et la voie Prog soient toutes les deux câblées, il vous faudra 2 X LMD18200 et 2 X MAX471.
Titre: DCC++ BaseStation - Contrôleur IR
Posté par: ponponmvo le novembre 30, 2016, 09:40:26 pm
Il y a plus d'un an, je me suis lancé dans la réalisation d'une centrale DCC à base d'Arduino UNO. La seule solution pratique à l'époque était d'utiliser la librairie CmdrArduino qui m'a fait beaucoup transpirer et qui n'était pas très pratique à mettre en œuvre.
Depuis, le DCC++ est arrivé et les choses se sont brusquement éclaircies grâce à toutes les contributions et astuces développées sur LOCODUINO.

Le réseau dont je dispose n'est encore qu'un réseau d'essai (pour la suite, on verra…) sur lequel roulent 4 locos ROCO que j'ai converties au DCC via des décodeurs Standard + de Lentz (réf. 10231 V1 et V2). Mes autres machines attendent patiemment leur conversion.

Ma solution fait appel au système DCC++ associé à un contrôleur basé sur une télécommande à infrarouge telle que celles utilisées pour les TV, chaines HiFi ou autres décodeurs. Elle convient e.a. pour de petits réseaux avec commande manuelle des appareils de voie et accessoires.

Les ordres émis par le contrôleur sous forme de messages standardisés DCC++ (ex. < t1 3 50 1>") sont transmis via l'interface série à la centrale qui se charge de les interpréter, de les mettre en forme et de les amplifier (module LMD18200) en direction de la voie.

La solution développée est semblable à celle décrite dans l’article de bobyAndCo (voir http://www.locoduino.org/spip.php?article185) sauf que le contrôleur est à base d’une télécommande à infrarouge.

Pour moi, l’utilisation de la télécommande offre deux avantages principaux :
-   La liaison est  sans fil;
-   La construction mécanique du contrôleur est réduite à sa plus simple expression : il n'y a pas de clavier, d’inverseurs mécaniques ou autres boutons rotatifs à prévoir.

Ce que fait ce contrôleur :

•   Inscription de CV sur la voie principale (donc pas sur voie de programmation);
•   Commande de vitesse (128 crans) et sens de marche des locos ;
•   Configurée pour 4 locos (mais extensible car cela dépend du nombre de boutons disponibles sur la TLC); attention, dans la version actuelle, les numéros de décodeurs associés à chaque loco sont codés 'en dur' dans le programme.
•   Conduite simultanée de plusieurs locos; chaque loco est appelée par un seul bouton de la TLC qui lui est dédié;
•   Coupure/activation du signal DCC sur la voie par la TLC;
•   Activation/désactivation d'une fonction via un bouton dédié (F0 = feux d'éclairage loco ON/OFF) ; une seule fonction est implémentée, mais on peut étendre car cela dépend du nombre de boutons disponibles sur la TLC);
•   Affichage des paramètres de la loco active (numéro, vitesse, sens de marche);
•   Commande de vitesse et sens de marche des locos en mode standard : flèche haut/bas = augmentation/diminution de vitesse;
•   Le contrôleur est équipé d'un autre mode de commande de vitesse : l'appui sur une des touches numériques de la TLC commande une vitesse correspondant à sa valeur en dizaine de km/h; un appui sur le chiffre 4 commande 40 km/h, sur le 9, 90 km/h et le zéro, l'arrêt. Un réglage fin est évidemment toujours possible en combinant avec les flèches haut/bas. Attention! En pratique, le contrôleur impose un cran de vitesse (0 à 127) déterminé; un réglage du décodeur de chaque loco est nécessaire pour assurer la correspondance avec la vitesse à l'échelle. Ce système présente l'avantage d'économiser les touches de la TLC tout en garantissant une exploitation facile (p. ex la touche 4 = vitesse sur un appareil de voie en position déviée, la touche 1 = vitesse d'approche avant attelage, etc.).

Ce que ce contrôleur ne fait pas :

•   Commander des aiguillages ou accessoires (quoique ce ne semble pas impossible à priori);
•   Lire les CV d'un décodeur ;

La solution (déjà expliquée par ailleurs voir e.a. http://forum.locoduino.org/index.php?topic=203.msg1804#msg1804) retenue pour la partie "centrale DCC++" est articulée autour de :

•   1 carte Arduino UNO;
•   1 booster à base de LMD 18200;
•   1 module convertisseur courant/tension MAX471.

Au sujet du module à base de LMD18200, je vous livre une petite astuce ; les commandes passées sur la baie ne permettent pas toujours de maîtriser parfaitement le matériel livré ; il peut arriver quelques surprises : sur le module qui m’a été livré, une partie des connections étaient  étaient repérées en … chinois ! Comme mes connaissances en cette langue sont (très, très) lacunaires, j’ai du procéder par déduction. Voici les correspondances obtenues :

Indications sur le module ->   correspondance
PWR ->   PWR
chinois ->   BRAKE
chinois ->   DIR
GND ->   GND
+5V   ->+5V



La carte Arduino est chargée avec le programme standard tel que développé par Gregg E. Berman (donc pas la version pour Nano modifiée par Dominique).

Pour le contrôleur, il faut :
•   1 carte Arduino UNO;
•   1 afficheur LCD 2 lignes 16 caractères I2C (display I2C/TWI LCD1602 de DFROBOT, article DFR0063/TOY0046);
•   1 capteur infrarouge TSOP 4838;
•   1 télécommande IR; j'ai utilisé la télécommande d'un ancien lecteur/enregistreur de DVD de marque PANASONIC; une autre peut également convenir, à condition qu'elle comporte suffisamment de boutons…
 

Le tout, à l'état de prototype, est actuellement monté sur une planche en MDF (voir la photo).

 


A l'avant-plan, on observe de gauche à droite le convertisseur courant/tension MAX471, le booster à base de LMD18200 et la carte "Centrale DCC++"; la carte contrôleur se situe derrière l'afficheur LCD. Le pupitre à l'extrême droite ne fait pas partie du projet.

En haut à gauche, un moteur et son décodeur qui servent de banc d'essai pour la centrale mais aussi pour les décodeurs et les machines.

Chaque carte est alimentée par sa propre source de tension. La puissance est fournie au booster par une alimentation de PC portable (U = 19,5 VDC) dont la fiche DC a été adaptée en conséquence.
L'alimentation de PC dispose de sa propre protection contre les courts-circuits et est particulièrement efficace mais elle me pose un problème de sélectivité; en effet, elle déclenche toujours en premier lieu avant que les détections par logiciel n'aient pu détecter le problème. Ce qui signifie que quand une loco talonne un aiguillage dont le cœur est alimenté électriquement tout s'arrête et il faut faire un reset général.

Je joins le sketch Arduino à téléverser dans la carte « contrôleur ».

Attention ! Une adaptation à votre télécommande est nécessaire car il y a fort à parier que les codes seront différents. Modifier les codes en regard de chaque instruction #define  du bouton correspondant.
Ainsi, si le code correspondant à « flèche haut » sur votre télécommande est, remplacer la ligne ‘#define arrow_up 3796283338’ par ‘#define arrow_up 4589652’.

Après avoir téléversé le sketch, activez le moniteur série de l’IDE et appuyez sur les différentes touches de votre télécommande ; vous verrez alors apparaître le code correspondant sur le moniteur.

La librairie à utiliser pour la télécommande peut être téléchargée en https://github.com/cyborg5/IRLib ; elle doit ensuite être installée en \libraries\ de votre IDE.

Attention ! Comme vous disposerez de deux cartes Arduino UNO reliées par la liaison série TX/RX, vous devez retirer cette liaison temporairement lors du téléversement des sketches sous peine d’obtenir une erreur en fin de compilation.
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le novembre 30, 2016, 09:54:45 pm
ponponmvo,

Je ne vois ni les photos dont vous parlez, ni votre sketch ???
Titre: Re : DCC++ BaseStation
Posté par: ponponmvo le novembre 30, 2016, 10:15:44 pm
Oups!

Merci de l'information.

Mais je dois réduire la taille des images.

En attendant, je joins le sketch.
Titre: Re : DCC++ BaseStation
Posté par: ponponmvo le novembre 30, 2016, 10:23:04 pm
Voici les photos manquantes.

Daniel.
Titre: Re : DCC++ BaseStation
Posté par: ponponmvo le décembre 04, 2016, 11:35:42 am
En complément à mon message précédent, je joins ci-dessous une petite explication de l'utilisation du contrôleur que j'ai décrit. J'ai également ajouté des photos des informations principales sur l'afficheur.

Trois menus sont disponibles et sélectionnables par les touches suivantes de la télécommande :

Menu STOP (touche PAUSE) : coupure du signal DCC vers la voie
Au démarrage, c'est le menu STOP qui est actif; aucun signal n'est envoyé vers la voie.
Si ce menu est activé en cours d'exploitation normale (menu RUN), les valeurs de vitesse des engins de traction sont ramenées à 0; le sens de marche est conservé.

Menu RUN (touche PLAY) : commande des locos (exploitation normale)
Pour commencer l'exploitation normale, appuyez sur la touche PLAY. Sélectionnez la loco que vous souhaitez commander par appui sur la touche qui lui est dédiée (voir les 4 touches du fond sur la photo de la télécommande). La touche la plus à gauche = loco n°1.
Pour régler la vitesse d’une loco, il y deux solutions :
•   Vous utilisez les flèches vers le haut pour augmenter ou vers le bas pour diminuer ; la progression a lieu cran par cran.
•   Vous utilisez le système plus rapides en appuyant sur une des touches du clavier numérique ; un appui sur 4 doit donner un cran 45 qui, sur 8, un 85 etc.

Pour inverser le sens de marche, utilisez les flèches gauche ou droite selon le cas.
Pour allumer les feux, utilisez la touche jaune.
L’écran renseigne sur la première ligne successivement le numéro de la loco sélectionnée (= adresse du décodeur correspondant, ici 62), le cran de marche (ici 25) et les fonctions sélectionnables (ici F = feux).
Sur la deuxième ligne, on peut trouver le menu actif (R=RUN), le sens de marche (ici > = avant) et l’état des fonctions (ici 0=feux allumés, sinon X = éteints).

Menu PROGRAM (touche PROG/CHECK) : configuration des CV
Pour utiliser ce menu, il ne peut y avoir qu'une et une seule loco sur la voie.
Introduisez d'abord le numéro de la CV que vous voulez modifier sans les zéros non significatifs à gauche; donc pour modifier la CV 1, tapez 1 puis confirmez par ENTER. Introduisez ensuite la valeur décimale que vous voulez lui affecter sans les zéros non significatifs à gauche; donc pour la valeur 3, tapez 3 puis confirmez par ENTER. Un point d'exclamation apparaît alors confirmant l'envoi de la commande. Pour retourner au menu RUN, appuyez sur PLAY.
Sur la photo (prise en fin de réglage de la CV 3), la première ligne affiche >6 qui est le dernier chiffre entré par la télécommande, CV NUM 3 qui est le numéro de la CV sélectionnée à l’étape précédente. La deuxième ligne indique P (menu PROGRAM), le point d’exclamation de confirmation de l’envoi de la commande et la valeur sélectionnée pour la CV (ici 6).
Titre: Re : DCC++ BaseStation
Posté par: Dominique38 le janvier 19, 2017, 09:38:32 am
Bonjour et merci pour les explications sur la liaison ethernet... que je vais mettre en pratique ce week-end.

J'ai juste une petite question sur le choix de la carte ethernet dans le fichier Config.h : quelle différence entre les choix 1 et 2, qui sont tout les deux des shield Ethernet Arduino ?

J'ai une carte Arduino Ethernet Shield 2, quel choix je dois faire ?

Merci d'avance

Bien cordialement

// DEFINE COMMUNICATIONS INTERFACE
//
//  0 = Built-in Serial Port
//  1 = Arduino.cc Ethernet/SD-Card Shield
//  2 = Arduino.org Ethernet/SD-Card Shield

//  3 = Seeed Studio Ethernet/SD-Card Shield W5200

#define COMM_INTERFACE   1
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 19, 2017, 11:23:15 am
Il existe deux shields, l’Arduino Ethernet et  l’Arduino Ethernet 2.

Suite à des différends entre les initiateurs du projet Arduino, vous savez peut être qu’il existe maintenant deux entités qu’il est bien difficile de différencier sauf  par leur marque « Arduino » ou « Genuino » ou plus souvent par leur adresses arduino.cc ou arduino.org. Cela n’est pas sans conséquence pour nous car les IDE par exemple ne sont pas tout à fait les mêmes et les bibliothèques Ethernet non plus.

Pour le shield Ethernet 2, la bibliothèque est celle de arduino.org [Ethernet2-> https://github.com/arduino-org/Arduino]

Pour l’autre shield, c’est la bibliothèque de arduino.cc « Ethernet » qui est incluse quand on télécharge l’IDE.

Mais il existe d’autres shields avec d’autres bibliothèques comme le [W5200-> https://www.seeedstudio.com/W5200-Ethernet-Shield-p-1577.html#]

Dans votre cas, il semble que l'option soit : #define COMM_INTERFACE 2
En cas de doute, le plus simple est sans doute d'essayer une option puis l'autre est de regarder dans le moniteur de l'IDE si l'adresse IP est reconnue (0.0.0.0 -> non reconnue) (192.168.1.xxx -> reconnue)


Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique38 le janvier 19, 2017, 09:58:29 pm
En cas de doute, le plus simple est sans doute d'essayer une option puis l'autre est de regarder dans le moniteur de l'IDE si l'adresse IP est reconnue (0.0.0.0 -> non reconnue) (192.168.1.xxx -> reconnue)

J'ai donc suivi votre conseil, et l'option qui marche est bien avec #define COMM_INTERFACE 2, une fois ajoutée la bibliothèque ethernet2 (version 1.0.3) correspond au shield (avec le chipset Wiznet W5500). Donc merci du conseil efficace  :) :)

Est-ce que je dois faire les modifications proposées pour #define COMM_INTERFACE 1 ?

Merci d'avance
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 19, 2017, 10:11:47 pm
Citer
Est-ce que je dois faire les modifications proposées pour #define COMM_INTERFACE 1 ?

Non bien sûr ! Quand ça marche vaut mieux plus toucher   >:(
Titre: Re : Re : DCC++ BaseStation
Posté par: Dominique38 le janvier 20, 2017, 08:05:43 am
Non bien sûr ! Quand ça marche vaut mieux plus toucher   >:(

oui, bien sûr.
ce que je voulais dire, c'est que c'est la partie ethernet qui marche, je n'ai pas encore testé avec DCC++ basestation et la commande des trains et donc je voulais savoir si il faut que je modifie config.h comme indiqué avec COMM_INTERFACE 1 ?
Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 27, 2017, 09:02:23 am
Bonjour à tous

l'application fournie page 5 (controller_mini_dccpp.zip) par bobyAndCo est superbe, merci pour ce travail.
ne disposant pas du shield ethernet ... :'( je ne peux pas l'utiliser tel qu'elle.

je cherche donc a modifier cette application pour qu'elle utilise la liaison serie (/dev/ttyUSB) plutôt que l'ethernet car mon pc est relié a l' "arduino dcc++ Base Station"

1 - d'après vous est-ce possible facilement et ce lien http://michelletilley.net/2012/03/02/controlling-an-arduino-from-nodejs.html (http://michelletilley.net/2012/03/02/controlling-an-arduino-from-nodejs.html) est-il une bonne base de départ
2 - faudra-t-il modifier dcc++ Base Station car dans ce cas j'abandonne directe  :D

Merci d'avance

cordialement
Pascal
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 27, 2017, 10:18:45 am
Bonjour Pascal,

Merci tout d'abord pour votre commentaire. Au delà de faire plaisir à mon égo :), vos retours sont importants pour savoir ce qui est apprécié par la communauté et ce qui ne l'est moins et ainsi orienter les sujets proposés.

Passer par node.js est une excellente idée. Je n'avais pas retenu cette solution car implanter Node et le faire fonctionner est tout de même un peu plus ardu pour la plupart des utilisateurs que de passer par MAMP. Je travaille sur des versions plus élaborées du Controller et sur d'autres parties de l'application : Le TCO dont je parle rapidement http://forum.locoduino.org/index.php?topic=166.msg2448#msg2448 (http://forum.locoduino.org/index.php?topic=166.msg2448#msg2448) et aussi un gestionnaire de réseau. Et il est vrai que Node est le plus puissance pour faire cela.

Par ailleurs, il faut savoir que Node permet d'exécuter du code en C/C++. On entrevoit tout le potentiel en lien avec l'Arduino.

On ne ventera sans doute jamais assez les qualités de DCC++ Base Station et par la même le travail de son auteur Gregg E. Berman. C'est si bien fait qu'il n'y a rien à changer dans DCC++ Base Station  :) C'est ce qui est très motivant car on sait que nos investissements en développement sont pérennes.

A la question "Est-ce possible facilement ?", il est un peu difficile de répondre. Quel est votre niveau en développement ? Si vous savez implanter Node, je pense que le plus compliqué sera fait. Dans tous les cas, je suis tout à fait disposer à vous aider car c'est une partie qui m'intéresse mais qui n'est pas ma priorité. Qui dit Node dit aussi qu'il n'y a plus grand chose à faire pour faire entrer Raspberry dans nos circuits. Il y a un très gros potentiel. Je préfère d'ailleurs savoir que Node tourne sur Linux que sur "Fenêtre".

Par ailleurs, le travail que vous pourrez faire intéressera la communauté j'en suis certain et j'espère que vous pourrez nous faire des retours.

La version actuelle de ce controller est ici : http://185.14.178.233/locoduino/controller_dccpp/controller.html (http://185.14.178.233/locoduino/controller_dccpp/controller.html). Je suis justement en train de faire quelques modifications cosmétiques qui seront rapidement terminées. N'hésitez pas si vous voulez les sources actuelles tout de suite ou les nouvelles probablement lundi au plus tard.

Bien à vous et beaucoup de plaisir avec Locoduino et vos Arduino's.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 28, 2017, 05:08:45 pm
Bonjour Christophe,

mon niveau en developpement est proche de 0 un peu de script bash  ::)

j'ai quand même pris des bouts à droite et à gauche , j'ai commencé a codé mon projet
je vous le joints car j'ai besoins d'un peu d'aides et de conseils

j'ai essayé de détailler avec des commentaires ce que je voulais faire

j'arrive a récupérer par exemple une trame <t1 3 50 0> mais elle a des caractères non voulus {}'' .. comment filtrer en javascript ??? (fonction tr et awk en bash)
j'arrive a envoyer une trame (d'essai) vers le port serie de dcc++ base station qui fait avancer ma loco

votre fichier controler.js attend un retour de l'arduino mais je ne sais comment et quoi lui envoyer ?
function afficheReponse(response) {
$scope.responseServeur = response;
$timeout(clearAfficheResponse, 1000);   // ... pendant 1 seconde
};

j'ai un problème au lancement de votre page qui me donne une erreur dans Log a coté du bouton power
Dès que je mets l'adresse ip de mon serveur  dans  controller.js , qu'attends t-il comme réponse de l'arduino ?  et cela refonctionne dès que je remets $scope.ipArduinoDcc = "192.168.1.200:2560";  ??

d'avance merci pour vos réponse
Cordialement
Pascal



Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 28, 2017, 06:03:17 pm
Bonjour Pascal,

Tout d'abord, vous n'avez pas la dernière version. Ca ne change rien au fonctionnement général mais ça explique :
Citer
J'ai un problème au lancement de votre page qui me donne une erreur dans Log a coté du bouton power

qui est corrigé depuis. Je vous adresserai la version actuelle dès que j'ai fini des évolutions importantes (2-3 jours).

La fonction :

function afficheReponse(response) {
$scope.responseServeur = response;
$timeout(clearAfficheResponse, 1000);   // ... pendant 1 seconde
};

sert à afficher la réponse de DCC++ Base Station quand il y en a une du type <T 1 50 0> quand on a envoyé par exemple avec succès <t1 3 50 0>. Si elle ne fonctionne pas pour l'instant, c'est à dire que Node ne renvoie pas le message au controller, ce n'est pas grave car ce n'est pas bloquant.

Quand vous dites :
Citer
j'arrive a envoyer une trame (d'essai) vers le port serie de dcc++ base station qui fait avancer ma loco

Vous parlez d'un message entré depuis le moniteur de l'IDE ou s'agit il bien d'un message qui part de Node ? Dans le dernier cas, vous n'êtes pas loin du but.

Quand vous dites :
Citer
j'arrive a récupérer par exemple une trame <t1 3 50 0> mais elle a des caractères non voulus {}''

c'est à quel niveau. Dans DCC++ ? Au niveau de Node ? Si c'est au niveau de DCC++, ça voudrait dire que Node relaie le message sous forme d'objet json {}. Mais DCC++ n'en tient pas compte puisqu'il ne retient dans la requette envoyée que ce qui est à partir de "<" jusqu'à ">". Cela ne devrait donc pas poser de problème.

Si c'est au niveau de Node, c'est à dire que Node reçoit ce message du controller, je suis étonné. Mais bon. Il y aurait effectivement moyen de filtrer en Javascript tout bêtement avec "replace"

var str = "{<t1 3 50 0>}";
var res = str.replace("{", "");
res = str.replace("}", "");

donc res = <t1 3 50 0> Ou mieux avec des expressions rationnelles "RegExp" si elles vous sont familières.

Soyez plus précis sur ce point.

Enfin, je ne comprends pas du tout :
Citer
Dès que je mets l'adresse ip de mon serveur  dans  controller.js , qu'attends t-il comme réponse de l'arduino ?  et cela refonctionne dès que je remets $scope.ipArduinoDcc = "192.168.1.200:2560";  ??

Bien à vous.

Christophe

Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 28, 2017, 09:44:42 pm
Merci pour votre réponse qui me débloque bien
j'ai modifié certaines fonctions et j'ai enfin une version fonctionnelle  srv-web-serial_v0.2.js  :P

je pilote la loco depuis votre interface html qui me plais bien ;)
le principe :  votre page envoie les infos sur le serveur de node.js (http) même port que vous 2560 au lieu de l'arduino dcc++ Base Station (version standard)
j'ai changé l'adresse ip pour qu'elle corresponde a mon serveur node.js dans le fichier controller.js ($scope.ipArduinoDcc = "192.168.0.11:2560";)
il renvoie les commandes sur le port serie vers l'arduino dcc++ Base Station (version standard)

il manque encore les retours de commande vers votre page html pour alimenter le log


ps : si ce n'ai déjà fait dans vos nouvelles versions
une petite demande d'évolution : pouvez-vous afficher un avertissement qu'il faut arrêter la loco pour changer son adresse (cv1) d'avance merci

Cordialement
Pascal

Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 28, 2017, 10:30:42 pm
Bonsoir Pascal,

Si je comprends bien, vous avez un controller opérationnel au moins pour ce qui concerne la traction : marche av/ar, vitesse. En ce qui concerne les fonctions ? Arrivez-vous à activer les lumières, les sons ... ?

Comme je vous le disais, le recours à Node.js est un très bon choix. Ce serait bien que vous fassiez un descriptif quand vous aurez fini car c'est une solution intéressante à publier.

Prenez du plaisir à développer votre solution et tenez-moi au courant de vos évolutions.

Vous avez raison, ça doit même pouvoir s'automatiser :
Citer
une petite demande d'évolution : pouvez-vous afficher un avertissement qu'il faut arrêter la loco pour changer son adresse (cv1) d'avance merci

Je mets la dernière main sur certaines évolutions qui concernent essentiellement le réglage des CV's. Tout d'abord une fonction Lecture de CV's qui permet de scanner dans le controller les réglages actuels des CV's de la loco qui est sur la voie de programmation. Il est aussi possible d'ajouter les libellés des CV's. Et bien sûr, tout est enregistré même à la mise hors tension.

(http://185.14.178.233/locoduino/images/scan2.png)

Les valeurs sont visibles dans une liste que l'on voit au bas de l'image ci-dessous. Par ailleurs on peut constater que les réglages sont possibles pour la voie de programmation (prog) ou voie principale (main).

(http://185.14.178.233/locoduino/images/reglages_cv2.png)

Le controller commence à être vraiment complet et je pense assez simple et convivial. Je ne voulais surtout pas une usine à gaz ! Mais ça, c'est les utilisateurs comme vous qui le direz.

J'ai fait des tests sur un I-Pad, c'est une expérience intéressante d'être complètement mobile autour du circuit et de pouvoir en même temps en piloter tous les paramètres. Vous pouvez-vous aussi dans votre configuration utiliser des terminaux portables si vous êtes relié au wifi de la box.

Au plaisir de vous aider car vous avez avancé vraiment bien.

Christophe.

Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 29, 2017, 02:16:17 am
Bonsoir,

J'ai mis en téléchargement la dernière version (2.4) du controller DCC++ en HTML : http://185.14.178.233/locoduino/controller_dccpp.zip (http://185.14.178.233/locoduino/controller_dccpp.zip)

La version démo en ligne est visible ici : http://185.14.178.233/locoduino/controller_dccpp/controller.html (http://185.14.178.233/locoduino/controller_dccpp/controller.html)

C'est une version admissible qui peut présenter quelques bugs mineurs.

Les principales améliorations tournent autour de la programmation des CV's. On peut programmer sur la voie principale (quand les décodeurs le permettent) et sur la voie de programmation.

J'ai aussi implanté une commande bien utile qui scanne les CV's de la loco qui est sur la voie de programmation et les présentent en liste. Ce scan n'est nécessaire que quand la loco n'est pas encore connue du controller.

(http://185.14.178.233/locoduino/images/reglages_cv3.png)

Pour répondre à la demande de Pascal, j'ai implanté une fonction qui arrête la loco quand on programme sur la voie principale  8)

Pour ceux qui ont déjà implanté le controller et qui auraient commencé à personnaliser leur fichier data.json, ne recopiez pas ce fichier au risque de perdre vos modifications. Idem pour le dossier img si vous avez ajouté vos propres images. Tous les autres fichiers doivent être recopiés pour écraser les anciens.

J'attends vos retours pour corrections.

Amitiés Locoduinesques.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 29, 2017, 11:02:46 am
Bonjour Christophe

beau travail , je passe de la version 1.8 à la 2.4
mes remarques ne sont pas représentatives car je n'ai pas la configuration recommandée. (pas de shield ethernet)

Création Machines - Fichier data.json
je n'ai pas de sauvegarde des nouvelles locos crées dans le fichier data.json (répertoire avec fichier controller.html) , j'ai bien essaye de copier les lignes de debug dans le fichier data.json mais cela ne fonctionne pas
si je supprime le fichier data.json ou en crée un vide ... impossible =>  Log : Fichier des locos sur disque chargé
si je prend votre fichier , j'ajoute mes 2 machines sans problème par l'interface et je peux les contrôler  avec votre interface + node.js
je ne vois pas de bouton sauvegarde pour les nouvelles machines
 
Test des fonctions
Je n'ai pas de machine récente ( 2 jouef 1980 + lenz standard + V2)
je vais installer une led pour faire un test de la fonction éclairage

Programmation CV
concernant la voie de programmation, je n'ai qu'un LDM18200 et donc pas de voie de programmation , il faut que je reconnecte les pins arduino et vous tiens au courant.
La modification du CV 1 sur voie principale fonctionne bien

Demande d'amélioration
pouvez-vous mettre le numéro de version en haut à droite de l'interface cela permet de savoir qu'elle version nous utilisons


Question sur controller.html : l'application pourrai t-elle fonctionner si nous n'avons pas de connection internet exterieur (juste le réseau local)
Question electronique : peut-on imaginer un bouton qui reconnecte les 3 pins de l'arduino pour basculer les même voies en "voie de programmation" pins : 10,3,A0 / "voie principale pins :  5,11,A1")

d'avance merci pour vos réponses

Bonne journée

Cordialement
Pascal
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 29, 2017, 12:18:07 pm
Bonjour Pascal,

Merci encore !

Concernant la sauvegarde dans le fichier data.json. La sauvegarde est appelée quand on quitte la page ou qu'on la recharge. Appel aux alentours de la ligne 695 $scope.saveParamPhp(); Le code de la fonction saveParamPhp() est aux alentours de la ligne 649. Mais je ne suis pas étonné que cela ne fonctionne pas dans votre cas car la fonction appelle un script php pour copier les données. Ce fichier de script est "save_data.php" qui est dans le même répertoire sur le disque. Or votre installation de Node.js ne doit probablement pas exécuter du PHP ? Voir ici https://www.npmjs.com/package/node-php-server (https://www.npmjs.com/package/node-php-server).

Ceci dit, j'ai développé un autre moyen de sauvegarder les datas avec l'appel de la fonction localStorage.setItem("locomotives",JSON.stringify($scope.locomotives)); aux alentours de la ligne 701 qu'il faudra décommenter.

Dans ce cas, il faudra aussi décommenter la ligne aux alentours de 720 $scope.loadLocalStorage (); pour que les données sauvegardées dans le localstorage soient chargées au lancement de l'application.

A tous les lancements de l'application, c'est le chargement des données contenues dans le localstorage (si il y en a) qui est réalisé. Le chargement du fichier data.json n'est opéré que si le localstorage est vide. En utilisation normale, c'est le plus simple. Le fichier data.json est appelé une première fois, puis les données sont chaque fois sauvegardées dans le localstorage et rappelé à partir de celui-ci à chaque ouverture. Mais ça veut dire que toute modification des datas doit se faire dans ce cas sur les données du localstorage et non dans le fichier data.json (qui est toujours mis à jour si PHP fonctionne mais qui n'est plus appelé tant que localstorage n'est pas vide).

Enfin, une autre solution existe qui serait de remplacer les opérations "File System" réalisées en PHP par les opérations FS de Node ("fs.writeFileSync" etc...).

Bon ça parait peut être un peu compliqué mais en "mode utilisateur", c'est très simple. Tout ceci est bien commenté dans le code à partir de la ligne 694.

Citer
Question sur controller.html : l'application pourrai t-elle fonctionner si nous n'avons pas de connection internet exterieur (juste le réseau local)

Réponse de normand (et pourtant je suis breton) : oui et non. Non en l'état car elle utilise des bibliothèques extérieures (ligne 9, 10 et 11 du fichier controller.html) :

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

Oui si vous téléchargez ces bibliothèques sur votre disque dur en recréant le paths des lignes dont je parle ci-dessus.

Question electronique : peut-on imaginer un bouton qui reconnecte les 3 pins de l'arduino pour basculer les même voies en "voie de programmation" pins : 10,3,A0 / "voie principale pins :  5,11,A1")
Je ne vois pas trop bien comment si j'ai une lecture littérale de ce que vous écrivez. Il y a certainement des bidouilles possibles, plus ou moins judicieuses. Selon moi, pour éviter de se faire ch..r et de voir éventuellement de la fumée sortir du bazar, il faut adopter l'un des montages que je préconise http://www.locoduino.org/spip.php?article187 (http://www.locoduino.org/spip.php?article187). Ajouter un LMD18200 et un MAX41 n'est pas ruinant !

Pour finir, je profite de ce post pour lancer un appel concernant la lecture et la programmation qui sont totalement impossibles avec certains décodeurs. Sur la voie de programmation essentiellement, mais il peut aussi arriver la même chose sur la voie principale. Cela fait un petit moment que Dominique et moi avons constatés ce problème mais n'avons aucune piste sérieuse pour comprendre. Le message retourné par DCC++ Base Station (en voie de programmation) est systématiquement terminé par -1 (code d'erreur) returns: <r CALLBACKNUM|CALLBACKSUB|CV Value)
            where VALUE is a number from 0-255 as read from the requested CV, or -1 if verificaiton read fails


Toutes vos suggestions sont les bienvenues pour essayer de trouver une solution à ce problème.

Bien cordialement.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 29, 2017, 03:59:58 pm
Sur I-Pad, c'est vraiment une expérience de jeu intéressante  ;D

(http://185.14.178.233/locoduino/images/IMG_1733.png)
Titre: Re : DCC++ BaseStation
Posté par: Dominique le janvier 29, 2017, 06:24:59 pm
En plus avec une superbe 241 !

Bravo  :D
Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 29, 2017, 08:35:43 pm
Bonsoir à tous

j'ai fait le test d'une fonction avec une led , la  <f 20 145> lumière fonctionne (avec nodejs)

je n'arrive pas a avoir le retour vers la page controller.html (log) des fonctions envoyées
j'ai le retour seulement sur la console de nodejs. avez-vous une idée comment faire le lien entre nodejs et controller.js et controller.html


j'ai effectué les modifications concernant
localStorage.setItem("locomotives",JSON.stringify($scope.locomotives));
 scope.loadLocalStorage
mais cela me retourne Modèle : {{ locoSelectionnee.nomLong }}
je suis sous firefox 51.0.1 et je ne connais rien à localstorage.
faut-il l'autoriser ou ???


concernant les bibliothèques extérieures (ligne 9, 10 et 11 du fichier controller.html)
j'ai télécharger ces fichiers en local et placer dans le repertoire /web
<script src="web/angular.min.js"></script>
<link rel="stylesheet" href="web/css/bootstrap.min.css">
<script src="https://web/jquery.min.js"></script>

il manque les boutons ?


concernant la voie de programmation et la lecture du cv 1
quand cela fonctionne 1 fois cela fonctionne  ... 2 , 3 ,10 fois (machine 1 => cv 1 : 20)
je change de loco cela fonctionne 1 fois  ... 2 , 3 ,10 fois (machine 2 => cv1 : 18)

par contre quand cela ne fonctionne pas 1 fois c'est jusqu'à l'infini. le seul moyen que j'ai trouvé c'est de faire <0> puis <1>.

d'avance merci
Cordialement
Pascal


Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 29, 2017, 09:27:45 pm
Bonsoir Pascal,

Citer
je n'arrive pas a avoir le retour vers la page controller.html (log) des fonctions envoyées
j'ai le retour seulement sur la console de nodejs. avez-vous une idée comment faire le lien entre nodejs et controller.js et controller.html

Je n'ai pas la réponse comme cela. Il faudra voir l'ensemble du code (Node et controller.js) et les échanges. Mais j'ai l'intuition que cela ne sera pas compliqué à résoudre.

Pour localstorage, désolé, je ne comprends pas du tout ce que vous dites ...  :-\  Envoyez moi le code de contrôler.js que vous avez modifié ça sera plus simple !

Alors pour les dossiers rapatriés en local, tout d'abord <script src="https://web/jquery.min.js"></script> je doute que ça fonctionne. Ne vaudrait il pas mieux mettre <script src="web/jquery.min.js">

Citer
il manque les boutons ?

J'ai bien peur qu'en copiant "web/css/bootstrap.min.css" vous n'ayez écrasé "css/w3css/w3.css" (<link rel="stylesheet" href="css/w3css/w3.css">) qui étaient déjà en local. C'est ce dossier là pour les boutons.

Et désolé une nouvelle fois, je ne vous comprends pas ici aussi :
Citer
par contre quand cela ne fonctionne pas 1 fois c'est jusqu'à l'infini. le seul moyen que j'ai trouvé c'est de faire <0> puis <1>.

Soyez plus précis. S'agit t'il d'une 3° loco ? Décrivez un peu plus le problème et la configuration concernée.

Mais vous avez passé tout le WE là dessus, ça explique sans doute un peu de fatigue. Dans tous les cas, vous avez drôlement bien avancé en peu de temps.

Bien amicalement.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 30, 2017, 06:02:48 pm
Bonsoir à tous,

Sur les recommandations de Pascal, j'ai ajouté un certain nombre de fonctionnalités à mon Controller DCC++.

(http://185.14.178.233/locoduino/images/menu_parametres.png)

J'ai ajouté le n° de version  :)

J'ai principalement ajouté une zone de paramétrage qui est rétractable en cliquant sur la petite flèche en haut à gauche de la fenêtre.

On peut choisir l'IP de DCC++ Base Station quand on a plusieurs configurations.

Le bouton "lecture de CV's" est passé ici ce qui est plus ergonomique et je lui ai ajouté une option (menu déroulant) portant sur le nombre de CV's que l'on souhaite lire.

Mais les principales nouveautés portent sur les sauvegardes :

- Il est possible d'activer ou de désactiver la sauvegarde automatique dans le localstorage. C'est une fonctionnalité très intéressante introduite avec HTML 5. Voir détails ici : http://www.alsacreations.com/article/lire/1402-web-storage-localstorage-sessionstorage.html (http://www.alsacreations.com/article/lire/1402-web-storage-localstorage-sessionstorage.html)
- Il est également possible de gérer manuellement le contenu du localstorage, enregistrement ou effacement.
- Enfin, on peut charger un fichier de données extérieur (data.json) ou sauvegarder ces données.

Voilà donc des options complètes de sauvegarde et qui vont permettre à Pascale de résoudre son problème (absence de PHP dans sa config actuelle).

J'ai mis en téléchargement la dernière version (2.7) du Controller DCC++ en HTML : http://185.14.178.233/locoduino/controller_dccpp.zip

La version démo en ligne est visible ici : http://185.14.178.233/locoduino/controller_dccpp/controller.html

PS pour Pascal : Attention si vous faites la MAJ à reporter les modifications que vous avez pu faire dans le HTML (bibliothèques que vous avez passées en local) ou dans le JS avant d'écraser ces fichiers.

Bien amicalement.

Christophe

Titre: Re : DCC++ BaseStation
Posté par: plnew le janvier 30, 2017, 08:07:15 pm
Bonjour Christophe

merci de penser à ma configuration particulière   8) ... que d'améliorations en quelques jours

le localstorage m'a encore posé des soucis mais cela doit passer par le cache de firefox et je lui demandait de ne conserver aucun historique ...
je ne suis pas certains de mon explication mais avec la version 2.7 je conserve bien mes 2 locos au redémarrage de firefox.

retour / commentaire => activé : true - Contenu : 1 élément =>   j'ai 2 locos donc pourquoi pas 2 éléments ?

le bouton "Enregistrer dans le fichier 'data-json' " par contre reste inopérant dans mon cas (pourquoi pas une option export sur le disque local )
j'ai php d'installer sur ma machine PHP 7.0.13-0ubuntu0.16.04.1


ma version de controller.html ne fonctionne toujours, les modifications par rapport à votre fichier :
<script src="web/angular.min.js"></script> => fichier angular.min.js télécharger et placé dans le repertoire web
<link rel="stylesheet" href="css/bootstrap.min.css"> => juste enlevé le chemin web , le fichier est dejà présent en local dans sous-repertoire css
<script src="web/jquery.min.js"></script> => fichier jquery.min.js  télécharger et placé dans le repertoire web

c'est le dessin des boutons qui pose problème ... si vous avez une idée , je suis preneur.

concernant le  fichier controller.js , n'étant pas à votre niveau de programmation( et de loin)  je me garde bien d'y toucher   :)
juste l'adresse IP de mon serveur a ajouter aux 2 existantes

d'ailleur si vous avez un peu de temps a me consacrer pour regarder mon fichier (joint), je n'ai toujours pas trouvé comment faire le retour entre le server node.js et les logs des pages controller.html/controller.js (ligne 97 a 108 de mon programme) d'avance merci

Cordialement
Pascal





Titre: Re : DCC++ BaseStation
Posté par: DDEFF le janvier 30, 2017, 08:56:04 pm
Salut Christophe,

Impressionnant ! Quel plaisir de voir de tels résultats. Et ça n'est pas fini !!  ;)

Amicalement
Denis
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 30, 2017, 09:40:18 pm
Bonsoir Pascal,

Rien ne vous échappe !

Citer
j'ai 2 locos donc pourquoi pas 2 éléments ?

En fait, c'est tout l'objet "locomotive" qui est envoyé au localstorage -> 1 élément. C'est exactement le même contenu que le fichier data.json, c'est comme si il disait "1 fichier dans le localstorage". Donc vous avez réussi à enregistrer dans le localstorage CQFD.

Mais il y a moyen d'être plus précis, il faudrait alors écrire : localStorage.locomotives.length qui renvérait le nombre d'éléments dans l'objet "locomotives" du localstorage.

Citer
le bouton "Enregistrer dans le fichier 'data-json' " par contre reste inopérant dans mon cas (pourquoi pas une option export sur le disque local ). j'ai php d'installer sur ma machine PHP 7.0.13-0ubuntu0.16.04.1

Enregistrer ou export c'est la même chose !

Si je n'abuse, 0ubuntu est un serveur à part entière, cela veut dire qu'il fonctionne en parallèle de Node sur votre machine. Vous avez donc 2 serveurs actifs, non ? Si c'est le cas, ça ne marche pas comme cela ! Comment voulez-vous que Node communique avec Oubuntu ? Pour moi la solution la plus élégante et efficace est d'installer le module File System de Node et d'utiliser les commandes https://www.npmjs.com/package/file-system (https://www.npmjs.com/package/file-system). C'est vraiment très simple pour quelqu'un qui est arrivé là où vous en êtes.

Citer
c'est le dessin des boutons qui pose problème ... si vous avez une idée , je suis preneur.

Envoyez moi une copie d'écran. Je ne vois pas comme cela. Envoyez moi aussi une capture du répertoire sur le disque, j'ai bien l'impression qu'il y a des dossiers qui ne sont pas à leur place.

Citer
juste l'adresse IP de mon serveur a ajouter aux 2 existantes

Vous pouvez surtout supprimer les 2 autres pour les remplacer par la votre :

$scope.ipArduinoSelect = ["192.168.1.200:2560"];
Attention, il n'y a pas de "," après "192.168.1.200:2560" principe des tableaux et des objets commun à tous les langages. Au passage, je m'aperçois que j'ai oublié le ";" à la fin de la commande, mais Javascript est très permissif !

Pour le retour des logs, je pense qu'il faut programmer quelque chose comme cela à la ligne 123 de votre .js

response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
         response.write('Message de test');
         response.end();

avec tout d'abord un message "en dur" : Message de test pout voir s'il apparait dans la fenêtre de log du Controller. Ensuite, ça fonctionne, il faut trouver le body renvoyé par le serveur de DCC++ Base Station, c'est le simple message de type <T 1 90 1>. Vous m'avez dit que vous le voyez sur la console, c'est une variable, elle est dans un callback sur evenement ".on(succes)" certainement de type .on('success', (function(response) {
   -> response étant le return de DCC++ Base Station
});

mais il faut trouver laquelle.

Et là, hop, il faut renvoyer le body du type :

response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
         response.write(response);
         response.end();

Cette page m'a l'air super bien faite : https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/ (https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/)

En tous les cas, j'ai regardé à nouveau votre code de "srv-web-serial_v0.3.js", c'est vraiment bien. Je l'ai déjà dit mais il y a derrière cela un gros potentiel car Node sait par exemple exécuter des programmes écrits en C/C++ est donc envoyer le commandes à l'Arduino par le port série. Ca va intéresser beaucoup de monde à Locoduino.

Courage  :P  ... et comptez sur moi pour vous aider.

Christophe




Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 30, 2017, 09:52:43 pm
Citer
Impressionnant ! Quel plaisir de voir de tels résultats. Et ça n'est pas fini !!  ;)

Merci Denis,

Il y a un peu de boulot, c'est vrai. Ce que j'espère surtout c'est que ça reste excessivement simple d'usage pour l'utilisateur, convivial et ergonomique.

Ce que fait Pascal t'intéressera au plus haut point puisqu'il s'agit ni plus ni moins de Node.js qui fait des merveilles sur Raspberry.

Et c'est pas fini !

(http://185.14.178.233/locoduino/images/et_c_pas_fini.jpg)

Bien amicalement.

Christophe
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le janvier 31, 2017, 01:08:54 am
Pascal,

Il m'est revenu une chose, vous avez bien le réglage "port série" dans le fichier Config.h ? de DCC++ Base Station ?

// DEFINE COMMUNICATIONS INTERFACE
//
//  0 = Built-in Serial Port
//  1 = Arduino.cc Ethernet/SD-Card Shield
//  2 = Arduino.org Ethernet/SD-Card Shield
//  3 = Seeed Studio Ethernet/SD-Card Shield W5200

#define COMM_INTERFACE   0

avec #define COMM_INTERFACE   0

En effet, dans votre configuration, la liaison HTTP se fait du navigateur à Node. Mais de Node à l'Arduino, vous êtes en série. Ca n'a pas empêché de fonctionner mais ça peut jouer pour le message de retour puisque COMM_INTERFACE n'est pas la même.

A voir !

Christophe
Titre: Re : DCC++ BaseStation
Posté par: Carcouaille le novembre 01, 2017, 03:07:48 pm
Une question :

Est-il vraiment nécessaire de mettre une carte SD avec les fichiers control.htm et locos.jso
si l'on utilise DCCpp Ethernet avec un serveur Web local ?

bien amicalement
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le novembre 01, 2017, 03:22:43 pm
Bonjour,

Non si tu disposes d'un serveur web (local ou non d'ailleurs). J'ai réalisé plusieurs versions de contrôleurs dont l'une des plus abouties est présentée ici : http://forum.locoduino.org/index.php?topic=302.msg2848#msg2848

Regarde aussi la doc. Ce contrôleur est même opérationnel en ligne mais je peux bien sûr te fournir toutes les sources pour héberger sur ton propre serveur

Par ailleurs, je suis juste en train de terminer une version de ce même contrôleur mais fonctionnant cette fois avec un serveur Node.js en liaison Ethernet ou série (qui dans ce dernier cas peut fonctionner sur un UNO). Cette version avec NodeJs est plus polyvalente et très rapide puisque les connexions HTTP sont remplacées par des sockets TCP/IP.

N'hésite pas à préciser ta demande et ton besoin... et aussi ton niveau en web (javascript, PHP et dans une moindre mesure HTML)

Bien amicalement

Christophe

Titre: Re : DCC++ BaseStation
Posté par: Carcouaille le novembre 01, 2017, 08:26:08 pm
Bonsoir,

Oui, je me suis rendu compte que la carte SD pouvait ne servir à rien.
J'ai installé tour à tour un serveur local sur mon PC, puis un autre serveur local sur une mémoire USB et les deux serveurs fonctionnent en 'localhost' avec ton "controller v2.7" que j'avais préalablement téléchargé.

Le serveur sur PC est UwAmp Wamp Server (http://www.uwamp.com/fr/?page=download).
Le serveur sur carte USB est USBWebserver v8.6 (http://downloadbull.com/portable-usb-webserver-8-6-free-download/).

Par contre, je n'arrive pas à faire passer les commandes sur la station DCCpp que j'ai montée sur un Mega 2560. J'ai vérifié en mode série si ma station DCC++ recevait bien les messages et c'est le cas! Montage avec un shield internet Arduino.org monté et par dessus un Pololu Dual MC33926 pour fournir le courant sur les rails.

En mode COMM_INTERFACE = à 2, malgré un IP qui semble bien correct tant sur la carte que sur le contrôleur HTML, pas moyen d'allumer "power" où d'éteindre la puissance.
L'IP du DDCpp a été contrôlée avec le moniteur série de l'IDE Arduino et la station répond en retour avec l'IP programmé.

En définitive, je suis à l'arrêt en ce moment.

Concernant mes notions de programmation en HTML elles sont assez faibles en ce moment.

PS : J'ai également essayé en mode COMM_INTERFACE à 1 avec un autre shield internet chinois avec "controller W5200" et c'est pareil : pas d'ordre reçu par la station

Bien amicalement Marco
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le novembre 02, 2017, 10:31:07 am
Bonjour Marco,

Tout d'abord, nous sommes arrivé (en version serveur web) à la version 3.0 que je t'invite à télécharger : http://176.154.165.92/locoduino/controller_dccpp_3.0.zip
Il y a eu de nombreuses améliorations entre la 2.7 et la 3

Pour ton problème, il faut vérifier plusieures choses :

1° - Jusqu'à la version 3.0 comprise, il faut faire un ajout de code dans le programme DCC++. As tu une version de DCC++ modifiée ? Voir la doc qui traite de ce point : http://176.154.165.92/locoduino/controller_dccpp/dccppController/reglages_dccpp.php

2° - L'installation de uwamp est selon moi la meilleure solution. Tu ne parles pas de problème de chargement de la page donc je suppose que tu la vois bien en localhost:8080/... selon comment tu as paramétré unwamp.

Ceci ressemble bien à des questions d'adresse IP. Il faut que tu puisses faire des pings pour t'assurer des adresses. Sur PC, ne ne connais pas le principe mais sur Mac par exemple, tu fais -> utilitaire de réseau et tu entres l'IP à vérifier (voir copie écran ci-dessous).

Dans l'immédiat, voilà les deux premières choses à vérifier selon moi.

Maintenant, je suis en train de finaliser une nouvelle version de ce contrôleur qui fonctionne avec un serveur NodeJs. Elle fonctionne mieux, est plus rapide et au final plus simple à configurer pour peu que l'on sache faire tourner NodeJs comme je l'explique dans la série d'articles : http://www.locoduino.org/spip.php?article216

Cette nouvelle version présente en plus l'avantage de fonctionner en Ethernet et en liaison série (donc sans shield Ethernet et éventuellement sur UNO). Si tu peux configurer NodeJs sur ton ordinateur, je te conseille vivement cette version. Comme je n'ai pas totalement fini les tests, je n'ai encore rien publié mais si cela t'intéresse, je peux te communiquer les sources rapidement. Sinon, je pense être prêt sous 8 jours environ.

Tiens moi au courant !

Christophe




Titre: Re : DCC++ BaseStation
Posté par: Thierry le novembre 02, 2017, 10:37:51 am
Sur PC, ne ne connais pas le principe mais sur Mac par exemple, tu fais -> utilitaire de réseau et tu entres l'IP à vérifier (voir copie écran ci-dessous).
Sur PC, il suffit d'ouvrir un ligne de commande (touche Windows, taper les lettres 'c' 'm' et 'd' et valider) puis de taper la commande ping 192.168.*.* avec les bons numéros à la place des étoiles. Soit l'Arduino répond, et ping donne un temps de communication, soit il échoue.
Titre: Re : DCC++ BaseStation
Posté par: Carcouaille le novembre 05, 2017, 08:23:26 am
Bonjour,

Merci Christophe et Thierry pour le travail que vous faites au travers de Locoduino.
Je viens effectivement de télécharger la dernière version du contrôleur dccpp_v3.
Tout fonctionne correctement maintenant, je m'explique :

Précédemment, en mettant le "controller" téléchargé depuis Github et destiné à être installé sur la carte SD du shield Ethernet, je me suis aperçu qu'il refusait de fonctionner sur mon PC Windows 10. Tout dernièrement en mettant en oeuvre le croquis décrit dans "Electronique & Loisirs Magasine" N° 140 pour shield Ethernet, ce dernier contrôleur ne fonctionnant toujours pas avec mon PC windows10, je décidais de le mettre en oeuvre sur mon PC portatif fonctionnant sous windows 7 et ça marche !?! A ce jour je ne sais toujours pas pourquoi Mozilla Firefox a un comportement différent sous les 2 systèmes d'exploitation  ?  J'ai également essayé Edge et Opéra mais c'est pareil......

Concernant le fonctionnement sous serveur local, ton contrôleur v3.0 marche apparemment tout à fait correctement sur mes 2 PC windows 7 & 10.
En fait, je me suis laissé 'berner' par les fonctions "power et "e stop" du panneau contrôleur. Je pensait que le bouton stop devait 'couper' l'alimentation générale et en regardant les lignes de codes, en fait il stoppe seulement tous les trains en mouvement !

Ma question : si urgence pourquoi ne pas couper la tension  réseau ?

Merci encore pour ce que vous faites pour notre hobby,
bien amicalement

Marco

PS:  je suis impatient de connaître la version 'finale' du contrôleur
Titre: Re : DCC++ BaseStation
Posté par: bobyAndCo le novembre 05, 2017, 09:36:02 am
Bonjour Marco,

C'est  très bien que tu aies pu faire fonctionner ce contrôleur et que tu puisses nous faire un retour.

Pour les boutons Power et e-stop, je pense que tu n'as pas eu une bonne lecture du code ! Le bouton e-stop respecte la norme NMRA et ne s'applique qu'à une seule locomotive, celle qui est sélectionnée. Ce bouton commande la vitesse à -1 qui est l'arrêt immédiat de la loco.

Voici le code :

        // Arret immediat de la locomotive
$scope.eStop = function() {
if($scope.locoSelectionnee != null) {
$scope.locoSelectionnee.vitesse = -1;
$scope.setTraction ();
}
}


Power envoie à DCC++ la commande <0> (ou <1>) donc coupure (ou mise sous tension) de l'alimentation.

Citer
Ma question : si urgence pourquoi ne pas couper la tension  réseau ?

Rien ne t'empêche d'utiliser le bouton Power si tu le souhaites mais... cela ne suffira pas toujours à arriver au résultat. En effet, une loco équipée d'un PowerPack continuera à rouler quelques secondes.

Maintenant, peut-être faut il que je réfléchisse à une fonction associée au bouton Power qui placerait toutes les locos en état vitesse -1 avant de couper l'alimentation et le tour serait joué !

Apparement, tu n'as pas eu de problème à installer le contrôleur sur un serveur local (Wamp).

La version NodeJs est opérationnelle, il me reste juste à peaufiner la sauvegarde et le chargement des données. Elle est beaucoup plus rapide que celle que tu utilises et autorise donc plus de choses. Sans doute dans 8 jours au maximum.

Il semble que de son côté, notre ami Thierry nous concocte aussi des choses autour de DCC++ compatible avec ce contrôleur ! Apparement, ça va être bientôt Noël sur Locoduino.

Bien amicalement

Christophe