Proyecto: puerta enrollable

Buenas a todos, ante todo soy nuevo en el foro y disculpadme si incumplo alguna norma, si me avisáis corrijo lo que haga falta.

Mi intención es probar de hacer una puerta enrollable estilo a la que podéis conocer como la adjuntada llamada "Puerta enrollable.jpg", pero mis conocimientos técnicos son un poco escasos aunque llego a defenderme. Sobre Arduino, aún no tengo mi kit inicial para empezar a hacer pruebas, pero después de haber leído el "Libro de proyectos de Arduino Starter Kit", me he animado a llegar hasta lo que voy a compartir en este post.

Cuando lo tenga más avanzado y pueda probar algo, subiré el código a Github para que sea más fácil compartirlo públicamente y que podamos compartir cambios y mejoras.

Por el momento me lo he planteado cogiendo ideas del proyecto para la puerta de gallinero, donde la puerta sube y baja hasta unos finales de carrera, a lo que le he añadido un control de presencia (Laser Break Beam Sensor según Fritzing, en la vida real creo que son como la imagen adjuntada llamada "Sensor.jpg") en la zona de la persiana para que no baje en caso de haber alguien en su zona, y 2 botones de subir y bajar para ponerlos a ambos lados, en substitución de su sensor lumínico para determinar cuando es de día o noche para que se abra o cierre.

Sensor.jpg

Esto me gustaría complementarlo con otros sensores de presencia, para que no sea necesario pulsar los botones de abrir y cerrar, pero para empezar ya tengo algo con que ir probando. A la vez el propio Arduino controlaría 2 relés que activarían un motor (todavía por determinar cual) para que este pueda subir o bajar, por ahora me he basado en la explicación para un motor de lavadora, que creo que será lo más similar, aunque no sé si será el más adecuado.

El esquema del circuito que llevo preparado hasta ahora es la imagen adjuntada con nombre "Persiana.png"

/*
 * Control automático y manual para subir y bajar una puerta enrollable con finales de carrera y 
 * control de presencia en medio de la puerta.
 * 
 * Ideas extraídas de:
 *  - Controlar motor lavadora con Arduino Teensy 2.0 ++: http://forum.arduino.cc/index.php?topic=198833.0
 *  - Proyecto puerta de gallinero con BH1750 y Arduino Pro Mini: http://forum.arduino.cc/index.php?topic=430607.0
 *  
 * Materiales:
 *  - 4 Pulsadores
 *  - 2 Resistencias de 10K
 *  - 1 Imán de neodimio
 *  - 2 Reed Swith
 *  - 2 Resistencias de 1K
 *  - 2 Led Verde
 *  - 2 Led Naranja
 *  - 2 Led Rojo
 *  - 3 Resistencias de 220
 *  - 2 Reles
 *  - 1 Motor (No se cual aún, que permita enroscar una PuertaEnrollable)
 *  - 1 Detector de presencia (No se cual aún)
 */

const int PulsadorArriba = 2;
const int PulsadorAbajo = 3;
const int LedVerde = 4;
const int LedNaranja = 5;
const int LedRojo = 6;
const int Rele1 = 7;
const int Rele2 = 8;
const int Rele3 = 9;
const int DetectorPresencia = 11;
const int FinCarreraInferior = 12;
const int FinCarreraSuperior = 13;

int pulsadorArribaEstado = 0;
int pulsadorAbajoEstado = 0;

void setup() {
  // Inicialización
  pinMode(PulsadorArriba, INPUT);
  pinMode(PulsadorAbajo, INPUT);
  pinMode(Rele1, OUTPUT);
  pinMode(Rele2, OUTPUT);
  pinMode(Rele3, OUTPUT);
  pinMode(DetectorPresencia, INPUT_PULLUP);
  pinMode(FinCarreraSuperior, INPUT_PULLUP);
  pinMode(FinCarreraInferior, INPUT_PULLUP);
  pinMode(LedVerde, OUTPUT);
  pinMode(LedNaranja, OUTPUT);
  pinMode(LedRojo, OUTPUT);
}

// Código principal
void loop() {
  // Leemos estado pulsados ARRIBA / ABAJO
  pulsadorArribaEstado = digitalRead(PulsadorArriba);
  pulsadorAbajoEstado = digitalRead(PulsadorAbajo);
  FinCarreraSuperiorEstado = digitalRead(FinCarreraSuperior);
  FinCarreraInferiorEstado = digitalRead(FinCarreraInferior);
  
  // Damos prioridad al pulsador de subir!
  if (pulsadorArribaEstado == HIGH) {
    // El pulsador de subir está pulsado
    subirPuertaEnrollable();
  } else if (pulsadorAbajoEstado == HIGH) {
    // El pulsador de bajar está pulsado
    bajarPuertaEnrollable();
  } else {
    // Si no hay orden de subir o bajar, revisamos los finales de carrera para saber donde estamos
    if (FinCarreraSuperiorEstado == LOW) {
      // La PuertaEnrollable esta subida
      Serial.print("Puerta enrollable subida...");
    } else if (FinCarreraInferiorEstado == LOW) {
      // La PuertaEnrollable esta bajada
      Serial.print("Puerta enrollable bajada...");
    } else {
      // En caso de duda, la subimos para evitar posibles accidentes
      subirPuertaEnrollable();
    }
  }
}

void subirPuertaEnrollable() {
  // Subir hasta fin carrera
  subirHastaFinCarrera();
  // Aviso lumínicio
  lucesPasoAbierto();
}

void bajarPuertaEnrollable() {
  // Aviso lumínicio
  lucesPasoCerrado();
  // Bajar hasta fin carrera
  bajarHastaFinCarrera();
}

void subirHastaFinCarrera() {
  Serial.print("Subiendo puerta enrollable...");
  FinCarreraSuperiorEstado = digitalRead(FinCarreraSuperior);
  while(FinCarreraSuperiorEstado == LOW) {
    conectarMotor();
    digitalWrite(Rele1, HIGH);    // Rele1 ON
    digitalWrite(Rele2, LOW);     // Rele2 OFF
  }
  desconectarMotor();
}

void bajarHastaFinCarrera() {
  Serial.print("Bajando puerta enrollable...");
  FinCarreraInferiorEstado = digitalRead(FinCarreraInferior);
  DetectorPresenciaEstado = digitalRead(DetectorPresencia);
  while(FinCarreraInferiorEstado == LOW) {
    if(DetectorPresenciaEstado == LOW) {
      conectarMotor();
      digitalWrite(Rele1, LOW);   // Rele1 OFF
      digitalWrite(Rele2, HIGH);  // Rele2 ON
    } else {
      subirPuertaEnrollable();
    }
    desconectarMotor();
  }
}

void desconectarMotor() {
  digitalWrite(Rele3, LOW);
}

void conectarMotor() {
  digitalWrite(Rele3, HIGH);
}

void lucesPasoAbierto() {
  digitalWrite(LedVerde, HIGH);   // enciende el LED
  digitalWrite(LedNaranja, HIGH); // enciende el LED
  digitalWrite(LedRojo, LOW);     // apaga el LED
}

void lucesPasoCerrado() {
  digitalWrite(LedVerde, LOW);    // apaga el LED
  digitalWrite(LedNaranja, LOW);  // apaga el LED
  digitalWrite(LedRojo, HIGH);    // enciende el LED
}

Las funciones de subirHastaFinCarrera y bajarHastaFinCarrera son en las que tengo que entretenerme un poco más, para valorar mejor como subir y bajar hasta el final de carrera, controlando además que no se haya interrumpido el sensor de presencia. Pero así lo comparto con vosotros y si hay alguien que domine mejor el tema, ya puedo empezar a recibir feedback para replantearme hacer cambios.

Sensor.jpg

No me he dado cuenta de que no lo he puesto dentro de Proyectos, alguien me lo podría mover por favor?

Bienvenido al foro Arduino shawe.
Debo felicitarte por ser tu primer Topico y presentarlo de modo perfecto.
Primero con buenas fotos, esquemas y códigos pero lo mas importante, haciéndolo respetando las normas del foro.
Eso esta dentro del 1% o menos de las personas que llegan a este foro y te aseguro que valoro mucho eso porque me la paso intentando corregir los hilos.

Bueno voy a mirar detenidamente tu código y luego te haré algún comentario si lo requiere. Pero eres metódico y eso da poco margen para el error.

Primera observación

// Damos prioridad al pulsador de subir!
  if (pulsadorArribaEstado == HIGH) {
    // El pulsador de subir está pulsado
    subirPuertaEnrollable();
  } else if (pulsadorAbajoEstado == HIGH) {
    // El pulsador de bajar está pulsado
    bajarPuertaEnrollable();
  } else {
    // Si no hay orden de subir o bajar, revisamos los finales de carrera para saber donde estamos
    if (FinCarreraSuperiorEstado == LOW) {
      // La PuertaEnrollable esta subida
      Serial.print("Puerta enrollable subida...");
    } else if (FinCarreraInferiorEstado == LOW) {
      // La PuertaEnrollable esta bajada
      Serial.print("Puerta enrollable bajada...");
    } else {
      // En caso de duda, la subimos para evitar posibles accidentes
      subirPuertaEnrollable();
    }
  }

Al esperar los estados de este modo, ejecutas varias veces las acciones.
A mi me gusta y da buenos resultados ver los flancos, eso implica por cada sensor leído, guardar al final de las comparaciones su estado con una variable llamada nombreAnt (anterior) y al momento de comparar ver el flanco 0-1 o 1-0 según sea necesario o como tengas conectado los sensores.
Entonces lo mismo quedaría así

void loop() {
  // Leemos estado pulsados ARRIBA / ABAJO
  pulsadorArribaEstado      = digitalRead(PulsadorArriba);
  pulsadorAbajoEstado       = digitalRead(PulsadorAbajo);
  FinCarreraSuperiorEstado  = digitalRead(FinCarreraSuperior);
  FinCarreraInferiorEstado  = digitalRead(FinCarreraInferior);
  
  // Damos prioridad al pulsador de subir!
  if (pulsadorArribaEstado && !pulsadorArribaEstadoAnt) { // El pulsador de subir está pulsado
      subirPuertaEnrollable();
  } 
  if (pulsadorAbajoEstado && !pulsadorAbajoEstadoAnt) {   // El pulsador de bajar está pulsado   
      bajarPuertaEnrollable();
  } 
  pulsadorArribaEstadoAnt = pulsadorArribaEstado;
  pulsadorAbajoEstadoAnt  = pulsadorAbajoEstado;

  // Si no hay orden de subir o bajar, revisamos los finales de carrera para saber donde estamos
  if (!FinCarreraSuperiorEstado && FinCarreraSuperiorEstadoAnt) {
      // La PuertaEnrollable esta subida
      Serial.print("Puerta enrollable subida...");
  } 

  if (!FinCarreraInferiorEstado && FinCarreraInferiorEstadoAnt) {
      // La PuertaEnrollable esta bajada
      Serial.print("Puerta enrollable bajada...");
  } 
  FinCarreraSuperiorEstadoAnt = FinCarreraSuperiorEstado;
  FinCarreraInferiorEstadoAnt = FinCarreraInferiorEstado;

  // En caso de duda, la subimos para evitar posibles accidentes
  // subirPuertaEnrollable();
  
}

No entendí lo de subirPuertaEnrrollable();

surbyte:
Bienvenido al foro Arduino shawe.
Debo felicitarte por ser tu primer Topico y presentarlo de modo perfecto.
Primero con buenas fotos, esquemas y códigos pero lo mas importante, haciéndolo respetando las normas del foro.
Eso esta dentro del 1% o menos de las personas que llegan a este foro y te aseguro que valoro mucho eso porque me la paso intentando corregir los hilos.

Bueno voy a mirar detenidamente tu código y luego te haré algún comentario si lo requiere. Pero eres metódico y eso da poco margen para el error.

Estuve ayudando un tiempo en HTCMania, y se lo que es que no se cumplan las normas cada 2x3 :wink:

De todos modos, no he encontrado fácilmente las normas por aquí hasta que he publicado mi post, pero ya tenía claro lo que quería poner y sólo he tenido que editarlo con las imágenes adjuntadas para que se vieran directamente.

Desde que he publicado el post, he estado informandome del tipo de motores que hay para estos fines y creo que estos tipos son los que puedo necesitar o por lo menos similares:

También debería enterarme de las monturas y ejes (o como se llame a la estructura base en si misma), y de lo que pesan las cortinas de PVC enroscable, pero encuentro poca información al respecto. Tengo un cliente que es aluminista, tal vez me pueda orientar e incluso facilitarme esta información y precios.

Para tener una orientación de ejemplo y precios publicados sin pedir presupuesto:

surbyte:
No entendí lo de subirPuertaEnrrollable();

Ahora revisaré un momento todo lo que me has comentado para entender mejor tus sugerencias de cambios.

Sobre lo de subirPuertaEnrollable, es porqué lo he separado en 2 funciones de subir, la que llamo desde el código principal, que da orden de subir hasta el final y luego encender las luces para avisar de que se puede pasar, y la que gestionaría el movimiento de subir hasta el fin de carrera, que es donde debería estar la lógica "más compleja".

Por lo que he visto, dependiendo del tipo de motor a utilizar, el propio motor ya tiene un sistema de control de fin de carrera, con lo que se podría eliminar este control del Arduino, y modificarlo con sensores de proximidad para ambos lados, para que se pueda abrir por proximidad, que era lo siguiente que quería mirar en cuanto tuviera más información relevante y que clarificase la situación.

Gracias por la explicación, algunos de esos cambios los he puesto, pero no todos y continúo explicando porqué no todos, aunque estoy abierto a todo, porque no estoy acostumbrado a pensar empleando mecanismos físicos.

Tu me has indicado lo siguiente:

surbyte:

void loop() {

// Leemos estado pulsados ARRIBA / ABAJO
  pulsadorArribaEstado      = digitalRead(PulsadorArriba);
  pulsadorAbajoEstado      = digitalRead(PulsadorAbajo);
  FinCarreraSuperiorEstado  = digitalRead(FinCarreraSuperior);
  FinCarreraInferiorEstado  = digitalRead(FinCarreraInferior);
 
  // Damos prioridad al pulsador de subir!
  if (pulsadorArribaEstado && !pulsadorArribaEstadoAnt) { // El pulsador de subir está pulsado
      subirPuertaEnrollable();
  }
  if (pulsadorAbajoEstado && !pulsadorAbajoEstadoAnt) {  // El pulsador de bajar está pulsado 
      bajarPuertaEnrollable();
  }
  pulsadorArribaEstadoAnt = pulsadorArribaEstado;
  pulsadorAbajoEstadoAnt  = pulsadorAbajoEstado;

// Si no hay orden de subir o bajar, revisamos los finales de carrera para saber donde estamos
  if (!FinCarreraSuperiorEstado && FinCarreraSuperiorEstadoAnt) {
      // La PuertaEnrollable esta subida
      Serial.print("Puerta enrollable subida...");
  }

if (!FinCarreraInferiorEstado && FinCarreraInferiorEstadoAnt) {
      // La PuertaEnrollable esta bajada
      Serial.print("Puerta enrollable bajada...");
  }
  FinCarreraSuperiorEstadoAnt = FinCarreraSuperiorEstado;
  FinCarreraInferiorEstadoAnt = FinCarreraInferiorEstado;

// En caso de duda, la subimos para evitar posibles accidentes
  // subirPuertaEnrollable();
 
}

Así que con eso entiendo que haría lo siguiente:

Si se quiere subir y no se estaba subiendo, se sube
Si se quiere bajar y no se estaba bajando, se baja
Si no esta en el fin de carrera superior, y no lo estaba, se sube
Si no esta en el fin de carrera inferior, y no lo estaba, se baja

Cómo son pulsadores independientes y no hay un sino, entiendo que podría hacer ambas acciones seguidamente, y mi idea de anidar if, else-if, else era intentar evitar esa situación.

La otra cosa es que tu estás consultando variables que no has sido definidas previamente, eso no podría llevar a problemas también, aunque sólo sea a veces?

He hecho algún cambio más incluyendo que se refresquen los valores en las ordenes de bajar y subir hasta fin de carrera, porqué entiendo que no refrescaba el valor tras entrar en el while, en el que tal vez sería mejor usar directamente el digitalRead en las condiciones que no una variable previamente asignada.

/*
 * Control automático y manual para subir y bajar una puerta enrollable con finales de carrera y 
 * control de presencia en medio de la puerta.
 * 
 * Ideas extraídas de:
 *  - Controlar motor lavadora con Arduino Teensy 2.0 ++: http://forum.arduino.cc/index.php?topic=198833.0
 *  - Proyecto puerta de gallinero con BH1750 y Arduino Pro Mini: http://forum.arduino.cc/index.php?topic=430607.0
 *  
 * Materiales:
 *  - 4 Pulsadores
 *  - 2 Resistencias de 10K
 *  - 1 Imán de neodimio
 *  - 2 Reed Swith
 *  - 2 Resistencias de 1K
 *  - 2 Led Verde
 *  - 2 Led Naranja
 *  - 2 Led Rojo
 *  - 3 Resistencias de 220
 *  - 2 Reles
 *  - 1 Motor (No se cual aún, que permita enroscar una PuertaEnrollable)
 *  - 1 Detector de presencia (No se cual aún)
 */

const int PulsadorArriba = 2;
const int PulsadorAbajo = 3;
const int LedVerde = 4;
const int LedNaranja = 5;
const int LedRojo = 6;
const int Rele1 = 7;
const int Rele2 = 8;
const int Rele3 = 9;
const int DetectorPresencia = 11;
const int FinCarreraInferior = 12;
const int FinCarreraSuperior = 13;

int pulsadorArribaEstado = 0;
int pulsadorAbajoEstado = 0;

void setup() {
  // Inicialización
  pinMode(PulsadorArriba, INPUT);
  pinMode(PulsadorAbajo, INPUT);
  pinMode(Rele1, OUTPUT);
  pinMode(Rele2, OUTPUT);
  pinMode(Rele3, OUTPUT);
  pinMode(DetectorPresencia, INPUT_PULLUP);
  pinMode(FinCarreraSuperior, INPUT_PULLUP);
  pinMode(FinCarreraInferior, INPUT_PULLUP);
  pinMode(LedVerde, OUTPUT);
  pinMode(LedNaranja, OUTPUT);
  pinMode(LedRojo, OUTPUT);
}

// Código principal
void loop() {
  // Leemos estado pulsados ARRIBA / ABAJO
  pulsadorArribaEstado = digitalRead(PulsadorArriba);
  pulsadorAbajoEstado = digitalRead(PulsadorAbajo);
  // Leemos estados de fines de carrera SUPERIOR / INFERIOR
  FinCarreraSuperiorEstado = digitalRead(FinCarreraSuperior);
  FinCarreraInferiorEstado = digitalRead(FinCarreraInferior);
  
  // Damos prioridad al pulsador de subir!
  if (pulsadorArribaEstado && !pulsadorArribaEstadoAnt) {
    // El pulsador de subir está pulsado
    subirPuertaEnrollable();
  } else if (pulsadorAbajoEstado && !pulsadorAbajoEstadoAnt) {
    // El pulsador de bajar está pulsado
    bajarPuertaEnrollable();
  } else {
    // Si no hay orden de subir o bajar, revisamos los finales de carrera para saber donde estamos
    if (!FinCarreraSuperiorEstado && FinCarreraSuperiorEstadoAnt) {
      // La PuertaEnrollable esta subida
      Serial.print("Puerta enrollable subida...");
    } else if (!FinCarreraInferiorEstado && FinCarreraInferiorEstadoAnt) {
      // La PuertaEnrollable esta bajada
      Serial.print("Puerta enrollable bajada...");
    } else {
      // En caso de duda, la subimos para evitar posibles accidentes
      subirPuertaEnrollable();
    }
    // Guardamos el estado anterior del valor
    FinCarreraSuperiorEstadoAnt = FinCarreraSuperiorEstado;
    FinCarreraInferiorEstadoAnt = FinCarreraInferiorEstado;
  }
  // Guardamos el estado anterior del valor
  pulsadorArribaEstadoAnt = pulsadorArribaEstado;
  pulsadorAbajoEstadoAnt  = pulsadorAbajoEstado;
}

void subirPuertaEnrollable() {
  // Subir hasta fin carrera
  subirHastaFinCarrera();
  // Aviso lumínicio
  lucesPasoAbierto();
}

void bajarPuertaEnrollable() {
  // Aviso lumínicio
  lucesPasoCerrado();
  // Bajar hasta fin carrera
  bajarHastaFinCarrera();
}

void subirHastaFinCarrera() {
  Serial.print("Subiendo puerta enrollable...");
  FinCarreraSuperiorEstado = digitalRead(FinCarreraSuperior);
  while(FinCarreraSuperiorEstado == LOW) {
    conectarMotor();
    digitalWrite(Rele1, HIGH);    // Rele1 ON
    digitalWrite(Rele2, LOW);     // Rele2 OFF
    //Refrescamos valor
    FinCarreraSuperiorEstado = digitalRead(FinCarreraSuperior);
  }
  desconectarMotor();
}

void bajarHastaFinCarrera() {
  Serial.print("Bajando puerta enrollable...");
  FinCarreraInferiorEstado = digitalRead(FinCarreraInferior);
  DetectorPresenciaEstado = digitalRead(DetectorPresencia);
  while(FinCarreraInferiorEstado == LOW) {
    if(DetectorPresenciaEstado == LOW) {
      conectarMotor();
      digitalWrite(Rele1, LOW);   // Rele1 OFF
      digitalWrite(Rele2, HIGH);  // Rele2 ON
      //Refrescamos valores
      FinCarreraInferiorEstado = digitalRead(FinCarreraInferior);
      DetectorPresenciaEstado = digitalRead(DetectorPresencia);
    } else {
      subirPuertaEnrollable();
    }
    desconectarMotor();
  }
}

void desconectarMotor() {
  digitalWrite(Rele3, LOW);
}

void conectarMotor() {
  digitalWrite(Rele3, HIGH);
}

void lucesPasoAbierto() {
  digitalWrite(LedVerde, HIGH);   // enciende el LED
  digitalWrite(LedNaranja, HIGH); // enciende el LED
  digitalWrite(LedRojo, LOW);     // apaga el LED
}

void lucesPasoCerrado() {
  digitalWrite(LedVerde, LOW);    // apaga el LED
  digitalWrite(LedNaranja, LOW);  // apaga el LED
  digitalWrite(LedRojo, HIGH);    // enciende el LED
}

Creo que tengo un motor de elevalunas de coche, que podría hacer la función para una maqueta, así que cuando reciba mi kit, tendré algo con que testearlo todo con características similares a las reales.

Ayer me llegó mi kit de Arduino, concretamente este este sobre el esquema original, lo que he cambiado es que no he puesto reles, en su lugar he puesto 3 leds, y no he puesto nada en los detectores, basicamente para comprobar que daría orden de subir y bajar con los botones.

Aparentemente, el código se flashea correctamente, desconecto el arduino de la corriente y conecto la placa de expansión encima del Arduino (que es donde he puesto todas las conexiones) y al conectar de nuevo el Arduino, no enciende ninguna lucecita. Alguna idea de que he podido hacer mal?

Si sirve de algo, que seguramente si, no he probado a seguir ningun tutorial básico, directamente esto es lo primero que pruebo en Arduino, antes de haber hecho pruebas básicas.

O sea que la placa de expansión te genera algún problema.
Mira si no hay corto. Prueba en la placa de expansión desconectada del arduino y sin tensión, si entre lo que indica como 5V y GND hay circuito abierto o el tester dice que hay un circuito en corto circuito.

surbyte:
O sea que la placa de expansión te genera algún problema.
Mira si no hay corto. Prueba en la placa de expansión desconectada del arduino y sin tensión, si entre lo que indica como 5V y GND hay circuito abierto o el tester dice que hay un circuito en corto circuito.

Eso he pensado surbyte, aunque no descarto que lo haya conectado mal, a pesar de haber seguido mi propio esquema :wink:

A ver si me acuerdo el lunes de traer el tester del trabajo, y por lo menos puedo descartar posibles problemas.