desktop

Conteo de pulsos con Arduino

Te hago la pregunta directa, tenés un Osciloscopio?
La segunda no es pregunta o si. Tenes que pedir sensores Hall a aliexpress, siendo que los podes conseguir localmente? No te va a cambiar tanto el bolsillo. Yo vivo en la Patagonia y lo consigo en una casa de Electrónica local.
Vos antes de descartar algo deberias asegurarte que ese algo (reed switch) funciona mal. el reed switch es bobo.. pero responde al iman. Si el imán esta mal orientado entonces fallará pero... ahora leo que hay un equipo comercial entonces ese equipo funciona bien, lo que me hace pensar que algo en tu esquema del reed switch no esta bien o no se comporta como esperas. Todo eso se responde con un osciloscopio.
 
No tengo osciloscopio.
El diagrama que tengo para el reed switch es este:
cuentapulsos-png.180299


Con algunos cambios:
en paralelo a D1 hay un capacitor de 100 nf
C1 = 1 uf
R1 = 680 ohm

Ojo que esto cuenta bien los pulsos, osea actualmente no pierdo pulsos, lo que sucede es que cuando debe parar por ejemplo en 693 se para en 695.
entonces cada vez que el receptor le envia el comando de ir a la posicion se mueve hacia arriba o abajo hasta que queda en 693. hay vecces que nunca se posiciona en ese punto y continuamente intenta posicionarse.
esto solo sucede al usar interrupciones en modo change, no lo note hasta el momento en FALLING o RISING

Usando el PWM parece estar resuelto.
Pero igual quiero usar los sensores hall porque deberian tener una mejor precision y hay actuadores que ya vienen con ese tipo de sensor asi dejo el posicionador pronto para usarlo con esos actuadores.
Voy a ver si mañana consigo algun sensor hall localmente.
 
El problema que encontré es que la resistencia de tu anterior esquema de 470 ohms no sirve y la amplitud de salida es baja.
Con 2k2 llegas a 2V y eso esta justamente en una zona donde puede o no dispararse la interrupción



Con2k2.png

Si usas una R de 4k7 funcionará bien y con 10k sin problemas.

Con4k7.png
 
Si siempre se para dos después mueve dos menos
No siempre se para 2 mas/menos hay veces que se mueve 3 mas/menos y hay veces que se para donde debe.


El problema que encontré es que la resistencia de tu anterior esquema de 470 ohms no sirve y la amplitud de salida es baja.
Con 2k2 llegas a 2V y eso esta justamente en una zona donde puede o no dispararse la interrupción



Ver el archivo adjunto 181238

Si usas una R de 4k7 funcionará bien y con 10k sin problemas.

Ver el archivo adjunto 181239

Los valores que veo del capacitor y la resistencia no son los actuales, ahora la resistencia es de 680 ohm y el capacitor de 1 uf.

Voy a probar entonces con 10k y 0.1uf

edit: saben si cuando se usa el PWM y el motor tiene un poquito de zumbido es malo para el motor?
 
Volvamos a esto

146579-97771b496cba3c4f9b18b445e86d5e5d.jpg


Si la rueda es la blanca y los imanes son los redondos y cuento 3, entonces la ubicación del reed switch tal como la dibujaste (Rojo) para mi no es la óptima. Confirmalo por favor.
 
Última edición:
IMG_20190803_155732.jpg
Los imanes estan en el engranaje negro y estan marcados con los puntos azules. el sensor esta por debajo del engranaje y separado unos 3 o 4 mm
Cuando el iman pasa por debajo del sensor quedan enfrentados, poco mas de la mitad del sensor queda cubierto por el iman.
Este es el sensor

Acá dejo un vídeo, no recuerdo si ya no lo había subido.
El codigo es el de arriba

Lo que se ve ahí es:
led rojo-> motor activo
led azul que destella ->esta conectado con el reed switch

apreto boton:
activa interrupcion
enciende led
se mueve motor
dispara interrupción
dentro de la interrupción:
apaga motor y led
suma 1 a la cuenta
desactiva interrupción

Como ven ahí los primeros 5 pulsos los cuenta perfectamente, pero después cuenta el pulso 6 y nunca se apaga el led y el motor sigue de largo
si quito la linea que desactiva la interrupcion lo que sucede es que cuenta 2 o 3 pulsos mas y ahi se apaga el motor y el led.
ese es el problema.
Ahora lo pude "solucionar" usando el PWM.
Muevo a baja velocidad si el destino esta a menos de 50 pulsos y cuando estoy moviendo a toda velocidad y faltan 50 pulsos para llegar, bajo la velocidad.
El unico problema es que con un actuador lineal que tengo, el motor zumba un poquito pero se mueve bien.
Consegui unos diodos mur460 (600v,4A,75ns) para usar con el mosfet y no consegui sensores hall (pienso que el lunes ya tengo unos que vienen para arduino que consegui en otra ciudad).
Descartado que el problema sea este actuador de la foto, pasa lo mismo con el lineal aunque no es tan frecuente.
Aun no probé cambiar la resistencia y el capacitor de pull-up, pero sinceramente no creo que sea ese el problema.
porque la interrupción se dispara e incluso suma 1 a la cuenta, pero el pin nunca cambio de estado.
Si fuera problema con el pull-up tendria un conteo de pulsos erroneos y no se posicionaria bien sobre los satelites. y por mas que se pase 2 o 3 pulsos si lo muevo hasta llegar a los pulsos necesarios, la señal es correcta.
 
Como pusiste el diodo MUR460 en antiparalelo con el motor no?
Pero la interrupcion se dispara pero ya te mostré que con 680 o 2k2 los pulsos no toman el nivel HIGH que deberían. Asegurate tener pulsos limpios que superen el umbral Vih del Arduino.
 
Como pusiste el diodo MUR460 en antiparalelo con el motor no?
Pero la interrupcion se dispara pero ya te mostré que con 680 o 2k2 los pulsos no toman el nivel HIGH que deberían. Asegurate tener pulsos limpios que superen el umbral Vih del Arduino.
Si el diodo esta bien colocado.
Voy a probar cambiar los componentes del pull-up. pero con lo que tengo ahora el tiempo de anti-rebote no supera los 700us.
 
Analizando tu programa empiezo a encontrar problemas.
Problema 1
Código:
const byte boton = 0;
Eso para mi es el PIN RX, que si usas el Serial. no tiene sentido usarlo.
Cambia a otro pin como el 4 por ejemplo

Problema 2.
cuando presionas el pin te quedas repitiendo eso mientras sigue presionado.

Código:
const byte motorPin = 7;
const byte giroPin  = 26;
const byte reedPin  = 20;
const byte botonPin = 14;

void setup() {
  pinMode(motorPin, OUTPUT); //motor
  pinMode(giroPin, OUTPUT); // sentido giro
  pinMode(reedPin, INPUT); //reed switch
  pinMode(botonPin, INPUT_PULLUP); //boton
  Serial.begin(9600)  // <=== CAMBIA LOS BAUDIOS;
  attachInterrupt(digitalPinToInterrupt(reedPin), sumarPulsosM1, RISING);
}

void sumarPulsosM1() {
  digitalWrite(7, LOW);
  detachInterrupt(digitalPinToInterrupt(reedPin)); //aca para la interrupcion
}

void loop() {
  boton = digitalRead(botonPin4);
  if (!estado && estado_ant){
      Serial.println("pulso");
      delay(100);
      digitalWrite(7,HIGH);
      delay(1000);
  }
  estado_ant = estado;
}

Prueba a ver si se comporta igual o no.
 
const byte boton = 0;
En mi codigo no esta eso, lo que hay es un int boton = 0 que almacena el estado del pin 14

Problema 2.
cuando presionas el pin te quedas repitiendo eso mientras sigue presionado.
Eso es cierto, pero como hay un delay el micro no responde durante ese tiempo y cuando ya solte el boton el estado es 0 nuevamente

Ese código estoy seguro que funcionaria correctamente porque la interrupción esta en modo RISING, lo pruebo y te comento.
 
Tenés razón, vi algo que no era.. lo del pin 0. Mis discullpas.


Entonces porque no agregas los pulsos contados simplemente asi con un

Código:
const byte motorPin = 7;
const byte giroPin  = 26;
const byte reedPin  = 20;
const byte botonPin = 14;
volatile unsigned int pulsos = 0;
bool flag = false;

void setup() {
  pinMode(motorPin, OUTPUT); //motor
  pinMode(giroPin, OUTPUT); // sentido giro
  pinMode(reedPin, INPUT); //reed switch
  pinMode(botonPin, INPUT_PULLUP); //boton
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(reedPin), sumarPulsosM1, RISING);
}


void sumarPulsosM1() {
  pulsos++;
  digitalWrite(motorPin, LOW);
  detachInterrupt(digitalPinToInterrupt(reedPin)); //aca para la interrupcion
  flag = true;
}

void loop() {
  boton = digitalRead(botonPin4);
  if (!estado && estado_ant){
      delay(100);
      digitalWrite(motorPin,HIGH);
      delay(1000);
  }
  estado_ant = estado;
  if (flag) {
      Serial.println("Pulsos:" + String(pulsos));
      flag = false;
  }
}
 
Este hilo ya está demasiado largo para mi gusto, y el principal problema que YO VEO es la forma de controlar el motor:
El soft está controlando el motor en lazo abierto y como no se conoce la dinámica del sistema están jugando a ver "quien le pone la cola al chancho" para determinar cuando tienen que parar el motor...y por eso es típico que el motor se pase, ya que el motor va al mango de velocidad todo el tiempo y por inercia sigue girando un poquito más cuando lo detienen. Seguramente, si los recorridos angulares son cortos, el motor no logrará la velocidad máxima y siempre se detendrá en posición (vamos, que con cuatro imanes y un reed-switch tenemos una resolución de un cuarto de vuelta, aunque no sé de cuanto es la relación de reducción del sistema), pero si el recorrido es mas largo se pasará del punto elegido.

YO haría lo siguiente:

1- Tirar todo el código a la basura.

2- Rediseñar y verificar el sistema de generación de pulsos tal como te han comentado, agrandando las resistencias y quitando algunos capacitores (sobre todo el de la entrada ISR por que tenes el opto al lado) ya que eso baja la velocidad del flanco y puede hacer que la tensión llegue al punto de disparo de la interrupción fuera de tiempo. En verdad, yo simularía el comportamiento y luego le metería un generador de funciones y un osciloscopio para ajustarlo a la realidad...pero si no tenés acceso a instrumentos, simulalo bien nomás.

3- Dejar de usar todo el bodrio de las interrupciones para contar a 20 Hz y mandar la señal del opto a la entrada de un timer, cosa de contar por hardware y no perder tiempo en interrupciones.

4- Escribir el soft para un controlador proporcional, que básicamente es restar de la posición deseada el valor del contador --> esto es el "error de posición", que se va reduciendo a medida que el motor se aproxima a destino, y hacer esto cada un cierto tiempo (controlado por las interrupciones de otro timer). El error de posición se multiplica por una constante y el valor resultante es lo que se aplica al motor vía PWM. De esa forma, a medida que se aproxima el motor a la posición deseada el control le baja la velocidad, y si ajustamos correctamente el valor de la constante va a llegar con la precisión deseada. Si no llega, se puede agregar una parte integral que reduzca el error de posición en estado estacionario a CERO, pero primero hay que ver como viene de precisión con la parte P únicamente.
El controlador es algo muy simple y PARECIDO a esto, donde KP es la constante (seguramente float) que hay que ajustar por prueba y error, pero debería arrancar en valor 1...
C-like:
void controlMotor() {
    errpos = pos_deseada - pulsos_contados;
    
    accionControl = KP * errpos;
    
    PWN = (int)accionControl;
}
Hay un "pequeño problema" que puede surgir, pero no lo estás controlando tampoco ahora, y para solucionarlo debemos saber algunas cosas del hardware que controla al motor.
 
Ok.
Voy a quitar el capacitor del pull_up y aumento la resistencia.

Entendí lo del control proporcional, voy a implementarlo. Me parece buena idea

Anteriormente había intentado contar pulsos con los timers pero no pude hacerlo andar.
El timer 0 lo uso con las funciones delay() y micros()
El timer 2 es usado por la función tone()
El timer 3 pienso usarlo para el control remoto IR
Así que me quedarían los timers 4 y 5
Si alguien tiene un ejemplo se los agradezco.
 
OK. Siempre comenzá con un valor pequeño de la constante KP y los vas aumentando DE A POCO hasta que el motor llegue a la posición deseada.

Que puede suceder???
Que el motor se pase de la posición final y en ese caso el controlador va a tratar de que el motor gire al revés para volver al punto destino (siempre dependiendo del valor de KP). La pregunta es: Puede el motor girar en ambos sentidos??
Si la respuesta es SI vamos a ver como podemos hacer para que se produzca la inversión (normalmente es usar una línea de salida adicional que va en 1 en un sentido y la ponés en 0 cuando querés girar al revés, además la acción de control se hará negativa y como no hay PWM negativo habrá que complementarlo para que sea positivo.

Si el hardware del motor permite esto, estamos hechos, si nó, habrá que vivir con un pequeño error y usar una KP ajustada para que el motor no se pase al llegar a destino.

Esto es importante esto es importante por que si el motor excede la posición destino el controlador intentará invertir el giro, pero como no puede y un PWM negativo es igual a uno positivo pero muuuuy grande en valor, vamos a tener que poner algunos controles adicionales o invertir el giro si el hardware lo permite, por que si nó el motor va a girar como un motor de helicoptero...

PD: la interrupcion del timer que uses y que activa el controlador debería ejecutarse - para empezar - cada 10 milisegundos y si va bien, este intervalo puede agrandarse de a poco. No me queda claro si vamos a controlar directamente el motor o al motor mas reducción, así que mejor empecemos por lo seguro...
 
Si el motor invierte el sentido de giro.
Yo tengo en una SD las diferentes posiciones guardadas cada una con la cantidad de pulsos en la que necesito posicionarme.
Entonces cuando tengo que ir por ejemplo a la posición 24, cargo los datos de la SD y en base a los pulsos actuales hago que el motor se mueva en un sentido u otro.
Por ejemplo si estoy en 456 pulsos y tengo que ir a 347 lo que hago es:
desactivo la interrupción actual
activo el relee que invierte el giro
activo la interrupción que RESTA pulsos
activo el motor.
cuando restan 50 pulsos para llegar (lo verifico dentro del loop) bajo la velocidad
llego a destino
paro motor

Y eso está funcionando bien.

Si yo entendí bien, lo que me comentas haría que el motor baje la velocidad progresivamente hasta llegar al destino?

Podria para probar implementarlo dentro del loop cada 10 ms cierto?
 
Sin ánimo de liarla.
La respuesta del motor no será muy lineal, tendrá una histéresis importante, muy importante probablemente.
Osea que si queremos moverlo poco no se moverá. Porque el error de posición es mínimo y al multiplicar por kp da una tensión que no es capaz de mover nada.

Yo modelaria lo siguiente. Perdón por la palabra, demasiado pretenciosa quizás...
Un mínimo de pwm al cual el motor sigue moviendose y se para sin saltarse nunca el pulso. Seguramente a esa velocidad no arrancará.
Entonces movería el motor con 100% hasta llegar cerca de "la meta" momento en el que pasaría a esa segunda velocidad, o bien de golpe o bien.progresivo. Para hacer 3sta progresión se pueden usar las propias interrupciones,

Tambien se podría implementar el control pero no sobre la posición sino sobre la velocidad, tomando el inverso del tiempo entre interrupciones
Así lo hacía yo en un motor que alcanzaba las 18000rpm para cortar la inyección cuando correspondía.
Yo no usaría el timer de contador, no le veo sentido en este caso.
 
Con un valor de PWM de 15 el motor arranca y se posiciona bien pulso a pulso.
Lo único que tengo otro motor que zumba un poquito pero también funciona correctamente
La tensión anda al rededor de 17-18 voltios con ese valor
 
Pues ya lo tienes, lo mueves todo el rato así y chimpún chimpero...

Bueno si a ese valor de pwm se mueve entonces si que te dará bastante proporcionalidad.

La pregunta es que pasa si solo lo quieres mover un saldo de imán. ¿Cuánto vale kp?
El ruido es normal porque el Arduino hace el pwm sobre el kHz y si el motor tiene algo con holgura puede que vibre.1kHz es perfectamente audible. Por eso a veces se montan pwm fuera de la frecuencia audible. (A los perros no les gustarán, supongo)
 
Atrás
Arriba