Problem: 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 pretty dumb. 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.
Wrapping UpIf anyone has any questions, please post in the comments! And check out my other tutorials!
https://www.hackster.io/k-gray/ir-controlled-individually-addressable-rgb-led-strip-376f1e
https://www.hackster.io/k-gray/home-automation-smart-plugin-with-esp8266-blynk-f8624c
https://www.hackster.io/k-gray/temperature-humidity-with-esp8266-blynk-114797
https://www.hackster.io/k-gray/ra-02-lora-with-esp8266-ecd71b
Comments