Go Down

Topic: Vitesse et capteur Hall (Read 1 time) previous topic - next topic

Walex68

Feb 21, 2017, 05:50 pm Last Edit: Feb 21, 2017, 05:55 pm by Walex68
Bonjour,

J'ai comme projet de faire un tableau de bord assez complet (température ambiante/moteur, heure, date, km parcouru, etc ...). L'ensemble est quasi fonctionnel (affichage sur écran graphique 128*64).

Cependant l'affichage de la vitesse n'est pas assez rapide et pas précise au km/h près.

Après de nombreuses recherches je ne trouve pas mieux que le code que j'ai fait ci-dessous, le problème de celui-ci est qu'il rafraîchit toutes les 3 sec seulement et n'est pas vraiment précis (marge de 3 km environ, par ex il va afficher 6km/h ou 10km/h mais pas les valeurs intermédiaires).

Pour faire simple je calcul les rpm en comptant le nombre de tour pendant une période (3 sec) et en fonction de ceux-ci avec un calcul j'en déduis la vitesse... (Le code est assez simple et bien commenté pour être compréhensible je pense :) ).

Je cherche donc à calculer la vitesse avec un rafraîchissement d'une seconde au plus et si possible précis au km/h près (à savoir qu'une fois ce problème résolu j'aimerais calculer la distance parcouru etc dans l'optique de la stocker sur sd (tripmaster)...).

Avez vous une solution à mon problème ? :D
Je sèche et ça fait des heures que je cherche et trouve des solutions très souvent incomplète ou incompréhensible sur les forums et autre c'est pour cela que je me permet de créer un nouveau poste.



Code: [Select]

unsigned int vitesse = 0; // Vitesse de la roue (du véhicule)
unsigned int rpm = 0; // Trs/min de la roue
unsigned int chrono = 0; // Valeur courante du chrono
unsigned int chrono_depart = 0; // Valeur de départ du chrono
unsigned int duree_test = 3000; // Durée du test de "vitesse" en ms (ex : 3 sec = 3000ms)
int capteur = 2; //Pin d'entrée du capteur hall
unsigned int compteur = 0; //Valeur de compteur (compte chaque passage de l'aimant devan le capteur hall)
float diametreR = 0.6; // Diametre de la roue /10 (ex: diamètre = 60cm /10 = 0.6)


void compteurInc()
{
  compteur++; //Incrémentation du compteur
}

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

  chrono_depart = millis();

  //La fonction compteurInc sera appelée sur chaque front descendant (FALLING) de "capteur" (pin 2=interuption 0)
  attachInterrupt(0, compteurInc, FALLING);
  digitalWrite(capteur, HIGH);
}

void loop()
{
  chrono = millis();

  if (chrono - chrono_depart > duree_test) {
    
   rpm=compteur*20;// Ex : Si mesure sur 3 secondes : il faut multiplier le nb de chgt par 20 pour avoir le nb de changement par minute
   vitesse=(rpm*3.14/60)*diametreR*3.6; // Calcul de la vitesse en km/h -> (rpm*pi/60)*diametredelaroue*3,6"(pour passer de m/s en km/h -> 3600sec...)"
   Serial.print("RPM : ");
   Serial.print(rpm);
   Serial.print(" trs/min     ");  
   Serial.print("Vitesse : ");
   Serial.print(vitesse,1);        
   Serial.println(" km/h");    
   chrono_depart = millis(); // Mise à zéro du chrono de départ
   compteur=0; // Mise à zéro du compteur
  
  }    
  
}


PS : Cette personne à réussi à faire un truc qui semble être précis et rapide, je lui est posé la question et il m'a envoyé une partie de son code (voir commentaire) mais je pige pas grand chose à son affaire :p https://www.youtube.com/watch?v=oeuFZTq3cmc

icare

#1
Feb 21, 2017, 06:04 pm Last Edit: Feb 21, 2017, 06:05 pm by icare
Bonjour,
Sans regarder ton soft, juste une petite remarque.
Tu fais le calcul de la vitesse en float et tu l'affectes à int donc pertes d'informations
Code: [Select]
Serial.print(vitesse,1);
Sera toujours un entier.
2B OR NOT(2B) = FF
Arduino 1.0.5 à 1.8.5 + gEdit + Ubuntu 18.04 LTS

Walex68

#2
Feb 21, 2017, 06:09 pm Last Edit: Feb 21, 2017, 06:16 pm by Walex68
Effectivement, quand j'ai test avec la vitesse en float j'ai oublié de retirer la ,1 ;p.
Ce n'est ça le problème mais merci de l'avoir remarquer :D

landid

Salut,
  que ce passe t'il si tu réduit duree_test à 1000 et que tu multiplie par 60 ?
Si le seul outil que vous avez est un marteau, vous verrez tout problème comme un clou.
      Abraham Maslow

Walex68

Si je réduit la durée du test, l'affichage est plus rapide (1 / sec) mais c'est encore moins précis... :/

landid

J'ai un peu regardé le code du compteur proposé par ElectroniZon et il semble assez similaire au tien. Il fait des mesures toutes les 4 secondes apparemment. Sauf que lui il spécifie bien des float partout en forçant le typage même pour les millis.

Code: [Select]
float vitesse = 0;
float distance = 0;
float tps = 0;

....etc..

void calcule() {
  float timems = float(timer[1] - timer[0]);
  float s = float(timems / 1000);
  vitesse = (2.05 / s) * 3.6;
  distance = distance + (2.05 * 2);
  if (timems < 4000) {
    tps = tps + ((timems * 0.001) * 2);
  }
}
Si le seul outil que vous avez est un marteau, vous verrez tout problème comme un clou.
      Abraham Maslow

aligote

#6
Feb 21, 2017, 06:41 pm Last Edit: Feb 21, 2017, 07:25 pm by aligote
.....................
Pour faire simple je calcul les rpm en comptant le nombre de tour pendant une période (3 sec) et en fonction de ceux-ci avec un calcul j'en déduis la vitesse... (Le code est assez simple et bien commenté pour être compréhensible je pense :) ).
.................
Bonsoir,

Je pense que le problème se situe ici.
Avec le principe retenu, la précision est mauvaise pour les faibles vitesses.

Par exemple dans le cas de 1200 t/mn cela fait 20 t/s en faisant un comptage toutes les s l'imprécision sera de 5%..... et rafraichir l'affichage toutes les secondes n'est pas confortable.
Il vaudrait mieux compter la durée d'une période (1 tour)
En reprenant l'exemple précédent 1 tour correspond à 50 ms, si le chronométrage est précis avec une erreur de 5µs (fonction micros() par exemple) alors l'imprécision ne serait que de 5/50.000 soit 0.01%
Pour cela l'usage d'un fonctionnement en interruption est obligatoire avec un s/p d'interruption qui tourne de façon autonome pour mettre à jour la variable période. l'affichage se faisant de façon asynchrone, par exemple en affichant 10 fois par s.

En résumé réaliser un période mètre à la place d'un fréquencemètre.

Serge .D

Walex68

J'ai essayé avec tout en float et ça ne change rien, dans tout les cas le rafraîchissement est de 3 sec (durée "d'analyse") :/

Par ex : avec 1000ms au lieu de 3000, ça rafraîchis toute les secondes mais on perd en précisions..
- 1 sec = palier de 6 km/h

Walex68

Bonne idée Serge ! Je pensais justement à un résonnement comme ça... Je vais étudier ça demain et vous tiens au jus ;)

Walex68

#9
Feb 22, 2017, 03:31 pm Last Edit: Feb 22, 2017, 03:36 pm by Walex68
Après réflexion j'ai fait un code qui compte le nombre de micro secondes en 1 tour, ça fonctionne bien... Maintenant le problème est de convertir le temps en fonction de la distance que parcourt la roue en 1 tour (1,8m environ, celle ci fait 556 tours pour faire 1km...) et là ça fait mal au cerveau de réfléchir à une conversion entre 2 unités différente haha :p, je n'arrive pas à trouver ce foutu calcul qui pourtant ne doit pas être bien compliqué ! Avez vous une idée ? :D


Code: [Select]
//float vitesse = 0; // Vitesse de la roue (du véhicule)
//float rpm = 0; // Trs/min de la roue
unsigned int chrono = 0; // Valeur courante du chrono
unsigned int chrono_depart = 0; // Valeur de départ du chrono
//unsigned int duree_test = 3000; // Durée du test de "vitesse" en ms (ex : 3 sec = 3000ms)
int capteur = 2; //Pin d'entrée du capteur hall
unsigned int compteur = 0; //Valeur de compteur (compte chaque passage de l'aimant devan le capteur hall)
//float diametreR = 0.6; // Diametre de la roue /10 (ex: diamètre = 60cm /10 = 0.6)
boolean x = false;

void compteurInc()
{
  compteur++; //Incrémentation du compteur
}

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

  chrono_depart = micros();

  //La fonction compteurInc sera appelée sur chaque front descendant (FALLING) de "capteur" (pin 2=interuption 0)
  attachInterrupt(0, compteurInc, FALLING);
  digitalWrite(capteur, HIGH);
}

void loop()
{
  x = false;
  
  while (x == false){

    if (compteur == 1) {
      chrono = micros();
    }
    
    if (compteur == 2) {
      detachInterrupt(capteur);
      Serial.println(chrono - chrono_depart);
      x = true;
      attachInterrupt(0, compteurInc, FALLING);
    }
  
  }

   chrono_depart = micros(); // Mise à zéro du chrono de départ
   compteur=0; // Mise à zéro du compteur
  
}

kamill

#10
Feb 22, 2017, 04:02 pm Last Edit: Feb 22, 2017, 04:25 pm by kamill
Bonjour,

La vitesse c'est d/t: la distance que divise le temps
Pour calculer la vitesse en km/h tu divise la distance en km par le temps en heure

distance en km 1.8[m]/1000
temps en heure T[µs]/1000000/3600

D'où vitesse [km/h]:1.8/1000/(T/1000000.0/3600)

Ta méthode pour mesurer la période est compliquée (et très imprécise). Tu peux mesurer la période directement en interruption.
de plus chrono et chrono_depart doivent être des unsigned long


Walex68

Merci ! J'ai trouvé un calcul un peut plus simple qui donne le même résultat :) :

Code: [Select]
vitesse = (3600000/chrono)*1.88

D'accord, j'ai fait ce code en fonction de mes connaissances :D.
Après test avec le calcul, celui ci fonctionne en revanche le calcul de temps est en effet très imprécis et aléatoire :/.
Donc le "chrono" est à revoir..

kamill

#12
Feb 22, 2017, 04:41 pm Last Edit: Feb 22, 2017, 04:49 pm by kamill
Ce n'est pas plus simple c'est la même chose en regroupant les constantes. J'avais fait un calcul didactique.
Il faut faire le calcul en flottant
vitesse = (3600000.0/(chrono-chrono_depart))*1.88

Il faut mesurer la période en interruption.

Walex68

Avec ce calcul les vitesses affiché par rapport au temps sont très précises en revanche le calcul de la période souffre de bug (freeze ou temps incorrect).

Je ne comprend pas trop ce que vous voulez dire par "mesurer la période en interruption", je les utilises déjà non ? Il y a t il une autre méthode ou fonction ?

Code: [Select]
float vitesse = 0; // Vitesse de la roue (du véhicule)
unsigned long chrono = 0; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de départ du chrono
int capteur = 2; //Pin d'entrée du capteur hall
unsigned int compteur = 0; //Valeur de compteur (compte chaque passage de l'aimant devan le capteur hall)
boolean x = false;
float tps;

void compteurInc()
{
  compteur++; //Incrémentation du compteur
}

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

  chrono_depart = micros();

  //La fonction compteurInc sera appelée sur chaque front descendant (FALLING) de "capteur" (pin 2=interuption 0)
  attachInterrupt(0, compteurInc, FALLING);
  digitalWrite(capteur, HIGH);
}

void loop()
{
  x = false;
 
  while (x == false){

    if (compteur == 1) {
      chrono = micros();
    }
     
    if (compteur == 2) {
      detachInterrupt(digitalPinToInterrupt(capteur));
      vitesse = (3600000.0/(chrono - chrono_depart))*1.88;
      Serial.print("Temps (microsec) : ");
      Serial.println(chrono - chrono_depart);
      Serial.print(vitesse);
      Serial.println(" km/h");
      x = true;
      attachInterrupt(0, compteurInc, FALLING);
    }
 
  }

   chrono_depart = micros(); // Mise à zéro du chrono de départ
   compteur=0; // Mise à zéro du compteur
   
}     
 

kamill

#14
Feb 22, 2017, 05:35 pm Last Edit: Feb 22, 2017, 05:36 pm by kamill
Dans ton programme tu incrémentes un compteur en interruption, tu ne mesures pas la période.
Tu mesures la période dans la loop() et comme tu initialises chrono_depart dans la loop() il n'est pas synchronisé avec le signal.

Exemple de programme qui mesure la période en interruption:
Code: [Select]
unsigned long chrono; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de départ du chrono
unsigned long periode;
bool flagMesure = false;

void compteurInc()
{
  chrono = micros();
  periode = chrono - chrono_depart;
  chrono_depart = chrono;
  flagMesure = true;    // on a une mesure de période valide
}

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

  //La fonction compteurInc sera appelée sur chaque front montant de "capteur" (pin 2=interuption 0)
  attachInterrupt(0, compteurInc, RISING);
  //  digitalWrite(capteur, HIGH);
}

void loop()
{
  if (flagMesure)
  {
    noInterrupts();
    unsigned long t = periode;
    flagMesure = false;
    interrupts();
    float vitesse=1.88/1000/(t/1e6/3600);
    Serial.print(t);
    Serial.print(" -> ");
    Serial.println(vitesse);
  }
}

Go Up