Garage door controller
Did your garage door controller die? This may be the cheapest solution for you!
Components and supplies
2
Limit Switch, Rod Lever
1
CURRENT SENSOR ACS712
1
Arduino Nano
1
jumper wires for arduino
1
Fuse and Holder 10A
1
2 relay module
1
Push Button
Tools and machines
1
Soldering Station
1
Wire Stripper
Apps and platforms
1
Arduino IDE
Project description
Code
Code
cpp
Code for the controller. Read comments thoroughly.
1// Universal Garage door control system made with an Arduino Nano microcontroller. 2// Originally developed for a Wayne Dalton garage door with a ecostar electric lift mechanism 3// The door movement is controlled by a single pushbutton and limited by two limit switches. 4// The door can be stopped mid-movement with the button, and its movement direction can also be changed anytime. 5// This code includes safety functions to protect the motor and handle error cases. 6// DURING THE FIRST TEST MAKE SURE THAT THE DOOR IS ACTUALLY MOVING IN THE SAME DIRECTION AS THE CODE "THINKS" !!!! 7// IF NOT, SWITCH THE POLARITY OF THE WIRES GOING TO THE MOTOR. 8 9// Pins 10const int button = 5; 11const int lowerLimit = 2; 12const int upperLimit = 11; 13const int relay1 = 8; 14const int relay2 = 7; 15const int currentSensor = A0; 16 17// Constants 18const int requiredPressTime = 500; 19const int maxMoveTime = 18000; // Change to match the movement time of your door 20const int upperMoveExtra = 6000; // Extra "puffer" because door moves slower when going up 21const int pressed = LOW; 22const int atBottom = LOW; 23const int atTop = LOW; 24const int maxCurrent = 5; // Change to fit your door 25const float sensitivity = 0.066; // (0.066 for 30A sensor), (0.100 for 20A), (0.185 for 5A) 26const int measurmentInterval = 500; // Time difference between current readings 27const int numReadings = 1000; // Number of readings used to calibrate zero current voltage 28 29// Variables 30String lastDirection = "stopped"; 31String currentMovement = "stopped"; 32int previousState = HIGH; 33int currentOverCounter = 0; 34unsigned long pressMoment = 0; 35unsigned long movementStartTime = 0; 36unsigned long previousMillis = 0; 37float zeroCurrentVoltage = 0.0; 38 39void setup() { 40 41 // Pin modes 42 pinMode(relay1, OUTPUT); 43 pinMode(relay2, OUTPUT); 44 pinMode(button, INPUT_PULLUP); 45 pinMode(lowerLimit, INPUT_PULLUP); 46 pinMode(upperLimit, INPUT_PULLUP); 47 48 // Relays initially off 49 digitalWrite(relay1, HIGH); 50 digitalWrite(relay2, HIGH); 51 52 zeroCurrentVoltage = calibrateZeroCurrentVoltage(); 53} 54 55 56// Calibrates the zero-current voltage to account for sensor offsets 57float calibrateZeroCurrentVoltage() { 58 59 long sum = 0; 60 61 // Calculates the sum of 1000 measurments 62 for (int i = 0; i < numReadings; i++) { 63 sum += analogRead(currentSensor); 64 delay(1); 65 } 66 67 float averageReading = sum / numReadings; 68 float zeroVoltage = averageReading * (5.0 / 1023.0); 69 return zeroVoltage; 70} 71 72 73void moveUp() { 74 lastDirection = "up"; 75 currentMovement = "up"; 76 movementStartTime = millis(); 77 digitalWrite(relay1, LOW); 78 digitalWrite(relay2, HIGH); 79} 80 81 82void moveDown() { 83 lastDirection = "down"; 84 currentMovement = "down"; 85 movementStartTime = millis(); 86 digitalWrite(relay1, HIGH); 87 digitalWrite(relay2, LOW); 88} 89 90 91void stop() { 92 currentMovement = "stopped"; 93 movementStartTime = 0; 94 digitalWrite(relay1, HIGH); 95 digitalWrite(relay2, HIGH); 96} 97 98 99// Reads if the button has been pressed for the specified time and returns LOW if it has. 100// This could be replaced by a simple digitalRead in the loop, but I decided to go this route because 101// significant interference caused by fluorescent lights in the garage sometimes caused the door to open by itself. 102int readButton() { 103 104 int buttonStatus = digitalRead(button); 105 106 // If the button is pressed and the state has changed. 107 if (buttonStatus == pressed && buttonStatus != previousState) { 108 pressMoment = millis(); 109 previousState = buttonStatus; 110 } 111 112 // If the button is released and the state has changed. 113 else if (buttonStatus != pressed && buttonStatus != previousState) { 114 previousState = buttonStatus; 115 pressMoment = 0; 116 } 117 118 // Returns LOW if the button has been pressed for the specified time. 119 if (pressMoment > 0 && (millis() - pressMoment >= requiredPressTime) && buttonStatus == pressed) { 120 pressMoment = 0; 121 return pressed; 122 } 123 return HIGH; 124} 125 126 127void intermediatePosition() { 128 // If the button is pressed while the door is moving, the door stops 129 if (currentMovement != "stopped") { 130 stop(); 131 } 132 else { 133 // If the door was stopped while moving up, it starts moving down when button is pressed 134 if (lastDirection == "up") { 135 moveDown(); 136 } 137 // If the door was stopped while moving down, it starts moving up when button is pressed 138 // The door also starts moving up when the button is pressed if the system is powered on while the door is in an intermediate position. 139 else if (lastDirection == "stopped" || lastDirection == "down") { 140 moveUp(); 141 } 142 } 143} 144 145 146// Prevents motor movement and possible damage in case of a malfunction. 147// Stops the motor if one of the limit switches is stuck. 148// Stops the motor if it has been running for more than the specified time. 149// Has different times for up and down movement because of speed difference. 150void malfunctionProtection(){ 151 152 // Stops the door if both limit switches are pressed at the same time. 153 if (digitalRead(lowerLimit) == atBottom && digitalRead(upperLimit) == atTop){ 154 stop(); 155 } 156 // Limits the door's upward movement time. 157 else if (currentMovement == "up" && (millis() - movementStartTime > maxMoveTime + upperMoveExtra)){ 158 stop(); 159 } 160 // Limits the door's downward movement time. 161 else if (currentMovement == "down" && (millis() - movementStartTime > maxMoveTime)){ 162 stop(); 163 } 164} 165 166 167// Protects the motor by measuring the current and stopping it if a set current is exceeded for a set time 168void checkCurrent() { 169 170 unsigned long currentMillis = millis(); 171 172 // Checks if the time since the last measurement exceeds the defined interval 173 if (currentMillis - previousMillis >= measurmentInterval) { 174 175 previousMillis = currentMillis; 176 int analogValue = analogRead(currentSensor); 177 178 // Converts the analog sensor reading to voltage 179 float sensorVoltage = analogValue * (5.0 / 1023.0); 180 181 // Converts voltage to current 182 float current = (sensorVoltage - zeroCurrentVoltage) / sensitivity; 183 184 // If the motor has been running for more than 2 seconds and the current exceeds the maximum allowed, updates counter 185 if(millis() - movementStartTime > 2000 && abs(current) > maxCurrent){ 186 currentOverCounter += 1; 187 } 188 else{ 189 currentOverCounter = 0; // Reset the counter if no overcurrent condition 190 } 191 } 192 193 // Stops the motor if the overcurrent condition persists for two consecutive intervals 194 if(currentOverCounter >= 2){ 195 stop(); 196 } 197} 198 199 200void loop() { 201 202 int buttonState = readButton(); 203 int lowerLimitState = digitalRead(lowerLimit); 204 int upperLimitState = digitalRead(upperLimit); 205 malfunctionProtection(); 206 checkCurrent(); 207 208 // The door stops when it is at the top 209 if (currentMovement == "up" && upperLimitState == atTop){ 210 stop(); 211 } 212 // The door stops when it is at the bottom 213 else if (currentMovement == "down" && lowerLimitState == atBottom){ 214 stop(); 215 } 216 217 // If the door is at the bottom when the button is pressed, it starts moving up 218 if (buttonState == pressed && lowerLimitState == atBottom){ 219 moveUp(); 220 } 221 222 // If the door is at the top when the button is pressed, it starts moving down 223 else if (buttonState == pressed && upperLimitState == atTop) { 224 moveDown(); 225 } 226 227 // If the button is pressed when the door is in an intermediate position 228 else if (buttonState == pressed && upperLimitState != atTop && lowerLimitState != atBottom) { 229 intermediatePosition(); 230 } 231}
Downloadable files
Code
Garage_Door_Control_System.ino
Documentation
Schematic
Schematic with motor and transformer wiring
capture (3).png

Finished project
IMG20240821181318.jpg

Finished project
IMG20240821181318.jpg

Comments
Only logged in users can leave comments