Go Down

Topic: Controlar vueltas de motor cabestrante (Read 2229 times) previous topic - next topic

MCasellas

Apr 19, 2018, 04:09 pm Last Edit: Apr 20, 2018, 08:36 am by MCasellas
Hola a todos,
hace mucho que os leo a la gran mayoría y os agradezco la comunidad que tenéis montada porque me ha sido de ayuda en otros casos.

Hoy escribo por primera vez para ver si me podéis orientar con lo que me traigo entre manos.

Soy un neofito en esto de arduino y la poca idea que tengo de programación es lo que he ido aprendiendo de este foro y tutoriales varios, por ello, aún me cuesta reconocer en qué estoy fallando.

Me dedico al mundo del arte y estoy haciendo una instalación escultórica donde una pieza suspendida se eleva y baja gracias a un cabestrante o polipasto. Mi necesidad es que la pieza suspendida suba o baje a dos puntos determinados, imaginemos un punto A(alto) y un punto B(bajo).

El motor está conectado a dos relés, uno para cada sentido de giro del motor (cuando se activa uno me suelta cuerda y cuando activo el otro relé, me recoge la cuerda). Lo malo es que el motor no mantiene la misma velocidad en ambos sentidos, cuando gira en un sentido va más rápido que en el sentido contrario. Esto me impide que, por ejemplo, al programar un tiempo de bajada de tres segundos y un tiempo de subida de otros tres segundos,  la pieza quede suspendida en el mismo punto que estaba anteriormente, provocando un desfase que va a más a medida que se repite el bucle programado.

En este punto, he de deciros que también he descartado la opción de poner interruptores de final de carrera, por razones estéticas y como no puedo programarlo por tiempos, estoy buscando la manera de hacerlo contando los pulsos de un sensor que me cuente las vueltas que da el motor (son muy pocas RPM, unas 20RPM, una vuelta cada 3 segundos). Para esto, estoy haciendo pruebas con un sensor de infrarrojos y también con uno electromagnético que son los que me permitirían poderse montar junto al tambor del motor.

Pues bien, por mi falta de conocimientos con la programación, no sé por qué el siguiente código no me funciona.

Code: [Select]

int sensor = 4; //sensor infrarrojos o electromagnético para contar vueltas del motor
int rele1 = 13; //suelta cuerda (baja la carga)
int rele2 = 12; //recoge cuerda (sube la carga)
int conta = 0;
int estadoCero = 0;


void setup() {
  Serial.begin(9600);   //iniciar puerto serie
  pinMode(sensor, INPUT);  //definir pin como entrada
  pinMode(rele1, OUTPUT);  //definir pin como salida
  pinMode(rele2, OUTPUT);  //definir pin como salida
  delay(8000);             //tiempo de espera hasta el inicio
  digitalWrite(rele1, HIGH); //activa el motor en un sentido para SOLTAR cuerda
 

}
 
void loop()
{
  int pl = digitalRead(sensor);  //lectura digital del sensor
  if (pl!=estadoCero){
    if (pl==LOW)
  {

   conta++;
   Serial.println(conta);
  }
}
  estadoCero=pl;
  if (conta==3){                //cuenta 3 vueltas del motor
    digitalWrite(rele1, LOW);   //detiene el motor para dejar de SOLTAR cuerda
    delay(8000);                //espera un tiempo
    digitalWrite(rele2, HIGH);  //activa el motor para RECOGER cuerda
      
  }
  
    if (conta==6){              //cuenta hasta 6 vueltas (3 vueltas soltando, 3 vueltas recogiendo)
    digitalWrite(rele2, LOW);   // detiene el motor para dejar de RECOGER
    conta=0;                    //Reinicia el contador desde 0
    delay(8000);                //Nuevo tiempo de espera para comenzar con bucle
    digitalWrite(rele1, HIGH);
    
  }    
  }




Con este código, consigo que el motor, hacia una dirección, se pare una vez contado el número de pulsos programado, pero cuando se activa el giro en el otro sentido, el contador no sigue su cuenta y nunca se me detiene.

Por ello os pido que si sois tan amables de indicarme dónde véis el fallo(o los fallos) estaré muy agradecido. Si tenéis un nuevo enfoque de cómo debería realizarlo, también os agradecería la orientación.

Un saludo a todos.

surbyte

Bueno la solucion mas simple es un sensor hall, magnético u optico que cuente vueltas.

Cada vuelta serán X cmts y si quieres ser mas preciso entonces pones una rueda dentada solidaria al eje del motor y podras tener mejor resolucion en cmts.

Si usas este método es facil decirle (sin importar la velocidad del motor) mueve 10 vueltas (por ejemplo) para un lado o mueve 20 para otro.


MCasellas

#2
Apr 19, 2018, 05:32 pm Last Edit: Apr 20, 2018, 02:08 am by surbyte
Gracias surbyte por mover el post y por responder.

Entiendo que lo que dices es lo que estoy tratando de hacer. Por cómo es el motor (ver foto), creo que la solución será contar las vueltas con uno magnético. El óptico, que es otro que estoy usando para pruebas, me falla cuando hay mucha cuerda en el "tambor" del cabestrante porque me lo detecta.

En la foto, verás que he puesto un vinilo negro dejando una cuña en blanco para usar el sensor óptico, pero esta cuña, la cambiaré por un imán (bien pegado con resina epoxi) al borde exterior que no me lo tape la cuerda y con idea de usar el sensor magnético. (En la foto está sin cuerda)

Mi problema, seguramente está en el código que es donde, sinceramente, no tengo mucha idea y por ello no logro a detectar los fallos. (Me siento un intruso tratando de programar esto!!)

La precisión de que la pieza suspendida se pare en el mismo sitio, no es un problema, pero imagino que con lo que dices, x vueltas a un lado, x vueltas al otro, evito que se descompense la subida y bajada y no termine la pieza en el suelo o en la polea del techo!! Jajajaja....



Moderador: Imagen editada para su visualización

tauro0221

Hi,
Mi sugerencia es que debes cambiar el motor electrico a stepper motor. Este te va a dar mas precision el los movimentos de distancia en las subidas y bajadas.Ahora si es muy pesado entoces vas a necesitar uno que tenga fuerza. Necesitaras uno que tenga engranajes como el que demostro que esta en venta en Ebay. Adjunto esta el link.

https://www.ebay.com/itm/Extruder-Gear-Stepper-Motor-Ratio-5-1-Planetary-Gearbox-Nema-17-Step-Motor-OSM/311763147895?epid=2111397028&hash=item4896881c77:g:tN8AAOSwM8ZZeZ9G 

MCasellas

Gracias tauro0221,

seguro que con ese motor, la situación sería más fácil de controlar. Pero la temática de la instalación versa sobre la idea de rescate, por eso mismo, debo usar el motor que mostré en la imagen. Sé que es complicado de entender el porqué de querer usarlo pero esto obedece a darle un sentido estético y temático a la instalación artística.

Aún así, muchísimas gracias por el aporte.

tauro0221

Hi,
Ese motor no vas a poder controlarlo como tu quires pues al enegizarlo el va arrancar imediatamente sin control. Una cosa que podrias hacer es energizarlo por medio de pulsos pero entonces tendras que cambiar los relais mechanicos a SSR. Asi puedes adjustar la duraccion del movimiento alargando o  acortandolo los pulsos.
 

MCasellas

#6
Apr 19, 2018, 06:54 pm Last Edit: Apr 19, 2018, 07:05 pm by MCasellas
Algo que no aclaré es que no se pretende estar todo el día subiendo y bajando a una posición exacta.

La intención es que pasados 20 minutos parado, baje (unas 10 vueltas) de una posición aproximada A(Alta) a una posición B(Baja) y después, de otros 20 minutos parado, suba (las mismas 10 vueltas) para quedar en la posición A(Alta) de inicio. Y que esto lo haga durante unas 4/8 horas al día en el horario de la exposición.

Es más, con los relés que estoy usando y los sensores que estoy probando (óptico y magnético), logro hacerlo parar justo en las vueltas que necesito, pero algo me falla en la programación porque no sigue con el loop.

La secuencia que tengo programada, o mejor dicho: quiero programar, en resumen es:

- Conecto todo, a los 8 segundos activo el motor en un sentido de giro. (soltar cuerda)
- Con el contador de pulsos y el sensor, paro el motor tras X vueltas.
- Pasados otros 8 segundos, se activa el motor en el otro sentido de giro. (recoger cuerda)

Estos primeros pasos, los hace. Pero ahí se queda el motor "recogiendo" cuerda sin que me continúe ejecutando el programa. Que lo que debería hacer, si estuviese bien programado, es continuar con lo siguiente:

- Nuevamente con el contador de pulsos, llegado a las X vueltas en sentido contrario, parar el motor.
- Pasados otros 8 segundos, volver a iniciar todo.

Tened en cuenta que los 8 segundos son con los que estoy haciendo las pruebas, finalmente, cuando todo funcione, serían los 20 minutos que mencioné antes.

surbyte

Hola @MCasellas, he estado viendo tu código y funciona bien, mira el código que es una variante solo para mostras como si los tuviera (RELE, motor)

Code: [Select]
int sensor = 4; //sensor infrarrojos o electromagnético para contar vueltas del motor
int rele1 = 13; //suelta cuerda (baja la carga)
int rele2 = 12; //recoge cuerda (sube la carga)
int conta = 0;
bool pl, estadoCero = false;
unsigned long start;

void setup() {
  Serial.begin(9600);   //iniciar puerto serie
  Serial.println("Inicializando.");

 
  pinMode(sensor, INPUT);  //definir pin como entrada
  pinMode(rele1, OUTPUT);  //definir pin como salida
  pinMode(rele2, OUTPUT);  //definir pin como salida
  delay(8000);             //tiempo de espera hasta el inicio
  digitalWrite(rele1, HIGH); //activa el motor en un sentido para SOLTAR cuerda
}
 
void loop() {
 //    pl = digitalRead(sensor);  //lectura digital del sensor
   
 //    if (!pl && estadoCero){  // si hay transicion de 1 a 0 entonces
// conta++;
// Serial.println(conta);
// }
 //  estadoCero = pl;
  if (millis()-start > 1000) {
  start = millis();
 
  Serial.println("Contador : " + String(++conta));
  }
 

  if (conta == 3){                //cuenta 3 vueltas del motor
    //digitalWrite(rele1, LOW);   //detiene el motor para dejar de SOLTAR cuerda
    Serial.println("Rele1 LOW");
    Serial.println("Pausa 20 min");
      delay(5000);                //espera un tiempo
    //digitalWrite(rele2, HIGH);  //activa el motor para RECOGER cuerda 
    Serial.println("Rele2 HIGH");
  }
 
    if (conta == 6){              //cuenta hasta 6 vueltas (3 vueltas soltando, 3 vueltas recogiendo)
    //digitalWrite(rele2, LOW);   // detiene el motor para dejar de RECOGER
    Serial.println("Rele2 LOW"); 
    Serial.println("Pausa 20 min");
      delay(5000);                //Nuevo tiempo de espera para comenzar con bucle
    //digitalWrite(rele1, HIGH);
    Serial.println("Rele1 HIGH");
      conta = 0;                    //Reinicia el contador desde 0
  }     
 }


He simulado los cambios con algo que me da cada 1 segundo un avance como si fuera una vuelta.

Esta es la salida

Quote
Inicializando.
Contador : 1
Contador : 2
Contador : 3
Rele1 LOW
Pausa 20 min
Rele2 HIGH
Contador : 4
Contador : 5
Contador : 6
Rele2 LOW
Pausa 20 min
Rele1 HIGH
Contador : 1
Contador : 2
Contador : 3
Rele1 LOW
Pausa 20 min
Rele2 HIGH
Contador : 4
Contador : 5
Contador : 6
Rele2 LOW
Pausa 20 min
Como verás no entiendo como dices que se queda en una posicion que es la de recoger cuerda.

Tu codigo resetea, y funciona bien. No hagas caso los delays porque los ajuste para no aburrime.

MCasellas

#8
Apr 21, 2018, 01:42 pm Last Edit: Apr 21, 2018, 05:51 pm by MCasellas
Muchísimas gracias surbyte, esta misma tarde miro cómo adaptar lo que me has enviado, lo he compilado y si, justo lo que me lanza la salida es lo que necesito que haga.

Lo que no me cuadra ahora es que me digas que mi código funciona bien. Te dejo un enlace a un video para que veas cómo actúa el motor tras iniciar el segundo giro, no para!! El contador deja de contar en la salida y no hay manera de hacerlo parar con el sensor.

Prueba parada motor con sensor

Gracias una vez más por tu generosidad.


tauro0221

Hi,
Una cosa que noto en el video es que estas usando relais. Cuando cierra/abres los relais se va a producir ruido y esto pude danar los contactos de los relais causando que estos se solden intermitentemente. Debes de anadirle un snoober en parallelo a los contatos o installarles un condensador de .i uf en paralello a los contactos. Voy a tratar de ver que mov debes de anadirle. Otro prueba sencilla que puedes hacer es de hacer un pequeno sketch que solamente cuentes las vueltas para ver si el sensor lo esta reconociendo el arduino. Esta sencilla prueba te va decir si estas leyendo bien el sensor. Te dejo saber que mov debes de usar cuando busque caul debesde usar.

tauro0221

Hi,
Encontre uno que te sirve para tu aplicaccion es el MOV V47ZA20P. Tambien te incluyo un link para que veas de que lo que estamos hablando de los snoobers y MOV y para que se usan.

http://www.littelfuse.com/~/media/electronics/product_catalogs/littelfuse_varistor_catalog.pdf.pdf


PeterKantTropus

#11
Apr 21, 2018, 09:51 pm Last Edit: Apr 21, 2018, 09:53 pm by PeterKantTropus
Tu problema reside en que el motor  , no incrementa una vez que llega a esta parte, porque simplemente se pierden los nuevos pulsos

Code: [Select]
if (conta==3){                //cuenta 3 vueltas del motor
               digitalWrite(rele1, LOW);   //detiene el motor para dejar de SOLTAR cuerda
               delay(8000);                //espera un tiempo
               digitalWrite(rele2, HIGH);  //activa el motor para RECOGER cuerda

Cuando se cumple conta==3  por cada "pase" del void loop se detendrá por el delay(8000) momento en que se estarán produciendo los cambios en el sensor y por lo tanto no se incrementara conta.

Tu programa funcionaria perfectamente si pasas el sensor a una interrupción o asignándole una bandera para que no se cumpla el  if (conta==3) en cada pase del loop.

Saludos
"Si no entra como tornillo, entra como clavo"

MCasellas

#12
Apr 22, 2018, 10:31 am Last Edit: Apr 22, 2018, 10:34 am by MCasellas
Antes que nada, no os hacéis ni idea de lo agradecido que estoy porque me estéis echando una mano con esto. Dicho esto:

surbyte,
muchas gracias una vez más, he intentado implementar la simulación que me sugeriste pero sin éxito. Como ya comenté , a pesar de haber consultado y realizado tantos tutoriales con prácticas, se me atraganta el "idioma" de programación. (Me pasa como con el inglés! jajajaja...) Pero de todos modos, voy a seguir probando puesto que como dices, la salida me lanza la secuencia que quiero que se ejecute.

tauro0221,
tendré en cuenta lo que me recomiendas para mejorar la instalación. Aunque de momento me preocupa más hacerla correr. Aún así muchas gracias!

PeterKantTropus,
gracias por unirte a la causa. En todos los tutoriales que he visto siempre avisan sobre el uso de los delays y, en este caso, andaba con la mosca detrás de la oreja porque metí un delay en el voidSetup sin saber si es correcto o no meterlo ahí. Sobre el delay que me indicas, no pensé que me diese problemas y lo introduje en esa línea de código porque necesito hacer ahí una segunda pausa entre la "suelta de cuerda" y la "recogida".
Code: [Select]
estadoCero=pl;
  if (conta==3){                //cuenta 3 vueltas del motor
   digitalWrite(rele1, LOW);   //detiene el motor para dejar de SOLTAR cuerda
   //delay(8000);                //espera un tiempo
   digitalWrite(rele2, HIGH);  //activa el motor para RECOGER cuerda

    
  if (conta==6){              //cuenta hasta 6 vueltas (3 vueltas soltando, 3 vueltas recogiendo)
    digitalWrite(rele2, LOW);   // detiene el motor para dejar de RECOGER
    conta=0;
      
  }

Anulando de ahí ese //delay, paso directamente de un sentido de giro, al sentido contrario y, aunque el conta siga haciendo sus cuentas, no me detiene el motor porque no pasa a LOW ni me reinicia el conta=0

Voy a investigar lo que me recomiendas de las interrupciones que no las he usado nunca. De echo, las descarté porque lo que entiendo de ellas es que algo debe llamarla y en mi caso, creo que no se trata de esto. Igualmente lo miraré también junto a lo que me proponía surbyte.

Una vez más, gracias a todos y disculpad mi terquedad en la materia. Os seguiré informando!


MCasellas

Hola a todos,
definitivamente soy un desastre.

He intentado implementar las interrupciones, sin ningún tipo de éxito con el código. (Lo sé, me hace falta aprender mucho aún.)

Lo más "cerca" que he estado de hacerlo funcionar, que es activando los reles con las cuentas del sensor, tampoco me sirve puesto que no es la lectura del sensor quien debe activar, sino que esta cuenta sólo necesito para parar el motor.

Ya decía yo que tanto estudiar a los impresionistas no me serviría en mis trabajos en plena era digital! Jajajaja...

Voy a ver si esta tarde asimilo mejor estos aportes de Prometec y Luis Llamas sobre las interrupciones.
https://www.luisllamas.es/debounce-interrupciones-arduino/

Arduino y las interrrupciones

Seguiré informando!

PeterKantTropus

En realidad las interrupciones no te bastaran, deberías hacer cambios en la estructura de tu programa. Ayuda mucho en este caso el pseudocodigo.

Tu programa tiene la siguiente estructura
-1 condiciones de inicio: subir
-2 Incrementar contador
-3 si el contador  llega a 3 parar subida, esperar, bajar
-4 si el contador  llega a 6 parar bajada, esperar, subir, poner contador a "0"
-5 reiniciar desde incrementar contador


El primer problema lo tienes en que mientras el programa esta en 3 o 4 no incrementa el contador (2). esto tiene solución con las interrupciones.
Otro problema seguramente lo tienes en la placa de control (estoy especulando), la mayoría de estas tiene protección contra cortos, si entra   dos ordenes  contradictorias se parara.
por esto al hacer parada bajada o subida, directamente se detenga y  el pseudocodigo tendrá la siguiente estructura.

-1 condiciones de inicio: subir
-2 Incrementar contador
-3 si el contador   llega a 3 parar , esperar, bajar
-4 si el contador  llega a 6 parar  , esperar, subir,poner contador a "0"
-5 reiniciar desde incrementar contado

Que se parece mas a la descripción de funcionamiento que haces. funciona hasta el primer pase del punto 3, luego entra en un loop en cual siempre se cumple 3 porque el "bajar" de este punto no llega a ejecutare por la rapidez  del ciclo inmediatamente le llega la orden de parar y esperar.
Una forma de corregirlo seria levantar una bandera para que cada "if" se ejecute una vez por cada ciclo

-1 condiciones de inicio: subir
-2 Incrementar contador
-3 si  el contador llega a 3 y no esta la bandera1 en alto: parar subir , esperar, bajar, levantar bandera1
-4 si el contador  llega a 6  :parar  bajar,  esperar, subir,poner contador a "0"  y bajar bandera1
-5 reiniciar desde (2)


De esa manera los puntos 3 y 4 solo se ejecutaran una vez por cada ciclo.

Si deseas un código mas limpio y utilizar interrupciones deberías cambiar la estructura del código.
Por las interrupciones el contador siempre funcionara por fuera del loop

-1 condiciones de inicio: subir
-2 si  el contador llega a 3 parar subir
-3  esperar
-4 bajar
-5 si el contador  llega a 6  :parar  bajar
-6 esperar
-7 subir
-8 poner contador a "0"  
-9 reiniciar desde (2)

saludos


























"Si no entra como tornillo, entra como clavo"

Go Up