DVDMDN
Published © GPL3+

Automatic Sliding Door for the Garage

How to build and configure a control unit based on Arduino for opening, closing and other actions for a motorized sliding door.

IntermediateFull instructions provided22,245
Automatic Sliding Door for the Garage

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Breadboard (generic)
Breadboard (generic)
To hold the Arduino Nano and the Oled display
×1
Adafruit Oled display
To show sensor status, time counter and actions.
×1
Relay Module (Generic)
4 relay module. I used only three of them.
×1
SparkFun Breadboard Power Supply 5V/3.3V
SparkFun Breadboard Power Supply 5V/3.3V
I used a 5V miniature power supply from 220V
×1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
For reset button (erase malfunction alarm)
×1

Story

Read more

Schematics

Main circuitry for control unit in FZZ format

How to connect the wiring to sensors, relays and radio module from the main control unit.

Schematics

Screenshoot from fritzing schematics

Pinouts

This is the list of the used Arduino pins and how to connect them to the rest of the components.

Safety relay

This hardware addon is in response to the question from irshad2318 (see the posts for this project)

Code

English Software code version

C/C++
Here you have the code with all the comments translated to english. It includes a short list of vocabulary in order to understand the meaning of variables and labels.
/*********************************************************************
  Automatism for sliding motorized door
*********************************************************************/

/* Comments are translated to english, but in order to help
   you understand the name of the variables and labels, here
   you have a quick vocabulary "Catalan-English":

      Bucle principal = Main loop
      Sequencia Obertura = Opening sequence
      Sequencia Tancament = Closing sequence
      Obrir = Open ; Obert = Opened
      Tancar = Close ; Tancat = Closed
      Bombeta = Light bulb
      Llum = light
      Porta = Gate / door
      Avaria = Failure
      Temps = Time
      Recorregut = door travel
*/


// Libraries for Oled Display
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// We define the pins to be used by the control circuitry
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;

// We define the pins to be used by the Oled display
#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);

// We define global variables
unsigned long TEMPS_PORTA_OBERTA = 20000;
unsigned long TEMPS_MAXIM_RECORREGUT = 15000;  //Later we'll redefine this value
int interval = 1000; // Interval is how long we wait
int TEMPS_DISPLAY = 1; // Time in seconds to display
int DURADA = 300;  // Cicle for light bulb
unsigned long previousMillis = 0;  // Tracks the time since last event fired
unsigned long currentMillis = millis();
unsigned long TEMPS_LLUM = 1000;  // time in milliseconds for light bulb status
boolean LLUM = false;  // light ON or OFF
boolean AVARIA = false;   //door travel time exceeded without detecting limiting switch

void setup() {
  // Turn off motor and light
  digitalWrite(MOTOR_OBRIR, HIGH);
  digitalWrite(MOTOR_TANCAR, HIGH);
  digitalWrite(BOMBETA, HIGH);

  // We initialize the pins for the automatism
  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);

  // Display initialization
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC);
  display.display(); // Show Adafruit initial logo
  delay(1000);
  display.clearDisplay();
  display.display();

  // We prepare the text size for the display (not important because later it is dinamically redefined)
  display.setTextSize(1);
  display.setTextColor(WHITE);
}



void loop() {

BUCLE_PRINCIPAL:
  delay(2000);
  previousMillis = millis();
  while (digitalRead(OBRIR) == HIGH)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("BUCLE PRINCIPAL ...");
    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();
    if (AVARIA and (millis() - previousMillis < 60000)) {
      digitalWrite(BOMBETA, LOW);
    } else (digitalWrite(BOMBETA, HIGH));
  }; // We wait until Open command is issued and meanwhile the display is being refreshed showing the status of the sensors
  goto SEQUENCIA_OBERTURA;

SEQUENCIA_OBERTURA:
  interval = 28000;  // Maximum time opening the door (if exceeded it will denote some failure)
  previousMillis = millis();

  digitalWrite(MOTOR_OBRIR, LOW);
  digitalWrite(BOMBETA, LOW);
  delay(1000);
A:
  if (digitalRead(OBERT) == HIGH) {
    goto PORTA_OBERTA;
  };
  if (digitalRead(OBRIR) == LOW)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("Esperant ordre per   tancar");  // "Waiting order to close"
    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();

    digitalWrite(MOTOR_OBRIR, HIGH);
    digitalWrite(BOMBETA, HIGH);
    delay(1000);
    while (digitalRead(OBRIR) == HIGH) {}; //Do nothing until OPEN command is issued
    goto SEQUENCIA_TANCAMENT;
  };

  //--Time control and display refreshing---------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Obrint porta");
  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();
  if ((currentMillis - previousMillis) >= interval)
  {
    digitalWrite(MOTOR_OBRIR, HIGH);
    AVARIA = true;   // 
    goto PORTA_OBERTA;
  };

  //--light Flashing frequence control------------------
  if ((currentMillis - TEMPS_LLUM) >= 1000)  //Flashing at low speed
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto A;


SEQUENCIA_TANCAMENT:
  interval = 28000;  //  Maximum time closing the door (if exceeded it will denote some failure)!
  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)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("Esperant ordre per   obrir");
    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();

    digitalWrite(MOTOR_TANCAR, HIGH);
    digitalWrite(BOMBETA, HIGH);
    delay(1000);
    while (digitalRead(OBRIR) == HIGH) {}; //Do nothing until OPEN command is issued
    goto SEQUENCIA_OBERTURA;
  };
  if (digitalRead(FOTOCELULA) == HIGH)
  {
    digitalWrite(MOTOR_TANCAR, HIGH);
    delay(1000);

    goto SEQUENCIA_OBERTURA;
  };

  //--Time control and display refreshing---------------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Tancant porta");
  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();
  if ((currentMillis - previousMillis) >= interval) {
    digitalWrite(MOTOR_TANCAR, HIGH);
    AVARIA = true;  
    goto BUCLE_PRINCIPAL;
  };

  //--light Flashing frequence control------------------
  if ((currentMillis - TEMPS_LLUM) >= 300)   //  Flashing at fast speed
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto B;

PORTA_OBERTA:
  interval = 30000;  // Time waiting before closing the door! (30 seconds to enter the car...)
  previousMillis = millis();
  digitalWrite(MOTOR_OBRIR, HIGH);
  delay(500);
C:
  if (digitalRead(OBRIR) == LOW) {
    goto SEQUENCIA_TANCAMENT;
  };

  //--Time control and display refreshing---------------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Porta Oberta         completament");
  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();
  if ((currentMillis - previousMillis) >= interval) {
    goto SEQUENCIA_TANCAMENT;
  };


  //--Special compound flashing frequency in waiting state------------------
  // (Short flashes of 100 milliseconds between long periods of 2 seconds)
  if (LLUM == false) {
    DURADA = 100;
  } else DURADA = 2000;
  if ((currentMillis - TEMPS_LLUM) >= DURADA)   //  
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto C;

}

Code

C/C++
This is the C++ code to compile and upload to the Arduino Nano
/*********************************************************************
  Automatisme per porta corredera motoritzada
*********************************************************************/

// Llibreries per fer servir el display
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Definim pins per automatisme porta
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;

// Definim pins per display
#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);

// Definim variables globals
unsigned long TEMPS_PORTA_OBERTA = 20000;
unsigned long TEMPS_MAXIM_RECORREGUT = 15000;  //Despres ho redefinim
int interval = 1000; // Interval is how long we wait
int TEMPS_DISPLAY = 1; // temps en segons per imprimir en pantalla
int DURADA = 300;  // Cicle bombeta senyalitzacio
unsigned long previousMillis = 0;  // Tracks the time since last event fired
unsigned long currentMillis = millis();
unsigned long TEMPS_LLUM = 1000;  // temps en milisegons de estat llum senyalitzacio
boolean LLUM = false;  // Llum encessa si ON i apagada si OFF
boolean AVARIA = false;   //Excedit el temps de recorregut sense detectar finals de carrera

void setup() {
  // Inicialitzem els pins per automatisme porta
  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);

  // Apaguem motors i llum
  digitalWrite(MOTOR_OBRIR, HIGH);
  digitalWrite(MOTOR_TANCAR, HIGH);
  digitalWrite(BOMBETA, HIGH);

  // Inicialitzem el display
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC);
  display.display(); // Mostra pantalla inicial de Adafruit
  delay(1000);
  display.clearDisplay();
  display.display();

  // preparem el display per texte
  display.setTextSize(1);
  display.setTextColor(WHITE);
}



void loop() {

BUCLE_PRINCIPAL:
  delay(2000);
  previousMillis = millis();
  while (digitalRead(OBRIR) == HIGH)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("BUCLE PRINCIPAL ...");
    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();
    if (AVARIA and (millis() - previousMillis < 60000)) {
      digitalWrite(BOMBETA, LOW);
    } else (digitalWrite(BOMBETA, HIGH));
  }; //Esperem fins que premem OBRIR i anem refrescant pantalla per mostrar estat sensors
  goto SEQUENCIA_OBERTURA;

SEQUENCIA_OBERTURA:
  interval = 28000;  // TEMPS MAXIM DE RECORREGUT PORTA OBRINT !!!!!!!!!
  previousMillis = millis();

  digitalWrite(MOTOR_OBRIR, LOW);
  digitalWrite(BOMBETA, LOW);
  delay(1000);
A:
  if (digitalRead(OBERT) == HIGH) {
    goto PORTA_OBERTA;
  };
  if (digitalRead(OBRIR) == LOW)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("Esperant ordre per   tancar");
    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();

    digitalWrite(MOTOR_OBRIR, HIGH);
    digitalWrite(BOMBETA, HIGH);
    delay(1000);
    while (digitalRead(OBRIR) == HIGH) {}; //No fem res fins que premem OBRIR
    goto SEQUENCIA_TANCAMENT;
  };

  //--Control-de-temps-i-impressió-en-pantalla---------------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Obrint porta");
  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();
  if ((currentMillis - previousMillis) >= interval)
  {
    digitalWrite(MOTOR_OBRIR, HIGH);
    AVARIA = true;   // 
    goto PORTA_OBERTA;
  };

  //--Control-de-cadencia-de-la-llum-intermitent------------------
  if ((currentMillis - TEMPS_LLUM) >= 1000)   //  Cadencia de la llum intermitent de senyalitzacio
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto A;


SEQUENCIA_TANCAMENT:
  interval = 28000;  // TEMPS MAXIM DE RECORREGUT PORTA TANCANT !!!!!!!!!
  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)
  {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("Esperant ordre per   obrir");
    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();

    digitalWrite(MOTOR_TANCAR, HIGH);
    digitalWrite(BOMBETA, HIGH);
    delay(1000);
    while (digitalRead(OBRIR) == HIGH) {}; //No fem res fins que premem OBRIR
    goto SEQUENCIA_OBERTURA;
  };
  if (digitalRead(FOTOCELULA) == HIGH)
  {
    digitalWrite(MOTOR_TANCAR, HIGH);
    delay(1000);

    goto SEQUENCIA_OBERTURA;
  };

  //--Control-de-temps-i-impressió-en-pantalla---------------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Tancant porta");
  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();
  if ((currentMillis - previousMillis) >= interval) {
    digitalWrite(MOTOR_TANCAR, HIGH);
    AVARIA = true;  
    goto BUCLE_PRINCIPAL;
  };

  //--Control-de-cadencia-de-la-llum-intermitent------------------
  if ((currentMillis - TEMPS_LLUM) >= 300)   //  Cadencia de la llum intermitent de senyalitzacio
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto B;

PORTA_OBERTA:
  interval = 30000;  // TEMPS MAXIM ESPERANT AMB PORTA OBERTA !!!!!!!!!
  previousMillis = millis();
  digitalWrite(MOTOR_OBRIR, HIGH);
  delay(500);
C:
  if (digitalRead(OBRIR) == LOW) {
    goto SEQUENCIA_TANCAMENT;
  };

  //--Control-de-temps-i-impressió-en-pantalla---------------------
  currentMillis = millis();
  TEMPS_DISPLAY = (currentMillis - previousMillis) / 1000;
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Porta Oberta         completament");
  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();
  if ((currentMillis - previousMillis) >= interval) {
    goto SEQUENCIA_TANCAMENT;
  };


  //--Control-de-cadencia-de-la-llum-intermitent------------------
  if (LLUM == false) {
    DURADA = 100;
  } else DURADA = 2000;
  if ((currentMillis - TEMPS_LLUM) >= DURADA)   //  Cadencia de la llum intermitent de senyalitzacio
  {
    LLUM = !LLUM;
    digitalWrite(BOMBETA, LLUM);
    TEMPS_LLUM = currentMillis;
  };

  goto C;

}

Credits

DVDMDN

DVDMDN

1 project • 25 followers

Comments