Retroazione tachimetrica

Ciao a tutti!
Ho un problema con un circuito di retroazione: ho un motore di una lavatrice e vorrei sfruttarne la tachimetrica per un controllo PID, ma il circuito che sto usando non sembra funzionare correttamente. Avrei bisogno, molto semplicemente, di un circuito che, ad ogni rotazione del motore (che corrispondono ad 8 impulsi della tachimetrica), mi dia altrettanti impulsi a 5VDC. La velocità massima del motore è intorno ai 14000 RPM.
La tachimetrica alla massima velocità del motore restituisce 24VAC, mentre l’ingresso del MCU (Arduino, in questo caso) accetta solo 5VDC.
Il circuito che ho provato ad utilizzare funziona fino a 3000RPM (ovvero 24000 impulsi al secondo della tachimetrica), ma oltre non funziona nulla, il valore di RPM è 0.

Posto anche il codice, nella speranza che qualcuno possa aiutarmi:

volatile byte rpmcount;
unsigned int rpm;
unsigned long timeold;


#include <LiquidCrystal.h>

LiquidCrystal lcd(12,11,10,9,8,7);

void rpm_fun()
 {
   
  
      rpmcount++;
 }

void setup()
 {
   lcd.begin(16, 2);  // intialise the LCD

   
   attachInterrupt(0, rpm_fun, RISING);

   

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   
   delay(10);
   
   detachInterrupt(0);
  
   //metto 7.5 al posto di 60 perchè ho 8 impulsi per ogni rotazione
   rpm = 7.5*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;

   
   lcd.clear();
   lcd.print("RPM=");
   lcd.print(rpm);

   
   attachInterrupt(0, rpm_fun, FALLING);
}

Grazie in anticipo.

P.S: ho uilizzato un BC547 al posto del transistor dello schema, ma la frequenza massima è comunque molto più elevata di quella di cui necessito (2KHz nel mio caso).

3000 RPM con 8 impulsi per rotazione secondo le mie modeste conoscenze sono 400Hz.

Che tipo di motore é che gira a 14000 RPM?

Ciao Uwe

ovvero… RPM sono “revolutions per minute:slight_smile:
giri al minuto!

Stefano

E' un motore universale con eccitazione in serie. La dinamo tachimetrica a 8 poli consiste in un magnete attaccate in asse al motore che induce una tensione in una bobina. Ho provato a togliere la bobina che può essere svitata e a misurare i giri al minuto utilizzando un sensore HALL. In entrambi i casi ho ottenuto una lettura dei giri abbastanza buona, ovviamente migliore nel secondo caso, ma il mio software, al di sopra dei 3700 giri al minuto, non leggeva più. Il mio problema riguarda proprio il software: che sia il comando lcd.print() a rallentare il processo? Cosa posso fare per avere un range di lettura da 0 a 14000 g/min.? Per uwefed: lo so, ma a 14000 g/min siamo comunque a 1866 Hz.

Ciao, 3700 rpm corrisponde ad un impulso ogni 2 mS -> 1/(3700/60*8 ). La funzione millis() legge fino al millisecondo quindi sei al limite della risoluzione: con micros() dovresti risolvere.

Ho provato con micros(), ma con entrambi i sensori ho letture assolutamente errate (ancora uguali a zero delle volte)

volatile byte rpmcount;
unsigned long rpm;
unsigned long timeold;
 #include <LiquidCrystal.h>

LiquidCrystal lcd(12,11,10,9,8,7);

void rpm_fun()
 {
   
  
      rpmcount++;
 }

void setup()
 {
   lcd.begin(16, 2);  // intialise the LCD

   
   attachInterrupt(0, rpm_fun, RISING);

   

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   
   delay(100);
   
   detachInterrupt(0);
  
   //metto 7.5*1000 al posto di 60 perchè ho 8 impulsi per ogni rotazione
   rpm = 7500*1000/(micros() - timeold)*rpmcount;
   timeold = micros();
   rpmcount = 0;

   
   lcd.clear();
   lcd.print("RPM=");
   lcd.print(rpm);

   
   attachInterrupt(0, rpm_fun, FALLING);
}

rpmcount non dovrebbe essere un unsigned long? Un byte è poco....

ciao

tra l'altro... tutte quelle operazioni con il display (che sono molto lente) le fai quando hai l'interrupt "staccato".

Penso che anche li perdi parecchi impulsi.

io sposterei così:

void loop()
 {
   
   delay(100);
   
   detachInterrupt(0);

   //metto 7.5*1000 al posto di 60 perchè ho 8 impulsi per ogni rotazione
   rpm = 7500*1000/(micros() - timeold)*rpmcount;
   timeold = micros();
   rpmcount = 0;

   attachInterrupt(0, rpm_fun, FALLING);
   lcd.clear();
   lcd.print("RPM=");
   lcd.print(rpm);

}

ciao pippo72

Ho provato in quel modo ma non funziona…
Ieri ero riuscito a farlo funzionare con questo codice, ma ho per sbaglio scritto qualcosa in più e ora non funziona.

Nessun’altro ha già provato a fare qualcosa di simile?

#include <LiquidCrystal.h>

LiquidCrystal lcd (12,11,10,9,8,7);

unsigned long contarpm=0;
unsigned long tempoInizio=0;
unsigned long totrpm=0;

void setup() 
{
  lcd.begin(16,2);
  attachInterrupt(0,rpm,RISING);
  lcd.setCursor(0,0);
  lcd.print("PRONTO");
  delay(1000);
  lcd.clear();
}

void loop() 
{
    attachInterrupt(0,rpm,RISING);
    if(millis()-tempoInizio>=1000)
    {
      totrpm=contarpm*60;
      tempoInizio=millis();
      contarpm=0;
   }
   detachInterrupt(0);
   lcd.clear();
   lcd.print(totrpm/8); //ho 8 impulsi
   delay(500);
   
}

void rpm()
{
  contarpm++;
}

ciao

guardando il tuo ultimo sketch allegato hai utilizzato millis per calcolare il tempo di aggiornamento della velocità (e questo è bene) però hai fatto anche un po di confusione:

dichiarazioni e setup direi che vanno bene.

Nel loop secondo me c'e un po' ti confusione; tutti i vari "attaccamenti" e "staccamenti" dell'interrupts vanno fatti solo nel momento che devi calcolare la velocità quindi vanno messi all'interno dell'IF. Quindi io all'interno dell'IF farei questo:

  • stacco l'interrupts
  • calcolo la velocità
  • riallineo tempoinizio con millis
  • riattacco l'interrupst
  • aggiorno il display

per come la hai scritta tu nel loop l'interrupts è praticamente sempre staccato. l'ultimo delay non serve.

ciao pippo72

Alcune considerazioni: contarpm deve essere di tipo volatile. L'interrupt non lo devi mai staccare, al massimo riazzeri la variabile e ogni mezzo secondo fai il calcolo. Il delay non loop non serve. Se non vuoi far sfarfallare il display cancella solo la parte necessaria e non tutto. La divisione per 8 ti conviene farla in una unica operazione quando calcoli totrpm e non ogni volta che scrivi nel display.

Ciao Paolo P!
Non credo di aver capito cosa intendi: non potresti farmelo vedere?