LOCODUINO

Ménage à trois (Ordinateur, Arduino, réseau)

.
Par : Christian

DIFFICULTÉ :

Le but de cet article est de décrire un exemple de réseau commandé par un ordinateur et un module Arduino servant d’interface entre les deux. Le réseau décrit ici est un réseau analogique réduit à sa plus simple expression : il comporte une voie terminus (voie 1) et une seule aiguille (A) à l’entrée d’une boucle de retournement. Néanmoins, ce petit réseau nous permet d’aborder des notions très intéressantes qui pourront être appliquées à des réseaux plus importants. Ceux qui pratiquent le numérique auront uniquement à gérer la boucle d’inversion, les voies étant toujours alimentées.

Architecture de l’ensemble

L’ordinateur permet d’afficher le TCO du réseau sur son écran ; en cliquant sur ce TCO, on peut commander l’aiguille, faire démarrer le train, inverser le courant d’alimentation pour le retour du train à la sortie de la boucle. La commande de l’aiguille est réalisée par Arduino, ainsi que l’alimentation de la voie. Les informations doivent être échangées entre l’ordinateur et Arduino. Cet échange se fait par le câble USB qui sert également à alimenter le module Arduino. La figure 1 montre l’architecture retenue.

Figure 1
Figure 1
Architecture du projet

Le coût de construction de ce mini réseau reste faible puisque le réseau n’est pas développé ; il suffit de quelques coupons de voie, une aiguille (à gauche, à droite ou symétrique peu importe), le tout monté sur une planche de medium rigidifiée par des tasseaux, un moteur d’aiguille à solénoïdes ou mieux un servomoteur utilisé comme moteur d’aiguille et bien entendu un module Arduino UNO. Il faut également quelques composants électroniques et deux relais 2RT. Vu la taille de l’ensemble, le train sera plutôt un autorail ou une draisine ou un convoi court et l’ensemble peut être décoré ou non, selon vos goûts et votre intérêt pour le décor.

Vous pouvez télécharger l’archive suivante qui vous donne le programme Processing et le programme pour Arduino, les deux fonctionnant ensemble ; les noms sont les mêmes, « TCO_Mini_Reseau ». Les commentaires sont nombreux et viennent en complément des explications données dans l’article. Commencez par téléverser le programme dans votre carte Arduino. Ensuite, mettez en route le programme Processing.

Vous devrez peut-être modifier la ligne 14 du programme Processing pour indiquer sur quel PORT série se trouve votre module Arduino. Ceci est expliqué dans le paragraphe Communication avec Arduino et doit être fait avant d’utiliser les programmes.
Archive_TCO_Mini_Réseau.zip


Notions abordées pour ce projet

La première chose à faire est de concevoir un TCO interactif en Processing devant réagir à des clics de souris ; ceci nous apprendra à manier Processing, programme qui se marie très bien avec Arduino puisque celui-ci a été conçu au départ pour travailler avec celui-là.

Ensuite, il faudra apprendre à faire communiquer Processing et Arduino, pour que les interactions sur le TCO soient communiquées à Arduino afin de le faire agir sur le réseau. Réciproquement, Arduino devra communiquer des informations à Processing pour que le TCO soit mis à jour.

Enfin, nous verrons comment concevoir des solutions pour qu’Arduino puisse commander l’alimentation des voies et l’aiguille.

Le TCO

La figure 2 montre le dessin du TCO élaboré par Processing. Il faut donc déjà avoir Processing sur son ordinateur ; pour l’installer, et le prendre un peu en main, reportez-vous à l’article Démarrer en Processing (1). Le TCO est constitué de pavés juxtaposés les uns à côté des autres selon une grille de 19 colonnes et 5 lignes ; comme toujours en informatique, la numérotation des lignes et des colonnes se fait en partant de zéro.

Figure 2
Figure 2
TCO élaboré avec Processing

Les pavés représentent donc des formes élémentaires fabriquées pour la circonstance selon les principes décrits dans l’article Processing pour nos trains. Par exemple, pour représenter la voie, nous avons des pavés droits horizontaux (en bleu), un pavé droit vertical (en vert), un pavé « slash / » (en jaune) et un pavé « antislash \ » (en orange), un pavé aiguille (en rouge) et des pavés courbes (en violet) dont il existe six modèles possibles. On remarque également sur le bord gauche un pavé butoir (en marron). Les autres pavés sont des pavés vides qui servent là où il n’y a pas de voie.

Les pavés droits font simplement appel à la fonction « rect » de Processing pour dessiner un rectangle. Les autres pavés font appel à des formes (shape en anglais) qu’il faut définir au préalable (fonction setup) ; ces formes sont appelées ici « barre » (pour la barre ressemblant au slash), « A_barre » (pour la barre ressemblant à l’antislash), et « arcX », X allant de 0 à 5 pour définir des formes courbes. Je ne vais pas détailler comment faire car cela a très bien été décrit dans l’article Processing pour nos trains ; je n’avais jamais pratiqué Processing avant la lecture de cet article et j’ai été capable de créer toutes ces formes après. On peut aussi s’économiser du travail en remarquant qu’il n’y a que trois modèles de courbe à dessiner, les trois autres modèles se déduisant par symétrie (miroir vertical) comme tout programme de dessin permet de faire.

PNG - 131.9 kio
Exemple de création des formes pour dessiner les pavés.
(Cliquez sur l’image pour l’agrandir)


Le dessin du TCO est fait ligne par ligne : les pavés font 9 X 9, mais pour mieux les voir, les dimensions sont multipliées par un zoom qu’on peut régler dans le programme à la ligne 18. Des boucles for sont utilisées lorsque le nombre de pavés identiques à juxtaposer est supérieur à 3. Chaque ligne possède son indice noté J, qui multiplié par 9 sert de coordonnées en y pour positionner le pavé. Les coordonnées en x du pavé correspondent à l’indice de colonne multiplié par 9. Nous avons laissé le programme faire les multiplications par 9, ainsi on distingue mieux où est positionné le pavé ; par exemple, à la ligne 1 du TCO pour laquelle J = 1, le pavé « slash » (pave_barre) est positionné en (11*9, J*9), ce qui correspond à la colonne d’indice 11 soit la douzième case. À la suite de ce pavé, de l’indice 12 à l’indice 17, on trouve des pavés vides. Pour positionner un pavé, il faut donc passer en argument ses coordonnées en x et en y. Lorsque tout le TCO est dessiné, on rajoute un peu de texte pour indiquer le sens départ (DEP) ou arrivée (RET pour retour) sur le TCO (au niveau du butoir) ainsi que le numéro de voie et le nom de l’aiguille pour le jour où on veut agrandir le réseau.

Le dessin du TCO se fait en plein écran, mais vous pouvez aussi choisir de lui donner une taille plus petite. La taille d’affichage du TCO se règle grâce aux lignes 60 et 61 (début du setup).
PNG - 71 kio
L’élaboration du TCO se fait ligne par ligne, puis on écrit du texte.
(Cliquez sur l’image pour l’agrandir)


Le pavé représentant l’aiguille doit être cliquable, ce qui veut dire qu’en cliquant dans le pavé, cela fait changer l’aiguille de direction. Ceci aussi est expliqué dans l’article déjà cité Processing pour nos trains ; j’ai simplement rajouté l’utilisation des coordonnées de la souris pour que seul le pavé soit cliquable (si vous cliquez à l’extérieur, rien ne se passe). Un troisième argument est nécessaire pour dessiner ce pavé : la direction de l’aiguille qui est repérée par la variable booléenne « bscA » qui vaut « true » si l’aiguille est déviée à droite. La facilité d’utilisation de Processing et la puissance de ses fonctions font que la souris se gère facilement.

PNG - 72 kio
Fonction mouseClicked().
(Cliquez sur l’image pour l’agrandir)


Communication avec Arduino

Canal de communication série
Maintenant que le TCO affiche le tracé des voies et la position de l’aiguille, il faut pouvoir transmettre cette information à la carte Arduino pour que celle-ci puisse agir sur la commande de l’aiguille pour la positionner comme l’indique le TCO. Pour cela, il est nécessaire d’établir un canal de communication série via le port sur lequel est connecté la carte Arduino. Pour éviter que le programme génère un message d’erreur ou plante si on n’oublie de brancher une carte Arduino en USB, on vérifie que le port demandé existe bien. Si c’est le cas, on peut créer le TCO à l’écran, sinon on affiche un message d’erreur (ligne 148 du programme) et rien d’autre ne se passe. La fonction vérifiant que le port demandé existe bien se trouve entre les lignes 37 à 57, comme le montre la capture d’écran ci-dessous.

PNG - 82.1 kio
Ouvre la connexion avec Arduino.
(Cliquez sur l’image pour l’agrandir)


Si votre carte Arduino est connectée au port COM1, remplacez "COM4" par "COM1" (sous Mac le nom du port peut être différent : il faut mettre la même chose que ce que l’IDE d’Arduino indique). Ce changement éventuel se situe à la ligne 14 du programme Processing.

Format des messages
Ensuite, la communication se fera en envoyant 3 caractères : le header (constitué du caractère ‘H’) qui permet de repérer le début de la communication, la numérotation de l’aiguille (ici, il n’y en a qu’une appelée A donc ce sera le caractère ‘A’) puis le caractère ‘1’ si l’aiguille est déviée (bscA = true) ou bien le caractère ‘0’ sinon. Pour un réseau comportant plus d’aiguilles, la deuxième serait B, la troisième C, etc. Les instructions sont du type :

myPort.write(HEADER) ou bien myPort.write(‘A’), etc.

La carte Arduino va récupérer ces caractères et selon que le dernier caractère est ‘0’ ou ‘1’, elle agira sur le moteur de l’aiguille et au final, allumera ou non la LED_BUILTIN (reliée à la sortie 13 sur une carte UNO).

Communication Arduino vers Processing
Un bouton poussoir est prévu pour commander en manuel l’aiguille ; dans ce cas, c’est la carte Arduino qui doit communiquer à Processing qu’elle change la position de l’aiguille pour que celui-ci mette à jour le TCO. Ce bouton poussoir est raccordé à l’entrée numérique 2 de la carte Arduino sur laquelle on peut prévoir une interruption. Lorsque le bouton poussoir est appuyé, la routine d’interruption est exécutée, ce qui change le statut de l’aiguille et envoie les 3 caractères vers Processing. La surveillance de la communication se fait en début de fonction draw ou loop. Que ce soit fait par Processing ou bien par Arduino, le décodage des informations reçues se fait en lisant le premier caractère reçu. Si c’est le H de header, on peut alors lire les deux autres caractères. Une série de tests permet alors de voir si on parle de l’aiguille (A), de la voie terminus (T) ou bien de la boucle (L). Lorsqu’on sait de quoi on parle, il suffit de regarder ce que vaut le troisième caractère pour modifier en conséquence les variables.

 
  // surveillance des données entrantes
  if(myPort.available() >= TOTAL_BYTES) // au moins 3 caractères disponibles
  {
    if(myPort.read() == HEADER) // est-ce bien l'entête ?
    {
      // oui, on peut lire les deux autres caractères
      caractere2 = myPort.read();
      caractere3 = myPort.read();
      if(caractere2 == 'A') // on parle de l'aiguille A
      {
        if(caractere3 == '0') {bscA = false;}
        if(caractere3 == '1') {bscA = true;}
      }
      if(caractere2 == 'T') // on parle de la voie terminus
      {
        if(caractere3 == '0') {sensVT = 0;}
        if(caractere3 == '1') {sensVT = 1;}
      }
      if(caractere2 == 'L') // on parle de la boucle
      {
        if(caractere3 == '0') {sensB = 0;}
        if(caractere3 == '1') {sensB = 1;}
      }
    }
  }

La partie de programme ci-dessus aurait pu aussi s’écrire avec des switch case comme montré ci-dessous. Le programme gagne en efficacité puisqu’il va directement au cas considéré sans avoir à tester des conditions fausses comme c’est le cas avec des séries de if.

  // surveillance des données entrantes
  if(myPort.available() >= TOTAL_BYTES) // au moins 3 caractères disponibles
  {
    if(myPort.read() == HEADER) // est-ce bien l'entête ?
    {
      // oui, on peut lire les deux autres caractères
      caractere2 = myPort.read();
      caractere3 = myPort.read();
      switch (caractere2) {
        case 'A' :  // On parle de l aiguille A
        switch (caractere3) {
          case '0' :
          bscA = false;
          break;
          case '1' :
          bscA = true;
          break;
        }
        break;
        case 'T' :  // On parle de la voie terminus
        switch (caractere3) {
          case '0' :
          sensVT = 0;
          break;
          case '1' :
          sensVT = 1;
          break;
        }
        break;
        case 'L' :  // On parle de la boucle (Loop)
        switch (caractere3) {
          case '0' :
          sensB = 0;
          break;
          case '1' :
          sensB = 1;
          break;
        }
        break;
        }

Commande de l’aiguille

À partir du moment où on est capable d’allumer une LED en réaction à une action de cliquer, on peut faire n’importe quoi d’autre, comme par exemple commander le moteur de l’aiguille ; il suffit pour cela d’amplifier le signal de sortie de la carte Arduino. On peut être tenté de mettre les instructions de commande du moteur dans la routine d’interruption, mais ce n’est pas une si bonne idée. En effet, une routine d’interruption doit être la plus courte possible (voir à ce sujet l’article Les interruptions (1)). Si l’aiguille est déplacée par des solénoïdes, l’impulsion durera 300 ms approximativement ; c’est déjà beaucoup, alors que dire d’une aiguille déplacée par un moteur lent ou un servomoteur qui fera le mouvement en plusieurs secondes ? La solution est de surveiller dans le programme principal chaque changement de la bascule « bscA » de l’aiguille A qui passe de false à true et réciproquement. Tout changement de cette bascule entraîne un mouvement de l’aiguille dans un sens ou dans l’autre. Nous verrons un peu plus loin comment la carte Arduino peut changer la direction de l’aiguille.

Commande de la voie

En analogique, le câblage de la voie terminus se fait en ménageant une zone de garage de longueur supérieure à la dimension de l’engin moteur avec une coupure sur le rail supérieur, coupure qui est pontée avec une diode 1N4004 ou 1N4007 positionnée dans le bon sens comme le montre la figure 3. Supposons que cette zone fasse les quatre premiers pavés du TCO.

Dans le sens arrivée, le rail positif (en rouge) ne peut pas alimenter la zone de garage : le train s’arrête sur celle-ci. Dans le sens départ, le rail négatif (en bleu) alimente la zone de garage car la diode est dans le bon sens : le train part. Il suffit donc d’inverser la polarité de l’alimentation sur la voie terminus pour faire repartir le train : cette inversion de polarité est gérée par la carte Arduino.

Figure 3
Figure 3
Voie terminus en analogique

Il reste à gérer la boucle de retournement pour qu’elle ne fasse pas court-circuit, qu’on soit en analogique ou en numérique. Encore une fois, on peut prévoir un dispositif commandé par la carte Arduino. En effet, comme le montre la figure 4, la portion de boucle située entre A et B est alimentée comme la voie de départ ; arrivée en B, les roues métalliques de l’engin moteur créent un court-circuit. Il faut donc agir lorsque tout le train se situe sur la portion A-B pour inverser la polarité de la voie terminus, ce qui permet le retour du train.

Figure 4
Figure 4
Attention au court-circuit !

Un capteur peut détecter la position du train et envoyer un signal à Arduino lorsqu’il est temps d’inverser la polarité de la voie terminus. Ce capteur est à positionner au milieu de la boucle à condition que la longueur du train soit inférieure à la moitié de la boucle. Pour des trains plus longs, il faut déplacer le capteur de telle sorte que tout le train soit sur la boucle quand le capteur se déclenche. Dans ce cas, si on veut utiliser la boucle dans les deux sens de circulation, il faut deux capteurs mais un seul doit se déclencher, en fonction du sens de circulation. Toutes ces variables sont connues de la carte Arduino qui peut alors gérer cela. Nous prendrons comme hypothèse que les trains sont courts (autorails par exemple) et nous positionnons un seul capteur à la moitié de la boucle, au niveau du pavé (2, 18). Un ILS ou une barrière infra-rouge peut faire l’affaire. Le signal de ce capteur est envoyé à la carte Arduino qui agit pour inverser le courant sur la voie terminus, tout en envoyant l’information à Processing pour que celui-ci mette à jour le TCO.

Représentation du sens de circulation sur le TCO

Deux variables définissent le sens de circulation du train sur la voie terminus et sur la boucle : sensVT et sensB. Sur la voie terminus, sensVT égale 0 pour le sens départ (0 comme le O de Output) et 1 pour le sens retour (1 comme le I de Input) ; pour la boucle sensB égale 0 si le train la parcourt dans le sens des aiguilles d’une montre et 1 dans le sens inverse. Les sens de circulation sont représentés par des couleurs différentes sur le TCO : par exemple, la voie de garage est en gris si elle n’est pas alimentée, en vert si le rail supérieur est négatif, en orange si le rail supérieur est positif (voir figure 3 et figure 5). On voit ainsi très bien la possibilité de court-circuit durant le parcours de la boucle si rien n’est fait. Il n’y a pas de changement de couleur pour le pavé droit vertical (2, 18) qu’on dessine en blanc. En regardant le haut de la boucle, on visualise tout de suite son sens de parcours : vert dans le sens des aiguilles d’une montre, orange dans le sens contraire. Pour construire les pavés, il faut un argument de plus permettant de définir la couleur : on peut prendre sensVT ou sensB selon le cas.


Si l’orange et le vert ne vous plaisent pas, vous pouvez modifier dans Processing la définition des couleurs « COULEUR_POSITIF » et « COULEUR_NEGATIF » (à la ligne 17 du programme Processing) : celle-ci se présente sous la forme de trois octets en hexadécimal donnant respectivement les quantités de rouge, de vert et de bleu (RGB pour Red, Green, Blue), le tout précédé du symbole dièse #. Par exemple, pour changer le vert en bleu, il suffit de mettre #0000FF à la place de #00FF00.

À l’initialisation, le train est à l’arrêt sur sa voie de garage représentée en gris car non alimentée. En cliquant sur la voie au niveau du butoir, celle-ci passe en vert : le train démarre. La couleur de la boucle dépend du sens de circulation donc du sens de déviation de l’aiguille. Il y a ainsi quatre cas possibles comme le montre la figure 5.

Figure 5
Figure 5
Circulation sur la boucle de retournement

En cliquant sur le butoir, on change la polarité de la voie permettant ainsi le départ du train ; il faut donc envoyer les informations à la carte Arduino pour que celle-ci agisse sur le réseau.

Envoi des informations de sens de circulation

La transmission TCO vers Arduino sera du même style que ce qui a été fait précédemment. Après le header ‘H’ signifiant le début de transmission, on trouve l’appellation de la voie qui est soit le caractère ‘T’ pour voie terminus (ou track = voie en anglais), soit le caractère ‘L’ pour boucle (loop an anglais). Vient ensuite le caractère ‘0’ ou ‘1’ pour définir le sens.

Arduino reçoit les informations, les décode et allume une LED reliée à la sortie 12 si la voie terminus est dans le sens du départ ainsi qu’une LED reliée à la sortie 11 si la boucle est parcourue dans le sens des aiguilles d’une montre.

On a vu plus haut qu’un capteur positionné en (2, 18) indique à Arduino quand il est temps de changer la polarité de la voie terminus pour éviter un court-circuit avec la boucle. Lorsqu’Arduino reçoit le signal, il positionne l’aiguille A dans le bon sens pour le retour, et change le sens de circulation sur la voie terminus pour le mettre en sens « retour ». Il doit donc envoyer les données concernant l’aiguille et la voie terminus au TCO pour que l’affichage soit conforme. Encore une fois, le même protocole de transmission est suivi. Le capteur est relié à l’entrée 3 qui permet également les interruptions sur une carte UNO.

Arduino et le réseau

C’est la carte Arduino qui agit sur le réseau, en fonction des informations qu’elle reçoit de la part de Processing, donc en fonction des ordres que vous donnez (départ d’un train, aiguillage pour déterminer les deux itinéraires possibles). Nous allons donc voir maintenant quelques solutions possibles pour qu’Arduino puisse agir sur le réseau.

Déplacement de l’aiguille avec solénoïdes

L’utilisation de moteur à solénoïdes nécessite deux sorties numériques de l’Arduino ; en fonction du sens de mouvement, on positionne l’une ou l’autre sortie à HIGH afin de commander un transistor (à effet de champ si possible) qui laissera passer le courant dans le solénoïde. Le transistor doit être capable de laisser passer un courant égal à ce que consomme le solénoïde ; il vaut mieux prévoir large. Bien évidemment, l’alimentation des solénoïdes doit se faire avec du courant continu puisque les transistors ne sont pas prévus pour du courant alternatif. Si les solénoïdes n’ont pas d’interrupteurs de fin de course, il faut impérativement calibrer la durée de l’impulsion au minimum requis pour permettre le mouvement et ne jamais dépasser ce que préconise le constructeur de l’aiguille (généralement une seconde).

Déplacement de l’aiguille avec un servomoteur

La meilleure solution pour déplacer les lames de l’aiguille est certainement le servomoteur utilisé en radiocommande parce que cela ne nécessite qu’une seule sortie sur la carte Arduino. De plus, il existe une bibliothèque très simple d’emploi qui permet de régler précisément le déplacement des lames et la vitesse de déplacement.

Le programme livré pour Arduino utilise la sortie 10 pour commander un servo moteur : il utilise la bibliothèque Servo livrée avec l’IDE. La description de cette bibliothèque est faite dans l’article La bibliothèque Servo. L’alimentation du servomoteur peut être prise sur la carte Arduino puisqu’il n’y a qu’une seule aiguille à commander. Si vous souhaitez rajouter des aiguilles à ce projet, il est préférable d’utiliser une alimentation séparée pour tous les servomoteurs comme le montre la figure 6.

Figure 6
Figure 6
Arduino et les servomoteurs

Le programme regarde si un positionnement de l’aiguille est nécessaire en comparant la valeur actuelle à la dernière valeur connue ; si ces valeurs sont différentes, la fonction aiguillage est appelée avec comme argument la position souhaitée (booléen bscA). Le positionnement de l’aiguille se fait entre deux valeurs extrêmes (butées) qu’il faudra régler en fonction de la géométrie de l’aiguille et de la transmission mécanique reliant le palonnier du servomoteur et les lames d’aiguille. Le mouvement se fait ensuite selon le sens voulu entre ces deux butées en incrémentant ou décrémentant grâce à la fonction writeMicroseconds(). Durant le mouvement, on fait clignoter la LED_BUILTIN puis à la fin du mouvement, on l’allume ou on l’éteint pour visualiser la position obtenue.

Alimentation des voies

La carte Arduino se charge de régler la polarité d’alimentation de la voie terminus et de la boucle. Pour cela, les signaux des sorties 11 et 12 sont recopiés sur les sorties 8 et 9 ; les courants des sorties 8 et 9 sont amplifiés avec un circuit ULN2803 (voir l’article Amplifier le signal de sortie d’un ARDUINO avec un ULN 2803) et ainsi peuvent commander deux relais monostables 2RT qui servent à inverser la polarité du courant sur les rails (pour plus de précision sur les relais, vous pouvez consulter le cours d’électronique téléchargeable en fichiers PDF dans l’article Démarrer en électronique). La figure 7 montre comment monter ces relais entre le transformateur et les rails.

Figure 7
Figure 7
Montage sur platine d’essai des relais

Conclusion

Vous disposez d’un TCO interactif en couleur sur l’écran de votre ordinateur et d’une carte Arduino capable de commander ce petit réseau. L’aiguille est commandée par un servomoteur et trois LED permettent de contrôler le bon fonctionnement de la carte Arduino. La figure 8 montre comment monter l’ensemble.

Figure 8
Figure 8
Schéma complet

Le but de ce petit réseau était surtout de découvrir des techniques pouvant s’appliquer à des réseaux plus importants, moyennant bien-sûr plus de travail. Réalisé à l’échelle Z ou N, il peut constituer un petit diorama que vous prendrez plaisir à décorer en cachant la majeure partie de la boucle de retournement dans une colline. En rajoutant une aiguille triple, vous pouvez constituer un mini-grill pour votre gare terminus, ce qui peut augmenter le plaisir du jeu. L’aiguille triple est un peu plus compliquée à commander (de même que les TJD et TJS) mais c’est tout-à-fait possible ; je vous laisse le découvrir par vous-même. Vous pouvez aussi concevoir un mode automatique pour la carte Arduino qui fera partir et revenir vos trains selon un horaire préétabli et si vous rajoutez une deuxième voie à votre boucle de retournement, vous pourrez varier les circulations en cachant les trains sous la colline le temps d’en faire circuler d’autres. Alors, qui a pensé que ce réseau était trop simple pour présenter de l’intérêt ?

Réagissez à « Ménage à trois (Ordinateur, Arduino, réseau) »

Qui êtes-vous ?
Votre message

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

Lien hypertexte

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

Rubrique « Projets »

Les derniers articles

Les articles les plus lus