Compte tour laser (compte tour, compteur de passage ect...)

Bonsoir, j'aurais aimé faire un compte tour universel avec un laser...

Grosso modo, a chaque illumination de la LDR l'arduino compte un tour et me donne le résultat en T/min, alors a priori c'est simple, mais je n'arrive pas au raisonnement qui fera que mon code va être fonctionnel !

La première application va être de déterminer la vitesse de rotation de mon ventilateur de plafond (oui, comme dans les westerns)
Pour la partie captation, c'est très facile, un laser, un miroir, et une ldr. Le miroir est fixé sur une des pales du ventilateur, le laser posé sur la table en direction du plafond, et la ldr sous le retour du laser, aussi la ldr ne recevra une impulsion uniquement toutes les 4 pâles.
Mon problème c'est que je ne vois pas comment dire a l'Arduino, tu compte le nombre de tour pendant 15s puis tu multiplie par 4 et tu me balance le résultat dans le moniteur série.

Je sais qu'il va y avoir de l'incrémentation, par exemple il va compter +1 pendant 15s, et si il compte 20, je veux qu'il le multiplie par 4 pour me donner 80 T/min.

Je vais encore y réfléchir cette nuit, mais si vous avez des pistes / conseils je suis preneur :smiley:
Merci d'avance :slight_smile:

Deux méthodes :

-mesurer le laps de temps entre deux tops
-compter le nombre de top dans un laps de temps déterminé

La première me semble plus précise.

Pourquoi vouloir multiplier par 4 ? le nombre de pales ne détermine pas le nombre de tour puisqu'une seule donne le top.... 1 top 1 tour.

Bonjour, je multiplie par 4 parce que je comptais compter sur seulement 15 secondes.

Par contre c'est pour les notions de temps et de comptage que j'ai du mal, tout ce fait avec des delay ou il existe des fonctions spéciales ?

la fonction pulseLn() devrait t'aider. Ca te donnera la période de tes impulsions (en microsecondes je crois).

Ensuite, on sait que Fréquence = 1/Période, or Fréquence est en Imp/s, il suffit de multiplier pas 60 pour avoir Imp/min.

Bref, vitesse = 60 000 000 / pulseLn();

Salut Super_Cinci,

Petite correction vu qu'en plus tu as répété ton erreur :

Super_Cinci:
la fonction pulseIn() devrait t'aider

J'ai essayé un peu, j'ai pas bien compris...

Mon capteur n'est jamais a 0 (LOW) ou 5V (HIGH), donc pour pulseIn, il faut que le capteur actionne une broche vide en INPUT en gros ?

A chaque passage du laser il faut :

int capteur = A0;
int mesure = 0;
int compteur = 0;
int mesureRpm = 7;
unsigned long temp;


void setup()
{
  Serial.begin(9600);
  pinMode(mesureRpm, INPUT);
}

void loop()
{
  mesure = analogRead(capteur);

  if ( mesure > 700 )
  {
    digitalWrite(mesureRpm, HIGH);
  }
  temp = pulseIn(mesureRpm, HIGH);

  if (temp == HIGH)
  {
    compteur++;
    Serial.print(compteur);
  }
}

Donc la en gros, a chaque lecture du laser, l'Arduino met la broche 7 en HIGH, et si mesureRpm = HIGH, je compte +1 ?
J'ai bon pour le moment ?

comme je l'utilise jamais, je n'ai pas fait gaffe que c'était I, je pensais à L comme Ln = Lenght, ça semblait cohérent. désolé pour l'erreur...

Compter sur une fenêtre de 15 secondes, ça a quelques inconvénients :

  • Actualisation seulement toutes les 15 sec, c'est super long...
  • si la vitesse bouge pendant les 15 sec, tu ne le verras pas, tu auras juste la vitesse moyenne sur cette fenêtre de temps.
  • si tu comptes 20, alors V = 80, ok. si tu comptes 19, V = 76 (soit une précision de +/-4 tr/min)... pas top la précision...

Avec pulseIn(), aux alentours de 80tr/min, tu auras une précision (théorique) de +/- 0,0001 tr/min et une actualisation à peu près toutes les secondes.

Tu dois aller te renseigner sur cette fonction pulseIn(), car tu n'as pas du tout compris comment elle marche. Ca renvoit une valeur numérique, pas un boolean!

http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.PulseIn

De plus, je t'ai donné une formule que je ne vois pas dans ton code, as-tu compris ce que j'ai raconté à propos de fréquence / période?

Super_Cinci:
comme je l'utilise jamais, je n'ai pas fait gaffe que c'était I, je pensais à L comme Ln = Lenght, ça semblait cohérent. désolé pour l'erreur...

Compter sur une fenêtre de 15 secondes, ça a quelques inconvénients :

  • Actualisation seulement toutes les 15 sec, c'est super long...
  • si la vitesse bouge pendant les 15 sec, tu ne le verras pas, tu auras juste la vitesse moyenne sur cette fenêtre de temps.
  • si tu comptes 20, alors V = 80, ok. si tu comptes 19, V = 76 (soit une précision de +/-4 tr/min)... pas top la précision...

Avec pulseIn(), aux alentours de 80tr/min, tu auras une précision (théorique) de +/- 0,0001 tr/min et une actualisation à peu près toutes les secondes.

Tu dois aller te renseigner sur cette fonction pulseIn(), car tu n'as pas du tout compris comment elle marche. Ca renvoit une valeur numérique, pas un boolean!

http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.PulseIn

De plus, je t'ai donné une formule que je ne vois pas dans ton code, as-tu compris ce que j'ai raconté à propos de fréquence / période?

Salut Super_Cinci, effectivement, j'avais mis de coté le fait que ça renvoi une valeur :cold_sweat:, je vais allez me renseignez plus en détail.

Pour la seconde partie, la formule que tu m'a donné, je ne l'ai pas utilisé dans le code parce que j'ai besoin pour certain truc de les voir fonctionner a "nu" pour comprendre comment ça fonctionne.

Bon, j'y arrive pas..
Ou du moins j'arrive pas a comprendre comment la fonction pulseIn pourrais m'aider...
Si j'ai bien compris elle mesure la durée d'une impulsion sur une broche de l'arduino ?

Mais deux choses :

La première, en quoi la durée de l'impulsion m'intéresse quand je doit mesuré l'écart entre deux des impulsions ?

La seconde, toujours si j'ai bien compris, la fonction calcul combien de temps la broche est en HIGH ou LOW, pour renvoyer une valeur de temps, hors, quand ma LDR reçois de la lumière, elle renvois une valeur de courant je croit (de 0 à 5V selon la resistance ?) donc comment lui faire calculer ça a ma fonction pulseIn ?

Ton capteur est à 0V au repos, et sort 5V à chaque passage de la pale puis se remet à l'état bas, ta fonction pulsIn() compte le temps entre chaque état haut.
Mais cette fonction me semble peu appropriée pour ça, car tu dois comptabiliser état Haut et état Bas pour avoir la valeur d'un tour.

Utilise plutôt une interruption conjointement avec la fonction millis().

Attention, la fonction millis() doit être utilisée en dehors de l'interrution

http://playground.arduino.cc/Main/ReadingRPM

Cette librairie devrait faire l'affaire: http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/

Jean-François:
Ton capteur est à 0V au repos, est sort 5V à chaque passage de la pale et se remet à l'état bas, ta fonction pulsIn() compte le temps entre chaque état haut.
Mais cette fonction me semble peu appropriée pour ça, car tu dois comptabiliser état Haut et état Bas pour avoir la valeur d'un tour.

Utilise plutôt une interruption conjointement avec la fonction millis().

Attention, la fonction millis() doit être utilisée en dehors de l'interrution

Arduino Playground - HomePage

Ca m'a l'air plus efficace du coup, a chaque interruption on compte +1 :smiley:
Je vais regarder plutôt de ce coté là :slight_smile:

Ca avance pas mal avec les interruptions :smiley:

J'arrive a compter et a ne rater aucune détection en faible luminosité, mais j'ai plusieurs choses que je ne comprend pas...

Arriver a 20 ou 30 je veut qu'une led s'allume et clignote, hors quand j'arrive a 20, la led clignote mais me bloque le comptage et le programme, je suis obligé de fermer la fenêtre serial et de la ré-ouvrir...

Ensuite, y a t'il un moyen de régler le seuil a partir duquel je passe de LOW a HIGH ? Histoire de pouvoir faire face a plusieurs situation lumineuse ?

int capteur = 2;
volatile int state = LOW; // déclartion d'une variable volatile
int R = 3;
int B = 5;
int V = 4;
int rpm = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(R, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(V, OUTPUT);
  attachInterrupt(0, compt, RISING); // attache l'interruption externe n°0 à la fonction compt()
}

void loop()
{
  state = digitalRead(capteur);
  digitalWrite(R, state); // la LED reflète l'état de la variable
  while(rpm == 20)
  {
    digitalWrite(B, HIGH);
    delay(100);
    digitalWrite(B, LOW);
   delay(200);

  }
  
  while(rpm == 30)
  {
    digitalWrite(V, HIGH);
    delay(100);
    digitalWrite(V, LOW);
    delay(200);
  }
}

void compt() // la fonction appelée par l'interruption externe n°0
{
  if(state == LOW)
  {
    rpm++;
    Serial.println(rpm); 
  }
}

Après ça il ne me manque qu'à écrire la formule pour me convertir ça en T/min et je fait les tests sur mon ventilo :smiley:

Bonjour,
Supprime tes delay pour faire clignoter tes leds.
Fait une recherche sur le site Arduino avec "blinking with out delay"
Voila déjà une des réponses : http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Bonsoir, effectivement ça résout le problème en partie, parce que de temps à autre le programme reste bloquer sur le blinkage de la led :cold_sweat:

Autrement, pourriez-vous m'aidez a comprendre ça (J'ai commenter directement le code) :

volatile byte half_revolutions; // Pourquoi volatile byte ?
unsigned int rpm; 
unsigned long timeold;

void setup()
 {
   Serial.begin(9600); // Communication serie
   attachInterrupt(0, rpm_fun, RISING); // interruption
   half_revolutions = 0;             // 
   rpm = 0;                          // Déclarer toutes les valeurs a 0 ??
   timeold = 0;                    //
 }
 void loop()
 {
   if (half_revolutions >= 20) // 
{   //
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(millis() - timeold)*half_revolutions;     // Je ne comprend pas cette ligne
     timeold = millis();     // Ni elle du coup
     half_revolutions = 0;     // Valeur mise a jour par l'interruption ?
     Serial.println(rpm,DEC);
   }
 }
 void rpm_fun()
 {
   half_revolutions++; 
   //Each rotation, this interrupt function is run twice // Pourquoi half_revolutions ?
 }

Merci a vous :slight_smile:

Bizounours:

volatile byte half_revolutions; // Pourquoi volatile byte ? volatile parce que la valeur est modifiée par l'interruption

unsigned int rpm;
unsigned long timeold;

void setup()
{
  Serial.begin(9600); // Communication serie
  attachInterrupt(0, rpm_fun, RISING); // interruption
  half_revolutions = 0;             //
  rpm = 0;                          // Déclarer toutes les valeurs a 0 ??
  timeold = 0;                    //  devrait être initialisée avec millis() sinon la première mesure est fausse
}
void loop()
{
  if (half_revolutions >= 20) //
{   //
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    // conversion de 2 impulsion par tour en tours par minute
    // on calcul le temps écoulé depuis la dernière mesure millis() - timeold puis on converti en tours/min
    rpm = 30*1000/(millis() - timeold)*half_revolutions;     // Je ne comprend pas cette ligne,
    timeold = millis();     // Ni elle du coup. on mémorise le temps où on a effectué du dernier calcul
    half_revolutions = 0;     // Valeur mise a jour par l'interruption ? on remet le compteur à zéro
    Serial.println(rpm,DEC);
  }
}
void rpm_fun()
{
  half_revolutions++;
  //Each rotation, this interrupt function is run twice
  // Pourquoi half_revolutions ? parce que l'interruption pète 2 fois par tour c'est écrit la ligne au-dessus
}




Le programme semble écrit pour un capteur qui génère 2 impulsions par tour.

volatil permet d'interdire au compilateur de faire des optimisations sur la variable en question. En particulier elle est relue à chaque fois qu'on l'utilise dans un calcul.

Merci de ta réponse, effectivement, la personne test un ventilateur visiblement :grin:
http://playground.arduino.cc/Main/ReadingRPM

en faite, je vient de percuté que millis permettais de connaitre une valeur de temps, je faisais l'amalgame avec delay :cold_sweat:

Bon ça peut paraître con, mais ça reste abstrait pour moi cette formule :

     rpm = 30*1000/(millis() - timeold)*half_revolutions;
     timeold = millis();
     half_revolutions = 0;
     Serial.println(rpm,DEC);

Pour le rpm, ça reviendrais au même de faire 30000(au lieu de 30*1000)/(millis() - timeold)*half_revolutions; ?

Idem, si j'ai qu'une impulsion je peut faire : ?

     rpm = 60000/(millis() - timeold)*revolutions;
     timeold = millis();
     revolutions = 0;
     Serial.println(rpm,DEC);

Bref, si vous avez un exemple concret parce que là j'avoue que j'y pige pas grand chose, je vois globalement, mais je n'arrive pas a le comprendre :sweat_smile:

Pour le rpm, ça reviendrais au même de faire 30000(au lieu de 30*1000)/(millis() - timeold)*half_revolutions; ?

Oui c'est juste pour la clarté de la chose. le 1000 c'est pour indiquer que l'on manipule des millisecondes .
Pour une impulsion par tour il faut effectivement mettre 60.

Un exemple:

     rpm = 60000/(millis() - timeold)*revolutions;

si révolution = 1
si (millis() - timeold) = 1000 1000 millisecondes = 1s

rpm = 60000/1000 = 60 tour/min