Pages: [1] 2 3   Go Down
Author Topic: Contagiri con LED - riduzione dell'errore con pulseIn  (Read 1768 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ciao a tutti, sono nuovo nel forum ed ho iniziato ad usare Arduino da poco, tuttavia sono a corto di tempo e necessiterei di qualche delucidazione.
Ho fatto una ricerca tra i vari contagiri RPM ma non riesco a trovare una risposta all'idea del software adeguata.
Tanto per iniziare, ho realizzato il seguente circuito: http://mckgyver.pbworks.com/w/page/20654133/Arduino_Tachometer
l'ho testato con il codice presente sotto e funziona, tuttavia non riesce a mantenere un numero costante di giri, ma ha un errore abbastanza alto( a 2500 giri, varia +/- di circa 100 giri).
Invece di contare il numero di impulsi in un certo intervallo, ritengo sia più preciso misurare il tempo trascorso tra due impulsi, ed ho provato ad utilizzare il pulseIn.
Inserendo il seguente sketch e testando con un fan F6015B12LY (9 pale, max 3000 giri/min), la durata tra un segnale ad un'altro è assurda (+1000000 us suppongo); inoltre non riesce a leggere i giri/min.
Lo sketch è il seguente, cos'è che sto sbagliando?
è sensato inoltre dire che contando gli la durata tra due impulsi, la misura dovrebbe essere più precisa?

Code:

//Pulsein code for rpm counting

//Define Variables
const float pi = 3.14;
unsigned long holes__angle = pi/2;
unsigned long duration;  //
unsigned long rad_sec;  //
unsigned long rpm;  //
unsigned long timeout = 10000000;  //
int ledPin = 2;             // LED connected to digital pin (changes state with each tic of code wheel)
int statusPin = 13;             // LED connected to digital pin (changes state with each tic of code wheel)

void setup()
 {
   Serial.begin(115200);
   Serial.println("CLEARDATA"); //clean excel spreadsheet
   Serial.println("LABEL,Time,Duration,RPM"); //clean excel spreadsheet
   pinMode(statusPin, OUTPUT); //
   pinMode(ledPin, INPUT); //
}
 void loop()
 {
   duration=pulseIn(ledPin,HIGH,timeout);
   rad_sec=(holes__angle*1000000)/duration;
   rpm=(rad_sec*60)/(2*pi);
   Serial.print("DATA,TIME,");Serial.print(duration);Serial.println(rpm);
    }

Logged

Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://forum.arduino.cc/index.php?topic=157511.0
Ciao
Io permetto di suggerirti di dare un'occhiata a questo mio topic
Ho sbattuto un bel po il muso pure io su pulse in senza ricavarne nullA di buono sostanzialmente
Se vai al penultimo post della prima pagina trovi il codice che ho fatto per avere rpm con interrupt
Non blocca il codice come pulsein ed e molto preciso in quanto riesco senza problemi a governare l, accensione di un motore a benzina
Spero possa esserti di aiuto
EDIT
Una cosa che ho imparato nei miei mesi di prove e che spesso la lettura imprecisa non arriva dal sensore ma da quello che fai con la lettura
Se fai operazioni con numeri interi ogni volta ti taglia via i decimali e a ogni passaggio perdi in precisione
« Last Edit: August 28, 2013, 08:11:44 am by lucaleo » Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 313
Posts: 21657
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Concordo con lucaleo sia sulla lentezza ed imprecisione dei calcoli con i float sia sull'uso degli interrupt al posto della pulseIn.
Logged


Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Concordo con lucaleo sia sulla lentezza ed imprecisione dei calcoli con i float sia sull'uso degli interrupt al posto della pulseIn.

questa la incornicio ahaha
è la prima volta che su due cose che scrivo non c'è manco una cagata smiley-grin

in ogni caso crix87 ho guardato un po' il tuo codice e onestamente non capisco bene come funziona (o meglio quello che mi pare di aver capito non può andare)

pulsein ti restituisce il tempo trascorso (in millisecondi? non ricordo, ma attenzione perchè non è detto che sia quello che pensi di usare) durante HIGH o LOW a seconda delle tue preferenze
tuttavia tu devi GIA SAPERE a quanti gradi corrisponde quel segnale sulla rotazione totale (puoi calcolarla sommando la durata di high e low se hai un solo dente a un regime stabile di giri o moltiplicando la somma per il numero di high e low dentro a un giro a seconda di quante pale, denti eccetera tu abbia)

il motivo è molto semplice, vedrai che a parità di dente se tu allontani o avvicini il sensore  al centro della rotazione la velocità angolare sarà sempre uguale, ma quella lineare cambia e quindi cambia anche l'ampiezza in gradi di un dente di esempio 3 millimetri di dente a 3 cm da centro o a 1 cm dal centro non sono per niente la stessa cosa

una volta che hai il sensore posizionato e lo hai calibrato allora da li non avrai grossi problemi, solo non fare un hardware ballerino perchè butti via ore e ore a caso (te lo garantisco  smiley-razz)

spero di non aver scritto tutto ciò inutilmente e che ti sia di aiuto ahaha

EDIT
ultima info per rendere tutto più comprensibile
non farti ingannare dal fatto che stai misurando una ventola

poniamo caso che hai 6 pale

un conto è guardare quando ci metti a leggere 6 pale e dividere un minuto per quel tempo ottenendo rpm (che va bene)

un conto è misurare quando dura una pala
di istinto viene da pensare 6 pale, 6 spazi quindi 6 pale 180° e 6 spazi 180° quindi ogni pala e ogni spazio valgono 30°
ma non è detto che sia così!!
6 pale e 6 spazi potrebbero anche essere 240° le pale e 120° gli spazi (a seconda di come è fatta la ventola) quindi ogni pala misurerebbe 40° e ogni spazio 20°

per questo per sfruttare la durata della pala o dello spazio è FONDAMENTALE sapere a quanti gradi corrisponde quella pala o quello spazio a quella DETERMINATA distanza dal centro della rotazione
« Last Edit: August 28, 2013, 09:02:57 am by lucaleo » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cari Lucaleo e Leo72, vi ringrazio per le risposte.
Lucaleo, in realtà probabilmente la mia situazione è più semplice, perchè devo testare delle turbine eoliche, il sensore misurerà la rotazione di un volano su cui andrò ad eseguire 4 fori (credo bastino, che ne dite), quindi spaziati di 90° (pi/2 radianti).
Ho capito la questione sulla distanza dal centro, ma non ho capito se si applichi al mio caso, in quanto io misurerei solo velocità angolari, non lineari, o mi sbaglio?
Adesso provo ad implementare il codice che mi hai suggerito, sperando che le cose migliorino! smiley-cool
Logged

Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

tutto dipende da come affronti il problema
se tu "conti i buchi" non ti interessa nulla di quello che ho scritto sul calcolo dei gradi
se tu conti "quanto dura un buco" devi per forza mettere questo dato in relazione a quanto dura un giro e per "indovinare" quanto dura il giro devi per forza sapere a quanti gradi su 360 corrisponde il buco
se misuri gli spazi senza buco moltiplicando per 4 avrai una misura molto vicina alla realtà ma ti mancheranno sempre i micros dei buchi che non puoi stimare se non sai quanti gradi sono smiley-grin

nel tuo caso potresti anche ottenere un buon risultato tramite gli interrupt (se usi pulsein blocchi tutto in continuazione) misurando sia la durata di un buco che la durata dello spazio senza, sommare i valori e moltiplicare per 4 e ottenere il tempo di un giro senza sapere a quanti gradi corrisponde il buco e lo spazio

oppure ancora più preciso fai un contatore, poi prendi i valori di ogni buco che passa e ogni spazio vuoto fino a quando non sono passati 4 buchi e 4 spazi, sommi tutto e hai il tempo esatto di ogni giro

io sul motore non posso usare questi metodi perchè devo sapere quanti giri sto facendo e in che posizione sono del giro prima di un certo momento, ma tu non hai questo limite credo
« Last Edit: August 28, 2013, 10:09:30 am by lucaleo » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mi consola il fatto che il codice dovrebbe essere più semplice di quello ce hai postato nell'altro topic  smiley

Quindi, per misurare i giri, posso ripartire da qui:
http://mckgyver.pbworks.com/w/page/20654133/Arduino_Tachometer
Tuttavia, invece di far aumentare i giri, come faccio a calcolare il tempo tra gli interrupt? uso sempre la libreria stopwatch o ci sono funzioni più semplici?
Logged

Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

guarda stopwatch l'ho usata perchè sono scarso e non riesco a usare la funzione millis o micros che sia  smiley-roll-sweat

tuttavia prendo spunto dal codice che hai postato e provo a modificarlo per quello che serve a te

magari imparo qualcosa su millis intanto smiley-grin

Code:
 //Arduino Code
  
  /*
  
   * Tachometer
  
   *
  
   * M.G.McKinley
  
   * 6/1/2009
  
   * Adjust
  
   */
  
  //Define Variables
  
  int ticsPerRev = 16;       // define number of tics per rev of code wheel
  
  float rpm = 0.0;  // I prefer float for rpm
  
  volatile int rpmcount =0;  // volitile because the variable is manipulated during the interrupt
  
  unsigned long timeold = 0; // used to calculate d_t= millis()-timeold;
  
  int d_t;
  
  
  
  
  
  void setup()
  
  {
  
    Serial.begin(9600);
  
    //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
  
    //Triggers on FALLING (change from HIGH to LOW)
  
    attachInterrupt(0, rpm_fun, FALLING);
  
  
  
  
  
  }
  
  void loop()
  
  {
  
    //Update RPM every second
  
  
  
    //Don't process interrupts during calculations
  
    detachInterrupt(0);
  
    d_t=millis()-timeold;
  
  
  
    if (d_t >= 1000)
  
    {
  
      rpm = float(60.0*1000.0)/float((d_t))*float(rpmcount)/ticsPerRev;
  
  
  
      timeold = millis();
  
      d_t=0; //reset d_t
  
  
  
      //Serial Port Output
  
  
  
      Serial.println(rpm);
  
  
  
      rpmcount = 0; //reset rpmcount
  
  
  
    }
  
    //Restart the interrupt processing
  
    attachInterrupt(0, rpm_fun, FALLING);
  
  }
  
  void rpm_fun()
  
  {
  
    //This interrupt is run at each codewheel tic
  
    detachInterrupt(0); //im not sure if this is necessary here
  
  
  
    rpmcount++; //update rpmcount
  
  
  
  
  
  
  
    attachInterrupt(0, rpm_fun, FALLING);
  
    }

ho tolto un po' di roba che faceva confusione per capire la dinamica del codice

così DOVREBBE funzionare, non sono per nulla bravo...

prova smiley-grin

ah mi raccomando ricordati di modificare il numero delle pale, per ora sono 16
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

grazie per la revisione, in effetti sembra andare meglio!
Li tolgo i float dal codice? meglio dichiarare le variabili con long?
Logged

Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

mah dipende da quanto può durare la rotazione forse puoi usare pure int visto che usi millis
però non me ne intendo... ho capito qualcosina da poco

in ogni caso quel codice non è pensato per essere molto preciso secondo me, quello imposta un intervallo per il loop di 1 secondo e ogni secondo guarda quanti denti sono passati e con qualche calcolo ti dice i giri

io proverei a far partire un contatore alla prima pala e fermarlo quando inizia la 16esima (con falling quando inizia la pala tu hai l'interrupt), in questo modo avresti il vero tempo di un giro

se ho scritto delle boiate che qualcuno mi corregga smiley-grin
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 313
Posts: 21657
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Millis restituisce un unsigned long, quindi devi usare questo tipo di dato per immagazzinare il valore restituito dalla funzione.
Logged


Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Millis restituisce un unsigned long, quindi devi usare questo tipo di dato per immagazzinare il valore restituito dalla funzione.

possibile che tu mi abbia appena spiegato perchè non sono mai riuscito a usare millis smiley-grin
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Vi allego il codice aggiornato - credo funzioni ma la ventola di prova non è attendibile smiley

Code:
//Arduino Code
/*
* Tachometer
*
* M.G.McKinley
* 6/1/2009
* Adjust
*/
//Define Variables
 
int ticsPerRev = 7;       // define number of tics per rev of code wheel
unsigned long rpm;  //
volatile int rpmcount;  // volitile because the variable is manipulated during the interrupt
unsigned long timeold; // used to calculate d_t= millis()-timeold;
unsigned long d_t;
 
void setup()
{
  Serial.begin(9600);
  Serial.println("CLEARDATA"); //clean excel spreadsheet
  Serial.println("LABEL,Time,RPM"); //clean excel spreadsheet
  attachInterrupt(0, rpm_fun, FALLING);
}
 
void loop()
{
  detachInterrupt(0);
  d_t=micros()-timeold;
  if (d_t >=500000)
   {
     rpm = (60*1000000)/((d_t))*(rpmcount)/ticsPerRev;
     timeold = micros();
     d_t=0; //reset d_t

//Serial Port Output
     Serial.print("DATA,TIME,");Serial.println(rpm);
     rpmcount = 0; //reset rpmcount
  }
     attachInterrupt(0, rpm_fun, FALLING);
}
 
void rpm_fun()
{
    detachInterrupt(0); //im not sure if this is necessary here
    rpmcount++; //update rpmcount
    attachInterrupt(0, rpm_fun, FALLING);
 
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tuttavia come detto non è ancora abbastanza accurato, stavo pensando di spostare l'INPUT dal pin2 al pin8 e utilizzare il timer1 inserito nel codice. tuttavia il timer1 non mi è chiarissimo e non riesco ad utilizzarlo:
1) credete che sia possibile utilizzardo, spostando solo un filo a livello hardware?
2) consigli a livello software? non riesco a trovare degli sketch adeguati per un rpm! smiley-roll-sweat
Logged

Offline Offline
Sr. Member
****
Karma: 4
Posts: 368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ma cosa devi fare?
è più semplice aiutarti se lo sappiamo
e poi sono curioso smiley-wink
Logged

Pages: [1] 2 3   Go Up
Jump to: