LOCODUINO
Parlons Arduino => Vos projets => Discussion démarrée par: JPM06 le juin 01, 2022, 04:48:29 pm
-
Bonjour à tous,
Je vous présente un projet sur lequel je travaille depuis quelques semaines: l'identification des trains par infrarouge.
Sur mon réseau, les trains sifflent quand ils passent à certains endroits, allument leurs lumières avant de pénétrer dans les tunnels, sont annoncés lorsqu'ils arrivent en gare ou en partent, etc.
Si j'ai pu installer ces gadgets facilement, avec seulement un peu de programmation, c'est parce que mon réseau est divisé en cantons et les trains suivis par informatique.
Mais lorsque l'idée m'est venue de réaliser le même genre d'animation sur les réseaux de mon association, qui sont digitaux mais ne sont pas cantonnés et n'ont qu'une centrale DC pour tout équipement, j'ai vite constaté qu'une fois la voie posée, peinte et ballastée, on hésite à la charcuter pour ajouter des détecteurs, quel qu'en soit le type.
J'ai donc cherché un système de localisation ne nécessitant pas de faire des coupures dans la voie, et encore moins de la démonter pour mettre des détecteurs en dessous.
C'est possible en utilisant l'infrarouge. Ce type de détection peut être vue comme une alternative à Railcom, RFID et autres. Et telle qu'elle est mise en oeuvre ici, aucune modification du matériel (locomotives, centrale...) n'est nécessaire.
Tous les détails sont sur mes pages web, mais deux points méritent d'être soulignés:
1: oui, il faut un minimum d'électronique à bord des trains. Désolé pour ceux pour qui c'est rhédibitoire (mais certains systèmes commerciaux ont aussi cette exigence).
2: deux systèmes sont décrits:
- avec émetteur IR dans les trains et détecteurs le long de la voie,
- et l'inverse: détecteurs dans les trains et émetteurs le long de la voie.
Chaque système a ses avantages et ses inconvénients.
Voyez plutôt: http://amfn.nice.free.fr/microcontroleurs/localir/index.htm (http://amfn.nice.free.fr/microcontroleurs/localir/index.htm)
-
Bonsoir à tous,
ayant moi-même testé la solution 2 selon les conseils donnés sur cette page: http://amfn.nice.free.fr/microcontroleurs/localir/rascar.htm, je peux confirmer le bon fonctionnement du principe, j'attends juste l'arrivée d' ATTINY45 en CMS pour intégrer l'ensemble dans une loco.
Un grand bravo à toi Jean-Pierre.
Cordialement
Antoine
-
Bonjour
http://www.trainelectronics.com/IR_Train_Identification/index.htm
-
Bonjour Marcel,
j'avais déjà testé ce montage il y a longtemps, mais dès que la loco avance à vitesse rapide, le récepteur n'a plus le temps de décrypter le code Sony.
C'est là que le principe change, on n'émet qu'un seul octet continuellement et si le récepteur reçoit 3 fois le même octet on valide. Cela donne quand même 254combinaisons possibles en supprimant le code 0.
Bonne journée
Antoine
-
Je trouve que c'est une excellent idée ;D
Je préfèrerai la solution de l'émetteur dans un wagon, diode émettrice placée sous le wagon, orientée à 45° (ou moins) vers l'avant pour que la plage de détection par le récepteur (phototransistor en biais entre les traverses) soit maximum et indépendante de la vitesse. Le tout alimenté par le DCC avec un régulateur et un condo à la place de la batterie pour ne pas s'em.. avec la recharge.
On peut tramsttre des mots de 10 bits ou + ou -, répétés 3 fois pour confirmer.
Avec un ATch'tiny ça doit le faire dans du N.
La baisse de luminosité au passage du train peut mettre en alerte le récepteur !
Je vais essayer, ça m'amuse 8)
-
Bonsoir Dominique,
aurais-tu un schéma de l'alimentation par le DCC que tu proposes, j'ai déjà commandé des ponts MB6S sur les conseils de Jean-Pierre ? Cela me permettra de faire faire les PCB.
Tu connais peut-être mieux les ATTINY que moi; peut-on programmer un ATTINY25 sans y graver le bootloader pour économiser de la mémoire ?
Amicalement.
Antoine
-
aurais-tu un schéma de l'alimentation par le DCC que tu proposes, j'ai déjà commandé des ponts MB6S sur les conseils de Jean-Pierre ? Cela me permettra de faire faire les PCB.
Cher Antoine,
Tu as le schéma classique de Minabay:
https://forum.locoduino.org/index.php?topic=556.msg6114#msg6114 (https://forum.locoduino.org/index.php?topic=556.msg6114#msg6114)
Pour l’AtTiny25, je ne sais pas.
-
Merci à toi Dominique et bonne journée.
-
Bonjour à tous,
Concernant le schéma de l'alimentation en DCC, le mien (testé ce matin sur breadboard) est exactement celui de CATPLUS:
http://www.trainelectronics.com/IR_Train_Identification/images/schematic_ir_id_large.gif (http://www.trainelectronics.com/IR_Train_Identification/images/schematic_ir_id_large.gif)
...mais des condensateurs beaucoup plus petits suffisent: 1µF CMS de chaque coté du 78L05.
Bien entendu, pour une version embarquée, la question de la captation se pose: plus elle est mauvaise et plus il faudra prévoir un gros condo en entrée du régulateur.Mais la consommation est tellement faible (2mA) que ça ne devrait pas poser de problème.
Et c'est testé avec des PIC 12F625, pas avec des ATtiny (je les attends).
Par ailleurs, ayant mis un peu d'ordre sur mon site, l'adresse exacte du projet est maintenant:
http://amfn.nice.free.fr/microcontroleurs/localir/index.htm (http://amfn.nice.free.fr/microcontroleurs/localir/index.htm)
Les vieilles pages vont être effacées.
Bon week-end!
-
Bonjour à tous,
Je viens d'ajouter quelques photos de l'installation de test LOTIR.
Pour les tests préliminaires, le NodeMCU est logé dans une boîte en forme de bâtiment technique posé le long de la voie.
De la sorte on n'a même pas à faire de trou entre les traverses.
http://amfn.nice.free.fr/microcontroleurs/localir/station.jpg
http://amfn.nice.free.fr/microcontroleurs/localir/station2.jpg
http://amfn.nice.free.fr/microcontroleurs/localir/station3.jpg
http://amfn.nice.free.fr/microcontroleurs/localir/station4.jpg
La boîte contient un NodeMCU encore sur son "breadboad", une batterie Li-Ion comme alimentation, un interrupteur et le détecteur infrarouge. Ce dernier est monté de façon à être réglable en hauteur.
Je rappelle que ceci n'est qu'une installation de test, et que diode et détecteur sont prévus pour être installés entre les rails.
JPM
-
Bonjour
ou en est ce projet. avance t il cela m'intéresse
-
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
-
Bonjour
A voir
http://www.trainelectronics.com/IR_Train_Detector_5-2007/index.htm
-
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 (http://www.trainelectronics.com/IR_Train_Identification/index.htm)
Christophe
-
L’idée de percer un plancher de wagon pour émettre un signal lumineux,… est lumineuse !
Ça doit entrer dans un wagon en N.
Deux questions me viennent à l’esprit :
- détecter l’approche d’un lecteur (phototransistors entre les traverses), avec une led émettrice IR quelques centimètre avant pour démarrer l’émission du signal d’identification.
- allonger la zone de lecture pour lire des messages aux passages à grande vitesse
-
Bonjour à tous,
Ce projet est en "stand-by" parce que je n'ai trouvé personne d'intéressé pour aller plus loin avec moi, c'est à dire vraiment équiper un réseau.
Et je n'ai pas non plus trouvé le temps de construire un réseau de démonstration.
Mon réseau personnel est opérationnel sans ça.
Mon but était essentiellement de valider des solutions techniques, et pour moi c'est fait.
Il semble que l'électronique, la programmation, le WiFi... font un peu peur, et surtout à des gens qui ont construit leur réseau sans ça.
Il est vrai qu'embarquer de l'électronique dans un train, surtout en HO, est problématique. Au final il semble qu'on préfère couper les rails pour y mettre des détecteurs classiques, comme dans les solutions du commerce. ("Solution du commerce" est le mot clé).
Ceci dit, plusieurs membres de mon association ont des réseaux en projet ou en construction. Je les garde à l'oeil! ;)
Quelques réponses aux derniers posts:
• oui, il s'agit bien d'identifier, et pas seulement de détecter. Pour une simple détection, voirhttp://amfn.nice.free.fr/det3.htm#Photo-%C3%A9lectriques (http://amfn.nice.free.fr/det3.htm#Photo-%C3%A9lectriques)
• certes, les LEDs qui dépassent font moche, mais ce n'est que pour les tests. Je n'ai pas voulu charcuter un wagon ou des maquettes de bâtiment.
• la vitesse maximum du convoi est indiquée: 1,25m/s, soit 390km/h en HO.
• pour mes tests j'ai alimenté l'électronique embarquée par batteries, mais dans une réalisation réelle, il faudrait l'alimenter depuis la voie... avec les problèmes que ça pose.
Notez qu'un de mes amis qui construit ses décodeurs lui-même m'en a fait un avec génération du code directement par le décodeur. L'électronique embarquée se réduit alors à la seule LED. Pourquoi les fabricants de décodeur ne font-ils pas ça aussi? :(
• merci pour les liens vers différents produits ou réalisations qui sont de la même famille.
Il existe un produit commercial (je l'ai découvert tardivement) qui offre les mêmes fonctionnalités, mais avec deux LEDS pour détecter le sens de passage. Désolé, je n'ai plus le lien.
• dernière remarque: à l'époque je n'ai pas choisi entre les deux solutions (LOTIR et RASCAR). Avec le recul je m'orienterais aujourd'hui vers une électronique embarquée minimum (LOTIR) et des détecteurs le long de la voie, mais connectés à un bus filaire. Le WiFi pourrait être introduit en bout de chaine pour agir sur la centrale.
Je suis avec intérêt vos commentaires.
-
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
(https://www.locoduino.org/local/cache-vignettes/L700xH701/nmra_4_8_encoding-c9a79.png?1724588262)
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
-
Bonjour,
Il serait intéressant de voir (= tester) si ce codage 4/8 permet de simplifier le filtrage des octets à la réception: actuellement j'attends d'avoir reçu trois octets successifs identiques pour les considérer comme valides. En passant à deux, par exemple, on pourrait soit augmenter la sensibilité du système (plus grande vitesse des convois, quoi qu'elle soit déjà importante), soit réduire la vitesse de signalisation de 19,2 à 9,6kbps, ce qui est toujours bon à prendre.
Mais il ne faudrait pas que le temps de traitement du filtrage réduise ces avantages à zéro.
JPM06
-
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
-
Bonjour Christophe,
J'ai d'abord eu du mal à comprendre pourquoi tu utilises dans ton code un PWM à 38kHz, mais je crois que l'illumination m'est venue: tu veux moduler le signal IR à 38kHz?
Mais dans le système présenté, l'IR n'est PAS modulé. Il y a de l'IR sur les 0 et rien sur les 1. C'est très simple, et ça marche.
Le programme de l'émetteur est d'ailleurs présenté là: http://amfn.nice.free.fr/microcontroleurs/localir/Lotir.mbas (http://amfn.nice.free.fr/microcontroleurs/localir/Lotir.mbas). C'est du MikroBASIC, mais ça se lit facilement, vu la simplicité de la chose.
(Simplement, le SoftSerial de mon IDE ne marchait pas bien, c'est pourquoi j'ai ré-écrit et étalonné la procédure).
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.
Affaire à suivre...
Jean-Pierre
-
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 (https://github.com/BOBILLEChristophe/directMFX_ESP32/blob/main/src/MfxRMT.cpp)
-
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
-
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).
(https://www.locoduino.org/IMG/png/trame02.png)
Un bit 1 a une durée de 560µs (2 x 280µs).
(https://www.locoduino.org/IMG/png/trame03.png)
Un bit 0 a une durée de 1000µs (2 x 500µs).
(https://www.locoduino.org/IMG/png/trame04.png)
Ls bits de synchro qui séparent les octets de données ont une durée de 2000µs environ (2 x 1 ms)
(https://www.locoduino.org/IMG/png/trame01.png)
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
-
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 !!!
(https://media1.tenor.com/m/GkTTwgJA5j8AAAAd/don-camillo-peppone.gif)
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
-
👏 Bravo !
-
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
-
Pour l’alimentation à partir du DCC, un bout fil dénudé enroulé autour de l’essieu avant, côté + avec une diode en série; un autre bout de fil dénudé autour de l’essieu arrière retourné côté -; une capa de stockage et un regulateur : ça doit le faire !
-
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.
(https://www.locoduino.org/IMG/jpg/_dsc1718.jpg)
(https://www.locoduino.org/IMG/jpg/_dsc1722.jpg)
(https://www.locoduino.org/IMG/jpg/_dsc1723.jpg)
(https://www.locoduino.org/IMG/jpg/_dsc1727.jpg)
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
https://www.youtube.com/watch?v=AcKqexFbGcc
-
Bonsoir Christophe
Bravo pour cette réalisation
Marcel
-
Bonjour à tous,
J'ai lancé la fabrication chez JLCPCB pour 20 ex de la carte en version Nano, en choisissant la panélisation soit 5X4. Il y aura du rab pour ceux qui souhaitent essayer !
(https://www.locoduino.org/IMG/png/pcb-2.png)
Voici les Gerber en PJ
Christophe
-
Voici le Gerber du récepteur.
(https://www.locoduino.org/IMG/png/ir_recepteur_tsop4838.png)
-
Bonsoir à tous,
En intégrant le fichier IRTimer.hpp (et juste celui là), le code de l'emetteur pour le Nano et pour l'ATtiny est maintenant le même.
J'ai fait les tests avec un ATtiny 45, les résultats sont là encore assez bluffants. Je crois que la qualité des composants VISHAY y est pour beaucoup et la modulation à 38 Khz aussi. J'ai regardé la datasheet du TSOP4838. C'est vraiment complet à l'intérieur pour filtre au mieux les signaux et garantir la qualité du traitement.
J'ai fait le Gerber pour l'ATtiny
(https://www.locoduino.org/IMG/png/detecteur_ir_attiny.png)
Voici le code de l'emetteur qui est le même pour le Nano ou les ATtiny
#include <Arduino.h>
// Configuration du timer pour PWM IR
# if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__)
#define IR_USE_AVR_TIMER2 // Utilise Timer2 pour l'envoi (pin D3)
#define IR_SEND_PIN 3 // Broche utilisée
# elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define IR_SEND_PIN 4 // Broche utilisée
#define IR_USE_AVR_TIMER_TINY1 // send pin = (pin 4) ATtiny25 / 45 / 85
# endif
#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.
constexpr uint8_t ID = 0xA5; // Identifiant à envoyer
constexpr uint16_t BIT_DURATION = 250; // Durée minimale d'un front en µs
// Envoie un octet codé via LED IR
void sendByte(uint8_t value) {
for (int i = 7; i >= 0; i--) { // MSB
bool bit = (value >> i) & 0x01;
if (bit) {
// 1
disableSendPWMByTimer();
delayMicroseconds(BIT_DURATION);
enableSendPWMByTimer();
delayMicroseconds(BIT_DURATION);
} else {
// 0
disableSendPWMByTimer();
delayMicroseconds(BIT_DURATION * 2);
enableSendPWMByTimer();
delayMicroseconds(BIT_DURATION * 2);
}
}
// Fin de trame
disableSendPWMByTimer();
delayMicroseconds(BIT_DURATION * 4);
enableSendPWMByTimer();
delayMicroseconds(BIT_DURATION * 4);
}
void setup() {
pinMode(IR_SEND_PIN, OUTPUT);
timerConfigForSend(38); // Fréquence IR : 38 kHz
disableSendPWMByTimer(); // Démarre éteint
}
void loop() {
sendByte(ID);
}
Le Gerber est téléchargeable ci-dessous.
Christophe
-
J'ai eu envie de me faire plaisir en cherchant à réduire autant que possible la taille de l'émetteur embarqué.
Du coup, je suis passé par l'option composants CMS et montage par JLCPCB (sauf l'ATtyny pour pouvoir le programmer).
La taille du composant est de 22 mm x 19 mm.
La led est minuscule et trouvera facilement sa place sous la locomotive ou un wagon.
(https://ce8dc832c.cloudimg.io/v7/_cdn_/14/0C/60/00/0/442433_1.jpg?width=640&height=480&wat=1&wat_url=_tme-wrk_%2Ftme_new.png&wat_scale=100p&ci_sign=6b15f9db3dd8ce320351095b456084baed0ce6bb)
(https://www.locoduino.org/IMG/png/identificationir_attiny_cms.png)
J'ai aussi réalisé le code pour Raspberry Pi Pico pour lire jusqu'à 16 capteurs sous interruption et envoyer les données à Rocrail :
https://github.com/BOBILLEChristophe/identification_de_trains_infrarouge_38Khz/blob/main/IdTrainIr38KhzPicoRecepteur_multiInter/IdTrainIr38KhzPicoRecepteur_multiInter.ino (https://github.com/BOBILLEChristophe/identification_de_trains_infrarouge_38Khz/blob/main/IdTrainIr38KhzPicoRecepteur_multiInter/IdTrainIr38KhzPicoRecepteur_multiInter.ino)
(https://media.3rails.fr/optimized/3X/a/4/a480a312b2645c4e10b294a4bf3134c7f22a6b5a_2_685x500.jpeg)
Christophe