Puerta brazos extensibles, de vez en cuando se queda a medio cerrar

Saludos,
Me llamo Carles y soy nuevo en el foro.
Os escribo porque tengo una puerta automática de 2 batientes con 2 motores 12V 1A conectados a un placa "arduino uno" que se abre desde el móbil via bluetooth. La puerta está programada para que se abra y cierre con una sola función al apretar el botón "open" de la aplicación. Generalmente la puerta funciona correctamente pero a veces cuando se está cerrando se queda semiabierta siempre en la misma posición teniendo que volver a apretar el botón "open" para que repita la operación y cierre bien. A la placa también hay conectado un pulsador parar abrir sólo uno de los batientes.
La alimentación del sistema y motores es con transformador 12V que pude suministrar 15A
No sé si hace falta que os enseñe esquema del montaje pués básicamente es saber porque se para de vez en cuando en el mismo sitio
Aquí os dejo el código e imagen del shield ( puente H ) conectada a placa arduino uno, aunque creo que todo está correcto
Veréis que uso "delay" para que la puerta reste abierta un cierto tiempo y es cuando se cierra que " a veces " no cierra del todo
Gracias.

#include "CytronMotorDriver.h"


CytronMD motorD(PWM_DIR, 9,8); //PWM = 9, DIR = 8 (PER DEFECTE)
CytronMD motorE(PWM_DIR, 11, 13);//PWM=11, DIR=13 (PER DEFECTE)



void obrir_dues(){
  motorD.setSpeed(255);
  delay(4000);
  motorE.setSpeed(255);
  delay(16000);
  motorD.setSpeed(0);
  delay(10000);
  motorE.setSpeed(0);
  delay(99000);
  motorE.setSpeed(-255);
  delay(17000);
  motorD.setSpeed(-255);
  delay(100);
  
  
}
/*
void tancar_dues(){
  //motorD.setSpeed(255);
  //delay(4000);
  motorE.setSpeed(-255);
  motorD.setSpeed(255);
  delay(15000);
  motorD.setSpeed(-255);
  delay(100);
}
*/

void obrir_dreta(){
  motorD.setSpeed(255);
  delay(300);
}

void tancar_dreta(){
  motorD.setSpeed(-255);
  delay(300);
}

void obrir_tancar_dreta(){
  motorD.setSpeed(255);
  delay(40000);
  motorD.setSpeed(-255);
  delay(100);
}

void parar(){
  motorD.setSpeed(0);
  motorE.setSpeed(0);
  delay(100);
}
/*
void parar_esquerra(){
  motorE.setSpeed(0);
  delay(100);
}
*/
void setup() {
  // put your setup code here, to run once:
  
  pinMode(7, INPUT);
  Serial.begin(9600);
  

}

void loop() {
  // put your main code here, to run repeatedly:
  
  if (Serial.available()>0){
    int estat = Serial.read();

    switch(estat){
      case '0':
      obrir_dues();
      break;
      case '1':
      parar();
      break;
      case '2':
      tancar_dues();
      break;
      case '3':
      obrir_dreta();
      break;
      case '4':
      tancar_dreta();
      break;
   }    
  }
  if (digitalRead(7) == HIGH){
    obrir_tancar_dreta();
    delay(300);
  }
  

}

shield.PNG

shield.PNG

Disculpad por las mayúsculas del título, intento quitar el post pero no puedo.

Gracias!

Bueno entiendo por lo que leo que no dispones de finales de carrera, algo que sería muy útil en este caso.
El motor D o E se hace girar hasta que se alcanza determinado un switch de puerta abierta y luego la operación inversa, se hace retroceder hasta encontrar el switch de puerta cerrada.
Si ellos estas sujeto a que tierra, problemas mecánicos, o alguna otra cuestión haga que los tiempos que antes eran suficientes ya no lo sean.

Puedes darnos mas datos del shield que usas, tal vez podamos aprovechar algo que tenga disponible para detectar los momentos de abertura y cierre pero lo ideal es con switches o fines de carrera porque no dan lugar a fallos.

Hola, Surbyte.

Gracias por responder.

Al principio usé final de carrera en los dos motores pero tuve problemas con las conexiones sea por la distancia de la placa arduino al final de carrera, por la sección del cableado, o por las mismas conexiones, así que decidí usar los propios finales de carrera del motor que es de engranajes

Para abrir la puerta los motores empiezan a girar junto con un delay hasta que encuentra su final de carrera. Aún con el mismo delay la puerta queda abierta hasta que terminado este delay cambia el sentido de giro del motor, funcionando bien un 90% de las veces

Paso características con link del SHIELD de 2 motores

Shield for Arduino form factor.
Bidirectional control for two brushed DC motor.
Control one unipolar/bipolar stepper motor.
Operating Voltage: DC 7V to 30V
Maximum Motor Current: 10A continuous, 30A peak
Buck regulator to produce 5V output (500mA max).
Buttons for quick testing.
LEDs for motor output state.
Selectable Arduino pins for PWM/DIR inputs.
PWM/DIR inputs compatible with 1.8V, 3.3V and 5V logic.
PWM frequency up to 20kHz (Output frequency is same as input frequency).
Overcurrent protection with active current limiting.
Temperature protection.
Undervoltage shutdown.

Al principio usé final de carrera en los dos motores pero tuve problemas con las conexiones sea por la distancia de la placa arduino al final de carrera, por la sección del cableado, o por las mismas conexiones, así que decidí usar los propios finales de carrera del motor que es de engranajes

Qué problema tuviste? Ruido? Cómo hiciste las conexiones?

Por favor necesitamos datos del actuador para saber algo mas sobre los finales de carrera. Son solo switches? Si lo son debes hacer alguna conexión pull up o down para garantizar la estabilidad de la lectura.

Como dije replanteemos el proyecto porque desde mi punto de vista así esta mal encarado.

Yo haría una rutina que lleve el actuador usando los motores adecuados hacia un lado y otro y se debe detener correctamente usando los finales de carrera. Si quieres hacerlo mejor, podrias tener doble final de carrera por seguridad. El que tiene en los engranajes y uno con la puerta abierta (detectandola) y otro con la puerta cerrada (haciendo lo mismo).
En cada caso usaríamos los dos finales de carrera para garantizar uno u otro movimiento completos.

Hola Carles.

Si te apetece, lee-te esto.
Es Pseudo-codigo, lo he escrito al vuelo sin el IDE, (Y no estoy muy acostumbrado al lenguaje Arduino) seguro que habrá algún error de sintaxis.
Pero es para que veas como lo puedes hacer sin delay() que siempre te dará problemas.
He intentado mantener tu lógica sin entrar a valorarla, y mantenido, pero comentadas, tus instrucciones originales dentro del código para poderlo comparar.

#include "CytronMotorDriver.h"

void setup(){

CytronMD motorD(PWM_DIR, 9,8); //PWM = 9, DIR = 8 (PER DEFECTE)
CytronMD motorE(PWM_DIR, 11, 13);//PWM=11, DIR=13 (PER DEFECTE)

  pinMode(7, INPUT);
  Serial.begin(9600);

global unsigned long RetardObrirDreta = 0;
global unsigned long RetardObrirEsquerra = 0;
global unsigned long RetardTancarDreta = 0;
global unsigned long RetardEsquerra = 0;
global unsigned long MaximTempsObertEsquerra = 0;
global unsigned long MaximTempsObertDreta = 0;
global unsigned long RetardPararDreta = 0;
global unsigned long RetardPararEsquerra = 0;
global unsigned long ara = 0;
}

void obrir_dues(){
RetardObrirDreta = millis();
RetardObrirEsquerra = RetardObrirDreta + 4000;
RetardPararDret = RetardObrirDreta + 30000;
RetardPararEsquerra =  RetardPararDret + 4000;
MaximTempsObertEsquerra = RetardPararEsquerra + 99000;
MaximTempsObertDreta = maximTempsObertEsquerra + 17000;
//  motorD.setSpeed(255);
//  delay(4000);
//  motorE.setSpeed(255);
//  delay(16000);
//  motorD.setSpeed(0);
//  delay(10000);
//  motorE.setSpeed(0);
//  delay(99000);
//  motorE.setSpeed(-255);
//  delay(17000);
//  motorD.setSpeed(-255);
//  delay(100);
}

void tancar_dues(){
RetardTancarEsquerra = millis();
RetardObrirDreta = RetardTancarEsquerra;
RetardTancarDreta = RetardObrirdreta + 15000;
  //motorD.setSpeed(255);
  //delay(4000);
//  motorE.setSpeed(-255);
//  motorD.setSpeed(255);
//  delay(15000);
//  motorD.setSpeed(-255);
//  delay(100);
}

void obrir_dreta(){
RetardObrirDreta = millis();
//  motorD.setSpeed(255);
//  delay(300);
}

void tancar_dreta(){
RetardTancarDreta = millis();
//  motorD.setSpeed(-255);
//  delay(300);
}

void obrir_tancar_dreta(){
  RetardObrirDreta=milis();
  RetardTancarDreta = RetardObrirDreta + 40000;
//motorD.setSpeed(255);
//  delay(40000);
//  motorD.setSpeed(-255);
 // delay(100);
}

void parar(){
  motorD.setSpeed(0);
  motorE.setSpeed(0);
 RetardObrirDreta = 0;
 RetardObrirEsquerra = 0;
 RetardTancarDreta = 0;
 RetardEsquerra = 0;
 MaximTempsObertEsquerra = 0;
 MaximTempsObertDreta = 0;
 RetardPararDreta = 0;
 RetardPararEsquerra = 0;
//  delay(100);
}
void parar_esquerra(){
  motorE.setSpeed(0);
 RetardObrirEsquerra = 0;
 RetardEsquerra = 0;
 MaximTempsObertEsquerra = 0;
 RetardPararEsquerra = 0;
//  delay(100);
}

void loop() {

ara = millis();

if RetardObrirDreta != 0 && RetardObrirDreta < ara{
RetardObrirDreta = 0;
motorD.setSpeed(255);
}

if RetardObrirEsquerra != 0 && RetardObrirEsquerra < ara{
RetardObrirEsquerra = 0;
motorE.setspeed(255);
}

if RetardTancarDreta != 0 && RetardTancarDreta < ara{
RetardTancarDreta = 0;
motorD.setSpeed(-255);
}

if RetardEsquerra != 0 && RetardEsquerra < ara {
RetardEsquerra = 0;
motorE.setSpeed(255);
}

if MaximTempsObertEsquerra != 0 && MaximTempsObertEsquerra < ara{
MaximTempsObertEsquerra=0,
motorE.setSpeed(-255);
}

if MaximTempsObertDreta != 0 &&MaximTempsObertDreta < ara{
MaximTempsObertDreta = 0;
MotorD.setSpeed(-255);
}

if RetardPararDreta != 0 && RetardPararDreta < ara{
RetarPararDreta = 0;
MotorD.setSpeed(0);
}
if RetardPararEsquerra != 0  && RetardPararEsquerra < ara{
RetardPararEsquerra = 0;
MotorE.setSpeed(0);
}
  
estat = 99;

  if (Serial.available()>0){
    int estat = Serial.read();

    switch(estat){
      case '0':
      obrir_dues();
      break;
      case '1':
      parar();
      break;
      case '2':
      tancar_dues();
      break;
      case '3':
      obrir_dreta();
      break;
      case '4':
      tancar_dreta();
      break;
   }    
  }
  
//   Aquí abajo, al leer un interruptor  te haria falta un debouncer() ;

if (digitalRead(7) == HIGH){
    obrir_tancar_dreta();
//    delay(300);
  }
  

}

Hola, Surbyte y Jordi.

Los actuadores llevan sus 2 “switches” de principio y final. En su momento cuando hice las pruebas hacían el recorrido correcto y probé con final de carrera externo funcionando pero al pasar el montaje a la puerta exterior me dió problemas el switch externo ( cambié grosor cableado, etc…) optando por quitarlo y trabajar con los propios del actuador.
Después de lo que habéis comentado optaré primero por el tema del delay y si así sigue fallando pasaré por el resto de soluciones por un tema de salud mental ya que este verano acabé frito con la puerta por las horas de pruebas, debido en parte a la falta de conocimientos en electrónica.

Muchas gracias por vuestra ayuda, ya que habéis abierto posibilidades que no tenía contempladas. Ha sido de gran utilidad

actuador lineal

Seas electrónico o no, los problemas se presentan siempre y tienes la suerte de poder venir a esta comunidad y pedir consejo para resolverlo.

Tanto jordi como yo insistimos en que la idea principal pasa por olvidar los delay() y que uses millis(). El programa que el te sugiere salvo detalles porque lo ha hecho al vuelo y a todos nos pasa, esta bien encarado.

Si tu accionas algo y esperas que el actuador llegue al otro extremo frenándolo con el limite de carrera no hay fallo posible.
Ahora si dices que el problema esta en los cables que le llevan la información al Arduino entonces trabajemos en eso.

Lo primero es que nada es tan simple como conectar dos cables al arduino. Así no se hacen las cosas.
Serán dos cables en un cable con malla. La malla se debe conectar a tierra, tanto de un final de carrera como del otro.
Un cable será común a ambos finales de carrera y el otro debe ir a una Resistencia de 10k x ejemplo a GND del Arduino.
Buscando esquemas para compartirte me encontré con este para una CNC. Final de carrera bastante completo.

No es lo que habitualmente recomiendo pero.. si se usa por algo será.
Tiene un diodo LED para indicar su estado, tal vez eso sea exagerado pero el capacitor y la R de 10K no lo son.

Hola, Surbyte.

Ayer posiblemente no me expliqué bien al referime al delay ya que quería decir que optaré primero por los millis().
En cuanto a los finales de carrera opté en su día por resistencia de 4,7K al GND para cada final con derivación anterior a la resistencia al pin correspondiente de arduino pero sin capacitor y tampoco por el cable con malla.
Lo miro, gracias.

Por cierto,

gracias a vuestras aportaciones estoy viendo los fallos tanto en diseño ( hardware ) como en software.

Salud!

Tendremos que agregar rutina anti-rebote por los fines de carrera.

Solo he agregado la rutina Bounce2 con 50 mseg de antirebotes pero faltan los dos finales de carrera.
Pulí el código de jordi que tenia muchos errores de sintaxis ya que lo hizo en su celular y es lógico.

#include <CytronMotorDriver.h>      // https://github.com/CytronTechnologies/CytronMotorDriver

CytronMD motorD(PWM_DIR, 9,8);      // PWM = 9, DIR = 8 (PER DEFECTE)
CytronMD motorE(PWM_DIR, 11, 13);   // PWM=11, DIR=13 (PER DEFECTE)

#include <Bounce2.h>                // https://github.com/thomasfredericks/Bounce2

Bounce debouncer = Bounce();

#define BUTTON_PIN  7
unsigned long RetardoAbrirDerecha       = 0;
unsigned long RetardoAbrirIzquierda     = 0;
unsigned long RetardoPararDerecha       = 0;
unsigned long RetardoPararIzquierda     = 0;
unsigned long RetardoIzquierda          = 0;
unsigned long MaximTempsAbrirIzquierda  = 0;
unsigned long MaximTempsAbrirDerecha    = 0;
unsigned long actual_millis             = 0;
byte estat;

void setup(){
  pinMode(BUTTON_PIN, INPUT);
  Serial.begin(9600);
  debouncer.attach(BUTTON_PIN);
  debouncer.interval(50); // interval in ms
}

void abrir_dues(){
  RetardoAbrirDerecha       = millis();
  RetardoAbrirIzquierda     = RetardoAbrirDerecha + 4000;
  RetardoPararDerecha       = RetardoAbrirDerecha + 30000;
  RetardoPararIzquierda     = RetardoPararDerecha + 4000;
  MaximTempsAbrirIzquierda  = RetardoPararIzquierda + 99000;
  MaximTempsAbrirDerecha    = MaximTempsAbrirIzquierda + 17000;
}

void cerrar_dues(){
  RetardoPararIzquierda   = millis();
  RetardoAbrirDerecha     = RetardoPararIzquierda;
  RetardoPararDerecha     = RetardoAbrirDerecha + 15000;
}

void abrir_derecha(){
  RetardoAbrirDerecha     = millis();
}

void cerrar_derecha(){
  RetardoPararDerecha     = millis();
}

void abrir_cerrar_derecha(){
  RetardoAbrirDerecha     = millis();
  RetardoPararDerecha     = RetardoAbrirDerecha + 40000;
}

void parar(){
  motorD.setSpeed(0);
  motorE.setSpeed(0);
  RetardoAbrirDerecha       = 0;
  RetardoAbrirIzquierda     = 0;
  RetardoPararDerecha       = 0;
  RetardoIzquierda          = 0;
  MaximTempsAbrirIzquierda  = 0;
  MaximTempsAbrirDerecha    = 0;
  RetardoPararDerecha       = 0;
  RetardoPararIzquierda     = 0;

}
void parar_izquierda(){
  motorE.setSpeed(0);
  RetardoAbrirIzquierda     = 0;
  RetardoIzquierda          = 0;
  MaximTempsAbrirIzquierda  = 0;
  RetardoPararIzquierda     = 0;
}

void loop() {
  actual_millis = millis();

  if (RetardoAbrirDerecha != 0 && RetardoAbrirDerecha < actual_millis) {
      RetardoAbrirDerecha = 0;
      motorD.setSpeed(255);
  }

  if (RetardoAbrirIzquierda != 0 && RetardoAbrirIzquierda < actual_millis) {
    RetardoAbrirIzquierda = 0;
    motorE.setSpeed(255);
  }

  if (RetardoPararDerecha != 0 && RetardoPararDerecha < actual_millis) {
    RetardoPararDerecha = 0;
    motorD.setSpeed(-255);
  }

  if (RetardoIzquierda != 0 && RetardoIzquierda < actual_millis) {
    RetardoIzquierda = 0;
    motorE.setSpeed(255);
  }

  if (MaximTempsAbrirIzquierda != 0 && MaximTempsAbrirIzquierda < actual_millis) {
    MaximTempsAbrirIzquierda=0,
    motorE.setSpeed(-255);
  }

  if (MaximTempsAbrirDerecha != 0 &&MaximTempsAbrirDerecha < actual_millis) {
    MaximTempsAbrirDerecha = 0;
    motorD.setSpeed(-255);
  }

  if (RetardoPararDerecha != 0 && RetardoPararDerecha < actual_millis) {
    RetardoPararDerecha = 0;
    motorD.setSpeed(0);
  }
  if (RetardoPararIzquierda != 0  && RetardoPararIzquierda < actual_millis) {
    RetardoPararIzquierda = 0;
    motorE.setSpeed(0);
  }

  estat = 99;

  if (Serial.available()>0){
      int estat = Serial.read();

      switch(estat){
        case '0': abrir_dues();
                  break;
        case '1': parar();
                  break;
        case '2': cerrar_dues();
                  break;
        case '3': abrir_derecha();
                  break;
        case '4': cerrar_derecha();
                  break;
      }   
  }
  // Actualiza la instancia Bounce
  debouncer.update();

  // 50 mseg de antirebotes
  bool value = debouncer.read();

  if (value == HIGH){
      abrir_cerrar_derecha();
  }
}

Muchas gracias, Surbyte.

Después me pongo con ello.

con la librería Bounce2 solo agregas dos objetos nuevos

Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();

con todo lo que va asociado claro como en el setup, la definición del pin

#define FINAL_IZQUIERDA   8
#define FINAL_DERECHA     9

// en el setup
    pinMode(FINAL_IZQUIERDA, INPUT);
    pinMode(FINAL_DERECHA, INPUT);
    debouncer2.attach(FINAL_IZQUIERDA);
    debouncer2.interval(100); // interval in ms
    debouncer3.attach(FINAL_DERECHA);
    debouncer3.interval(100); // interval in ms

// en el loop 

 // Actualiza la instancia Bounce
  debouncer2.update();
  debouncer3.update();

  // 100 mseg de antirebotes
  bool value2 = debouncer2.read();          // FINAL CARRERA IZQUIERDA
  bool value3 = debouncer3.read();          // FINAL CARRERA DERECHA

Gracias!!!