Porte de garage coulissante automatisée avec Arduino Nano
Composants nécessaires
| Composant | Quantité | Notes |
|---|---|---|
| Arduino Nano R3 | 1 | Format compact, idéal pour boîtier |
| Écran OLED 0,96" 128x64 (SPI) | 1 | Adafruit SSD1306, pour diagnostic/local |
| Module relais 4 canaux (5V) | 1 | 3 relais utilisés : moteur ouverture, moteur fermeture, lampe signalisation |
| Alimentation 5V / 220V (mini bloc) | 1 | Alimente l'Arduino et la logique relais |
| Bouton poussoir 12 mm (reset alarme) | 1 | Efface les défauts |
| Plaque d'essai + fils | 1 | Pour prototypage ; prévoir PCB final |
Composants externes non listés (partie puissance) :
- Moteur 220V existant (non modifié)
- Récepteur radio 220V + télécommandes (existant)
- Relais de puissance 220V pour le moteur (commandés par le module relais 5V)
- Fin de course ouverture (NO) + Fin de course fermeture (NO)
- Photocellule de sécurité (barrière infrarouge, NO)
Contexte et motivation
L'auteur a dû remplacer le contrôleur d'origine de sa porte de garage après qu'un lézard ait causé un court-circuit 220V sur la carte électronique. Plutôt que racheter un contrôleur commercial, il a conçu le sien avec Arduino Nano, en ajoutant des fonctions de sécurité et de diagnostic absentes de l'original.
Architecture du système
Entrées (pull-up internes, actif LOW)
- FOTOCELULA (Pin 2) : Photocellule sécurité — HIGH = obstacle détecté
- TANCAT (Pin 7) : Fin de course FERMÉ — HIGH = porte fermée
- OBERT (Pin 3) : Fin de course OUVERT — HIGH = porte ouverte
- OBRIR (Pin 4) : Commande radio « Ouvrir » — LOW = commande active (relais radio tire vers GND)
Sorties (relais actif LOW)
- BOMBETA (Pin 5, Relais 1) : Lampe signalisation clignotante
- MOTOR_OBRIR (Pin 6, Relais 2) : Moteur sens OUVERTURE
- MOTOR_TANCAR (Pin 12, Relais 3) : Moteur sens FERMETURE
Affichage OLED (SPI)
MOSI=11, CLK=13, DC=9, CS=10, RESET=8
L'OLED est monté sur la carte de contrôle (sous le couvercle) et sert uniquement au débogage et réglage (temps de parcours, état capteurs, mode en cours).
Logique de fonctionnement (Machine à états)
Le code utilise une structure à étiquettes et goto (style automate) pour gérer les séquences :
État principal : BUCLE_PRINCIPAL
- Attend commande « Ouvrir » (OBRIR LOW)
- Affiche en continu sur OLED : état capteurs, temps, alarme
- Si alarme (AVARIA) : clignotement lent de la lampe pendant 60s
Séquence OUVERTURE (SEQUENCIA_OBERTURA)
- Active moteur ouverture + lampe clignotante lente (1 Hz)
- Surveille : fin de course OUVERT → passe à PORTA_OBERTA
- Si nouvelle commande OUVRIR pendant ouverture : stoppe moteur, attend commande pour fermer
- Timeout 28s → alarme (AVARIA), arrêt moteur
État PORTE OUVERTE (PORTA_OBERTA)
- Moteur arrêté, lampe clignotement composé (court 100ms / long 2s)
- Attente 30s (temps pour entrer/sortir le véhicule)
- Si commande OUVRIR reçue → fermeture immédiate
- Timeout 30s → lancement fermeture automatique
Séquence FERMETURE (SEQUENCIA_TANCAMENT)
- Active moteur fermeture + lampe clignotante rapide (300 ms)
- Surveille : fin de course FERMÉ → retour BUCLE_PRINCIPAL
- Sécurité : si photocellule détecte obstacle → stoppe moteur, réouvre
- Si commande OUVRIR reçue → stoppe, réouvre
- Timeout 28s → alarme, arrêt moteur
Affichage OLED (informations temps réel)
L'écran affiche en permanence :
- Phase en cours (Ouverture, Fermeture, Attente, Boucle principale...)
- Chronomètre de l'action en cours (secondes)
- État photocellule, fin de course OUVERT/FERMÉ, commande radio
Code complet (version commentée en anglais)
/*********************************************************************
* Automatisme pour porte coulissante motorisée
* Arduino Nano + OLED SSD1306 (SPI) + Module relais 3 canaux
*********************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- Broches automatisme ---
const int FOTOCELULA = 2; // Photocellule (INPUT_PULLUP)
const int BOMBETA = 5; // Relais 1 : Lampe
const int TANCAT = 7; // Fin de course FERMÉ
const int OBERT = 3; // Fin de course OUVERT
const int MOTOR_OBRIR = 6; // Relais 2 : Moteur OUVERTURE
const int MOTOR_TANCAR = 12; // Relais 3 : Moteur FERMETURE
const int OBRIR = 4; // Commande radio (actif LOW)
// --- Broches 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);
// --- Paramètres temporels (ms) ---
unsigned long TEMPS_PORTA_OBERTA = 30000; // Temps porte ouverte avant auto-fermeture
unsigned long TEMPS_MAX_RECORREGUT = 28000; // Timeout parcours (alarme)
int interval = 1000;
int TEMPS_DISPLAY = 1;
int DURADA = 300; // Cycle clignotement lampe
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long TEMPS_LLUM = 1000;
bool LLUM = false; // État lampe
bool AVARIA = false; // Défaut : timeout parcours
void setup() {
// Arrêt initial
digitalWrite(MOTOR_OBRIR, HIGH);
digitalWrite(MOTOR_TANCAR, HIGH);
digitalWrite(BOMBETA, HIGH);
// Config broches
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);
// OLED
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) { // Attente commande
afficherStatut("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) { // Nouvelle commande -> annule ouverture
afficherStatut("Esperant ordre per tancar");
digitalWrite(MOTOR_OBRIR, HIGH); digitalWrite(BOMBETA, HIGH); delay(1000);
while (digitalRead(OBRIR) == HIGH) {}; // Attend relâchement
goto SEQUENCIA_TANCAMENT;
}
actualitzarDisplayTemps("Obrint porta");
if (millis() - previousMillis >= interval) { digitalWrite(MOTOR_OBRIR, HIGH); AVARIA = true; }
clignoterLampe(1000); // 1 Hz
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) { // Commande ouvrir pendant fermeture
afficherStatut("Esperant ordre per obrir");
digitalWrite(MOTOR_TANCAR, HIGH); digitalWrite(BOMBETA, HIGH); delay(1000);
while (digitalRead(OBRIR) == HIGH) {}; goto SEQUENCIA_OBERTURA;
}
if (digitalRead(FOTOCELULA) == HIGH) { // Obstacle détecté
digitalWrite(MOTOR_TANCAR, HIGH); delay(1000); goto SEQUENCIA_OBERTURA;
}
actualitzarDisplayTemps("Tancant porta");
if (millis() - previousMillis >= interval) { digitalWrite(MOTOR_TANCAR, HIGH); AVARIA = true; goto BUCLE_PRINCIPAL; }
clignoterLampe(300); // Rapide
goto B;
PORTA_OBERTA:
interval = 30000;
previousMillis = millis();
digitalWrite(MOTOR_OBRIR, HIGH); delay(500);
C:
if (digitalRead(OBRIR) == LOW) goto SEQUENCIA_TANCAMENT;
actualitzarDisplayTemps("Porta Oberta completament");
if (millis() - previousMillis >= interval) goto SEQUENCIA_TANCAMENT;
// Clignotement spécial : court 100ms / long 2000ms
if (!LLUM) DURADA = 100; else DURADA = 2000;
if (millis() - TEMPS_LLUM >= DURADA) { LLUM = !LLUM; digitalWrite(BOMBETA, LLUM); TEMPS_LLUM = millis(); }
goto C;
}
// --- Fonctions utilitaires ---
void afficherStatut(const char* phase) {
display.clearDisplay();
display.setTextSize(1); display.setCursor(0, 0); display.println(phase);
display.setCursor(0, 20);
display.print("Fotocel.lula: "); display.println(digitalRead(FOTOCELULA));
display.print("Sensor TANCAT: "); display.println(digitalRead(TANCAT));
display.print("Sensor OBERT: "); display.println(digitalRead(OBERT));
display.print("Ordre OBRIR: "); display.println(!digitalRead(OBRIR));
display.display();
}
void actualitzarDisplayTemps(const char* phase) {
currentMillis = millis();
TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
display.clearDisplay();
display.setTextSize(1); display.setCursor(0, 0); display.println(phase);
display.setTextSize(2); display.setCursor(90, 0); display.println(TEMPS_DISPLAY);
display.setTextSize(1); display.setCursor(0, 20);
display.print("Fotocel.lula: "); display.println(digitalRead(FOTOCELULA));
display.print("Sensor TANCAT: "); display.println(digitalRead(TANCAT));
display.print("Sensor OBERT: "); display.println(digitalRead(OBERT));
display.print("Ordre OBRIR: "); display.println(!digitalRead(OBRIR));
display.display();
}
void clignoterLampe(unsigned long periode) {
if (millis() - TEMPS_LLUM >= periode) {
LLUM = !LLUM; digitalWrite(BOMBETA, LLUM); TEMPS_LLUM = millis();
}
}
Schéma de câblage (Fritzing)
Voir les images du projet pour :
- Schéma complet de la carte de contrôle (Arduino Nano + OLED + Relais + Entrées)
- Raccordement des capteurs (fin de course, photocellule), module radio, relais de puissance 220V
- Tableau de correspondance broches
Flux de travail (Flowcharts)
Trois diagrammes de flux résument la logique :
- Boucle principale + Séquence ouverture
- Porte ouverte + Séquence fermeture
- Gestion sécurité (photocellule) et alarmes
Améliorations apportées vs contrôleur d'origine
- Photocellule de sécurité (arrêt/réouverture si obstacle)
- Timeouts configurables sur parcours (détection panne mécanique)
- Signalisation lumineuse différenciée selon phase (lente, rapide, composée)
- Diagnostic temps réel sur OLED (sans PC)
- Réinitialisation alarme par bouton dédié
- Code structuré, commenté, modifiable
⚠️ Sécurité importante
Ce projet implique du 220V. Ne l'entreprenez que si vous êtes compétent en électricité. Toujours :
- Couper le secteur avant toute intervention
- Tester sur banc d'essai (simulation) avant raccordement moteur réel
- Utiliser des relais de puissance adaptés au courant du moteur
- Respecter les normes locales (NF C 15-100 en France)
- Prévoir un disjoncteur différentiel 30 mA en amont
Processus de fabrication
- Breakout compact DHT Température & Humidité pour Raspberry Pi – ATtiny85 & DHT22/DHT11
- Les meilleurs accessoires pour exploiter pleinement le potentiel de votre Raspberry Pi
- SIGHT : Lunettes intelligentes pour autonomiser les aveugles
- Construire un drone sous‑marin avec Raspberry Pi : conception, développement et assemblage
- Automatisation de tournage à poulie mobile de précision pour production suisse et de série
- Stimuler la croissance : comment l'automatisation permet aux PME d'assurer un avenir radieux
- Comment sélectionner des amortisseurs de haute qualité pour votre véhicule
- Scie à ruban manuelle : solution de coupe durable et portable pour tout projet
- Qu'est-ce qu'une presse de puissance automatique ? – La machine ultime de formage de tôle