Nouvelles:

25/06/2023 : Mise à jour du forum. En cas de bug, merci de contacter le Grand Sachem

Menu principal

Compteur de vitesse

Démarré par Ph Blondé, 07 Mars 2023 à 15:29:24

« précédent - suivant »

0 Membres et 1 Invité sur ce sujet

Ph Blondé

Philippe Blondé
Un 59 dans le 22

Alain17

#16
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.

Ph Blondé

#17
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.
Philippe Blondé
Un 59 dans le 22

Alain17

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.

ih74330

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
il vaut mieux traîner la patte sur le bon chemin, que cavaler sur le mauvais .....

Ph Blondé

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

Philippe Blondé
Un 59 dans le 22

juanito

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

Ph Blondé

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.
Philippe Blondé
Un 59 dans le 22

Ph Blondé

#23
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  :)

Philippe Blondé
Un 59 dans le 22

CC6536

Ben moi aussi j'ai des portiques avec des aimants au Gros-moulin  :))  :)) mais ça me sert à autre chose.
Trop de taxes, trop de Tva.

ih74330

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.
il vaut mieux traîner la patte sur le bon chemin, que cavaler sur le mauvais .....

Alain17

#26
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...

Philippe de l Est

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
Je l'ai fait parce que je ne savais pas que c'était impossible de le faire !

Arthur

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.

Ph Blondé

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é.
Philippe Blondé
Un 59 dans le 22