Voir les contributions

Cette section vous permet de consulter les contributions (messages, sujets et fichiers joints) d'un utilisateur. Vous ne pourrez voir que les contributions des zones auxquelles vous avez accès.


Messages - bobyAndCo

Pages: 1 [2] 3 4 ... 76
16
Vos projets / Re : Identification des trains par infrarouge
« le: mai 10, 2025, 04:42:08 pm »
Bonjour à tous,

J'ai embarqué dans un wagon le TSAL6400 + Arduino Nano + pont de diode + régulateur 5V + capa et diverses résistances.

J'avais un peu la flemme de programmer un ATtiny. De cette manière, ceux qui peuvent être rebutés par l’ATtiny constatent que c’est tout à fait réalisable avec un Nano.









Je crois que la vidéo parle d’elle-même. Je doute qu’aucun train ne circule jamais à cette vitesse et vous constaterez qu’il y a de la marge avec le nombre de captures à chaque passage !

Bon week-end à tous et bon train

Christophe




17
Vos projets / Re : Identification des trains par infrarouge
« le: mai 09, 2025, 08:09:43 pm »
Merci Dominique.

De mon côté, je veux remercier Jean-Pierre (JPM06) d'avoir apporté ce sujet sur un autre outil d'identification à côté de Railcom et du RFID. Il y a beaucoup de côtés positifs dont la fiabilité et le cout très raisonnable.

Deux petites ombres au tableau toutefois : l'encombrement qui oblige à placer l'ensemble dans un wagon "suiveur" et la nécessité de s'alimenter sur la voie (DCC ou DC).

Christophe

18
Vos projets / Re : Identification des trains par infrarouge
« le: mai 09, 2025, 07:35:43 pm »
Bonsoir à tous,

Heureusement pour moi, la journée se termine sur une note beaucoup plus positive que la presque totalité de ma journée. J'ai en effet passé de nombreuses heures à tenter de faire fonctionner la réception sur un ESP32 sans jamais parvenir à quelque chose de fiable. L'ESP me renvoyant de nombreuses erreurs de lecture sur les interruptions renvoyant donc des valeurs erronées.

Jusqu'à ce que je me décide à passer sur un Raspberry Pi Pico. Et là, oh merveille, tout c'est mis à fonctionner parfaitement du premier coup !!!



Jusqu'ici je n'avais réalisé que quelques projets avec le Raspberry. Ayant un peu la flemme de changer ma façon de coder. Mais là, je vais revoir mon approche et chercher à systématiser le Raspberry, plus puissant, moins cher, disposant de plus de broches qu'un ESP32 et au final plus fiable.

Voici le code (de test) du récepteur qui ne cherche qu'à afficher la valeur transmise au travers de la led et du TSOP.

#include <Arduino.h>
#include "pico/multicore.h"
#include "pico/util/queue.h"

volatile uint32_t duration = 0;

constexpr byte pinIn = 15;  // Broche du TSOP

bool receiving = false;
uint8_t currentByte = 0;
int8_t bitIndex = 7;

// File pour les bits détectés
queue_t durationQueue;

enum DecodeState {
  IDLE,
  RECEIVING
};
DecodeState currentState = IDLE;

void handleIR() {
  static uint32_t lastTime = 0;
  uint32_t now = micros();
  uint32_t duration = now - lastTime;
  lastTime = now;
  queue_try_add(&durationQueue, &duration);
}

void setup() {
  Serial.begin(115200);
  pinMode(pinIn, INPUT);
  // Initialisation de la queue pour 16 durées
  queue_init(&durationQueue, sizeof(duration), 16);
  attachInterrupt(digitalPinToInterrupt(pinIn), handleIR, RISING);
}

void loop() {
  uint32_t duration = 0;
  if (queue_try_remove(&durationQueue, &duration)) {
   
    switch (currentState) {

      case IDLE:
        if (duration > 1600 && duration < 2400) {
          // Début de trame détecté
          currentByte = 0;
          bitIndex = 7;
          currentState = RECEIVING;
        }
        break;

      case RECEIVING:

        if (duration >= 400 && duration <= 700) {
          // Bit 1
          currentByte |= (1 << bitIndex);
          bitIndex--;
        } else if (duration >= 800 && duration <= 1200) {
          // Bit 0
          currentByte &= ~(1 << bitIndex);
          bitIndex--;
        } else {
          // Durée invalide
          currentState = IDLE;
          break;
        }

        if (bitIndex < 0) {
          Serial.printf("Octet reçu : 0x%02X\n", currentByte);
          currentState = IDLE;
        }
        break;
    }
  }
}


Je n'ai aucune erreur et donc je ne pense pas nécessaire de mettre en place un mécanisme de contrôle. (checksum)

Je vais maintenant passer le code de l'emetteur sur un ATTiny (25/45/85) et dessiner des PCB pour toute la partie emission et réception. Je communiquerai les schémas dès que je les aurai réalisés.

Christophe


19
Vos projets / Re : Identification des trains par infrarouge
« le: mai 08, 2025, 08:03:25 pm »
Bonjour à tous,

Aujourd’hui, travail sur le codage des bits. J’ai retenu le principe qui est que un bit est toujours constitué d’un front montant et d’un front descendant de même durée (comme pour le DCC).



Un bit 1 a une durée de 560µs (2 x 280µs).



Un bit 0 a une durée de 1000µs (2 x 500µs).



Ls bits de synchro qui séparent les octets de données ont une durée de 2000µs environ (2 x 1 ms)



Voici par exemple représenté l’octet de data 0xAA qui est une alternance de 0 et de 1 10101010 pour une durée moyenne de 6 ms ce qui fait avec le bit de synchro plus de 100 envois par seconde.

Je précise que les copies d’écran correspondent à des mesures en sortie du TSOP4838. Vous pouvez constater que le signal est très propre.

Le code définitif pour l'émetteur, qui sera sur un ATTiny (25, 45 ou 85) est très simple mais j'ai repris le fichier IRTimer.hpp de IRremeote :


```cpp
#include <Arduino.h>

// Configuration du timer pour PWM IR
#define IR_USE_AVR_TIMER2              // Utilise Timer2 pour l'envoi (pin D3)
#define SEND_PWM_BY_TIMER              // Active le mode PWM matériel

#include "IRTimer.hpp" // Part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.

#define IR_SEND_PIN 3                   // Broche utilisée
constexpr uint8_t DATA = 0xAA;          // Octet à envoyer
constexpr uint16_t BIT_DURATION = 500;  // Durée d’un bit en µs

// Envoie un octet codé via LED IR
void sendManchesterByte(uint8_t value) {
  for (int i = 7; i >= 0; i--) {
    bool bit = (value >> i) & 0x01;
    if (bit) {
      // 1
      disableSendPWMByTimer();  delayMicroseconds(BIT_DURATION / 2);
      enableSendPWMByTimer();   delayMicroseconds(BIT_DURATION / 2);
    } else {
      // 0
      disableSendPWMByTimer();  delayMicroseconds(BIT_DURATION );
      enableSendPWMByTimer();   delayMicroseconds(BIT_DURATION );
    }
  }
  // Fin de trame
  disableSendPWMByTimer();
  delayMicroseconds(BIT_DURATION * 2);
  enableSendPWMByTimer();
  delayMicroseconds(BIT_DURATION * 2);
}

void setup() {
  pinMode(IR_SEND_PIN, OUTPUT);
  timerConfigForSend(38);             // Fréquence IR : 38 kHz
  disableSendPWMByTimer();            // Démarre éteint
}

void loop() {
  sendManchesterByte(DATA);
}

```


Reste à tester maintenant avec le code sur le récepteur (ESP32) ce que j'espère pouvoir terminer rapidement. Cela permettra de voir s'il faudra ajouter un checksum pour vérifier la conformité de l'envoi.

Christophe



20
Vos projets / Re : Identification des trains par infrarouge
« le: mai 07, 2025, 07:10:38 pm »
Bonjour à tous,

Premiers tests aujourd’hui avec les composants tout juste reçus. Pour les leds émettrices, j’ai pris des TSAL6400 de VISHAY 5mm (0,31€ pièce) et comme récepteur le TSOP4838 de chez VISHAY également.

Premier constat, les performances sont assez stupéfiantes, aucun problème de distance et l’angle dans lequel le faisceau est actif est également assez stupéfiant ce qui peut permettre des mesures sur une durée assez longue.

Les signaux mesurés à l’oscillo à la sortie du TSOP4838 sont très propres. Pour les fronts les plus courts, je mesure environ 600µS ce qui devrait me permettre d’allonger les alternances telles que je les avais envisagées au départ (13µs !!!). Il y a de la marge.

Premiers résultats encourageants donc… à suivre

Christophe



21
Vos projets / Re : Re : Identification des trains par infrarouge
« le: mai 02, 2025, 09:43:16 pm »
Concernant la modulation de l'IR, elle n'est nécessaire que pour une transmission à plus longue distance avec de la lumière parasite. Mais la distance émetteur-récepteur est ici de l'ordre du centimètre, et les deux sont face à face.

Par ailleurs, si on modulait l'IR, il faudrait bien entendu le démoduler ensuite au niveau du récepteur pour filtrer. Il existe justement des démodulateurs tout faits (pour télécommandes TV et autres) et j'en ai essayé. Mais on perd énormément en débit, pour des raisons autant théoriques (filtrage = retard) que pratiques.

Il y a plusieurs avantages à coder comme je le propose. Je profite de la fréquence à 38Khz pour créer un signal codé sur 2 * 8 bits. Simple et efficace et suffisant. Nul besoin de recourir à des biblio extérieures comme SoftwareSerial (pas très performante) ou IR Remote (lourde et complexe).

Effectivement, côté réception, j’utilise cette fois une routine d’interruption qui, en fonction de plages de durées peut facilement décoder les messages.

J’ai justement développé le code pour la réception sur un ESP32. Là aussi, pas besoin de biblio externe et l’on obtient un code léger et rapide.

Ultérieurement, j’envisagerai peut-être de passer sur RMT qui dans ce cas devrait pouvoir mettre environ 8 à 10 émetteurs IR sous surveillance. Intéressant.

https://www.makerguides.com/esp32-and-ir-remote-interface/

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/rmt.html

Voici le code pour un ESP32 sous interruption :

const byte irPin = 2;  // D2 (INT0) connecté à la sortie du TSOP4838

volatile uint64_t lastTime = 0;
volatile uint64_t pulseWidth = 0;

volatile byte receivedBytes[2]; // [0] = identifiant, [1] = checksum
volatile byte bitCount = 0;
volatile byte byteIndex = 0;
volatile bool receiving = false;
volatile bool newData = false;

void setup() {
  Serial.begin(115200);
  pinMode(irPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(irPin), handleIR, CHANGE);
}

void loop() {
  if (newData) {
    byte id = receivedBytes[0];
    byte chk = receivedBytes[1];

    if ((id ^ 0xA5) == chk) {
      Serial.print("ID valide : 0x");
      Serial.println(id, HEX);
    } else {
      Serial.print("Erreur checksum - ID: 0x");
      Serial.print(id, HEX);
      Serial.print(" / Checksum: 0x");
      Serial.println(chk, HEX);
    }
   
    newData = false;
    byteIndex = 0;
    bitCount = 0;
  }
}

// Interruption sur changement d’état du signal TSOP
void handleIR() {
  uint64_t now = micros();
  pulseWidth = now - lastTime;
  lastTime = now;

  // Détecter le bit de start : burst long (2.4 ms)
  if (pulseWidth > 2000 && pulseWidth < 3000) {
    receiving = true;
    bitCount = 0;
    byteIndex = 0;
    receivedBytes[0] = 0;
    receivedBytes[1] = 0;
    return;
  }

  if (!receiving) return;

  // Interprétation des bits en fonction des durées mesurées
  if (pulseWidth >= 1000 && pulseWidth < 1300) {
    // Bit 1 = 600 burst + 600 silence
    receivedBytes[byteIndex] = (receivedBytes[byteIndex] << 1) | 1;
    bitCount++;
  } else if (pulseWidth >= 1600 && pulseWidth < 2000) {
    // Bit 0 = 600 burst + 1600 silence
    receivedBytes[byteIndex] = (receivedBytes[byteIndex] << 1);
    bitCount++;
  }

  // Passage à l'octet suivant
  if (bitCount == 8) {
    bitCount = 0;
    byteIndex++;
    if (byteIndex >= 2) {
      receiving = false;
      newData = true;
    }
  }
}




Christophe

PS : J'ai codé une centrale MFX avec RMT sur ESP32, c'est top : https://github.com/BOBILLEChristophe/directMFX_ESP32/blob/main/src/MfxRMT.cpp

22
Vos projets / Re : Identification des trains par infrarouge
« le: mai 02, 2025, 05:13:45 pm »
Bonjour JPM06,

L'hypothèse du 4/8 ne se justifie sans doute pas. Peut-être même n'y a t'il pas besoin de contrôle. Mais ça, c'est ça vérifier selon le taux d'erreurs aux essais.

J'ai malheureusement pas beaucoup de temps et peut-être pas les composants, mais j'ai commencé à écrire un code simple mais complet pour un émetteur sur ATTiny. J'ai même ajouté un checksum très sommaire mais certainement suffisant.

bit de start + data + checksum + bit de stop.

/*

  idTrainIr38kHzATTiny_emetteur
 
  Identification de trains avec led IR à 38Khz

  Programme pour ATTiny 25/45/85

           _______
  (Reset) -|1   8|- Vcc
     PB3  -|2   7|- PB2
     PB4  -|3   6|- PB1 ← LED IR (OC0B)
     GND  -|4   5|- PB0
           -------

*/

// Définition de la broche utilisée pour la LED IR (PB1 = pin 6)
#define LED_BIT PB1
#define LED_DDR DDRB
#define LED_PORT PORTB

// Octet d'identification du convoi
const byte identifiant = 0x5A; // Exemple

void setup() {
  // Configurer la broche PB1 comme sortie (celle connectée à la LED IR)
  LED_DDR |= (1 << LED_BIT);
  // Initialiser le Timer0 en PWM à 38 kHz sur OC0B (PB1)
  setup38kHzPWM();
}

void loop() {
  byte checksum = identifiant ^ 0xA5;  // XOR avec une constante arbitraire 0xA5
  // Émission d'une trame IR : Start + ID + Checksum + Stop
  sendStartBit();
  sendByte(identifiant);
  sendByte(checksum);
  sendStopBit();
  delay(500);
}

// Configuration du Timer0 pour produire du PWM à 38 kHz sur OC0B (PB1)
void setup38kHzPWM() {
  // Mode Fast PWM avec TOP = OCR0A (Mode 7 : WGM02 + WGM01 + WGM00)
  // OCR0A définit la période → fréquence = 16MHz / (2 × (OCR0A + 1))
  TCCR0A = _BV(WGM01) | _BV(WGM00) | _BV(COM0B1); // Sortie sur OC0B activée
  TCCR0B = _BV(WGM02) | _BV(CS00); // Pas de préscaler (division par 1)
  // Pour 38 kHz : OCR0A = 210 → période ≈ 26.3 µs
  OCR0A = 210;
  // Rapport cyclique 50 % → OCR0B = moitié de OCR0A
  OCR0B = 105;
}

// Active ou désactive le signal PWM sur OC0B (PB1)
void enablePWM(bool on) {
  if (on) {
    // Active le lien entre le Timer0 et la broche PB1
    TCCR0A |= _BV(COM0B1);
  } else {
    // Déconnecte le Timer0 de la broche
    TCCR0A &= ~_BV(COM0B1);
    // Force la broche PB1 à l'état LOW (éteint la LED IR)
    LED_PORT &= ~(1 << LED_BIT);
  }
}

// Envoie un octet (8 bits) bit par bit, MSB en premier
void sendByte(byte data) {
  for (int i = 7; i >= 0; i--) {
    if (data & (1 << i))
      sendBit1();
    else
      sendBit0();
  }
}

// Envoie un bit logique '1' : 600 µs burst + 600 µs silence
void sendBit1() {
  enablePWM(true);             // Allume la LED IR (signal 38 kHz)
  delayMicroseconds(600);      // Durée du burst
  enablePWM(false);            // Éteint la LED
  delayMicroseconds(600);      // Rien
}

// Envoie un bit logique '0' : 600 µs burst + 1600 µs silence
void sendBit0() {
  enablePWM(true);             // Allume la LED IR
  delayMicroseconds(600);      // Durée du burst
  enablePWM(false);            // Éteint la LED
  delayMicroseconds(1600);     // Espace long
}

// Envoie un bit de start (synchronisation) : burst de 2400 µs
void sendStartBit() {
  enablePWM(true);             // Allume la LED IR
  delayMicroseconds(2400);     // Long burst = signal de synchronisation
  enablePWM(false);            // Éteint la LED
  delayMicroseconds(600);      // Pause après start
}

// Envoie un bit de stop
void sendStopBit() {
  enablePWM(false);            // LED éteinte
  delayMicroseconds(2000);     // fin
}

Si quelqu'un veut tester avec un UNO je peux fournir le code, il y a juste les ports à changer (à priori)

#define LED_BIT PB1
#define LED_DDR DDRB
#define LED_PORT PORTB

void setup38kHzPWM() {
  // Timer2 en mode Phase Correct PWM à 38 kHz sur OC2B (D3)
  TCCR2A = _BV(WGM21) | _BV(COM2B1);  // COM2B1 = PWM activé
  TCCR2B = _BV(WGM22) | _BV(CS20);    // CS20 = pas de prescaler
  OCR2A = 210;                        // Fréquence = 16MHz / (2 * (OCR2A + 1)) ≈ 38 kHz ≈ 26.3 µs
  OCR2B = 105;                        // 50 % de duty cycle
}

// Active ou désactive le PWM sur D3
void enablePWM(bool on) {
  if (on)
    TCCR2A |= _BV(COM2B1);        // Activer sortie OC2B
  else {
    TCCR2A &= ~_BV(COM2B1);       // Désactiver OC2B
    LED_PORT &= ~(1 << LED_BIT);  // Mettre D3 à LOW
  }
}

Sans garantie cependant pour le UNO

Christophe

23
Vos projets / Re : Identification des trains par infrarouge
« le: mai 01, 2025, 06:49:45 pm »

JPM06 utilise un TSAL4400 alors que Dave Bodnar utilise un TSAL6400

Référence | Angle (°) | Intensité (mW/sr) | Faisceau
TSAL4400 |    ±22     | 45                       | Moyen
TSAL6400 |    ±25     | 30                       | Large (tolérant)

Une rapide recherche semble donner un certains avantage au TSAL6400 hormis pour l'intensité. Quelqu'un à t'il un avis sur ce point.

Par ailleurs, je me pose la question de savoir s'il faut utiliser le port série (UART) ou alors fabriquer son propre protocole et utiliser un timer pour générer le signal et une interruption pour le lire.

Le protocole série ne peut pas fonctionner à 38 Khz et il faudra de toute façon passer par une biblio qui elle même utilisera des timers. Et la structure des trames est plus "lourde". Je pense même que l'on pourrait reprendre le principe de codage adopté par Railcom (4/8). Voir l'article sur les décodeurs Railcom : https://www.locoduino.org/spip.php?article334



On limite à 127 le nombre de locos identifiables (mais c'est déjà pas mal) et on a un fonctionnement très léger et beaucoup plus rapide. Des avis sur le sujet?

J'ai très envie de réaliser ce projet car je le trouve amusant, assez simple et économique. Les ATTiny que je trouve on utilise pas suffisamment sont taillés sur mesure pour ce type de job. Pour l'émission tout au moins.

Christophe

24
Vos projets / Re : Identification des trains par infrarouge
« le: mai 01, 2025, 09:42:44 am »
Merci Marcel,

J'ai lu en diagonale, mais il me semble que ce système ne permet pas l'identification (juste la détection). Contrairement au lien que tu avais partagé le 2 juin 2022 (qui concerne également un montage de Dave Bodnar) :

http://www.trainelectronics.com/IR_Train_Identification/index.htm

Christophe


25
Vos projets / Re : Identification des trains par infrarouge
« le: avril 30, 2025, 09:50:16 pm »
C’est à l’occasion du « up » que vient de faire Brunotoutsimple sur ce sujet que je le découvre.

J’aime bien le principe et il peut s’agir en effet d’un montage simple, économique et pas trop encombrant.

Je suis prêt à apporter ma contribution, en particulier sur le développement du code.

Mais je suis assez réservé sur plusieurs points et pour lesquels j’aimerais vos éclairages si vous en avez :

- Quand je regarde les photos avec ces leds qui dépassent des wagons et des bâtiments, je me dis que c’est inacceptable hormis sur un réseau de test
Je comprends la remarque qui est avancée pour l’installation sur un réseau déjà décoré, quoique ! Je verrais plutôt une led sous le réseau et une autre embarquée et traversant le fond du wagon. Ce serait beaucoup plus discret.

- L’idée de ne coder que sur un octet est bien vue. C’est suffisant car ça permet de reconnaitre jusqu’à 255 locomotives ou convois différents.

- La principale question avant de se lancer est de savoir jusqu’à quelle vitesse de convoi le système est encore capable de fonctionner ? A 38Khz, il faut environ 210µs pour lire 8 bits. 26,32µS par bit, tous les µC savent faire. Mais en fonction de l’angle de la led quelle est la vitesse du convoi possible ? Le plus simple est bien sûr de faire les tests pour mesurer en pratique cette vitesse sur un banc de test.

Dans l’attente de retours que j’espère nombreux.

Christophe

26
Aide / Re : trame fonction
« le: avril 17, 2025, 11:00:46 am »
Bonjour

Oui il est possible d’envoyer plusieurs commandes de fonctions en activant ou en désactivant plusieurs bits à la fois dans la trame DCC

Christophe

27
Bonjour,

Que sont devenus Chaton et Georges ?

Christophe

28
Présentez vous ! / Re : Présentation
« le: avril 04, 2025, 08:22:12 am »
Bienvenue Kellan sur le forum des fondus d'Arduino et autres µc pour le train miniature.

J'espère mais je ne doute pas que tu trouveras les réponses à tes questions et tes attentes.

N'hésite pas à décrire ton projet si tu en as un ou tes sujets d'intérêts particuliers.

Christophe

29
Vos projets / Re : Projet partagé d'un gestionnaire de réseau
« le: mars 26, 2025, 03:06:00 pm »
J'ai créé ma zone coté A (z11), j'ai aussi créé ma zone côté B (z2) puis validé et ... plus d'écran et ce message

voir fichier joint

30
Vos projets / Re : Projet partagé d'un gestionnaire de réseau
« le: mars 26, 2025, 02:28:55 pm »
Même problème avec la v21 quand je valide "quelle est la zone après A", j'entre Z11, je valise et.... planté

Pages: 1 [2] 3 4 ... 76