There is a new version of this tutorial that is updated found here:
https://www.hackster.io/k-gray/automated-driveway-gates-ef5c75
StoryProblem: My driveway is a public turn-around. Solution: gates. So we bought some gates, but getting out of the car to open two gates twice a day is really monotonous. I looked at automated gate kits, but they range from $400 - $900; in short, way too much. I decided to make my own, seeing that it would be more cost effective and much more fun!
Connecting the Motor Driver and Linear ActuatorsThe motor driver board has 10 pins; 2 gnd, 2 +5v, 2 pwm, and 4 io.
Driver - Arduino
5V - 5V
GND - GND
IN1 - D4
IN2 - D3
IN3 - D2
IN4 - D1
PWM does not have to be connected. Connect the linear actuator(s) to the black screw terminal(s). It does not matter which way you connect the linear actuator(s), but if you have two, you need to make sure that they are both connected the same way.
I am in the process of installing this and ran into a problem. The 3.3v logic output of the ESP8266's pins won't turn on the actuators. So I decided to connect the ESP8266 to the Arduino because the Arduino's logic level is 5v. I didn't have any logic level converters so I connected them in such a way that you don't need a logic level converter.
Arduino - ESP
A2 - D4
A3 - D3
A4 - D2
A5 - D1
optional:
A0 - 5V
A1 - GND
Powering the MicrocontrollerTo power this setup, I had a couple ideas. Most Arduinos have a VIN pin and a builtin voltage regulator so the VIN pin of the motor driver would be connected to the VIN pin of the Arduino. Some Arduinos though, like the Pro Mini do not have a builtin voltage regulator. This means we need an external voltage regulator, and the simplest idea, is to just use a 5v regulator connected to the VIN pin of the motor driver.
This setup needs a lot of Blynk parts. Here's what it's suppose to look like when done.
Start by downloading the Blynk app on your iPhone. Sign up and make a new project named "Driveway Gate".
Then add a new esp8266 device with wifi.
Next, tap your project page and select "Button" on the popout page.
Click the button and change the "Output" pin to "V0". Change the mode to "PUSH".
All the rest of the settings for each module are shown below.
Drill a hole in the side of the waterproof enclosure for a power cable and the linear actuator cables. Add a hole on the back of the case for power and data. Once everything is connected with jumper wires, place the motor driver, Arduino and ESP8266 inside the waterproof enclosure and screw the cover on. Install the box to your gate post, run the power cable to your house and run the linear actuator cables to the linear actuator(s).
For installing the linear actuator(s), use this website.
Setting Up Arduino IDEIf you need help installing or using the Arduino IDE, go to https://www.arduino.cc/en/Guide/HomePage
In the Arduino IDE, open a new sketch and paste the code "Automated-Driveway-Gates.ino". Or, go to the Github directory and download the code. After you have your main sketch ready, open a new tab and name it "settings.h".
Paste the "settings.h" code into this new tab, and you're ready to go. Upload the code and open the serial monitor on baud rate 9600.
Code ExplanationThe code is made in such a way that you can change all the settings in a separate settings.h file instead of going through and changing the code. Here's the breakdown of the settings.h.
//blynk
#define BLYNK_AUTH_TOKEN "your_auth"
#define BLYNK_GREEN "#23C48E"
#define BLYNK_RED "#D3435C"
#define BLYNK_YELLOW "#ED9D00"
#define BLYNK_BLUE "#04C0F8"
#define YOUR_LAT 43.419868
#define YOUR_LONG -72.467632
//WiFi
char WIFI_SSID[] = "your_ssid";
char WIFI_PASS[] = "your_pass";
IOT and WiFi settings.
#define emergencyButton 14 //just in case you forget your phone, click this button on the box.
//GATE
String Mode = "button"; //automatic or button
#define gateNumber 2 //how many gates; 1 or 2
int gateOpenAmount = 10; //only for automatic mode, seconds
#define gateDirection 1 //1 or 2
//linear actuator
#define inchesPerSec .39 //inches per sec of linear actuator
#define maxActuatorStroke 16 //max stroke of linear actuator
#define percentOfMaxStroke 1 //0 through 1
#define a1 2 //first linear actuator
#define a2 0 //first linear actuator
#define b1 4 //second linear actuator
#define b2 5 //second linear actuator
This is all the gate settings. You can change the settings for how your gates are setup and the info on your linear actuators. The percentOfMaxStroke is to define how much of the linear actuator is being used while opening the gates. Input can be from 0.01 - 1.
Driveway Gate code breakdown.
#define BLYNK_PRINT Serial
#include "settings.h"
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <BlynkSimpleEsp8266.h>
#include <math.h>
Including libraries.
int timer = 0;
int button;
int emergency;
int setting;
int delayAMOUNT;
int gpsSelect;
int distanceSelect;
int comingHome;
int openTest;
int closeTest;
float GPSLat;
float GPSLong;
float dist_calc=0;
float dist_calc2=0;
float diflat=0;
float diflon=0;
Making places to hold info.
BLYNK_CONNECTED() {
Blynk.syncAll();
Serial.println("Syncing...");
delay(2000);
}
BLYNK_WRITE(V0){
button = param.asInt();
}
BLYNK_WRITE(V1){
emergency = param.asInt();
}
BLYNK_WRITE(V2){
setting = param.asInt();
if (setting == 1) {
Mode = "automatic";
}
else if (setting == 0) {
Mode = "button";
}
}
BLYNK_WRITE(V3){
gateOpenAmount = param.asInt();
}
BLYNK_WRITE(V4){
delayAMOUNT = param.asInt();
}
BLYNK_WRITE(V5){
GpsParam gps(param);
GPSLat = gps.getLat();
GPSLong = gps.getLon();
}
WidgetLED led(V6);
BLYNK_WRITE(V8){
gpsSelect = param.asInt();
}
BLYNK_WRITE(V9){
distanceSelect = param.asInt();
}
BLYNK_WRITE(V10){
comingHome = param.asInt();
}
BLYNK_WRITE(V12){
openTest = param.asInt();
}
BLYNK_WRITE(V13){
closeTest = param.asInt();
}
Setting up Blynk inputs.
Serial.begin(9600);
if (gateNumber == 1){
pinMode(a1, OUTPUT);
pinMode(a2, OUTPUT);
}
else if (gateNumber == 2){
pinMode(a1, OUTPUT);
pinMode(a2, OUTPUT);
pinMode(b1, OUTPUT);
pinMode(b2, OUTPUT);
}
pinMode(emergencyButton, INPUT_PULLUP);
In setup, we start the serial and setup the pin modes.
Blynk.begin(WIFI_SSID,WIFI_PASS,BLYNK_AUTH_TOKEN);
led.on();
led.setColor(BLYNK_RED);
Here we just get the Blynk started.
void loop() {
Blynk.virtualWrite(V11, WiFi.RSSI());
if (emergencyButton == LOW){
Serial.println("Emergency Button!");
Blynk.notify("Emergency Button on Gates was just Pressed!!!");
gates();
}
if (button == 1){
Serial.println("Button pressed.");
gates();
}
if (emergency == 1){
Serial.println("M");
led.setColor(BLYNK_YELLOW);
manual();
delay(delayAMOUNT*1000);
led.setColor(BLYNK_RED);
}
if (gpsSelect != 1){
Blynk.virtualWrite(V7,calcDist(GPSLat, GPSLong, YOUR_LAT, YOUR_LONG));
if (comingHome == 1){
Serial.println(calcDist(GPSLat, GPSLong, YOUR_LAT, YOUR_LONG));
if (calcDist(GPSLat, GPSLong, YOUR_LAT, YOUR_LONG) < distanceSelect){
Serial.println("GPS triggered!");
opengates();
}
}
} Blynk.run();
}
In the loop, we handle Blynk. First we write our signal strength to virtual pin 11. Then we handle if the emergency button on the back of the box was pressed. Next, we handle the main gate button and the emergency button on Blynk. Lastly, we handle GPS and put Blynk.run();
to stay connected to the Blynk server.
void gates(){
Serial.println("Got Mail!");
if (Mode == "automatic"){
Serial.println("Mode = Automatic");
Serial.println("Opening gate...");
led.setColor(BLYNK_BLUE);
openGate();
waitForGate();
allStop();
led.setColor(BLYNK_GREEN);
Serial.println("Open.");
Serial.println("Waiting...");
delay(gateOpenAmount*1000);
Serial.println("Closing gate...");
led.setColor(BLYNK_BLUE);
closeGate();
waitForGate();
allStop();
led.setColor(BLYNK_RED);
Serial.println("Closed.");
}
else if(Mode == "button"){
Serial.println("Mode = Button");
if (timer == 0){
Serial.println("Openning gate...");
led.setColor(BLYNK_BLUE);
openGate();
waitForGate();
allStop();
led.setColor(BLYNK_GREEN);
Serial.println("Open.");
timer = 1;
}
else if(timer == 1){
Serial.println("Closing gate...");
led.setColor(BLYNK_BLUE);
closeGate();
waitForGate();
allStop();
led.setColor(BLYNK_RED);
Serial.println("Closed.");
timer = 0;
}
}
}
This is the function to open the gate(s).
void openGate(){
if (gateDirection == 1){
if (gateNumber == 1){
digitalWrite(a1, HIGH);
digitalWrite(a2, LOW);
}
else if (gateNumber == 2){
digitalWrite(a1, HIGH);
digitalWrite(a2, LOW);
digitalWrite(b1, HIGH);
digitalWrite(b2, LOW);
}
}
else if (gateDirection == 2){
if (gateNumber == 1){
digitalWrite(a1, LOW);
digitalWrite(a2, HIGH);
}
else if (gateNumber == 2){
digitalWrite(a1, LOW);
digitalWrite(a2, HIGH);
digitalWrite(b1, LOW);
digitalWrite(b2, HIGH);
}
}
}
void closeGate(){
if (gateDirection == 1){
if (gateNumber == 1){
digitalWrite(a1, LOW);
digitalWrite(a2, HIGH);
}
else if (gateNumber == 2){
digitalWrite(a1, LOW);
digitalWrite(a2, HIGH);
digitalWrite(b1, LOW);
digitalWrite(b2, HIGH);
}
}
else if (gateDirection == 2){
if (gateNumber == 1){
digitalWrite(a1, HIGH);
digitalWrite(a2, LOW);
}
else if (gateNumber == 2){
digitalWrite(a1, HIGH);
digitalWrite(a2, LOW);
digitalWrite(b1, HIGH);
digitalWrite(b2, LOW);
}
}
}
void allStop() {
if (gateNumber == 1){
digitalWrite(a1, LOW);
digitalWrite(a2, LOW);
}
else if (gateNumber == 2){
digitalWrite(a1, LOW);
digitalWrite(a2, LOW);
digitalWrite(b1, LOW);
digitalWrite(b2, LOW);
}
}
void manual() {
if (gateNumber == 1){
digitalWrite(a1, HIGH);
digitalWrite(a2, HIGH);
}
else if (gateNumber == 2){
digitalWrite(a1, HIGH);
digitalWrite(a2, HIGH);
digitalWrite(b1, HIGH);
digitalWrite(b2, HIGH);
}
}
void opengates(){
Serial.println("Mode = Button");
Serial.println("Openning gate...");
led.setColor(BLYNK_BLUE);
openGate();
waitForGate();
allStop();
led.setColor(BLYNK_GREEN);
Serial.println("Open.");
timer = 1;
}
These are the functions that I used in the next code up to make it easier.
void waitForGate() {
delay((inchesPerSec*(maxActuatorStroke/percentOfMaxStroke))*1000);
}
Also a function for making the coding for opening the gate(s) easier. It takes the inchesPerSec we already defined, and multiplies it by the max stroke divided by the percentage of the stroke.
float calcDist(float CurrentLatitude, float CurrentLongitude, float SavedLatitude, float SavedLongitude)
{
// HaverSine version
const float Deg2Rad = 0.01745329252; // (PI/180) 0.017453293, 0.0174532925
//const double EarthRadius = 6372.795; //6372.7976 In Kilo meters, will scale to other values
const float EarthRadius = 20908120.1; // In feet 20908128.6
float DeltaLatitude, DeltaLongitude, a, Distance;
// degrees to radians
CurrentLatitude = (CurrentLatitude + 180) * Deg2Rad; // Remove negative offset (0-360), convert to RADS
CurrentLongitude = (CurrentLongitude + 180) * Deg2Rad;
SavedLatitude = (SavedLatitude + 180) * Deg2Rad;
SavedLongitude = (SavedLongitude + 180) * Deg2Rad;
DeltaLatitude = SavedLatitude - CurrentLatitude;
DeltaLongitude = SavedLongitude - CurrentLongitude;
a =(sin(DeltaLatitude/2) * sin(DeltaLatitude/2)) + cos(CurrentLatitude) * cos(SavedLatitude) * (sin(DeltaLongitude/2) * sin(DeltaLongitude/2));
Distance = EarthRadius * (2 * atan2(sqrt(a),sqrt(1-a)));
Blynk.virtualWrite(V7, Distance);
return(Distance);
}
Here we use the Haversine formula to find the distance from our phone to the gate.
ALPR (Automatic License Plate Recognition) and Text Messages(Updated as of July 1st 2021)
This section is for adding ALPR and Text to your gates! The Raspberry Pi Takes a photo and sends it to Sighthound, which then returns the results. If there is a car in the photo, it tells you the make, model, color, type, region, and plate number! Once it has this info, it texts your phone with all of it! And if the License plate matches stored favorites, it opens the gates!!
Parts:
- Raspberry Pi (I'm using a 3b+)
- Raspberry Pi Camera (I'm using a aftermarket with IR lamps)
Services:
All of the code can be found in the same Github repository.
Here is a lot of useful information from Adafruit about Adafruit IO.
https://learn.adafruit.com/welcome-to-adafruit-io/overview
When you first open terminal, type cd and then the directory name. Next, type python
lpr-recognition.py
into the terminal and hit enter. There might be some invalid path returns. Just recheck them for the correct ones or ask a question in the comments.
This will keep running, until you press control c. What this code does is first takes a picture and saves it as image.jpg in the folder. Next, this image is forwarded to Sighthound's ALPR API service, which returns all the useful info, or nothing, if there is no car. Next, this info is organized and texted to you, and, if the plate number matches with the either of the ones on lines #276 and #284, then you are texted again, and a value of one is sent to Adafruit IO. If the plates do not match, a value of zero is sent. When the Adafruit IO value goes high, or to one, the D1-Mini controlling the gates detects that and opens them. There you have ALPR based automated gates!
New Version (PCB) and Results(Updated as of April 8th 2021)
This is an update on this project. I have now been working on perfecting a PCB for this project since I wrote it. I have tried 5 different designs, and through much trial and error, have finally got a working design, that needed no troubleshooting at all! It utilizes the high Iout of the RZ7886 at 13A! Each driver is only capable of driving one motor though, so I used two of them. Here is the parts list for the PCB:
- Buzzer (optional)
- 470µf Electrolytic Capacitor
- 4x 10µf Ceramic/Electrolytic Capitors
- Diode (I used DS34W)
- NPN Transistor (I used AS2304)
- 4x 10kΩ Resistors (Optional)
- L7805CV
- AMS1117-3.3 (Optional)
- Wemos D1-Mini
- ESP-12F (Optional)
- 2x RZ7886
The schematic/PCB can be found here. I used LCSC.com for parts, JLCPCB.com for PCBs, and EasyEDA.com for PCB designing.
Here is a picture of the completed setup with everything labelled:
Here is a video of it working:
Wrapping UpIf you have any questions, please post in the comments! And check out my other tutorials!
and my website
Comments