Go Down

Topic: Help vitesse moyenne avec un capteur à effet hall (Read 291 times) previous topic - next topic

fantome92

Bonjour, pour mon lycée je dois faire un projet ou je dois acquérir la vitesse instantanée d'un kart et sa vitesse moyenne, j'ai déjà réussi a avoir ma vitesse instantanée mais je suis bloquer pour avoir la vitesse moyenne
voici mon montage du capteur :

voici mon code arduino :
Code: [Select]
unsigned int capteur = 2; // Capteur effet hall
unsigned long chrono; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de depart du chrono
unsigned long chrono_2; // Valeur courante du chrono 2
unsigned long chrono_depart_2 = 0; // Valeur de depart de chrono 2
unsigned long periode; // La periode calcule pour un tour de roue
unsigned int duree_inactivite = 5000; // Duree d'inactivite de la vitesse si le kart n'avance pas pendant 5 seconde
float vitesse_moyenne = 0; // Variable de la vitesse moyenne
float vitesse = 0; // Variable de vitesse
float periR = 1.7; // Périmetre de la roue en m d*pi/100
bool flagMesure = false; // Concerne la mesure de la vitesse



void compteurInc()
{
  chrono = micros();
  periode = chrono - chrono_depart;
  chrono_depart = chrono;
  flagMesure = true; // On a une mesure de periode valide
}
void setup()
{
  Serial.begin(9600); // Initialisation du moniteur

  chrono_depart_2 = millis();

  // La fonction compteurInc est appelée sur chaque front descendant (FALLING) du "capteur" (PIN 2 = interuption 0)
   attachInterrupt(0, compteurInc, FALLING);
   digitalWrite(capteur, HIGH);
   
   
 

}

void loop()
{
  chrono_2 = millis();

  if (flagMesure == false && (chrono_2 - chrono_depart_2 > duree_inactivite)){
    vitesse = 0;
    Serial.print(vitesse,0);
    Serial.println(" km/h");
    delay(500);
  }
  else if (flagMesure)
  {
    noInterrupts();
    unsigned long t = periode;
    flagMesure = false;
    interrupts();
    vitesse=periR/1000/(t/1e6/3600); // On calcule la vitesse en fonction de la période et de la distance que parcourt la roue en 1 tour (périmètre).
    Serial.print(vitesse,1);
    Serial.println(" km/h");
    chrono_depart_2 = millis(); // On remet à zéro le chronomètre de départ 2 (compteur d'inactivité) 
  }


 
 

 
 
}


donc voilà j'ai ma vitesse instantanée qui s'affiche mais je suis perdu pour afficher la vitesse moyenne en meme temps dans le moniteur.

dbrion06

Si vous avez 5 notes, comment calculez vous leur moyenne?
si vous avez Nsamples notes, comment calculez vous leur moyenne?
Si vous avez Nsamples vitesses instantanées?

fantome92

Si j'ai 5 note , on additionne les 5 note et on divise par le nombre total donc 5, je sais comment calculer mais en le codant avec arduino j'ai largement beaucoup de mal je ne comprend pas beaucoup...

dbrion06

Bon, je vois trois façons de calculer une moyenne:
a) au fil de l'eau:
 je remplis une valeur notée cumul par cumul+=vitesseInstantanée  ; j'incrémente iSamples (initialisé à zero)
 tous les Nsamples (le test est donc if (iSamples  == Nsamples ) )
je divise cumul par iSamples  ; je remets iSamples  à zero
   --> vous calculez de temps en temps une vitesse moyenne
b) par moyenne glissante
vous vous donnez un tableau de vitesses, de taille Nsamples; à chaque vitesse instantanée disponible
vous inserez tab[iSample] = vitesseInstantanée  ;
vous incrementez iSamples, et vous le repliez pour qu'il puisse toujours servir d'indice de tableau
     iSamples = (1 +  iSamples) % Nsamples;
vous calculez la moyenne des Nsamples elements de ce tableau (comme pour une moyenne de notes)
Au départ, les valeurs sont forcement bizarres... mais vous avez un rafraîchissement très rapide.

c) par un filtre
moyenne = 0.75* moyenne + 0.25 * vitesseInstantanée  ;
(en 2 tours -revoyez votre cours sur les suites géomètriques-, l'erreur sur la valeur initiale est divisée par 2; elle est divisée par 1000 en 20 tours). Le choix de 1/4 3/4 comme coefficients est que la division par une puissance de deux est très rapide sur tout contrôleur.


fantome92

Merci pour ces informations, mais je suis bloqué pour mon code arduino, parce que vraiment je ne vois pas du tout comment faire cela en utilisant un code.
Si vous pourriez m'aidez je vous en serai très reconnaissant.

lesept

Cherche "arduino average library" sur Google, tu trouveras des choses toutes faites
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

fantome92

J'ai essayé de chercher, je n'ai pas trouvé je sais que je dois prendre plusieurs vitesse instantanée et ensuite diviser sur un intervalle de temps mais je ne sais le programmer...

higgins91

la solution a de dbrion06 est donc à privilégier.

Code: [Select]


la tu déclare les variables:
une pour la moyenne: moy
une pour le nombre de mesure: nbmesure


unsigned int capteur = 2; // Capteur effet hall
unsigned long chrono; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de depart du chrono
unsigned long chrono_2; // Valeur courante du chrono 2
unsigned long chrono_depart_2 = 0; // Valeur de depart de chrono 2
unsigned long periode; // La periode calcule pour un tour de roue
unsigned int duree_inactivite = 5000; // Duree d'inactivite de la vitesse si le kart n'avance pas pendant 5 seconde
float vitesse_moyenne = 0; // Variable de la vitesse moyenne
float vitesse = 0; // Variable de vitesse
float periR = 1.7; // Périmetre de la roue en m d*pi/100
bool flagMesure = false; // Concerne la mesure de la vitesse



void compteurInc()
{
  chrono = micros();
  periode = chrono - chrono_depart;
  chrono_depart = chrono;
  flagMesure = true; // On a une mesure de periode valide
}
void setup()
{
  Serial.begin(9600); // Initialisation du moniteur

  chrono_depart_2 = millis();

  // La fonction compteurInc est appelée sur chaque front descendant (FALLING) du "capteur" (PIN 2 = interuption 0)
   attachInterrupt(0, compteurInc, FALLING);
   digitalWrite(capteur, HIGH);
   
   
 

}

void loop()
{
  chrono_2 = millis();

  if (flagMesure == false && (chrono_2 - chrono_depart_2 > duree_inactivite)){
    vitesse = 0;
    Serial.print(vitesse,0);
    Serial.println(" km/h");

A cet endroit tu fais l'addition de ta vitesse avec ta variable de moyenne:
moy=moy+vitesse
nbmesure=nbmesure+1

et à la suite tu fais une condition si le nombre est > à x mesures
if nbmesure>x
   moy=moy/nbmesure
    Serial.println("moy");
    moy=0
    nbmesure=0
fin if



    Serial.println(" km/h");
    delay(500);
  }
  else if (flagMesure)
  {
    noInterrupts();
    unsigned long t = periode;
    flagMesure = false;
    interrupts();
    vitesse=periR/1000/(t/1e6/3600); // On calcule la vitesse en fonction de la période et de la distance que parcourt la roue en 1 tour (périmètre).
    Serial.print(vitesse,1);
    Serial.println(" km/h");
    chrono_depart_2 = millis(); // On remet à zéro le chronomètre de départ 2 (compteur d'inactivité)
  }

 
}



reste plus qu'a coder "au propre"  :D

fantome92

Bonjour merci d'avoir répondu donc j'ai fais comme vous m'avez dis je ne sais pas si c'est ok
Code: [Select]


float nbmesure = 0; // nombre de mesure
float moy = 0; //  moyenne variable
unsigned int capteur = 2; // Capteur effet hall
unsigned long chrono; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de depart du chrono
unsigned long chrono_2; // Valeur courante du chrono 2
unsigned long chrono_depart_2 = 0; // Valeur de depart de chrono 2
unsigned long periode; // La periode calcule pour un tour de roue
unsigned int duree_inactivite = 5000; // Duree d'inactivite de la vitesse si le kart n'avance pas pendant 5 seconde
float vitesse_moyenne = 0; // Variable de la vitesse moyenne
float vitesse = 0; // Variable de vitesse
float periR = 1.7; // Périmetre de la roue en m d*pi/100
bool flagMesure = false; // Concerne la mesure de la vitesse



void compteurInc()
{
  chrono = micros();
  periode = chrono - chrono_depart;
  chrono_depart = chrono;
  flagMesure = true; // On a une mesure de periode valide
}
void setup()
{
  Serial.begin(9600); // Initialisation du moniteur

  chrono_depart_2 = millis();

  // La fonction compteurInc est appelée sur chaque front descendant (FALLING) du "capteur" (PIN 2 = interuption 0)
   attachInterrupt(0, compteurInc, FALLING);
   digitalWrite(capteur, HIGH);
   
   
 

}

void loop()
{
  chrono_2 = millis();

  if (flagMesure == false && (chrono_2 - chrono_depart_2 > duree_inactivite)){
    vitesse = 0;
    Serial.print(vitesse,0);
    Serial.println(" km/h");
    moy=moy+vitesse;
    nbmesure=nbmesure+1;

if (nbmesure>0);
   moy=moy/nbmesure;
    Serial.println("moy");
    moy=0;
    nbmesure = 0;



    Serial.println("km/h");
    delay(500);
  }
  else if (flagMesure)
  {
    noInterrupts();
    unsigned long t = periode;
    flagMesure = false;
    interrupts();
    vitesse=periR/1000/(t/1e6/3600); // On calcule la vitesse en fonction de la période et de la distance que parcourt la roue en 1 tour (périmètre).
    Serial.print(vitesse,1);
    Serial.println(" km/h");
    chrono_depart_2 = millis(); // On remet à zéro le chronomètre de départ 2 (compteur d'inactivité)
  }

 
}

dbrion06

A priori, votre solution n'est pas trop incorrecte; cependant, il est plus que vraisemblable que votre moyenne soit le cas dégénéré où on fait le calcul de la moyenne ... sur une (1+0; 0+1; 1*1) donnée et elle doit donc se confondre avec la vitesse instantanée (au prix de lignes de code en plus...)
Code: [Select]

if (nbmesure == nSamples);
   moy = moy/ (float)nSamples ;
    Serial.println("moy");
    moy = 0.0;
    nbmesure = 0;



    Serial.println("km/h");
    delay(500); // A quoi sert ce delai?
  }
(non testé)
Pour ce faire, il vous faut déclarer nSamples
cons uint8_t nSamples = 5; // vous faites une moyenne sur 5 valeurs; adaptez si besoin

De même, nbmesures n'a pas à être déclaré en float: un integer (int, uint8_t ou ...) fait très bien l'affaire (et lui rajouter 1 est plus rapide et consomme moins de cycles que rajouter 1.0 à un float; la conversion n'a lieu que pour la  division)

Cette solution (au besoin, améliorée pour qu'elle compile: je n'ai pas testé) vous permettrait d'échapper au cas trivial (qui n'est pas faux, mais mange d"es ressources inutilement) que vous avez programmé (moyenne == instantané)

fantome92

Bonjour, merci d'avoir répondu, du coup je n'ai pas trop compris je dois m'y prendre comment ? je laisse le code que j'ai fais ou je dois rajouter des lignes de codes notamment ce que vous venez de me montrer ?

dbrion06

Vous remplacez le bloc
if (nbmesures>0) {
....
}
par le bloc que je vous ai passé.


Nora: ce serait plus beau si vous remplaciez aussi :   Serial.println("moy"); par :   Serial.println(moy);
(je n'ai pas testé ce bloc: je suppose que vous pouvez comprendre 5 lignes de code .... sinon, ce serait absurde de les demander....
 et je susi sûr  que vous avez de meilleurs moyens que moi -disponibilité d'un arduino et de son IDE - de tester)



fantome92

Merci d'avoir répondu du coup cela me donne ça :
Code: [Select]
uint8_t nSamples = 5; // vous faites une moyenne sur 5 valeur adaptez si besoin
int nbmesure = 1; // nombre de mesure
float moy = 0; //  moyenne variable
unsigned int capteur = 2; // Capteur effet hall
unsigned long chrono; // Valeur courante du chrono
unsigned long chrono_depart = 0; // Valeur de depart du chrono
unsigned long chrono_2; // Valeur courante du chrono 2
unsigned long chrono_depart_2 = 0; // Valeur de depart de chrono 2
unsigned long periode; // La periode calcule pour un tour de roue
unsigned int duree_inactivite = 5000; // Duree d'inactivite de la vitesse si le kart n'avance pas pendant 5 seconde
float vitesse_moyenne = 0; // Variable de la vitesse moyenne
float vitesse = 0; // Variable de vitesse
float periR = 1.7; // Périmetre de la roue en m d*pi/100
bool flagMesure = false; // Concerne la mesure de la vitesse



void compteurInc()
{
  chrono = micros();
  periode = chrono - chrono_depart;
  chrono_depart = chrono;
  flagMesure = true; // On a une mesure de periode valide
}
void setup()
{
  Serial.begin(9600); // Initialisation du moniteur

  chrono_depart_2 = millis();

  // La fonction compteurInc est appelée sur chaque front descendant (FALLING) du "capteur" (PIN 2 = interuption 0)
   attachInterrupt(0, compteurInc, FALLING);
   digitalWrite(capteur, HIGH);
   
   
 

}

void loop()
{
  chrono_2 = millis();

  if (flagMesure == false && (chrono_2 - chrono_depart_2 > duree_inactivite)){
    vitesse = 0;
    Serial.print(vitesse,0);
    Serial.println(" km/h");
    moy=moy+vitesse;
    nbmesure=nbmesure+1;

if (nbmesure == nSamples);
   moy = moy/(float)nSamples ;
    Serial.println(moy);
    moy = 0.0;
    nbmesure = 0;



    Serial.println("km/h");
    delay(500); // A quoi sert ce delai?
 
  }
  else if (flagMesure)
  {
    noInterrupts();
    unsigned long t = periode;
    flagMesure = false;
    interrupts();
    vitesse=periR/1000/(t/1e6/3600); // On calcule la vitesse en fonction de la période et de la distance que parcourt la roue en 1 tour (périmètre).
    Serial.print(vitesse,1);
    Serial.println(" km/h");
    chrono_depart_2 = millis(); // On remet à zéro le chronomètre de départ 2 (compteur d'inactivité)
  }

 
}


Et le delay je le supprime ou pas si vous pensez qu'il ne sert à rien ? mon code est mieux comme cela ? et que signifie "uint8_t" s'il vous plaît ?

dbrion06

uintXX_t est une façon de spécifier sans ambiguité le nombre d'octets que l'on veut utiliser (uint8_t pour un octet, uint16_t pour deux octets, uint32_t pour 4 octets). Il offre l'avantage d'être portable : un code testé sur un vieux PC (où les entiers sont des (u)int32_t) peut fonctionner , avec des chances raisonnables, sur un arduino(où les entiers sont des (u)int16_t).

Votre code est vraisemblablement moins mauvais comme ça: C'est à VOUS de voir

a) s'il se compile (c'est trivial: il suffit d'appuyer sur un bouton si vous disposez d'un IDE arduino)

b) s'il donne des valeurs vraies ou réalistes (je ne peux pas organiser votre façon de tester)

Si JE pense que le delay ne sert à rien, c'est MON opinion( hors sujet de ce fil et VOUS êtes libre d'être en désaccord.
Je ne peux que vous signaler que delay mange un nombre fou de cycles,
à ne RIEN faire d'utile,
 et qu'il existe des façons plus habiles d'interdire un bloc de programme de s'executer pendant xxx millisecondes, sans perte de ressources: un bel exemple est dans
fichiers->exemples->digital->blinkWithoutDelay IIRC.

Go Up