Cuenta más o menos pulsos depende de la velocidad de giro

Hola a todos.

Me estoy volviendo loco con un proyecto. se trata de un contador de metros lineales de cinta.

Uso un Arduino UNO, una pantalla lcd,un rodillo unido a una rueda dentada con 20 muescas y un optocoplador.

El problema me da al medir los pulsos, si giro la rueda despacio me da una lectura mayor que si la giro a más velocidad*.

HE leído varios foros y paginas web, y no doy con la solución.

No se si el problema sera la velocidad de lectura del arduino, estoy pensando en cambiarlo por otro, pero tengo miedo que el problema persista.

Este es uno de los sketch que utilizo para leer los pulsos.

volatile int contador = 0;


// La librería para el LCD 16x2 I2C
#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C lcd(0x3F, 16, 2);
void setup() {
  // put your setup code here, to run once:

 attachInterrupt( 1, ServicioBoton, RISING);   
 lcd.begin();


}

void loop() {

lcd.setCursor(0, 0);
        lcd.print (contador);


}

void ServicioBoton()

  
  { contador++ ;
   
  }

Una vez que los pulsos sean estables a cualquier velocidad, lo intentare pasar a centímetros.

Agradecería cualquier pista o posible solución.

Muchísimas gracias de antemano

Hi,
Tratas de hacer un lcd.clear() antes de darle display al counter. Creo que cuando posicionas el curso puede dejar caracteres del display anterior. No se si estoy en lo correcto pero es buno hacee el clear antes de darle display a la variable.

Hola Tauro0221.

Gracias por responder tan pronto!

Tampoco me funcionó. Ademas en otro sketch sacaba el contador por monitor serial y me daba el mismo error

Soy novatillo y autodidacta en esto, me apunto lo de lcd.clear(); de todos modos

Muchas gracias!

Comparándolo con el ejemplo del manual

El código que muestras es susceptible de mejoras.
Tampoco muestras el esquema de la electrónica.

Y esta frase.....

davidrummer:
../..
si giro la rueda despacio me da una lectura mayor que si la giro lentamente.
--/..

Tendrías que revisarla.

Hi,
Otra cosa es si usas un optocoupler tipo interruptor es buena idea de pintar la rueda de negro no brillante.Yo tuve problemas con un projecto y la rueda de diente era de metal con un brillo. Pintandola se fue el problema. Esto no quire decir que tengas el mismo problema pero que lo tengas en consideracion.

jordi3sk97:
Comparándolo con el ejemplo del manual
attachInterrupt() - Arduino Reference

pinMode() - Arduino Reference

El código que muestras es susceptible de mejoras.
Tampoco muestras el esquema de la electrónica.

Y esta frase.....

Tendrías que revisarla.

Hola jordi3sk97

Tienes razón, voy a intentar adaptarlo el ejemplo al proyecto a ver que tal y subir unas fotos del esquema eléctrico.

No me había dado cuenta de la frase jajaja, ahora lo corrijo. Quería decir que si giro la rueda lentamente mide mas pulsos que si la giro mas rápido, algo así como 70 pulsos girándola lenta y 25 girándola rapido.

Muchas gracias por la orientación!

hola Tauro0221!

Pues mira no lo había oído nunca.

mi rueda es de plástico negro, no tiene mucho brillo, pero a ver si puedo probar con otra rueda mas mate a ver que tal.

Muchas gracias por el consejo!

Hi,
Que tipo de interruptor estas usando.

Hola.

estoy usando el fc-03 como este

Adjunto una imagen de la rueda con el opto.

Lo tengo conectado a las salida digital 3 alimento la pantalla lcd y el interruptor desde arduino.

Gracias Tauro

Hola tauro0221 y jordi3sk97.

Creo que esto esta empezando a funcionar gracias a vuestra ayuda. llevaba 2 semanas loco con este tema y al fin parece (al menos de momento) que mide lo mismo independientemente de la velocidad en la que lo haga girar.

dejo aquí el sketch por si le puede ayudar a alguien más.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 16, 2);

const byte interruptPin = 3;
volatile  long contador = 0;
long T0 = 0; // variable anti rebote
int centimetros = 0;


void setup() {
  // pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING);
  lcd.begin();
  Serial.begin(9600);
}

void loop() {
  centimetros = contador / 20 * 6.5; /*(((contador * 0.107 * 3.141592) * (19.01 / 2) / 10));*/

  // lcd.clear();
  lcd.setCursor(5, 0);
  lcd.print (centimetros);




}

void blink() {
  //state = !state;
  //contador++;
  {
    if ( millis() > T0  + 2)   //2 es el tiempo en millis  para evitar rebotes
    { contador++ ;
      T0 = millis();
    }
  }
}

Muchisimas gracias a los dos!!!

Hi,
Yo estaba mirando tu sketch y en el no declaraba el pin del interrupt como input. Otra cosa que noto es que las abertura esta muy grande. Yo las cambiaria por un disco que tenga las abertura mas pequena o un agujero para hacrlo mas facil. Esto te garantiza un pulso mas limpio. Se que ya esta trabajando pero debes de mejorar las aberturas.
Otra cosa que puedes hacer para no tener que usar delays es de ejecutar la instruccion "noInterrupts() " imediatamente que entre en la rutina que lleva la cuenta y cuando regresas imediatamente haces nterrupts() asi no tienes que usar delays.

En el sketch original estabas utilizando una interrupción sobre el pin 1 , pero el Arduino UNO solo tiene interrupción en los pines 2 y 3 , por eso el último sketch te funciona.

Saludos

Buenas Tauro.

Creo que declara la entrada como input en esta linea pinMode(interruptPin, INPUT_PULLUP);.

Lo de las muescas mas pequeñas, lo voy a intentar, porque creo que así también tendría más definición , no? o eso me pareció entender en algún foro.

El "noInterrupts() " iría justo cuando acabara la función de la interrupción, voy a ver si encuentro algún ejemplo.

Gracias otra vez Tauro!

No hace falta declarar una entrada como entrada para que luego trabaje como interrupción.

Entradas son entradas e interrupciones son las que dispone el Arduino en uso tal como dice @PeterKanTropus.

INT0 es pin 2
INT1 es pin 3.

Esta línea puede mejorarse aunque sea correcta, debes simplificar operaciones, porque toda matemática es lenta.

 centimetros = contador / 20 * 6.5;

6.5/20 = 0.325 entonces

 centimetros = contador * 0.325;

hará lo mismo de modo mas rápido.

Bueno, ahora que revisé todo tu código en su contexto me pregunto para que usas interrupciones? No creo que una rueda gire tan rápido como para no leer cambios.
Pero... debes probarlo, asi que te voy a sugerir un código que no usa interrupciones pero si mira los cambios en un pin y lo presenta en el LCD.

Prueba a ver, es el mismo pin okay?

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 16, 2);

const byte ruedaPin = 3;
long contador = 0;
int centimetros = 0;
bool status, statusAnt = false;

void setup() {
  // pinMode(ledPin, OUTPUT);
  pinMode(ruedaPin, INPUT_PULLUP);
  lcd.begin();
  Serial.begin(9600);
}

void loop() {
 
  status = digitalRead(ruedaPin):
 
  if (status && !statusAnt) {
      contador++;  
      centimetros = contador 0.325; 
      // lcd.clear();
      lcd.setCursor(5, 0);
      lcd.print (centimetros);
  }
  statusAnt = status; 
}

PeterKantTropus:
En el sketch original estabas utilizando una interrupción sobre el pin 1 , pero el Arduino UNO solo tiene interrupción en los pines 2 y 3 , por eso el último sketch te funciona.

Saludos

Hola PeterKantTropus.

Pues pensaba que con el 1 se refería al INT3 y con el 0 a INT2 o algo así leí en algunos ejemplos.

el sensor leer lee, pero claro lee mal.

Gracia por la ayuda!

surbyte:
No hace falta declarar una entrada como entrada para que luego trabaje como interrupción.

Entradas son entradas e interrupciones son las que dispone el Arduino en uso tal como dice @PeterKanTropus.

INT0 es pin 2
INT1 es pin 3.

Esta línea puede mejorarse aunque sea correcta, debes simplificar operaciones, porque toda matemática es lenta.

 centimetros = contador / 20 * 6.5;

6.5/20 = 0.325 entonces

 centimetros = contador * 0.325;

hará lo mismo de modo mas rápido.

Bueno, ahora que revisé todo tu código en su contexto me pregunto para que usas interrupciones? No creo que una rueda gire tan rápido como para no leer cambios.
Pero... debes probarlo, asi que te voy a sugerir un código que no usa interrupciones pero si mira los cambios en un pin y lo presenta en el LCD.

Prueba a ver, es el mismo pin okay?

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);

const byte ruedaPin = 3;
long contador = 0;
int centimetros = 0;
bool status, statusAnt = false;

void setup() {
  // pinMode(ledPin, OUTPUT);
  pinMode(ruedaPin, INPUT_PULLUP);
  lcd.begin();
  Serial.begin(9600);
}

void loop() {

status = digitalRead(ruedaPin):

if (status && !statusAnt) {
      contador++; 
      centimetros = contador 0.325;
      // lcd.clear();
      lcd.setCursor(5, 0);
      lcd.print (centimetros);
  }
  statusAnt = status;
}

Hola surbyte.
Pues uso las interrupciones porque las vi en algún proyecto que usaba ruedas dentadas para medir distancias, y di por hecho que tenia que ser así. pero probando tu código, va mil veces mejor!! sin ningún desfase. Voy a intentar entenderlo y si no te importa lo implementare a mi programa.

He calculado que mas o menos el sensor de óptico de la rueda le de a arduino unos 400 pulsos por segundo.

También simplificare las operaciones matemáticas todo lo que pueda a partir de ahora.

Muchas gracias por tu ayuda!!!

Hi,
Pregunta que voltaje tiene el sensor cuando hay luz y cuando no hay. Si no hay luz esta +5 voltios y cuando tiene luz lee zero voltios. Para mi creo que las aberturas son muy grandes y esto te crea problemas en los pulsos. Deberia tratar de ponerlas que te de un pulso pequeno.

hola tauro.

o ya no se que pensar! creia que a muescas mas separadas peor definición tenia, pero mas fiabilidad. voy a intentar hacer una con maor numero de dientes.

muchas gracias otra vez!!

Hi,
Creo que el problema es de las aberturas son muy grandes y esto hace que puede causar recibir luz externa a la senal infraroja del sensor. Por eso es de hacerlas lo mas pequena posible para prevenir interferencia externa. Yo tuve problemas cuando trate de leer las revolucines de un plato de tocar discos. Tuve que pintar la parte de abajo con pintura sin brillo y pude resolver el problema. Si sigues con el problema podrias tratar el hall effect sensor con un megneto y asi eliminas cualquier interferrencia externa. Cada que que el magneto pasa por el sensor este te da un pulso que puedes usarlo para que trigue el interupt. Sigue tratando hasta que puedas resolver el problema con el sensor que tienes.

A ver tauro mi código funcionó sin problemas con las aberturas como estan. Entonces no hay problema con la abertura sino con el código que usa interrupciones, no te parece?

Habrá que enfocarse en el código anterior y modificarlo para que trabaje correctamente.
No hay rebotes, mi código no implementa rebotes, solo cuento flancos.