Smart Parking System
Introduction
Parking problems are not uncommon, especially for big cities. By 2023, market spending for smart parking products and services is expected to grow at a CAGR of 14% and surpass $3.8B according to an IoT Analytics report. The growth of market spending is good news because it will force people to try to find a solution to these traffic problems instead of taking no action.
The problem is quite obvious. But a bigger question is what can technology do to solve it? Is there any way to solve the problem?
In recent years an efficient design of a Wireless Sensor Network has become a leading area of research. A Sensor is a device that responds and detects some type of input from both the physical or environmental conditions, such as pressure, heat, light, etc. The output of the sensor is generally an electrical signal that is transmitted to a controller for further processing.
This smart parking solution is built which will use an ultrasonic sensor to detect vehicle presence and trigger the gate to open or close automatically. The ESP8266 NodeMCU will be used here as the main controller to control all the peripherals attached to it.
ESP8266 is the most popular controller to build IoT based applications as it has inbuilt support for Wi-Fi to connect to the internet.
In this Smart Parking System, we will send data to the web server for looking up the availability of space for vehicle parking. Here we are using Google Sheets as a database to get the parking availability data.
Components Required
Hardware Requirements
ESP8266 NodeMCU
Ultrasonic Sensor
RFID Module
DC Servo Motor
IR Sensors
16x2 i2c LCD Display
Jumpers
Software Requirements
Arduino IDE
Google Sheets
Circuit Diagram:
Circuit diagram for this IoT based vehicle parking system is given below. It involves two NodeMCU,two IR sensors, two servo motors, one ultrasonic sensor and two 16x2 LCD.
Here the ESP8266 will control the complete process and also send the parking availability information to Google Firebase so that it can be monitored from anywhere in the world over the internet. Two IR sensors are used at entry and exit gate to detect the presence of car and automatically open or close the gate. IR Sensor is used to detect any object by sending and receiving the IR rays, learn more about IR sensor here.
Two servos will act as entry and exit gate and they rotate to open or close the gate. Finally an Ultrasonic sensor is used to detect if the parking slot is available or occupied and send the data to ESP8266 accordingly.
Working:
Here the ESP8266 will control the complete process and also send the parking availability information to Google Sheets so that it can be monitored from anywhere in the world over the internet.
The IR sensors and RFID Reader will be placed in the parking slots that will encounter the presence of the cars inside the parking slots. One IR sensor and one RFID Reader will be placed beside the main entrance of the parking lot and exit of parking lot.Ultrasonic sensor are placed at every parking area to detect the presence of vehicles.As soon as the sensors get the presence of a car in front of the entrance, it will send signal to the ESP8266 to check if there is an empty slot inside the parking lot.
When NodeMCU acknowledges that there is an empty slot or more then it will send a signal to the dc servo motor which will open the main entrance. On the other hand if NodeMCU encounters no empty slots at the time of a car trying to make an entrance, the gate will not open.
This is how the availability of parking can be tracked online on Firebase as shown in the snapshot below:
Finally an Ultrasonic sensor is used to detect if the parking slot is available or occupied and send the data to ESP8266 accordingly.
CODE
#include <ESP8266WiFi.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#includeRFID.h>
#include<SPI.h>
#include<LiquidCrystal.h>
#define WIFI_SSID "CircuitDigest" // input your home or public wifi name
#define WIFI_PASSWORD "circuitdigest101" //password for Wifi
String Available = ""; //availability string
String fireAvailable = "";
LiquidCrystal_I2C lcd(0x27, 16, 2); //i2c display address 27 and 16x2 lcd display
Servo myservo; //servo as gate
Servo myservos; //servo as gate
int Empty; //available space integer
int allSpace = 90;
int countYes = 0;
int carEnter = D0; // entry sensor
int carExited = D4; //exi sensor
int TRIG = D7; //ultrasonic trig pin
int ECHO = D8; // ultrasonic echo pin
int led = D3; // spot occupancy signal
int pos;
int pos1;
long duration, distance;
void setup() {
delay(1000);
Serial.begin (9600); // serial debugging
Wire.begin(D2, D1); // i2c start
myservo.attach(D6); // servo pin to D6
myservos.attach(D5); // servo pin to D5
pinMode(TRIG, OUTPUT); // trig pin as output
pinMode(ECHO, INPUT); // echo pin as input
pinMode(led, OUTPUT); // spot indication
pinMode(carExited, INPUT); // ir as input
pinMode(carEnter, INPUT); // ir as input
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); //try to connect with wifi
Serial.print("Connecting to ");
Serial.print(WIFI_SSID); // display ssid
while (WiFi.status() != WL_CONNECTED) {
Serial.print("."); // if not connected print this
delay(500);
}
Serial.println();
Serial.print("Connected to ");
Serial.println(WIFI_SSID);
Serial.print("IP Address is : ");
Serial.println(WiFi.localIP()); //print local IP address
lcd.begin(); //begin lcd
lcd.home();
lcd.setCursor(0, 0); // 0th row and 0thh column
lcd.print("Welcome,Show Your Card Here");
}
void loop() {
//Check if any RFID Tags Detected or not?
if(rfid.isCard() )
{
//if RFID Tag is detected, check for the Unique ID,
//and print it on the Serial Window
if(rfid.readCardSerial() )
{
lcd.clear();
lcd.print("UNIQUE ID is:- ");
delay(500);
lcd.setCursor(0,1); //Set LCD Cursor to Second Row, First Character
digitalWrite(TRIG, LOW); // make trig pin low
delayMicroseconds(2);
digitalWrite(TRIG, HIGH); // make trig pin high
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
duration = pulseIn(ECHO, HIGH);
distance = (duration / 2) / 29.1; // take distance in cm
Serial.print("Centimeter: ");
Serial.println(distance);
int carEntry = digitalRead(carEnter); // read ir input
if (carEntry == HIGH) { // if high then count and send data
countYes++; //increment count
Serial.print("Car Entered = " ); Serial.println(countYes );
lcd.setCursor(0, 1);
lcd.print("Car Entered");
for (pos = 140; pos >= 45; pos -= 1) { // change servo position
myservos.write(pos);
delay(5);
}
delay(2000);
for (pos = 45; pos <= 140; pos += 1) { // change servo position
// in steps of 1 degree
myservos.write(pos);
delay(5);
}
Sheet.pushString("/Parking Status/", Available ); // send string to Google Sheet
lcd.clear();
}
int carExit = digitalRead(carExited); //read exit ir sensor
if (carExit == HIGH) { //if high then count and send
countYes--; //decrement count
Serial.print("Car Exited = " ); Serial.println(countYes);
lcd.setCursor(0, 1);
lcd.print("Car Exited");
for (pos1 = 140; pos1 >= 45; pos1 -= 1) { // change servo position
myservo.write(pos1);
delay(5);
}
delay(2000);
for (pos1 = 45; pos1 <= 140; pos1 += 1) { // change servo position
// in steps of 1 degree
myservo.write(pos1);
delay(5);
}
Firebase.pushString("/Parking Status/", fireAvailable ); // send string to firebase
lcd.clear();
}
if (distance < 6) { //if distance is less than 6cm then on led
Serial.println("Occupied ");
digitalWrite(led, HIGH);
}
if (distance > 6) { //if distance is greater than 6cm then off led
Serial.println("Available ");
digitalWrite(led, LOW);
}
Empty = allSpace - countYes; //calculate available data
Available = String("Available= ") + String(Empty) + String("/") + String(allSpace);
// convert the int to string
fireAvailable = String("Available=") + String(Empty) + String("/") + String(allSpace);
lcd.setCursor(0, 0);
lcd.print(Available); //print available data to lcd
}
CODE for RFID:
#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define SS_PIN D4
#define RST_PIN D0 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
#define BUZZ_PIN D8
#define GATE_PIN D3
const char* host = "script.google.com";
const int httpsPort = 443;
const char* fingerprint = "46 B2 C3 44 9C 59 09 8B 01 B6 F8 BD 4C FB 00 74 91 2F EF F6"; // for https
//***********Things to change*******************
const char* ssid = "";
const char* password = "";
String GOOGLE_SCRIPT_ID = ""; // Replace by your GAS service id
const String unitName = "headquarter"; // any name without spaces and special characters
//***********Things to change*******************
uint64_t openGateMillis = 0;
WiFiClientSecure client;
void LcdClearAndPrint(String text)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(text);
}
void Siren()
{
for (int hz = 440; hz < 1000; hz++) {
tone(BUZZ_PIN, hz, 50);
delay(5);
}
for (int hz = 1000; hz > 440; hz--) {
tone(BUZZ_PIN, hz, 50);
delay(5);
}
digitalWrite(BUZZ_PIN, LOW);
}
void Beep()
{
for (int i = 0; i < 1000; i++)
{
analogWrite(BUZZ_PIN, i);
delayMicroseconds(50);
}
digitalWrite(BUZZ_PIN, LOW);
}
void Beep2()
{
tone(BUZZ_PIN, 1000, 30);
delay(300);
digitalWrite(BUZZ_PIN, LOW);
}
void setup() {
pinMode(GATE_PIN, OUTPUT);
pinMode(BUZZ_PIN, OUTPUT);
digitalWrite(GATE_PIN, LOW);
digitalWrite(BUZZ_PIN, LOW);
Serial.begin(921600);
lcd.begin(); // Init with pin default ESP8266 or ARDUINO
// lcd.begin(0, 2); //ESP8266-01 I2C with pin 0-SDA 2-SCL
// Turn on the blacklight and print a message.
lcd.backlight();
LcdClearAndPrint("Loading");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Started");
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Initialize serial communications with the PC
while (!Serial);
// Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
delay(4); // Optional delay. Some board do need more time after init to be ready, see Readme
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
LcdClearAndPrint("Ready");
}
byte readCard[4];
void HandleDataFromGoogle(String data)
{
int ind = data.indexOf(":");
String access = data.substring(0, ind);
int nextInd = data.indexOf(":", ind + 1);
String name = data.substring(ind + 1, nextInd);
String text = data.substring(nextInd + 1, data.length());
Serial.println(name);
LcdClearAndPrint(name);
lcd.setCursor(0, 1);
lcd.print(text);
if (access=="-1")
{
lcd.print(" " + String("denied"));
Siren();
LcdClearAndPrint("Ready");
}
else if(access=="any")
{
lcd.print(" " + String("go in"));
OpenGate();
}
else if (access=="fridge")
{
lcd.print(" " + String("take it"));
OpenGate();
}
}
void OpenGate()
{
openGateMillis = millis()+5000;
digitalWrite(GATE_PIN, HIGH);
Beep();
delay(100);
Beep();
}
void CloseGate()
{
openGateMillis = 0;
digitalWrite(GATE_PIN, LOW);
Beep2();
LcdClearAndPrint("Ready");
}
void loop() {
if (openGateMillis > 0 && openGateMillis < millis())
{
CloseGate();
}
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when
idle.
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.println(F("Scanned PICC's UID:"));
String uid = "";
for (uint8_t i = 0; i < 4; i++) { //
readCard[i] = mfrc522.uid.uidByte[i];
Serial.print(readCard[i], HEX);
uid += String(readCard[i],HEX);
}
Serial.println("");
Beep();
LcdClearAndPrint("Please wait...");
String data = sendData("id=" + unitName + "&uid=" + uid,NULL);
HandleDataFromGoogle(data);
mfrc522.PICC_HaltA();
}
String sendData(String params, char* domain) {
//google scripts requires two get requests
bool needRedir = false;
if (domain == NULL)
{
domain=(char*)host;
needRedir = true;
params = "/macros/s/" + GOOGLE_SCRIPT_ID + "/exec?" + params;
}
Serial.println(*domain);
String result = "";
client.setInsecure();
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return "";
}
if (client.verify(fingerprint, domain)) {
}
Serial.print("requesting URL: ");
Serial.println(params);
client.print(String("GET ") + params + " HTTP/1.1\r\n" +
"Host: " + domain + "\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected()) {
String line = client.readStringUntil('\n');
//Serial.println(line);
if (needRedir) {
int ind = line.indexOf("/macros/echo?user");
if (ind > 0)
{
Serial.println(line);
line = line.substring(ind);
ind = line.lastIndexOf("\r");
line = line.substring(0, ind);
Serial.println(line);
result = line;
}
}
if (line == "\r") {
Serial.println("headers received");
break;
}
}
while (client.available()) {
String line = client.readStringUntil('\n');
if(!needRedir)
if (line.length() > 5)
result = line;
//Serial.println(line);
}
if (needRedir)
return sendData(result, "script.googleusercontent.com");
else return result;
}
CODE for GoogleScript.js:
var timeZone="CST";
var dateTimeFormat="dd/MM/yyyy HH:mm:ss";
var logSpreadSheetId="";
function sendEmail(message, id) {
var subject = 'Something wrong with ' + id;
MailApp.sendEmail(emailAddress, subject, message);
}
function doGet(e) {
var access="-1";
var text='go home';
var name='Who are you?';
var json;
var error="idk";
Logger.log(JSON.stringify(e)); // view parameters
var result = 'Ok'; // assume success
if (e.parameter == 'undefined') {
result = 'No Parameters';
} else {
var uid = '';
var onlyPing=false;
var id = 'headquarter';
var error = '';
for (var param in e.parameter) {
var value = stripQuotes(e.parameter[param]);
switch (param) {
case 'uid':
uid = value;
break;
case 'id':
id = value;
break;
default:
result = "unsupported parameter";
}
}
var sheet=SpreadsheetApp.getActive().getActiveSheet();
var data = sheet.getDataRange().getValues();
if (data.length == 0)
return;
for (var i = 0; i < data.length; i++) {
if (data[i][0] ==uid)
{
name=data[i][1];
access=data[i][2];
text=data[i][3];
break;
}
}
addLog(uid,id,name,access);
}
// json = {
// 'access':access,
// 'name': name,
// 'text':text,
// 'error':error}
result=(access+":"+name+":"+text);
return ContentService.createTextOutput(result);
// return ContentService.createTextOutput(JSON.stringify(json)
).setMimeType(ContentService.MimeType.JSON);
}
function addLog(uid,entrance, name,result) {
var spr=SpreadsheetApp.openById(logSpreadSheetId);
var sheet = spr.getSheets()[0];
var data = sheet.getDataRange().getValues();
var pos = sheet.getLastRow() + 1;
var rowData = [];
rowData[0] = Utilities.formatDate(new Date(), timeZone, dateTimeFormat);
rowData[4]=entrance;
rowData[1] = uid;
rowData[2] = name;
rowData[3] = result;
var newRange = sheet.getRange(pos, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
/**
* Remove leading and trailing single or double quotes
*/
function stripQuotes(value) {
return value.replace(/^["']|['"]$/g, "");
}
Summary of project:
In a nutshell, Smart Parking is a parking solution that can include in-ground Smart Parking sensors, cameras or counting sensors. These devices are usually embedded into parking spots or positioned next to them to detect whether parking bays are free or occupied.
Using the project we can track the record of cars entered in a parking lot as well as see if there are any available slots in the parking lot.
Comments
Post a Comment