Puerta Corredera de Garaje Automatizada con Arduino Nano
Componentes y materiales
| Arduino Nano R3 | 1 |
| Protoboard (genérica) | 1 |
| Pantalla OLED 0.96" 128x64 (SPI, Adafruit SSD1306) | 1 |
| Módulo de relés 4 canales (genérico) | 1 |
| Fuente conmutada 5V desde 220VAC (mini) | 1 |
| Pulsador 12 mm (reset de alarma) | 1 |
| Motor AC 220V original de la puerta | 1 |
| Receptor de radiofrecuencia con mandos (comercial) | 1 |
| Fotocélula de seguridad (barrera IR) | 1 |
| Finales de carrera (abierto/cerrado) | 2 |
Sobre el proyecto
Antecedentes
El controlador original de la puerta corredera falló por un cortocircuito causado por un lagarto que entró en la electrónica de 220V. En lugar de comprar uno nuevo, se diseñó un controlador basado en Arduino Nano con mejoras de seguridad y funcionalidad.
⚠️ ADVERTENCIA: ALTA TENSIÓN
Este proyecto manipula 220VAC (o 110VAC). Solo para personas con experiencia en instalaciones eléctricas. Riesgo de electrocución, incendio y daño a equipos. Siempre simule y pruebe con cargas resistivas antes de conectar el motor real. Use relés dimensionados para la corriente del motor y aislamiento adecuado.
Arquitectura del sistema
- Unidad de control principal: Arduino Nano + OLED + módulo relés (3 usados: motor abrir, motor cerrar, luz señalización).
- Potencia: Relés de 220VAC para motor y luz; fuente 5V para electrónica.
- Entradas: Fotocélula (seguridad), finales de carrera (abierto/cerrado), señal "ABRIR" del receptor RF (contacto seco).
- Salidas: Relé motor abrir, relé motor cerrar, relé luz intermitente.
Pinout (resumen)
| Señal | Pin Nano | Nota |
|---|---|---|
| Fotocélula | D2 | INPUT_PULLUP, activo LOW |
| Final cerrado (TANCAT) | D7 | INPUT_PULLUP |
| Final abierto (OBERT) | D3 | INPUT_PULLUP |
| Orden abrir (OBRIR) desde RF | D4 | INPUT_PULLUP, activo LOW |
| Relé luz (BOMBETA) | D5 | Relé 1, activo LOW |
| Relé motor abrir (MOTOR_OBRIR) | D6 | Relé 2, activo LOW |
| Relé motor cerrar (MOTOR_TANCAR) | D12 | Relé 3, activo LOW |
| OLED SPI: MOSI=D11, CLK=D13, DC=D9, CS=D10, RST=D8 |
Lógica de funcionamiento (máquina de estados)
El código usa goto para transiciones entre etiquetas que representan estados. Aunque no es estilo académico, es funcional y claro para esta aplicación.
- BUCLE_PRINCIPAL: Espera orden "ABRIR" (pin OBRIR LOW). Refresca OLED con estado de sensores cada 2s. Si hay avería (AVARIA), parpadea luz 1 min.
- SEQUENCIA_OBERTURA: Activa motor abrir + luz. Tiempo máx 28s (interval). Si llega final abierto (OBERT HIGH) → PORTA_OBERTA. Si se presiona ABRIR durante apertura → para motor, espera orden cerrar → SEQUENCIA_TANCAMENT. Refresca OLED con contador segundos. Luz parpadea lento (1s).
- PORTA_OBERTA: Puerta totalmente abierta. Espera 30s (interval) o nueva orden ABRIR → SEQUENCIA_TANCAMENT. OLED muestra cuenta atrás. Luz parpadeo compuesto (corto 100ms / largo 2s).
- SEQUENCIA_TANCAMENT: Activa motor cerrar + luz. Tiempo máx 28s. Si llega final cerrado (TANCAT HIGH) → BUCLE_PRINCIPAL. Si se presiona ABRIR → para, espera orden abrir → SEQUENCIA_OBERTURA. Si fotocélula detecta obstáculo (HIGH) → para motor, espera 1s, vuelve a SEQUENCIA_OBERTURA (seguridad). Luz parpadea rápido (300ms).
Pantalla OLED
Muestra en tiempo real:
- Fase actual (abriendo, cerrando, espera, bucle principal...)
- Tiempo transcurrido en la acción principal (segundos)
- Estado de fotocélula, finales de carrera, orden ABRIR
- Indicador de avería (AVARIA)
Útil para ajuste fino (tiempos máximos, lógica de seguridad) sin necesidad de PC conectado.
Diagramas de flujo
Ver imágenes en sección Flow Charts: tres diagramas cubren bucle principal, secuencia apertura y secuencia cierre con todas las ramas de seguridad.
Código (versión comentada en inglés)
/*********************************************************************
* Automatismo para puerta corredera motorizada
*********************************************************************/
// Vocabulario: Bucle principal=Main loop, Sequencia Obertura=Opening sequence,
// Sequencia Tancament=Closing sequence, Obrir=Open, Tancar=Close,
// Bombeta=Light bulb, Porta=Gate, Avaria=Failure, Temps=Time, Recorregut=Travel
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Pines automatismo
int FOTOCELULA = 2;
int BOMBETA = 5; // Relay 1
int TANCAT = 7;
int OBERT = 3;
int MOTOR_OBRIR = 6; // Relay 2
int MOTOR_TANCAR = 12; // Relay 3
int OBRIR = 4;
// Pines OLED SPI
#define OLED_MOSI 11
#define OLED_CLK 13
#define OLED_DC 9
#define OLED_CS 10
#define OLED_RESET 8
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
// Variables globales
unsigned long TEMPS_PORTA_OBERTA = 20000;
unsigned long TEMPS_MAXIM_RECORREGUT = 15000;
int interval = 1000;
int TEMPS_DISPLAY = 1;
int DURADA = 300;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long TEMPS_LLUM = 1000;
bool LLUM = false;
bool AVARIA = false;
void setup() {
digitalWrite(MOTOR_OBRIR, HIGH); // relés activo LOW
digitalWrite(MOTOR_TANCAR, HIGH);
digitalWrite(BOMBETA, HIGH);
pinMode(FOTOCELULA, INPUT_PULLUP);
pinMode(TANCAT, INPUT_PULLUP);
pinMode(OBERT, INPUT_PULLUP);
pinMode(OBRIR, INPUT_PULLUP);
pinMode(BOMBETA, OUTPUT);
pinMode(MOTOR_OBRIR, OUTPUT);
pinMode(MOTOR_TANCAR, OUTPUT);
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC);
display.display(); delay(1000);
display.clearDisplay(); display.display();
display.setTextSize(1); display.setTextColor(WHITE);
}
void loop() {
BUCLE_PRINCIPAL:
delay(2000);
previousMillis = millis();
while (digitalRead(OBRIR) == HIGH) { // espera orden ABRIR (LOW)
actualizarOLED("BUCLE PRINCIPAL");
if (AVARIA && (millis() - previousMillis < 60000)) digitalWrite(BOMBETA, LOW);
else digitalWrite(BOMBETA, HIGH);
}
goto SEQUENCIA_OBERTURA;
SEQUENCIA_OBERTURA:
interval = 28000;
previousMillis = millis();
digitalWrite(MOTOR_OBRIR, LOW); digitalWrite(BOMBETA, LOW); delay(1000);
A:
if (digitalRead(OBERT) == HIGH) goto PORTA_OBERTA;
if (digitalRead(OBRIR) == LOW) { // nueva orden ABRIR durante apertura
actualizarOLED("Esperant ordre per tancar");
digitalWrite(MOTOR_OBRIR, HIGH); digitalWrite(BOMBETA, HIGH); delay(1000);
while (digitalRead(OBRIR) == HIGH) {}; goto SEQUENCIA_TANCAMENT;
}
actualizarTiempoYOLED("Obrint porta");
if ((millis() - previousMillis) >= interval) { digitalWrite(MOTOR_OBRIR, HIGH); AVARIA = true; }
parpadearLuz(1000); // lento
goto A;
SEQUENCIA_TANCAMENT:
interval = 28000;
previousMillis = millis();
digitalWrite(MOTOR_TANCAR, LOW); digitalWrite(BOMBETA, LOW);
if (digitalRead(TANCAT) == LOW) delay(1000);
B:
if (digitalRead(TANCAT) == HIGH) { digitalWrite(MOTOR_TANCAR, HIGH); digitalWrite(BOMBETA, HIGH); goto BUCLE_PRINCIPAL; }
if (digitalRead(OBRIR) == LOW) { // nueva orden ABRIR
actualizarOLED("Esperant ordre per obrir");
digitalWrite(MOTOR_TANCAR, HIGH); digitalWrite(BOMBETA, HIGH); delay(1000);
while (digitalRead(OBRIR) == HIGH) {}; goto SEQUENCIA_OBERTURA;
}
if (digitalRead(FOTOCELULA) == HIGH) { // obstáculo
digitalWrite(MOTOR_TANCAR, HIGH); delay(1000); goto SEQUENCIA_OBERTURA;
}
actualizarTiempoYOLED("Tancant porta");
if ((millis() - previousMillis) >= interval) { digitalWrite(MOTOR_TANCAR, HIGH); AVARIA = true; goto BUCLE_PRINCIPAL; }
parpadearLuz(300); // rápido
goto B;
PORTA_OBERTA:
interval = 30000;
previousMillis = millis();
digitalWrite(MOTOR_OBRIR, HIGH); delay(500);
C:
if (digitalRead(OBRIR) == LOW) goto SEQUENCIA_TANCAMENT;
actualizarTiempoYOLED("Porta Oberta completament");
if ((millis() - previousMillis) >= interval) goto SEQUENCIA_TANCAMENT;
parpadearCompuesto(); // 100ms ON / 2000ms OFF
goto C;
}
// Funciones auxiliares (actualizarOLED, actualizarTiempoYOLED, parpadearLuz, parpadearCompuesto)
// ... implementadas en el código completo original.
El código completo incluye las funciones auxiliares de refresco OLED y parpadeo. La versión original en catalán está también disponible en el proyecto.
Esquemáticos
Ver sección Schematics: incluye esquemático Fritzing, lista de pines (pinouts.txt) y foto del cableado real con módulo relés y OLED en protoboard.
Proceso de manufactura
- Breakout compacto DHT de temperatura y humedad para Raspberry Pi – ATtiny85 y DHT22/DHT11
- Los mejores accesorios para aprovechar al máximo tu Raspberry Pi
- SIGHT: Gafas Inteligentes para Capacitar a Personas Ciegas
- Construcción de un dron submarino con Raspberry Pi: Diseño, desarrollo y ensamblaje
- Cómo seleccionar amortiguadores de alta calidad para su vehículo
- Sierra de Cinta Manual: Solución de Corte Duradera y Portátil para Cualquier Proyecto
- ¿Qué es una Prensa de Potencia Automática? – La Máquina Definitiva de Conformado de Chapa Metálica
- Impulsando el Crecimiento: Cómo la Automatización Empodera a las PYMEs para un Futuro Brillante
- Una despedida sentida: mi viaje de 40 años en la edición
- Pentodos: El Quinto Elemento para Mejorar el Rendimiento del Tubo
- Automatización de cabezal deslizante de precisión para torneado suizo y de producción