compteur de vitesse

Bonjour, je voudrais réaliser un compteur de vitesse pour vélo avec un capteur à effet hall et un écran oled.

  • Mon afficheur OLED est de 0.96’’ 128*64 en I2C ( adresse I2C trouvé avec scanner = 0x3C ) SSD1306.

  • Mon capteur à effet hall est un UGN3503 qui envoie du 2.5v quand aucun champs magnétique augmente quand un champs magnétique “nord” se rapproche ( quand il passe environ 3v ) et diminue quand un champs magnétique “sud” se rapproche. Mon capteur est donc analogique pas comme les “autres”( la majorité ).

Je n’ai aucun problème au niveau cablâge ( ecran 5v et gnd + sda sur sda et sci sur sci ) (effet hall supply sur 5v gnd sur gnd et output sur A0 ) par contre au niveau programmation je n’arrive pas du tout; j’ai déjà regardé les différents articles de capteur à effet hall tachymetre mais je ne comprends rien à ceux-ci.

J’ai déjà un code qui devrais m’afficher sur serial le temps entre deux interruptions mais qui m’affiche millis :

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

void loop(){
  unsigned long temps = millis();
  unsigned long tempstrouve;
  unsigned long dernierPassage;

  if(analogRead(A0) <= 410  || analogRead(A0) >=615 ){  //si un aimant pole nord ou un aimant pole sud passe devant le capteur
    tempstrouve = temps - dernierPassage;
 dernierPassage = temps;
    Serial.println(tempstrouve);
  }
}

Je ne sais même pas si c’est la bonne méthode pour calculer la vitesse et j’ai surtout un problème pour arriver à calculer la vitesse à partir d’un périmètre de roue et d’un temps entre deux interruptions!.. :confused:

Tu devrais stocker la valeur lue dans une variable int et faire ton test sur cette variable.
Pour la vitesse, il suffit de diviser la distance par le temps, donc le périmètre par l'intervalle de temps mesuré
Il faut bien sûr faire une division en float sinon ça ne sera pas précis

Maintenant j’arrive à lire sur serial le tempstrouve correctement donc c’est ok pour ça mais j’ai réécri le programme pour avoir la vitesse :

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

void loop(){
  unsigned long temps = millis();
  int tempstrouve;
  unsigned long dernierPassage;
  int perimetre = 2;  //entrer le périmètre de la roue en m, le périmètre est égal à   pi*diamètre     ou      pi*2* rayon
  int vitesse;

  if(analogRead(A0) <= 410  || analogRead(A0) >=615 ){  //si un aimant pole nord ou un aimant pole sud passe devant le capteur
    tempstrouve = temps - dernierPassage;
    dernierPassage = temps;
    vitesse = (perimetre / (tempstrouve / 1000))*3.6; //donne la vitesse en km/h grace à v = d/t
    Serial.println(vitesse);
    delay(50);  //delay juste pour les tests et que ce soit lisible
    
  }
}

Mais ça ne fonctionne pas, le serial m’envoie n’importe quoi toujours en descendant la valeur ( valeur plus faible que précédente ) alors que j’augmente la cadence de passage de l’aimant.

il me la descend jusqu’à 0 puis juqu’à des nombres négatifs !!!

Bonjour,

La variable dernierPassage doit être conservée entre chaque appel de loop(). Il faut la déclarer static

static unsigned long dernierPassage;

Il faut aussi que la valeur de A0 sorte de l'intervalle avant de faire la mesure suivante.

Maintenant ça m’affiche tout le temps -3 sauf parfois 0 ou 3 ou 7

le code :

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

void loop(){
  unsigned long temps = millis();
  int tempstrouve;
  static unsigned long dernierPassage;
  int perimetre = 2;  //entrer le périmètre de la roue en m, le périmètre est égal à   pi*diamètre     ou      pi*2* rayon
  int vitesse;


  if(analogRead(A0) <= 410  || analogRead(A0) >=615 ){  //si un aimant pole nord ou un aimant pole sud passe devant le capteur
    tempstrouve = temps - dernierPassage;
    dernierPassage = temps;
    vitesse = (perimetre / (tempstrouve / 1000))*3.6; //donne la vitesse en km/h grace à v = d/t
    Serial.println(vitesse);
    delay(50);  //delay juste pour les tests et que ce soit lisible
    
  }
}

Et aussi je ne sais pas comment faire

kamill:
Il faut aussi que la valeur de A0 sorte de l’intervalle avant de faire la mesure suivante.

Et il faut définir vitesse en float
float vitesse;

au risque de dire une co…

si Mr kamil dit :
“…Il faut aussi que la valeur de A0 sorte de l’intervalle avant de faire la mesure suivante.”
c’est peut étre que :
manque changement d’ état…

au moment déclenchant le calcul résultat de comptage :

if(analogRead(A0) <= 410 || analogRead(A0) >=615 ){

il faut prendre en compte que la loop précédente été avec un analog read hors intervalle…

un peut comme une variable anti-rebond…

if(analogRead(A0) <= 410 || analogRead(A0) >=615 ||…ici… ){

…par exemple…

Maintenant ça m’affiche 3.60

Je suis vraiment désolé mais je ne comprends toujours pas le truc d’intervalle, que dois-je changer à mon code ??

Peut-être qu’il faut que je mette une sorte de delay ou un truc du genre :

if(analogRead(A0) <= 410 || analogRead(A0) >=615 & DernierPassage > 50){

???

J’essaye autrement :wink:

la fonction loop tourne à une cadence de plusieurs centaines de fois par seconde (cela dépend du code quel contient).

Le capteur sera dont vu “actif” (…<= … || … >= …) dans une suite importante d’appels consécutif de la fonction loop. Du coup le calcul de vitesse = … ne fonctionne pas puisque les variables temps et dernierPassage ne représente pas 2 passages consécutifs du capteur mais 2 tours de boucles consécutifs…

Il faut donc que tu n’effectues le calcul si tu viens d’un état inactif à un état actif. Tu peux par exemple gérer une variable dernierEtat reflétant l’état détecté dans le tour précédent, que tu consulteras au moment de prendre la décision de faire le calcul.

Un peu la même technique que dernierPassage :wink:

Il faut que tu prennes en compte uniquement le franchissement du seuil et non si tu as déjà franchi le seuil.
Tu dois utiliser un flag pour ça.

void loop() {
  int perimetre = 2;  //entrer le périmètre de la roue en m, le périmètre est égal à   pi*diamètre     ou      pi*2* rayon
  static unsigned long dernierPassage;
  static bool flagMesure = false;
  int tempstrouve;
  int vitesse;

  if (analogRead(A0) <= 410  || analogRead(A0) >= 615) { //si un aimant pole nord ou un aimant pole sud passe devant le capteur
    if (flagMesure)
    {
      unsigned long temps = millis();
      tempstrouve = temps - dernierPassage;
      dernierPassage = temps;
      vitesse = (perimetre / (tempstrouve / 1000)) * 3.6; //donne la vitesse en km/h grace à v = d/t
      flagMesure = false;     // pour attente cycle suivant
      Serial.println(vitesse);
      //    delay(50);  //delay juste pour les tests et que ce soit lisible
    }
  }
  else
  {
    flagMesure = true;  // prêt pour une nouvelle mesure
  }
}

@ Belo.

euuuuuuuuuuu…

if(analogRead(A0) <= 410 || analogRead(A0) >=615 ||…ici… ){
le rajout ||…ici…
c’ est pas bon /trop condensé… …scusa me…

C 'est effectivement efectivement plus compréhensible
les soluce Kamil et mieux explique par supercc…

Maintenant j’ai compris le principe, j’ai essayé le code de kamill avec en plus float vitesse mais ça ne marche pas ( sur le serial ), ça me donne ça ( capture d’écran en bas en lien ). Ce n’est que des multiples de 3.6 (03.6, 13.6, 2*3.6 ) et justement j’utilise 3.6 dans mes calculs , y-a-t’il un rapport ??

Et aussi cette partie la m’intrigue :

if (flagMesure) Il ne faut pas mettre un truc du genre “if (flagMesure == true)”

En C :

  • var vaut le contenu de la variable (normal ;-))
  • en C, seule les valeurs 0 et false sont considérées comme "faux" et tout le reste est vrai (plus original !) : true 1, -1, 34.8 sont vrais

donc if(var) ne sera vrai que si var est !=0 ou !=false. Mais si tu veux tu peux écrire if(var!=0) ou if(var == true).

Tu dois avoir un problème dans la formule !

EDIT : précisions + correction

Affiches le tempsTrouve, peut être que la résolution n'est pas suffisante.

"if (flagMesure)" et "if (flagMesure == true)" sont identiques. Ce sont tous deux des booleens.
C'est inutile de comparer flagMesure à true ou false puisqu'il vaut déjà true ou false

J'affiche le tempstrouve et c'est bon, ça m'affiche le tempstrouve.

Peut-être devrais-je faire plusieurs calculs au lieu d'un gros ?
( au lieu de ça : vitesse = (perimetre /(tempstrouve / 1000)) * 3.6;

Et remplacer par ça :

vitesse = perimetre / tempstrouve;
vitesse = vitesse * 3600;

J'ai essayé comme au dessusmais ça m'affiche que 0.00 dés que je passe l'aimant

Et ça donne combien pour tempsTrouve?

Quand j'affiche tempstrouve ba ça me donne le temps en ms entre chaque passage de l'écran

Belo:
Peut-être devrais-je faire plusieurs calculs au lieu d'un gros ?
( au lieu de ça : vitesse = (perimetre /(tempstrouve / 1000)) * 3.6;

Et remplacer par ça :

vitesse = perimetre / tempstrouve;
vitesse = vitesse * 3600;

J'ai essayé comme au dessusmais ça m'affiche que 0.00 dés que je passe l'aimant

Ton problème est de faire une division en flottant. Mais si tes nombres sont des int et que tu ne précises pas que tu veux un flottant, ta division sera entière.
Pour ça plusieurs solutions, la plus simple est de dire explicitement que tu veux du flottant

vitesse = perimetre * 1.0 / tempstrouve;
vitesse = vitesse * 3600.0;

Sinon tu peux faire un cast, une promotion, qui va changer temporairement un int en float, le temps de l'opération

 vitesse = (float) perimetre / tempstrouve;
vitesse = vitesse * 3600;

Belo:
Peut-être devrais-je faire plusieurs calculs au lieu d'un gros ?
( au lieu de ça : vitesse = (perimetre /(tempstrouve / 1000)) * 3.6;
...

Il faut faire le calcul en flottant

vitesse = (perimetre /(tempstrouve / 1000.0)) * 3.6

D'accord, maintenant ça y est, j'ai la vitesse en km/h.
Et finalement j'ai changé le vitesse en int car je ne souhaite pas de nombres à virgule.

J'ai réalisé un second programme qui m'affiche cette vitese mais sur un écran oled cette fois-ci, je travaille pour mesurer la distance et l'afficher et travaille avec l'EEPROM ( j'essaye ) pour afficher dans un second menu la distance totale et d'autres trucs ( vitesse max ...).

J'aurais sans doute besoin d'aide pour l'EEPROM car je n'ai jamais utilisé celle-ci mais ayant lu des tutos, je pense que ça devrait le faire....