EspaceTrain.Com - Le Forum

Modélisme ferroviaire => Arduino et ses clones, digital, électricité, électronique, logiciels => Arduino et ses clones => Discussion démarrée par: Ph Blondé le 07 Mars 2023 à 15:29:24

Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:29:24
Bonjour à tous,

   Il y a quelques temps, Philippe de l'Est me disait qu'il avait vu, pour nos trains, un compteur de vitesse fonctionner sur la base d'un Arduino et qu'il serait intéressant de voir ça.

   Comme c'est possible (montages existants présentés sur le Net) et avant de se lancer, nous avons échangé sur quelques points :

- Pouvoir choisir et enregistrer l'échelle pratiquée : N, TT, HO, 0 et I (1/32) ; cf. le tableau des échelles suivant la norme NEM010.
- Pouvoir choisir et enregistrer la longueur de la zone de mesure : 20, 40, 60, 80 et 100 cm.
- Faire en sorte que cela fonctionne sans tenir compte du sens de passage des trains. C'est peut-être là une différence avec quelques montages semblables trouvés sur le Net.
- Afficher la vitesse de passage en km/h ainsi que l'échelle et de la distance choisies sur un écran.
- Sauf à modifier le choix de l'échelle et/ou de la longueur de la zone de mesure, n'avoir rien à faire d'autre que de regarder l'affichage et ... les trains qui passent.
- Faire un ensemble transportable.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:30:44
LA REALISATION

La zone de mesure :

Deux étriers enjambent une ou plusieurs voies. Ils sont solidaires l'un de l'autre afin d'avoir une distance constante entre eux. Ils portent les détecteurs et la toute petite électronique donnant un signal (+5v) au passage d'un train.

Ces étriers ont une hauteur de passage telle qu'ils peuvent enjamber des voies avec caténaire et les poteaux ou les portiques qui la soutiennent.

Ici le système est conçu pour le N, le TT et le HO. Pour le 0, le I ou d'autres grandes échelles, il faut naturellement adapter les dimensions.

Les étriers ont été réalisés par imprimante 3D par YDModels, merci à Yves. Ceci ne reste qu'un exemple, on peut imaginer d'autres solutions.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:31:53
Et en vrai de vrai :
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:32:42
Les composants

Pour plus de précision (sans tomber dans les extrêmes) on a utilisé des détecteurs à rayon laser. Certains utilisent des détecteurs à ultrason ; pourquoi pas, c'est une autre logique.

L'Arduino est un NANO ; le nombre de broches (entrées et sorties) correspond aux besoins.
L'écran d'affichage est un écran LCD de 2 lignes et 16 colonnes.

La sélection de l'échelle et des distances de mesure se fait par la bascule d'interrupteurs en boitier DIP ; des petits machins comme ça :
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:34:09
Le montage électronique :

Sur le schéma on trouve autour de l'Arduino : l'écran LCD, les deux détections laser et le choix de l'échelle et de la distance de mesure.

Pour l'alimentation de l'ensemble, on a le choix entre la fabriquer soi-même (pas compliqué) ou utiliser des modules tout faits et ajustables en tension.

Les liaisons entre le circuit principal et les détecteurs utilisent des câbles de radiocommande de 1m. Pourquoi se prendre la tête lorsque c'est déjà tout fait, surtout au niveau de la connectique et du prix.

Voici les schémas (pour l'alimentation on a les deux choix) :
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:34:57
Branchement de l'écran LCD :

Ici, sur le schéma, c'est un Arduino UNO qui est utilisé. Pour un NANO c'est exactement le même repérage au niveau des numéros des broches.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:35:39
Et en vrai de vrai :
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:40:30
Vérification du montage :

Avant de l'installer, régler l'alimentation pour une tension de sortie d'environ 5,1 V.

Le contrôle de la prise en compte du choix de l'échelle et de la longueur de la zone de mesure peut être fait à l'aide d'un petit programme qui va bien. Une fois chargé et lancé, il suffit de jouer sur les différents interrupteurs des deux boitiers DIP pour voir le résultat s'afficher sur l'écran LCD.

En même temps on peut régler le contraste de l'écran LCD.

Le programme :

// COMPTEUR DE VITESSE POUR LE MODÉLISME FERROVIAIRE - TEST DU MONTAGE ET DU CHOIX ECHELLE ET DISTANCE - MAJ : 24_02_2023

// LES ÉCHELLES TRAITEES : N (1/160), TT (1/120), HO (1/87), 0 et 1/35.
// LA DISTANCE DE MESURE PEUT SE FAIRE SUR 20cm, 40cm, 60cm, 80cm ou 100cm

// LE CHOIX DES ÉCHELLES ET DISTANCES SE FAIT PAR BASCULE DE MICRO-SWITCHES.
// CHOIX DE L'ÉCHELLE : 5 MICRO-SWITCHES (BASCULE ON/OFF) ; DE 1/160 A 1/35 - DE GAUCHE A DROITE.
// CHOIX DE LA DISTANCE : 5 MICRO-SWITCHES (BASCULE ON/OFF) POUR LES DISTANCES - DE GAUCHE A DROITE.

// DECLARATION DES VARIABLES

#include <LiquidCrystal.h>
const uint8_t rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; // Broches pour NANO et UNO
LiquidCrystal lcd (rs, en, d4, d5, d6, d7);

const int Echelle_160 = 8;
const int Echelle_120 = 9;
const int Echelle_87 = 10;
const int Echelle_45 = 11;
const int Echelle_32 = 12;
int Echelle_Choisie;

const int Distance_20cm = 18;
const int Distance_40cm = 17;
const int Distance_60cm = 16;
const int Distance_80cm = 15;
const int Distance_100cm = 14;
int Distance_Choisie;

void setup()
{
  pinMode (Echelle_160, INPUT);
  pinMode (Echelle_120, INPUT);
  pinMode (Echelle_87, INPUT);
  pinMode (Echelle_45, INPUT);
  pinMode (Echelle_32, INPUT);

  digitalWrite (Echelle_160, LOW);
  digitalWrite (Echelle_120, LOW);
  digitalWrite (Echelle_87, LOW);
  digitalWrite (Echelle_45, LOW);
  digitalWrite (Echelle_32, LOW);

  pinMode (Distance_20cm, INPUT);
  pinMode (Distance_40cm, INPUT);
  pinMode (Distance_60cm, INPUT);
  pinMode (Distance_80cm, INPUT);
  pinMode (Distance_100cm, INPUT);

  digitalWrite (Distance_20cm, LOW);
  digitalWrite (Distance_40cm, LOW);
  digitalWrite (Distance_60cm, LOW);
  digitalWrite (Distance_80cm, LOW);
  digitalWrite (Distance_100cm, LOW);

  lcd.begin (16,2);
  lcd.clear();
}

void loop()
{
  Test_Choix_Echelle();
}


void Test_Choix_Echelle()
{

  Echelle_Choisie = digitalRead (Echelle_160);
  if ( Echelle_Choisie == HIGH )  { lcd.clear(); lcd.setCursor (0,0);  lcd.print ("ECHELLE : 1/160");}

  Echelle_Choisie = digitalRead (Echelle_120);
  if ( Echelle_Choisie == HIGH )  { lcd.clear(); lcd.setCursor (0,0);  lcd.print ("ECHELLE : 1/120"); }

  Echelle_Choisie = digitalRead (Echelle_87);
  if ( Echelle_Choisie == HIGH )  { lcd.clear(); lcd.setCursor (0,0);  lcd.print ("ECHELLE : 1/87"); }

  Echelle_Choisie = digitalRead (Echelle_45);
  if ( Echelle_Choisie == HIGH )  { lcd.clear(); lcd.setCursor (0,0);  lcd.print ("ECHELLE : 1/45"); }

  Echelle_Choisie = digitalRead (Echelle_32);
  if ( Echelle_Choisie == HIGH )  { lcd.clear(); lcd.setCursor (0,0);  lcd.print ("ECHELLE : 1/32"); }

  Test_Distance_De_Mesure();
}
 
void Test_Distance_De_Mesure()
{
  Distance_Choisie = digitalRead (Distance_20cm);
  if ( Distance_Choisie == HIGH )  { lcd.setCursor (0,1);  lcd.print ("DISTANCE : 20cm"); }
 
  Distance_Choisie = digitalRead (Distance_40cm);
  if ( Distance_Choisie == HIGH )  { lcd.setCursor (0,1);  lcd.print ("DISTANCE : 40cm"); }
 
  Distance_Choisie = digitalRead (Distance_60cm);
  if ( Distance_Choisie == HIGH )  { lcd.setCursor (0,1);  lcd.print ("DISTANCE : 60cm"); }
 
  Distance_Choisie = digitalRead (Distance_80cm);
  if ( Distance_Choisie == HIGH )  { lcd.setCursor (0,1);  lcd.print ("DISTANCE : 80cm"); }
 
  Distance_Choisie = digitalRead (Distance_100cm);
  if ( Distance_Choisie == HIGH )  { lcd.setCursor (0,1);  lcd.print ("DISTANCE : 100cm"); }

  delay (1000);
  Test_Choix_Echelle();
}




Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:42:11
LA PROGRAMMATION

L'idée :

Il s'agit donc simplement d'enregistrer le temps mis par un train pour passer entre deux points éloignés d'une certaine distance connue puis de calculer et d'afficher ce que cela donne en km/h en fonction de l'échelle pratiquée.

On a ce qu'il faut ...

Lorsqu'un Arduino est alimenté, une fonction particulière est active : la fonction « millis () ». Cette fonction renvoie le nombre de millisecondes écoulées depuis la mise sous tension de l'Arduino. Sa valeur max est de 4 294 967 295 ms (49 jours) ; passé la valeur max on retourne à 0.

Il suffit donc d'enregistrer la valeur de la fonction millis () au passage d'un train devant un premier détecteur et faire de même lors de son passage devant le second détecteur. En faisant la différence de ces deux valeurs on obtient la valeur du temps mis par ce train pour franchir la distance qui sépare un détecteur de l'autre.



Particularité de la détection :

On ne tient pas compte de savoir quel détecteur a été déclenché en premier. Quel que soit le sens de roulement du train et qu'il y ait une ou deux voies (voire plus) cela fonctionne toujours.

Les détecteurs n'ont pas d'ordre de priorité. C'est le premier enclenché qui actionne la fonction millis ()  dont la valeur est enregistrée dans une variable « DEBUT-COMPTAGE ».

Connaissant le premier détecteur on en déduit donc qui est le second. Ce dernier est mis en « attente/observation ».

Lorsque le train sort de la zone de mesure, il active ce second détecteur et la valeur de la fonction millis () est enregistrée dans une variable « FIN-COMPTAGE ».
Le temps de parcours est la différence entre les deux valeurs enregistrées de la fonction millis.
Logique :

Présentée ci-dessous ; le fichier .pdf est également joint
 
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:43:57
Le calcul de la vitesse :

La soustraction entre les valeurs « FIN-COMPTAGE » et « DEBUT-COMPTAGE » donne le temps de passage. Avec la valeur de la distance entre les deux détecteurs on trouve donc la vitesse en cm/ms. Il reste à transformer cette vitesse en km/h en tenant compte de la valeur de l'échelle pratiquée.

Inutile de refaire le calcul à chaque fois. La valeur obtenue est en cm/ms, il suffit donc de la passer en cm/s puis de la multiplier par la valeur d'une constante propre à chaque échelle et qui tient compte des changements d'unités.

Cette constante, calculée une fois pour toute, peut prendre les valeurs suivantes :
• Pour le N (1/160) : 5,760
• Pour le TT (1/120) : 4,320
• Pour le HO (1/87) : 3,132
• Pour le 0 (1/45) : 1,620
• Pour le I (1/32) : 1,152

Dans le programme il s'agira de faire une bête division suivie d'une aussi bête multiplication.

Le résultat est exprimé par un nombre entier. Il nous semblait inutile d'écrire « 151,23547 km/h »  :)

Le programme :

// COMPTEUR DE VITESSE POUR LE MODÉLISME FERROVIAIRE - VERSION 7 - MAJ 04-03-2023

// LES ÉCHELLES TRAITEES : N (1/160), TT (1/120), HO (1/87), 0 (1/45) et I (1/32).
// LA DISTANCE DE MESURE PEUT SE FAIRE SUR 20cm, 40cm, 60cm, 80cm ou 100cm

// LA DÉTECTION DES PASSAGES SE FAIT PAR COUPURE D'UN RAYON LASER.
// LES ÉMETTEURS LASER SONT RÉGLAGLES :
//      - EN INTENSITE PAR VARIATION DE LEUR TENSION D'ALIMENTATION
//      - EN NETTETE PAR UNE FOCALE A VIS.

// LE CHOIX DES ÉCHELLES ET DISTANCES SE FAIT PAR BASCULE DE MICRO-SWITCHES.
// CHOIX DE L'ÉCHELLE : 5 MICRO-SWITCHES (BASCULE ON/OFF) ; DE 1/160 A 1/35 - DE GAUCHE A DROITE.
// CHOIX DE LA DISTANCE : 5 MICRO-SWITCHES (BASCULE ON/OFF) POUR LES DISTANCES - DE GAUCHE A DROITE.

// FAIRE UN RESET APRÈS CHAQUE MODIFICATION DE L'ÉCHELLE ET/OU DE LA DISTANCE DE MESURE.
// UN BOUTON POUSSOIR RÉALISERA CE RESET PAR MISE A 0V DE LA BROCHE RST DE L'ARDUINO.

// LA MESURE DE VITESSE EST FAITE QUELQUE SOIT LE SENS DE PASSAGE DU TRAIN
// LE DÉTECTEUR B PEUT ÊTRE ACTIVÉ AVANT LE A OU LE A AVANT LE B.
// LE REPÉRAGE DES DÉTECTEURS NE DONNE PAS D'ORDRE DE PRIORITÉ.


// DECLARATION DES VARIABLES

#include <LiquidCrystal.h>
const uint8_t rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; // Broches pour NANO et UNO
LiquidCrystal lcd (rs, en, d4, d5, d6, d7);

const int Detecteur_A = A6;
int Etat_Detecteur_A;

const int Detecteur_B = A7;
int Etat_Detecteur_B;

const int Echelle_160 = 8;
const int Echelle_120 = 9;
const int Echelle_87 = 10;
const int Echelle_45 = 11;
const int Echelle_32 = 12;
int Echelle_Choisie;
float Coefficient;

const int Distance_20cm = 18;
const int Distance_40cm = 17;
const int Distance_60cm = 16;
const int Distance_80cm = 15;
const int Distance_100cm = 14;
int Distance_Choisie;
int Valeur_Distance_choisie;

unsigned long Temps_Au_Detecteur_Entree= millis();
unsigned long Temps_Au_Detecteur_Sortie= millis();
unsigned long Temps_De_Parcours;
float Vitesse_De_Parcours;

int Vitesse_Reelle;
// Le int de Vitesse_Reelle permet de récupérer la valeur entière du nombre.


void setup()
{
  pinMode (Detecteur_A, INPUT);
  pinMode (Detecteur_B, INPUT);
  digitalWrite (Detecteur_A, LOW);
  digitalWrite (Detecteur_B, LOW);

  pinMode (Echelle_160, INPUT);
  pinMode (Echelle_120, INPUT);
  pinMode (Echelle_87, INPUT);
  pinMode (Echelle_45, INPUT);
  pinMode (Echelle_32, INPUT);

  digitalWrite (Echelle_160, LOW);
  digitalWrite (Echelle_120, LOW);
  digitalWrite (Echelle_87, LOW);
  digitalWrite (Echelle_45, LOW);
  digitalWrite (Echelle_32, LOW);

  pinMode (Distance_20cm, INPUT);
  pinMode (Distance_40cm, INPUT);
  pinMode (Distance_60cm, INPUT);
  pinMode (Distance_80cm, INPUT);
  pinMode (Distance_100cm, INPUT);

  digitalWrite (Distance_20cm, LOW);
  digitalWrite (Distance_40cm, LOW);
  digitalWrite (Distance_60cm, LOW);
  digitalWrite (Distance_80cm, LOW);
  digitalWrite (Distance_100cm, LOW);

  lcd.begin (16,2);
  lcd.clear();
}


void loop()
{
  Test_Choix_Echelle();
}


void Test_Choix_Echelle()
{

  Echelle_Choisie = digitalRead (Echelle_160);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 5.760;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/160");}

  Echelle_Choisie = digitalRead (Echelle_120);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 4.320;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/120"); }

  Echelle_Choisie = digitalRead (Echelle_87);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 3.132;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/87"); }

  Echelle_Choisie = digitalRead (Echelle_45);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 1.620;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/45"); }

  Echelle_Choisie = digitalRead (Echelle_32);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 1.152;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/32"); }

  Test_Distance_De_Mesure();
}
 
void Test_Distance_De_Mesure()
{
  Distance_Choisie = digitalRead (Distance_20cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 20;
  lcd.setCursor (9,0);  lcd.print ("D=20cm"); }
 
  Distance_Choisie = digitalRead (Distance_40cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 40;
  lcd.setCursor (9,0);  lcd.print ("D=40cm"); }
 
  Distance_Choisie = digitalRead (Distance_60cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 60;
  lcd.setCursor (9,0); lcd.print ("D=60cm"); }
 
  Distance_Choisie = digitalRead (Distance_80cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 80;
  lcd.setCursor (9,0);  lcd.print ("D=80cm"); }
 
  Distance_Choisie = digitalRead (Distance_100cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 100;
  lcd.setCursor (9,0);  lcd.print ("D=100cm"); }

  Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B();
}


void Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()
{
  do
  {
    Etat_Detecteur_A = analogRead (Detecteur_A);
    Etat_Detecteur_B = analogRead (Detecteur_B);
    Temps_Au_Detecteur_Entree = millis();
  }
  while ((Etat_Detecteur_A <= 200) && (Etat_Detecteur_B <= 200));

  if (Etat_Detecteur_A >= 500)
    { lcd.setCursor (2,1); lcd.print ("DETECTEUR A");
      Attente_Du_Passage_Sur_Le_Detecteur_B(); }
  else
    if (Etat_Detecteur_B >= 500)
      { lcd.setCursor (2,1); lcd.print ("DETECTEUR B");
      Attente_Du_Passage_Sur_Le_Detecteur_A(); }
}


void Attente_Du_Passage_Sur_Le_Detecteur_B()
{
  do
  {
    Etat_Detecteur_B = analogRead (Detecteur_B);
    Temps_Au_Detecteur_Sortie = millis();
  }
  while (Etat_Detecteur_B <= 200);
  lcd.setCursor (2,1); lcd.print ("DETECTEUR B");
  delay (2000);
  Calcul_Affichage_Vitesse ();
}


void Attente_Du_Passage_Sur_Le_Detecteur_A()
{
  do
  {
    Etat_Detecteur_A = analogRead (Detecteur_A);
    Temps_Au_Detecteur_Sortie = millis();
  }
  while (Etat_Detecteur_A <= 200);
  lcd.setCursor (2,1); lcd.print ("DETECTEUR A");
  delay (2000);
  Calcul_Affichage_Vitesse ();
}


void Calcul_Affichage_Vitesse ()
{
  Temps_De_Parcours = ((Temps_Au_Detecteur_Sortie - Temps_Au_Detecteur_Entree) / 1000);
  // Vitesse en cm/s
  Vitesse_De_Parcours = (Valeur_Distance_choisie / Temps_De_Parcours);
  // Vitesse en km/h
  Vitesse_Reelle = ( Vitesse_De_Parcours * Coefficient);

  lcd.setCursor (0,1);
  lcd.print ("               ");
  delay (1000);

  lcd.setCursor (2,1);
  lcd.print ("V = ");     lcd.print (Vitesse_Reelle);     lcd.print (" km/h");

  delay (9000);

  Test_Choix_Echelle();
}


Sous sa forme .ino, .txt et .doc
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:47:44
Les liens pour trouver les composants :

Fabrication des étriers : https://www.ydmodels.com/ (https://www.ydmodels.com/)

Arduino Nano, écran LCD : AZ-Delivery AZ-Delivery https://www.az-delivery.de/fr/collections/arduino-kompatibel-nano-uno-mega-pro-mini-az-delivery/products/nano-v3-mit-ch340-arduino-kompatibel (https://www.az-delivery.de/fr/collections/arduino-kompatibel-nano-uno-mega-pro-mini-az-delivery/products/nano-v3-mit-ch340-arduino-kompatibel)

Alimentation variable : Z-Delivery Microprocessor https://www.microprocessor-fr.com/Vente/product_info.php?cPath=58_64&products_id=1167&osCsid=94a9258b711b7caf3b1fcbd9ba2f388b (https://www.az-delivery.de/fr/collections/stromversorgung/products/lm2596s-dc-dc-step-down-modul-1?variant=12228728324192%5B/url%5DEmetteur%20laser%20:%20%5Burl="https://www.amazon.fr/RUNCCI-YUN-Photor%C3%A9sistance-R%C3%A9sistance-D%C3%A9pendant-Lumi%C3%A8re/dp/B08N1F5YBG/ref=sr_1_7?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=3SM3BVDR3XBZS&keywords=emetteur+laser&qid=1677492934&sprefix=emetteur+lase%2Caps%2C99&sr=8-7"%5Dhttps://www.amazon.fr/RUNCCI-YUN-Photor%C3%A9sistance-R%C3%A9sistance-D%C3%A9pendant-Lumi%C3%A8re/dp/B08N1F5YBG/ref=sr_1_7?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=3SM3BVDR3XBZS&keywords=emetteur+laser&qid=1677492934&sprefix=emetteur+lase%2Caps%2C99&sr=8-7%5B/url%5DPhototransistors%20:%20Microprocessor%20%5Burl="https://www.microprocessor-fr.com/Vente/product_info.php?cPath=58_64&products_id=1167&osCsid=94a9258b711b7caf3b1fcbd9ba2f388b)

Plaque à bandes et composants électroniques : REICHELT https://www.reichelt.com/fr/fr/carte-de-laboratoire-cem3-pas-2-54-mm-bandes-re-510-s1-p105477.html?&trstct=pos_0&nbc=1 (https://www.reichelt.com/fr/fr/carte-de-laboratoire-cem3-pas-2-54-mm-bandes-re-510-s1-p105477.html?&trstct=pos_0&nbc=1)
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:49:46
QUELQUES COMPLÉMENTS :

Le calcul de la constante à appliquer pour passer aux km/h :
La vitesse c'est l'expression d'une distance parcourue en un temps donné, soit v = d / t
Ici nous avons une vitesse qui s'exprime en centimètre par milliseconde (cm/ms) ; divisée par 1000 cela donne des cm/s.

Pour passer en km/h, pour le HO par exemple, il suffit de :

Multiplier par 87 pour tenir compte de l'échelle, multiplier à nouveau par 3600 pour passer des secondes en heure et enfin diviser par 100 000 pour passer des cm en km. Soit pour le cas du HO : (87 x 3600) / 100 000 = 3,132 ; 3,132 sera donc le coefficient multiplicateur.

D'où l'intérêt de faire le calcul de ce coefficient une fois pour toute et pour les échelles programmées.

Exemple :

Un train, en HO, parcourt 100 cm en 5 000 ms
Sa vitesse est donc de 100 cm pour 5000 ms ou 100 cm pour 5s ou encore 20 cm/s
Sa vitesse « réelle » sera de 20 x 3,132 = 62,64 km/h et affichée à 63 km/h (arrondi supérieur).
Si c'est un train en N, la vitesse « réelle » sera de 20 x 5,760 = 115,20 km/h et affichée à 115 km/h (arrondi inférieur) ; un peu moins du double de l'échelle HO, ce qui est normal compte tenu du rapport entre les deux échelles pratiquées.

Le montage électronique :

Pour la détection, un essai avec des photorésistances a montré que la réaction est bien trop lente ; le choix s'est donc porté sur des phototransistors. Afin de ne pas « marquer » ceux-ci par une trop importante intensité lumineuse, une résistance de 150 Ω a été placée en série sur chaque émetteur laser (en rappelant le danger pour nos yeux... et ceux des animaux). Les émetteurs laser fonctionnent sous 5V et sont déjà équipés d'une résistance CMS de 1k.

Les 2 fois 5 résistances de 10k sont là pour « tirer » (assurer) à 0V les broches d'entrée de l'Arduino lorsque l'interrupteur correspondant à l'échelle ou la distance choisie n'est pas activé. On peut réaliser cette action dans le programme informatique (mise à LOW de la broche dans le setup), mais aux essais sur plaquette ce n'était pas toujours stable ; le prix des résistances étant négligeable, alors assurons !

Modifications de l'échelle ou de la distance de mesure :

Pour valider le changement de choix d'échelle et/ou de distance de mesure, il suffit d'appuyer sur le bouton « reset » de l'Arduino. Mettre un bouton poussoir sur une des deux bornes « RST » de l'Arduino n'aurait rien ajouté ;  mais on peut le faire...
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 15:50:39
La vidéo « kivabien »

Ici, la zone de mesure fait 80 cm. Deux profilés en alu de section L seront ajoutés pour relier les angles supérieurs des étriers afin de renforcer la rigidité de l'ensemble.

Sur la vidéo on voit que les LEDs rouges (simple rôle de témoin) clignotent au passage des éléments de train. Cela n'a aucune incidence car c'est à la première coupure du rayon laser que l'on enregistre la valeur de millis().

Bon amusement à tous.

Titre: Compteur de vitesse
Posté par: Charles_2_Bordeaux le 07 Mars 2023 à 16:11:56
Bonjour Philippe,
Felicitations.
Chapeau bas.
Titre: Compteur de vitesse
Posté par: PK204 le 07 Mars 2023 à 17:36:52
Bravo pour la création de ce compteur de vitesse et aussi 2ieme bravo pour le tuto si bien détaillé
 :D
Titre: Compteur de vitesse
Posté par: Ph Blondé le 07 Mars 2023 à 19:12:32
Merci à vous deux  :)
Titre: Compteur de vitesse
Posté par: Alain17 le 07 Mars 2023 à 22:59:53
Citation de: Ph Blondé...
Le programme :
...
Philippe, bravo pour ce programme.

Juste une remarque sur la structure du programme :

comme tu le sais, la fonction setup() est automatiquement exécutée au démarrage de l'Arduino et est classiquement utilisée pour réaliser les initialisations nécessaires au fonctionnement du programme. Puis, la fonction loop() est appelée comme son nom l'indique "en boucle" (indéfiniment).

Normalement, le code de la fonction loop() devrait se terminer pour que la fonction puisse être re-appelée "en boucle".

Classiquement, la fonction loop() appelle successivement une ou plusieurs fonctions et ressemble à ça :

// Structure classique de la fonction loop
// Fonction loop appelée en boucle
void loop(){
  ...
  Fonction1();
  ...
  Fonction2();
  ...
  Fonction3();
  ...
}

// Fonction 1
void Fonction1(){
  ...
}

// Fonction 2
void Fonction2(){
  ...
}

// Fonction 3
void Fonction3(){
  ...
}

Donc, la fonction Fonction1 est appelée, puis la Fonction2, puis la Fonction3, tout cela en boucle grâce à la fonction loop.

Mais dans le cas de ton programme, la structure est différente :

La fonction Test_Choix_Echelle appelle la fonction Test_Distance_De_Mesure qui appelle elle même la fonction Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B qui appelle elle même la fonction Attente_Du_Passage_Sur_Le_Detecteur_B ou la fonction Attente_Du_Passage_Sur_Le_Detecteur_A qui appelle elle même la fonction Calcul_Affichage_Vitesse qui appelle elle même la fonction Test_Choix_Echelle etc...

Le problème ici, c'est que les appels successifs de ces fonctions s'empilent dans la mémoire RAM de l'Arduino et engendrent une récursivité : au final, la fonction Test_Choix_Echelle s'appelle elle même indéfiniment. Ce n'est pas forcement un problème si ces appels successifs ne sont pas infinis.

Mais dans ton cas, ces appels successifs ne s'arrêtent jamais et vont s'empiler jusqu'à ce que ... la mémoire soit saturée et le programme "plantera". Mais il est possible que tu n'ai jamais constaté de plantage car cet empilement est assez lent (environ toutes les 12 secondes).

Pour résoudre le problème, il suffit de revenir à la structure classique de la fonction loop:

//------------------------------------------------
void loop()
{
  Test_Choix_Echelle();
  Test_Distance_De_Mesure();

  Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B();

  Calcul_Affichage_Vitesse ();
}

Il faut bien sûr adapter les fonctions appelées :

//------------------------------------------------
void Test_Choix_Echelle()
{

  Echelle_Choisie = digitalRead (Echelle_160);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 5.760;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/160");}

  Echelle_Choisie = digitalRead (Echelle_120);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 4.320;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/120"); }

  Echelle_Choisie = digitalRead (Echelle_87);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 3.132;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/87"); }

  Echelle_Choisie = digitalRead (Echelle_45);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 1.620;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/45"); }

  Echelle_Choisie = digitalRead (Echelle_32);
  if ( Echelle_Choisie == HIGH )
  { Coefficient = 1.152;
  lcd.clear(); lcd.setCursor (0,0);  lcd.print ("E=1/32"); }

// Suppression de l'appel à Test_Distance_De_Mesure()
}
 
//------------------------------------------------
void Test_Distance_De_Mesure()
{
  Distance_Choisie = digitalRead (Distance_20cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 20;
  lcd.setCursor (9,0);  lcd.print ("D=20cm"); }
 
  Distance_Choisie = digitalRead (Distance_40cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 40;
  lcd.setCursor (9,0);  lcd.print ("D=40cm"); }
 
  Distance_Choisie = digitalRead (Distance_60cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 60;
  lcd.setCursor (9,0); lcd.print ("D=60cm"); }
 
  Distance_Choisie = digitalRead (Distance_80cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 80;
  lcd.setCursor (9,0);  lcd.print ("D=80cm"); }
 
  Distance_Choisie = digitalRead (Distance_100cm);
  if ( Distance_Choisie == HIGH )
  { Valeur_Distance_choisie = 100;
  lcd.setCursor (9,0);  lcd.print ("D=100cm"); }

// Suppression de l'appel à Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()
}

//------------------------------------------------
void Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()
{
  do
  {
    Etat_Detecteur_A = analogRead (Detecteur_A);
    Etat_Detecteur_B = analogRead (Detecteur_B);
    Temps_Au_Detecteur_Entree = millis();
  }
  while ((Etat_Detecteur_A <= 200) && (Etat_Detecteur_B <= 200));

  if (Etat_Detecteur_A >= 500)
    { lcd.setCursor (2,1); lcd.print ("DETECTEUR A");
      Attente_Du_Passage_Sur_Le_Detecteur_B(); }
  else
    if (Etat_Detecteur_B >= 500)
      { lcd.setCursor (2,1); lcd.print ("DETECTEUR B");
      Attente_Du_Passage_Sur_Le_Detecteur_A(); }
}

//------------------------------------------------
void Attente_Du_Passage_Sur_Le_Detecteur_B()
{
  do
  {
    Etat_Detecteur_B = analogRead (Detecteur_B);
    Temps_Au_Detecteur_Sortie = millis();
  }
  while (Etat_Detecteur_B <= 200);
  lcd.setCursor (2,1); lcd.print ("DETECTEUR B");
  delay (2000);

// Suppression de l'appel à Calcul_Affichage_Vitesse()
}

//------------------------------------------------
void Attente_Du_Passage_Sur_Le_Detecteur_A()
{
  do
  {
    Etat_Detecteur_A = analogRead (Detecteur_A);
    Temps_Au_Detecteur_Sortie = millis();
  }
  while (Etat_Detecteur_A <= 200);
  lcd.setCursor (2,1); lcd.print ("DETECTEUR A");
  delay (2000);

// Suppression de l'appel à Calcul_Affichage_Vitesse()
}

//------------------------------------------------
void Calcul_Affichage_Vitesse ()
{
  Temps_De_Parcours = ((Temps_Au_Detecteur_Sortie - Temps_Au_Detecteur_Entree) / 1000);
  // Vitesse en cm/s
  Vitesse_De_Parcours = (Valeur_Distance_choisie / Temps_De_Parcours);
  // Vitesse en km/h
  Vitesse_Reelle = ( Vitesse_De_Parcours * Coefficient);

  lcd.setCursor (0,1);
  lcd.print ("               ");
  delay (1000);

  lcd.setCursor (2,1);
  lcd.print ("V = ");     lcd.print (Vitesse_Reelle);     lcd.print (" km/h");

  delay (9000);

// Suppression de l'appel à Test_Choix_Echelle()
}

Le fonctionnement doit être identique mais sans le risque de plantage.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 08 Mars 2023 à 09:32:24
Bonjour Alain,
Merci pour ta réponse et ton explication. :D
Je ne connaissais pas et avoue avoir toujours fait ainsi ... sans avoir vu quoique ce soit

Cependant cela m'intéresse.

Pour ce programme, on aurait donc cette structure:

void loop()
{
Test_Choix_Echelle();
Test_Distance_De_Mesure() ;
Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B() ;
Calcul_Affichage_Vitesse ()
}

void Test_Choix_Echelle()
{----}
 
void Test_Distance_De_Mesure()
{----}

void Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()
{----}

void Attente_Du_Passage_Sur_Le_Detecteur_B()
{----}

void Attente_Du_Passage_Sur_Le_Detecteur_A()
{----}

void Calcul_Affichage_Vitesse ()
{----}


Dans l'algorithme on a :
- Si c'est le détecteur A qui est activé le premier alors on va tester le détecteur B
- Mais si c'est le détecteur B qui est d'abord activé alors on va tester le détecteur A.

Ceci pour pouvoir donner la vitesse quelque soit le sens de marche d'un train ou lorsqu'il y a 2 voies

Comment gèrerais-tu cela?
Merci d'avance pour ta réponse.
Titre: Compteur de vitesse
Posté par: Alain17 le 08 Mars 2023 à 09:59:43
Citation de: Ph Blondé...
Comment gèrerais-tu cela?
Regarde dans mon message d'hier soir dans la dernière partie de 'Code' : j'y ai mis ton code que j'ai adapté à cette modification.
Titre: Compteur de vitesse
Posté par: ih74330 le 08 Mars 2023 à 11:56:22
bonjour,
c'est beau, très technique, mais pas forcément à la portée de tout un chacun, moi le premier (et je le regrette bien).  :o
pour faire la même chose, j'utilise 2 choses : un fichier EXCEL et un voltmètre sur la voie. Le voltmètre ici n'a pas besoin d'être d'une précision extrême puisqu'il va juste servir de "compteur"....
j'utilise ce système là depuis que EXCEL existe ou presque (1984 en ce qui me concerne) ; à l'époque ARDUINO .....  ::)
Dans le fichier EXCEL, on renseigne en A2 la longueur de la boucle de référence en mètres linéaires avec 2 décimales, le plus précisément possible, et l'échelle en B2. Le fichier recalcule tout le reste.
Le haut du tableau donne km/h par km/h le temps au tour jusqu'à 200km/h, le bas du tableau 5km/h par 5km/h le temps au tour, aux 3 tours ou aux 5 tours, jusqu'à 400km/h. Pourquoi 3 et 5 tours ? tout simplement pour plus de précision.....  :D
Ensuite, j'ai une fiche par train. Je sais qu'avec 8,3V dans la voie, ce train est à telle vitesse, avec 12,5V, il est à telle autre vitesse, etc .... Donc, quand je veux faire rouler tel train à telle vitesse, je sais combien je dois envoyer de Volts dans la voie .... Facile, non ?  ::)
Tout ceci est vrai en analogique. En digital, le voltmètre n'est plus d'aucune utilité, donc pour la vitesse de pointe, c'est facile de la programmer, pour le reste c'est le chrono ....  :)
Concernant le digital, j'ai envisagé la possibilité de faire un compteur personnalisé par train, à mettre autour du régulateur de la commande, mais c'est tjs à l'état de projet ....
table correspondance vitesse circuit démo.xls
Titre: Compteur de vitesse
Posté par: Ph Blondé le 08 Mars 2023 à 13:42:17
Citation de: Alain17 le 08 Mars 2023 à 09:59:43Regarde dans mon message d'hier soir dans la dernière partie de 'Code' : j'y ai mis ton code que j'ai adapté à cette modification.
OK, donc après la fonction :
void Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()

On enchaine, sans passer par le loop, sur les 2 fonctions
void Attente_Du_Passage_Sur_Le_Detecteur_B()
void Attente_Du_Passage_Sur_Le_Detecteur_A()

Elles restent donc à leur place mais ne sont pas citées dans le loop.

Je suppose donc qu'à la fin de chacune on remonte automatiquement au loop pour passer à la fonction "calcul"

En tout cas, c'est fort intéressant ce que tu viens de m'apprendre

Titre: Compteur de vitesse
Posté par: juanito le 08 Mars 2023 à 13:44:22
Bonjour,
Et il n'existe plus les wagons tachymétriques ?
https://www.easy-miniatures.com/wagon-de-mesure-tso-ep-v-41508.html
Y'a çà aussi chez Piko...
https://www.piko-shop.de/en/artikel/messwagen-nl-vi-26211.html
A priori toujours en vente... :D
Titre: Compteur de vitesse
Posté par: Ph Blondé le 08 Mars 2023 à 13:52:35
Citation de: ih74330 le 08 Mars 2023 à 11:56:22bonjour,
c'est beau, très technique, mais pas forcément à la portée de tout un chacun, moi le premier (et je le regrette bien).  :o

pour faire la même chose, .......

Concernant le digital, j'ai envisagé la possibilité de faire un compteur personnalisé par train, à mettre autour du régulateur de la commande, mais c'est tjs à l'état de projet ....

C'est également une bonne méthode, le tout c'est que cela nous fasse cogiter et nous amuse.
Merci pour le fichier. :D

Une petite remarque : en général ce que je fais s'applique tant pour la nana logique que pour le numérique.

Pour l'utilisation des Arduino, je connais au moins trois personnes sur ce forum dont ce n'était pas du tout, mais alors pas du tout, leur tasse de thé. Et pourtant, progressivement et en échangeant (on a passé de grands moments au téléphone), ils ont multiplié le nombre d'applications sur leur réseau surtout au niveau des animations ; donc hors cadre du train proprement dit.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 08 Mars 2023 à 14:03:29
Citation de: juanito le 08 Mars 2023 à 13:44:22Bonjour,
Et il n'existe plus les wagons tachymétriques ?
https://www.easy-miniatures.com/wagon-de-mesure-tso-ep-v-41508.html
Y'a çà aussi chez Piko...
https://www.piko-shop.de/en/artikel/messwagen-nl-vi-26211.html
A priori toujours en vente... :D
Si, il a existé chez Fleischmann (je crois) un wagon tachymétrique. Le chrono était déclenché en passant au dessus de deux aimants (début et fin de zone de mesure). Je pense qu'il n'est plus fabriqué.

Pour PIKO, 259 euros ... ah qu'en même  :-\

Maintenant s'il faut, pour chaque train, le décrocher et le ré-atteler....

Cela ne reste, enfin pour moi, qu'un moment de détente à partir d'une idée.
Certains font du Sudoku (*), moi c'est le train et le fer à souder  :)
Mais on ne réussit pas tout (Cf. ma poubelle  ::)  )


(*) : et Nord devant. Je suis loiiiiiiinnnnn  :)

Titre: Compteur de vitesse
Posté par: CC6536 le 08 Mars 2023 à 15:28:24
Ben moi aussi j'ai des portiques avec des aimants au Gros-moulin  :))  :)) mais ça me sert à autre chose.
Titre: Compteur de vitesse
Posté par: ih74330 le 08 Mars 2023 à 15:51:55
Citation de: Ph Blondé le 08 Mars 2023 à 13:52:35Pour l'utilisation des Arduino, je connais au moins trois personnes sur ce forum dont ce n'était pas du tout, mais alors pas du tout, leur tasse de thé. Et pourtant, progressivement et en échangeant (on a passé de grands moments au téléphone), ils ont multiplié le nombre d'applications sur leur réseau surtout au niveau des animations ; donc hors cadre du train proprement dit.
je suis un convaincu, mais je sais que si je fourre mon nez là-dedans, je vais y passer ma vie, et je n'ai pas que ça à faire. Étant informaticien de formation, ça ne devrait pas me poser de problème particulier, avec moi, ça va juste être chronophage .... Concernant le comptage de vitesse, ma solution me convient amplement, et est rôdée de très longue date.
Titre: Compteur de vitesse
Posté par: Alain17 le 08 Mars 2023 à 19:54:27
Citation de: Ph BlondéOK, donc après la fonction :
void Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B()

On enchaine, sans passer par le loop, sur les 2 fonctions
void Attente_Du_Passage_Sur_Le_Detecteur_B()
void Attente_Du_Passage_Sur_Le_Detecteur_A()

Elles restent donc à leur place mais ne sont pas citées dans le loop.
Je suppose donc qu'à la fin de chacune on remonte automatiquement au loop pour passer à la fonction "calcul"
C'est tout à fait cela : quand l'appel d'une fonction est terminée, le code se poursuit juste après l'endroit où elle a été appelée.

Exemple :
//------------------------------------------------
void loop()
{
  Test_Choix_Echelle();
  Test_Distance_De_Mesure();

  Attente_Du_Passage_Sur_Le_Detecteur_A_Ou_Sur_Le_Detecteur_B();

  Calcul_Affichage_Vitesse ();
}

La fonction loop appelle Test_Choix_Echelle. Quand l'exécution de cette fonction est terminée, la fonction loop appelle alors Test_Distance_De_Mesure, etc...
Titre: Compteur de vitesse
Posté par: Philippe de l Est le 08 Mars 2023 à 22:31:46
Comme d'hab : merci Philippe

Au depart de l'idee, c'est regler la vitesse d'une loco a son maxi pour eviter que la 030 rattrape le TGV.
Mais aussi, la vitesse d'une rame pour controler l'effet de la"compensation de charge".
De plus, avec un systeme deplacable, cela permet une utilisation sur n'importe quelle voie ou reseau...

Encore une belle realisation à ton actif. M erci

Philippe, de l'Est
Titre: Compteur de vitesse
Posté par: Arthur le 08 Mai 2023 à 07:04:14
beau projet, et très bien expliqué, merci !
Je suis un fan d'Arduino, que j'utilise déjà pour les feux d'une potence.
Pour la détection, j'aime bien les petits capteurs infra-rouge FC-51, pas chers et très simples (alimentation par le +5V, signal de sortie vers l'Arduino, distance de détection réglable). Ca devrait le faire aussi, je pense.
Titre: Compteur de vitesse
Posté par: Ph Blondé le 08 Mai 2023 à 10:09:36
Citation de: Arthur le 08 Mai 2023 à 07:04:14beau projet, et très bien expliqué, merci !
Je suis un fan d'Arduino, que j'utilise déjà pour les feux d'une potence.
Pour la détection, j'aime bien les petits capteurs infra-rouge FC-51, pas chers et très simples (alimentation par le +5V, signal de sortie vers l'Arduino, distance de détection réglable). Ca devrait le faire aussi, je pense.
Bonjour et merci pour l'appréciation.
J'utilise également ces capteurs qui fonctionnent très bien.

J'ai choisi des émetteurs laser :
- Pour plus de précision,
- pour pouvoir régler plus facilement l'alignement entre l'émetteur et le récepteur (on voit le rayon lumineux),
- parce que je suis un curieux  :)

Également oublié de donner le lien pour ces émetteurs laser : https://www.amazon.fr/RUNCCI-YUN-Photor%C3%A9sistance-R%C3%A9sistance-D%C3%A9pendant-Lumi%C3%A8re/dp/B08N1F5YBG/ref=sr_1_6?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=3685W4CVUFDSA&keywords=%C3%A9lectronique+module+laser&qid=1683532607&sprefix=%C3%A9lectronique+module+laser%2Caps%2C96&sr=8-6

Comme dit un peu plus haut, ne pas utiliser les photorésistances livrées car elles ne réagissent pas immédiatement.

J'ai lu quelque part que l'on pouvait détecter et donc voir l'émission IR avec un iphone équipé pour prendre des photos. Pas encore expérimenté.