Go Down

Topic: [SOLUCIONADO] Incoherencia al leer pulsos para ver las RPM (Read 616 times) previous topic - next topic

frmotors

Hola.
En su momento me hice un generador de sañal para simular un motor a injeccion, una vez acabado quiero visualizar las rpm desde otro arduino.
asi que empece usando una salida digital del "master" y mandado un pulso cada vuelta al "Slave" que esta conectado a una pantalla.
funciona relativamente bien pero un poco inestables las rpm, me puse a buscar y vi varias opciones que usan las interrupciones asi que aplique el codigo a mi situacion.
Desde ese momento las rpm son estables pero hay una cosa que no funciona bien ni con la opcion digital ni con la Iqr.

Las RPM que visualizo no son exactas pero eso puede ser por algun delay que puedo ver a posterior, voy subiendo rpm y cuando paso de 2880rpm que son 124108us baja a 2460rpm visualizando 145900us y asi sucesivamente a 4100 5400 etc... el calculo es correcto de las rpm falla los micros() (creo)
He verificado con un osciloscopio y la señál del puso es correcta y si conecto una adquisicion de datos a la salida las rpm son correctas y sin este salto.
Por lo que se aprecia es como si cada vez va acortando el tiempo hasta que hace el salto en ese momento las rpm son exactas.
¿Alguna idea?
Muchas gracias.

Code: [Select]




#include <openGLCD.h>  //Cargamos la libreria para la pantalla 128x64 GLCD.

volatile byte rpmcount = 0;   //Variable para la interrupcion.
unsigned int rpm = 0;         //Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.
unsigned long timeactual = 0; //Variable time long ya que trabajamos en microsegundos y nos movemos por encima de los 100.000 en algunos casos.
unsigned long timeold = 0;    // Misma situacion timeactual.
unsigned long timenew = 0;    // Misma situacion anterior.



void setup()
{

  attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.


  GLCD.Init();  //inicializamos la pantalla
  GLCD.ClearScreen(); //limpiamos la pantalla
  GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente
}

void rpm_fun()
{
  rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
}




void loop()
{


  if (rpmcount == 6) {  //cuando tenemos cinco pulsos
    timeactual = micros();   //asignamos a la variable timeactual los microsegundos actuales.

    detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM


    timenew = (timeactual - timeold); //despejamos el tiempo que se a necesitado para tener los 5 pulsos.
   
  delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
               // y a altas rpm casi no se pueden ver.
    rpm = (((6 * 1000000) / (timenew)) * 60); //hacemos el calculo de las RPM




    GLCD.ClearScreen(); // limpiamos la pantalla
    GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
    GLCD.print(rpm);      // imprimimos el valor rpm en pantalla
   
    GLCD.CursorToXY(0, 15);// seleccionamos una segunda posicion en patalla
    GLCD.print(timenew); // imprimios los micros() que se han tardado los 5 pulsos

  attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion 

    rpmcount = 0;    // ponemos a cero el contador
    timeold = micros(); // asignamos el tiempo actual.

  }
}






surbyte

Te recomiendo que leas las Normas del foro y luego apliques como se deben postear los códigos. No como adjuntos sino pegados usando tag para cada cosa. En este caso tag de códigos </> este es un ícono, no algo que tienes que poner antes de tu código, te lo comento porque ya alguien hizo eso.


Cuando lo hagas responderé.

frmotors

Lo siento, si que lei las normas pero me equivoque al poner el codigo.
Gracias.

surbyte

A ver si estos pequeños y sutiles cambios mejoran.
Si no ocurre, te propongo un cambio radical de la rutina de medición.
Pruébala y nos comanteas!!
Code: [Select]

#include <openGLCD.h>  //Cargamos la libreria para la pantalla 128x64 GLCD.

volatile byte rpmcount = 0;   // Variable para la interrupcion.
unsigned int rpm = 0;         // Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.
unsigned long timeactual = 0; // Variable time long ya que trabajamos en microsegundos y nos movemos por encima de los 100.000 en algunos casos.
unsigned long timeold = 0;    // Misma situacion timeactual.
unsigned long timenew = 0;    // Misma situacion anterior.
volatile bool flag = false;


void setup() {

  attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.


  GLCD.Init();  //inicializamos la pantalla
  GLCD.ClearScreen(); //limpiamos la pantalla
  GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente 
}

void rpm_fun() {
  rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
  if (rpmcount >= 6) {
     timeactual = micros();
     flag = true;
  }
}

void loop() {


  if (flag) {  //cuando tenemos seis pulsos 
         //asignamos a la variable timeactual los microsegundos actuales.
      detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM
      timenew = (timeactual - timeold); //despejamos el tiempo que se a necesitado para tener los 5 pulsos.
   
      delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
               // y a altas rpm casi no se pueden ver.
      rpm = 100000 / timenew; //hacemos el calculo de las RPM

      GLCD.ClearScreen(); // limpiamos la pantalla
      GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
      GLCD.print(rpm);      // imprimimos el valor rpm en pantalla
    
      GLCD.CursorToXY(0, 15);// seleccionamos una segunda posicion en patalla
      GLCD.print(timenew); // imprimios los micros() que se han tardado los 5 pulsos
      flag = false;
      rpmcount = 0;    // ponemos a cero el contador
      attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion  
      timeold = micros(); // asignamos el tiempo actual.
  }
}



frmotors

Hola de nuevo.
Gracias por responder tan rapido.
He probado el codigo y no se veian las rpm al verificarlo he visto que has modificado la formula de calculo, al ponerla como al principio se visualizan pero el problema sigue igual no he apreciado diferencias.
Depende del numero de pulsos el salto se produce mas o menos veces.
De momento no se me ocurre nada he probado muchas combinaciones y siempre pasa, de la unica forma que casi no se aprecia es poner un numero muy alto de pulsos ej. 100 pero en este caso el sistema es inutilizable por el tiempo que necesita para ver las RPM.
Muchas gracias.

surbyte

Ahhh tienes razón. TU problema ocurre que estas midiendo mal.
6 pulsos tienen un error tremendo. Deberían ser 60 pulsos para bajar ese error/10

Prueba con un delay de 1000 mseg y con 60 pulsos
agrega si sigues usando mi código volatile a la definición de timeactual que lo olvidé.


frmotors

necesito que se vean rapido por eso no puedo poner un numero alto de pulsos.
En un principo asignaba un tiempo determinado y leia cuantos pulsos lee en ese tiempo pero la resolucion es muy baja RPM max 13000 = 216hz pero a 2000rpm seria 33,3hz los decimales no sirven asi que un pulso son muchas rpm.

Lo curioso del tema es que es un problema recurrente siempre en el mismo sitio y siempre hace lo mismo no es falta de precision es como si cuando se llega a un valor de microsegundos salta unos pocos,
Podria aumentar el numero de pulsos por giro pero ya no me serviria para el uso que quiero darle.

He hecho una crokis de lo que ocurre.
            subo a 3600rpm=97000us cae a 2940rpm=120000us
sigo subiendo   4200rpm=85900us  cae a 3500rpm=102000us
                     5400rpm=66700us  cae a 4400rpm=80000us
                     6000rpm=60000us  cae a 5000rpm=71800us.

Cada vez que cae cuando subo paso otra vez por el numeor de rpm donde habia caido antes.
Es un poco extraño si fuera por la precision de los pulsos seria inestable +-500 o 700 rpm pero aqui si dejo la frecuencia fija las rpm estan estables.
Gracias.


noter

#7
Jun 05, 2016, 11:07 pm Last Edit: Jun 05, 2016, 11:08 pm by noter
¿Y por qué no utilizas directamente el método de Nick Gammon? Creo que es bastante más preciso, y además mide más rápido pues creo que medía el periodo entre dos pulsaciones.

surbyte

#8
Jun 06, 2016, 12:06 am Last Edit: Jun 06, 2016, 12:08 am by surbyte
Primero te recomiendo leas este artículo Computo de incertezas en la medición de contadores

Basicamente dice que para frecuencias bajas debes medir el período y no la frecuencia como esas haciendo.
Asi que midamos el período.

Si quieres medir señales de tan baja frecuencia debes tener una compuerta o GATE por un lapso de tiempo que asegure una lectura precisa. Tu GATE de 100 mseg no es preciso, no asegura una buena lectura.
Asi que si medimos el tiempo entre transiciones de la interrupción tendremos una lectura muy buena y estable.

Ya te sugeríré algo que te sirva.

frmotors

Parece que lo he solucionado, he probado la opcion de Nick Gammon y no funciona, sucede lo mismo o mas.
asi que pensando en el cometario de surbyte he hecho unas modificaciones usando la logica, al final he tenido que poner un correctivo para que el valor sea exacto +- 10rpm.


Code: [Select]


#include <openGLCD.h>  //Cargamos la libreria para la pantalla 128x64 GLCD.

volatile byte rpmcount = 0;   // Variable para la interrupcion.
unsigned int rpm = 0;         // Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.

unsigned long tiempo_1=0;     // Variables para cada pulso
unsigned long tiempo_2=0;
unsigned long tiempo_3=0;
unsigned long tiempo_4=0;
unsigned long tiempo_5=0;
unsigned long tiempo_6=0;
unsigned long tiempo_7=0;
unsigned long tiempo_total=0;


volatile bool flag = false;


void setup() {

  attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.


  GLCD.Init();  //inicializamos la pantalla
  GLCD.ClearScreen(); //limpiamos la pantalla
  GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente
}

void rpm_fun() {
 tiempo_7=tiempo_6;  //creamo una operacion que cada vez que entra asigna el tiempo al tiempo anterior y asi tenemos los 7 tiempos para hacer las 6 lecturas
 tiempo_6=tiempo_5;
 tiempo_5=tiempo_4;
 tiempo_4=tiempo_3;
 tiempo_3=tiempo_2;
 tiempo_2=tiempo_1;
 tiempo_1=micros();
  rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
 
 if (rpmcount >= 8) //si queremos el tiempo de 6 dientes necesitamos 7 tiempos y al octavo salta, ahora calcular el tiempo en cada pulso.
 {
   tiempo_total= ((tiempo_6-tiempo_7) + (tiempo_5 - tiempo_6) + (tiempo_4 - tiempo_5) + (tiempo_3 - tiempo_4)+(tiempo_2 - tiempo_3)+(tiempo_1 - tiempo_2))*1.006;// calculamos el tiempo total de 6 pulsos + un correctivo
     flag = true;
  }
}

void loop() {


  if (flag) {  //cuando tenemos seis pulsos
         
      detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM
     
      delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
               // y a altas rpm casi no se pueden ver.
      rpm = (((6000000) / (tiempo_total))*60); //hacemos el calculo de las RPM

      GLCD.ClearScreen(); // limpiamos la pantalla
      GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
      GLCD.print(rpm);      // imprimimos el valor rpm en pantalla
      GLCD.CursorToXY(0, 14);
      GLCD.print(tiempo_total);
      flag = false;
      rpmcount = 0;  // ponemos a cero el contador
      attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion 
      
 tiempo_1=0;    //Ponemos todas la variables a 0
 tiempo_2=0;
 tiempo_3=0;
 tiempo_4=0;
 tiempo_5=0;
 tiempo_6=0;
 tiempo_7=0;
 tiempo_total=0;
 
  }
}


surbyte

Nick Gammon no funciona? Por favor.. algo haces mal.
En fin si alcanzaste un resultado satisfactorio bien pero puede mejorarse.
Hubo mucho trabajo este fin de semana y no pudo buscarte la respuesta mas apropiada. Debía probarla y simularla y eso lleva tiempo.

Si esta SOLUCIONADO agregale eso al título.

frmotors

Primer muchas gracias.

Creo que me he expresado mal, si que funciona pero hace lo mismo podria decir que hace un diente de sierra poco mas o menos como los otros programas, supongo que seria adaptarlo.
Con la opcion ultima es coherente rapido y preciso lo he verificado con el osciloscopio y ocn la adquisicion de datos al maximo hay 10 rpm de error que sera un chorrada ya que si hago el calculo con la calculadora me da exacto.

Si teneis un momento y podeis hecharle un vistazo, seguro que habar mas de una "cosa ilogica" yo me quede con el clipper en msdos y estoy muy oxidado.

Un Saludo.

Go Up