Auteur Sujet: Détection RailCom© : Des solutions complètes, matérielles et logicielles.  (Lu 17571 fois)

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #15 le: décembre 28, 2024, 11:35:15 am »
Bonjour,

Peux-tu être plus précis sur la version du programme et le nom du projet.

Ceux-ci s'affichent dans le moniteur série au démarrage du programme et sont également écrits dans le programme :

#define VERSION "v 1.4"
#define PROJECT "Railcom Detector ESP32 (freeRTOS)"

becbunsen

  • Jr. Member
  • **
  • Messages: 50
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #16 le: décembre 28, 2024, 01:38:29 pm »
A priori, c'est la version 1.4
J'ai copié/collé directement le code dispo sur le site sans aucune modification.
J'ai juste branché la sortie detection sur le GPIO14
J'avais auparavant essayé avec Railcom in class sur la pin 33 mais ça ne fonctionnait pas non plus.
Je me demandais comment pouvoir controler le signal qui sort de la carte

/*
   Programme de lecture et de décodage des messages Railcom ©
   qui retourne l'adresse d'un décodeur (adresse courte ou longue)

   Fonctionne exclusivement sur ESP32
*/

#ifndef ARDUINO_ARCH_ESP32
#error "Select an ESP32 board"
#endif

#include <Arduino.h>

#define VERSION "v 1.4"
#define PROJECT "Railcom Detector ESP32 (freeRTOS)"
#define AUTHOR  "christophe BOBILLE Locoduino : christophe.bobille@gmail.com"

#include <RingBuf.h> // https://github.com/Locoduino/RingBuffer
#define NB_ADDRESS_TO_COMPARE 100 // Nombre de valeurs à comparer pour obtenir l'adresse de la loco
RingBuf<uint16_t, NB_ADDRESS_TO_COMPARE> buffer;

TaskHandle_t ReceiveData;                         
TaskHandle_t ParseData;                           

// Identifiants des données du canal 1
#define CH1_ADR_LOW 4
#define CH1_ADR_HIGH 8

const byte railComRX = 14; // GPIO14 connecté à  RailCom Detector RX
const byte railComTX = 12; // GPIO12 non utilisée mais doit être déclarée

// Queue
#define QUEUE_SIZE 10
QueueHandle_t xQueue;

void receiveData(void *pvParameters)
{
  TickType_t xLastWakeTime;
  xLastWakeTime = xTaskGetTickCount();
  uint8_t compt{0};
  uint8_t inByte{0};
  for (;;)
  {
    while (Serial1.available() > 0)
    {
      if (compt == 0)
        inByte = '\0';
      else
        inByte = (uint8_t)Serial1.read();
      compt++;
      if (compt == 3)
        compt = 0;
      xQueueSend(xQueue, &inByte, 0);
       Serial.println(inByte);
    }
    // Serial.println("---------");
    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10)); // toutes les x ms
  }
}

void parseData(void *pvParameters)
{
  bool start{false};
  byte inByte{0};
  uint8_t rxArray[8]{0};
  uint8_t rxArrayCnt{0};
  byte dccAddr[2]{0};
  int16_t address{0};
  TickType_t xLastWakeTime;
  xLastWakeTime = xTaskGetTickCount();

const byte decodeArray[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 51, 255, 255, 255, 52,
                        255, 53, 54, 255, 255, 255, 255, 255, 255, 255, 255, 58, 255, 255, 255, 59, 255, 60, 55, 255, 255, 255, 255, 63, 255, 61, 56, 255, 255, 62,
                        57, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36, 255, 255, 255, 35, 255, 34, 33, 255, 255, 255, 255, 31, 255, 30, 32, 255,
                        255, 29, 28, 255, 27, 255, 255, 255, 255, 255, 255, 25, 255, 24, 26, 255, 255, 23, 22, 255, 21, 255, 255, 255, 255, 37, 20, 255, 19, 255, 255,
                        255, 50, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 255, 13, 12, 255, 255, 255, 255, 10, 255,
                        9, 11, 255, 255, 8, 7, 255, 6, 255, 255, 255, 255, 255, 255, 4, 255, 3, 5, 255, 255, 2, 1, 255, 0, 255, 255, 255, 255, 15, 16, 255, 17, 255, 255, 255,
                        18, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 43, 48, 255, 255, 42, 47, 255, 49, 255, 255, 255, 255, 41, 46, 255, 45, 255, 255,
                        255, 44, 255, 255, 255, 255, 255, 255, 255, 255, 66, 40, 255, 39, 255, 255, 255, 38, 255, 255, 255, 255, 255, 255, 255, 65, 255, 255, 255, 255,
                        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};

  auto check_4_8_code = [&]() -> bool
  {
    if(decodeArray[inByte] < 255)
    {
      inByte = decodeArray[inByte];
      return true;
    }
    return false;
  };

  auto printAdress = [&address]()
  {
    Serial.printf("Adresse loco : %d\n", address);
  };

  for (;;)
  {
    do
    {
      xQueueReceive(xQueue, &inByte, pdMS_TO_TICKS(100));
      if (inByte == '\0')
        start = true;
    } while (! start);
    start = false;

    for (byte i = 0; i < 2; i++)
    {
      if (xQueueReceive(xQueue, &inByte, pdMS_TO_TICKS(100)) == pdPASS)
      {
        if (inByte > 0x0F && inByte < 0xF0)
        {
          if (check_4_8_code())
          {
            rxArray[rxArrayCnt] = inByte;
            rxArrayCnt++;
          }
        }
      }
    }

    if (rxArrayCnt == 2)
    {
      if (rxArray[0] & CH1_ADR_HIGH)
        dccAddr[0] = rxArray[1] | (rxArray[0] << 6);
      if (rxArray[0] & CH1_ADR_LOW)
        dccAddr[1] = rxArray[1] | (rxArray[0] << 6);
      address = (dccAddr[1] - 128) << 8;
      if (address < 0)
        address = dccAddr[0];
      else
        address += dccAddr[0];

      uint16_t j = 0;
      buffer.pop(j);
      buffer.push(address);
      bool test = true;
      do
      {
        if (buffer[j] != address)
          test = false;
        j++;
      } while (test && j <= buffer.size());

      if (test && address > 0)
      {
        printAdress();
      }
      // else
      //   Serial.println("NOK");
    }
    rxArrayCnt = 0;
    for (byte i = 0; i < 2; i++)
      rxArray[i] = 0;

    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100)); // toutes les x ms
  }
}

void setup()
{
  Serial.begin(115200);

  Serial.printf("\n\nProject :    %s", PROJECT);
  Serial.printf("\nVersion :      %s", VERSION);
  Serial.printf("\nAuthor :       %s", AUTHOR);
  Serial.printf("\nFichier :      %s", __FILE__);
  Serial.printf("\nCompiled :     %s", __DATE__);
  Serial.printf(" - %s\n\n", __TIME__);

  Serial1.begin(250000, SERIAL_8N1, railComRX, railComTX); // Port série pour la réception des données (250k bauds)
  uint16_t x = 0;
  for (uint8_t i = 0; i < NB_ADDRESS_TO_COMPARE; i++) // On place des zéros dans le buffer de comparaison
    buffer.push(x);
  xQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint8_t)); // Création de la file pour les échanges de data entre les 2 tâches
  xTaskCreatePinnedToCore(receiveData, "ReceiveData", 2048, NULL, 10, NULL, 0); // Création de la tâches pour la réception
  xTaskCreatePinnedToCore(parseData, "ParseData", 2048, NULL, 10, NULL, 1); // Création de la tâches pour le traitement

  while (true)
    ;
}

void loop(){}

Tu reconnaiteras la carte :)
je ne m'en sers que comme branchement de la pin14, pour le reste (Can..) rien n'est activé dans le code
« Modifié: décembre 28, 2024, 01:44:00 pm par becbunsen »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #17 le: décembre 28, 2024, 02:19:21 pm »
Bon j'ai regardé. J'avais une version plus récente (1.5) qui fonctionne chez moi.

Elle est en PJ. Dis moi si ça fonctionne pour toi et je mettrai à jour sur le site

Christophe




bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #18 le: décembre 28, 2024, 04:31:16 pm »
J'en ai profité pour tester les autres versions que j'avais publiées.

La plus intéressante à mon sens est ici sur le Github : https://github.com/Locoduino/Railcom_detector_inClass/tree/main/src

Il s'agit d'une version où, tout d'abord, le code est organisé en fichiers séparés, un peu comme un bibliothèque. Ce qui fait que la partie de code exposé à l'utilisateur est très sommaire et plus simple à comprendre. Ce code est par ailleurs organisé sous forme de classe c++. Il est donc possible de créer plusieurs instances qui fonctionnent en parallèle. On peut relier jusqu'à trois lecteurs Railcom. Trois étant le nombre de ports série hardware sur un ESP32.

Voici le code du fichier principal :



/*

   Programme de lecture, de decodage et d'affichage des messages Railcom ©
   qui retourne l'adresse d'un decodeur (adresse courte ou longue) sur le port serie (250000 bauds)

   Fonctionne exclusivement sur ESP32
   © christophe bobille - locoduino.org

   lib_deps = locoduino/RingBuffer@^1.0.3 / https://github.com/Locoduino/RingBuffer

*/

#ifndef ARDUINO_ARCH_ESP32
#error "Select an ESP32 board"
#endif

#include <Arduino.h>
#include "Railcom.h"

#define VERSION "v 1.7"
#define PROJECT "Railcom Detector ESP32"
#define AUTHOR  "christophe BOBILLE Locoduino : christophe.bobille@gmail.com"

#define  UNUSED_PIN 255

Railcom railcom_0(GPIO_NUM_14, (gpio_num_t) UNUSED_PIN);  // Instance de la classe Railcom
Railcom railcom_1(GPIO_NUM_16, (gpio_num_t) UNUSED_PIN);  // Instance de la classe Railcom
Railcom railcom_2(GPIO_NUM_13, (gpio_num_t) UNUSED_PIN);  // Instance de la classe Railcom

void setup()
{
  Serial.begin (250000); // <- ATTENTION

  Serial.printf("\n\nProject :    %s", PROJECT);
  Serial.printf("\nVersion :      %s", VERSION);
  Serial.printf("\nAuthor :       %s", AUTHOR);
  Serial.printf("\nFichier :      %s", __FILE__);
  Serial.printf("\nCompiled  :      %s - %s \n\n", __DATE__, __TIME__);
}


void loop ()
{
  // Affiche toutes les secondes dans le moniteur serie l'adresse de la locomotive
  Serial.printf("Adresse loco 0 = %d\n", railcom_0.address());
  Serial.printf("Adresse loco 1 = %d\n", railcom_1.address());
  Serial.printf("Adresse loco 2 = %d\n", railcom_2.address());

  delay(1000);
}


Il faut faire attention à la vitesse du port série programmée à 250Kbs. Il faut paramétrer le moniteur série de l'IDE en fonction.

Il suffit juste de régler la bonne broche pour chaque entrée de lecteur Railcom

Christophe
« Modifié: décembre 28, 2024, 04:34:50 pm par bobyAndCo »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #19 le: décembre 28, 2024, 04:50:28 pm »
Je profite de ce fil pour savoir si quelqu'un peut m'apporter la réponse :

J'ai vu qu'il était normalement possible de détecter le sens de roulage des locomotives avec Railcom. Or je ne vois pas comment. Depuis que j'ai fait l'acquisition d’un oscilloscope, je me rattrape et je passe à la moulinette tout ce que j’aurais aimé faire avec au paravant.

J’ai donc scanné le retour du signal Railcom. J’espérais voir à l’oscillo un changement quelconque en changeant le sens de roulage ou en retournant la locomotive. Mais que nenni, l’image ne change pas !

Le signal en bleu est le DCC, celui en jaune Railcom. Je trouve étonnant que Railcom ait une polarité positive au repos (quand il n’y a pas de signal). Mais peut-être que tout ceci tient à la conception même de la carte.

Christophe
« Modifié: décembre 28, 2024, 04:57:50 pm par bobyAndCo »

becbunsen

  • Jr. Member
  • **
  • Messages: 50
    • Voir le profil

Il faut faire attention à la vitesse du port série programmée à 250Kbs. Il faut paramétrer le moniteur série de l'IDE en fonction.

Il suffit juste de régler la bonne broche pour chaque entrée de lecteur Railcom

Christophe

Je vais ré-essayer ça lundi (je bosse tout le WE)
Sinon, sur cette page, ils parlent en effet d'autres informations que l'on peut récuperer par le railcom (tout en précisant que ça dépend du décodeur)
Pour ma part, j'ai des lenz standard V2
https://usuaris.tinet.cat/fmco/railcom_en.html

Autre petit souci, notamment par rapport à ce schema sur le site

j'ai du inverser le DCC entre l'entrée et la sortie. je ne pense pas avoir fait d'erreur de câblage mais si je branchais tel que sur le schéma, ma centrale se mettait en court circuit à l'arrivée de la loco dans la zone.

Merci de ton retour en tous cas
« Modifié: décembre 28, 2024, 05:18:13 pm par becbunsen »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #21 le: décembre 28, 2024, 05:50:46 pm »

Autre petit souci, notamment par rapport à ce schema sur le site

j'ai du inverser le DCC entre l'entrée et la sortie. je ne pense pas avoir fait d'erreur de câblage mais si je branchais tel que sur le schéma, ma centrale se mettait en court circuit à l'arrivée de la loco dans la zone.

Merci de ton retour en tous cas


En DCC malgré ce que l'on pense souvent, il y a une polarité. Si tu as été obligé de modifier la polarité sur la carte Railcom, c'est qu'au niveau de tes rails, il y a une inversion de polarité et pas dans la carte Railcom. Tout tes rails intérieurs doivent être branchés sur la même polarité (couleur de câble) et tous les rails extérieurs sur l'autre polarité !!!
« Modifié: décembre 28, 2024, 07:37:31 pm par bobyAndCo »

bk4nt

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
Bonjour,

Sur "Railcom out", c'est normalement un signal UART classique: 1 au repos... arrive un start bit (0), suit la data (8 bits), un stop bit (1), puis le signal reste 1 si la transmission est finie.

Le sens de la loco, on le trouvera aux sorties des deux LM339.

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #23 le: décembre 28, 2024, 06:04:26 pm »
Ok, je comprends l'histoire de polarité avec l'UART 1 état repos 0 état actif. Merci

Le sens de la loco, on le trouvera aux sorties des deux LM339.

Comment peut-on récupérer cette info ? Aurait-il fallu un branchement supplémentaire ?

bk4nt

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
Ok, je comprends l'histoire de polarité avec l'UART 1 état repos 0 état actif. Merci

Le sens de la loco, on le trouvera aux sorties des deux LM339.

Comment peut-on récupérer cette info ? Aurait-il fallu un branchement supplémentaire ?

Sur "Railcom out", on trouve la combinaison des sorties LM339, via le 7402. Un signal adapté à un UART, peu importe le sens de la loco.

Pour le sens, il faudrait exploiter la sortie d'un LM339 au moins, ajouter quelques composants et un optocoupleur.

bk4nt

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
Comment peut-on récupérer cette info ? Aurait-il fallu un branchement supplémentaire ?

Il s'agirait d'un projet en soi... j'avais pensé à ce qui suit, avec un RP2040

La base de ce schéma récepteur Railcom a 20 ans. Une solution alors simple et efficace: n'importe quel AVR ou PIC entrée de gamme avec un UART pouvait recevoir du Raicom. A l'époque, les CPU n'étaient ni aussi rapides ni aussi dotées que celles d'aujourd'hui.

Sais tu si un UART software à base de RMT peut fonctionner à 250kbps? Il n'y a que quelques octets à recevoir, de temps en temps. Tu peux peut-être faire des tests avec Railcom out, ou encore avec un UART qui envoie quelques octets/s à 250k vers un UART RMT...

Ca ne dit rien d'une vitesse max (qui serait aussi fonction du nombre d'octets/s à traiter):
https://github.com/naffej/esp32-rmt-uart

Edit... je viens de voir ce lien, plus haut. Ca peut donc fonctionner avec du software serial:
https://github.com/Locoduino/Railcom_detector_inClass/tree/main/src


On a trois points qui nous intéressent sur la carte Railcom:
- la sortie de V1/3, la détection du cutout Railcom
- les sorties des deux LM339


Ca ferait 3/4 fils à raccorder:
- V1/3, pour activer deux Rx UART RMT au moment du cutout seulement
- les deux Rx UART RMT étant connectés aux sorties des LM339
- le GND de l'esp32 étant raccordé au DDC 0V

Selon le sens de la loco, le retour Railcom se fera par l'un ou l'autre des deux UART RMT.

En étant prudent avec les alims, il devrait être possible de faire de premiers essais sans optocoupleurs. Sinon, il faut isoler.


Sur ce schéma, R14/C6 doivent être utiles à éliminer du bruit. C'est plutôt à cet endroit, sur C6, qu'il faudrait raccorder les Rx RMT, en utilisant deux portes 7402: une porte et circuit R/C pour chacun des LM339, pour des signaux distincts.

Aux différents points de ce récepteur, la donnée Railcom est inversée ou non. Selon les signaux et où l'esp est connecté, il pourrait y avoir à adapter la bibliothèque UART RMT. Ou le schéma serait à modifier pour une polarité adaptée.
« Modifié: décembre 28, 2024, 08:10:45 pm par bk4nt »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #26 le: décembre 28, 2024, 08:24:03 pm »
Pour que ce que tu proposes fonctionne, il faut que d'une manière ou d'une autre, les informations véhiculées par l'un ou l'autre rail soient différentes. Mais j'ai beau chercher, je ne vois nulle part quelque chose qui confirmerait cela.

Je crois qu'il faut ressortir l'oscillo, décidément un bon investissement, et regarder si le retour d'infos se fait sur un seul rail, ce dont je doute cependant !!!

Sais tu si un UART software à base de RMT peut fonctionner à 250kbps? Il n'y a que quelques octets à recevoir, de temps en temps. Tu peux peut-être faire des tests avec Railcom out, ou encore avec un UART qui envoie quelques octets/s à 250k vers un UART RMT...

Et pourquoi ne pas utiliser les UART hard ? Quoiqu'il en soit, Hard ou Soft, à 250Kbs ça ne doit pas poser de problème sur un ESP ou un RP.

C'est des tests qui peuvent en effet être facilement réalisés, il n'est pas compliqué d'envoyer 2 octets à 250 Kbs à partir d'un µc et de les lire avec un autre.

bk4nt

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #27 le: décembre 28, 2024, 08:37:16 pm »
Si on a des UART hard libre, ça le fera aussi. Les UART soft permettant plus de possibilités, dont d'en avoir plus, et manifestement, ça suffit pour d'aussi petits débits.

Avec Railcom, les décodeurs envoient un courant DC/pulsé dans la voie; la data. La polarité du signal reçu sera fonction de l'orientation physique de la loco sur la voie.

Si c'est un signal positif, c'est un des LM339 qui le détecte. Sinon, c'est l'autre LM339. L'un a sa ref à +18mV, l'autre à -18 mV.

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1143
  • HO avec DCC++
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #28 le: décembre 28, 2024, 08:41:08 pm »

Avec Railcom, les décodeurs envoient un courant DC/pulsé dans la voie; la data. La polarité du signal reçu sera fonction de l'orientation physique de la loco sur la voie.

Si c'est un signal positif, c'est un des LM339 qui le détecte. Sinon, c'est l'autre LM339. L'un a sa ref à +18mV, l'autre à -18 mV.

Ok, effectivement c'est OK alors. Au même moment, je viens de trouver quelque choses d'assez détaillé qui traite de cela, je regarde et je te redis.

bk4nt

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
Re : Détection RailCom© : Des solutions complètes, matérielles et logicielles.
« Réponse #29 le: décembre 28, 2024, 08:48:48 pm »
Pour moi, c'est du DC pulsé, la data. Et la polarité est fonction de l'orientation de la loco sur la voie.

Donc, c'est l'un ou l'autre des LM339 qui détecte le signal, selon qu'il soit positif ou négatif.