#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Define LCDs (I2C address 0x27 for user display, 0x26 for reference display)
LiquidCrystal_I2C userLCD(0x27, 16, 2);
LiquidCrystal_I2C referenceLCD(0x26, 16, 2);
// Define ultrasonic sensor pins
#define TRIG_LEFT 6
#define ECHO_LEFT 7
#define TRIG_RIGHT 8
#define ECHO_RIGHT 9
// Define button pins
#define BUTTON_BIKE 2
#define BUTTON_CAR 3
// Constants for better readability
#define TOTAL_SLOT_WIDTH 250 // Total parking slot width in cm (2.5 meters)
#define BIKE_WIDTH_MIN 60 // Minimum bike width in cm
#define BIKE_WIDTH_MAX 90 // Maximum bike width in cm
#define CAR_WIDTH_MIN 200 // Minimum car width in cm
#define CAR_WIDTH_MAX 220 // Maximum car width in cm
#define MAX_BIKES 2 // Maximum number of bikes in the slot
#define DISPLAY_CHANGE_TIME 2000 // 2 seconds display time
#define DEBOUNCE_DELAY 250 // Button debounce delay
// System states
enum SystemState {
ASK_VEHICLE_TYPE, // Display "Which is your vehicle?"
SHOW_AVAILABILITY, // Show if slot #17 is available
UPDATE_OCCUPANCY // Internal state to update occupancy
};
// Global variables
SystemState currentState = ASK_VEHICLE_TYPE;
unsigned long stateChangeTime = 0;
unsigned long lastButtonPress = 0;
int occupiedWidth = 0; // Currently occupied width in cm
int remainingWidth = TOTAL_SLOT_WIDTH; // Remaining width in cm
int bikeCount = 0;
bool carParked = false;
void setup() {
// Configure ultrasonic sensor pins
pinMode(TRIG_LEFT, OUTPUT);
pinMode(ECHO_LEFT, INPUT);
pinMode(TRIG_RIGHT, OUTPUT);
pinMode(ECHO_RIGHT, INPUT);
// Configure button pins with internal pull-up resistors
pinMode(BUTTON_BIKE, INPUT_PULLUP);
pinMode(BUTTON_CAR, INPUT_PULLUP);
// Initialize LCDs
userLCD.init();
userLCD.backlight();
referenceLCD.init();
referenceLCD.backlight();
// Initialize serial for debugging
Serial.begin(9600);
Serial.println("Smart Parking System Initialized");
// Reset system to default state
resetSystem();
}
void loop() {
// Measure distance for reference
int leftDistance = getDistance(TRIG_LEFT, ECHO_LEFT);
int rightDistance = getDistance(TRIG_RIGHT, ECHO_RIGHT);
int currentWidth = 0;
if (leftDistance > 0 && rightDistance > 0 && leftDistance < 400 && rightDistance < 400) {
currentWidth = rightDistance - leftDistance;
}
// State machine for display and interaction
switch (currentState) {
case ASK_VEHICLE_TYPE:
// Display "Which is your vehicle?"
displayVehicleQuestion();
// Check if buttons are pressed (with debouncing)
if ((millis() - lastButtonPress) > DEBOUNCE_DELAY) {
// Bike button pressed
if (digitalRead(BUTTON_BIKE) == LOW) {
// Check if a bike can fit
if (remainingWidth >= BIKE_WIDTH_MAX) {
// Enough space for a bike
bikeCount++;
occupiedWidth += BIKE_WIDTH_MAX;
remainingWidth = TOTAL_SLOT_WIDTH - occupiedWidth;
Serial.print("Bike added. Count: ");
Serial.print(bikeCount);
Serial.print(", Remaining width: ");
Serial.println(remainingWidth);
// Change state to show availability
currentState = SHOW_AVAILABILITY;
stateChangeTime = millis();
}
lastButtonPress = millis();
}
// Car button pressed
if (digitalRead(BUTTON_CAR) == LOW) {
// Check if a car can fit
if (remainingWidth >= CAR_WIDTH_MIN && bikeCount == 0) {
// Enough space for a car
carParked = true;
occupiedWidth += CAR_WIDTH_MAX;
remainingWidth = TOTAL_SLOT_WIDTH - occupiedWidth;
Serial.println("Car added. No more space available.");
// Change state to show availability
currentState = SHOW_AVAILABILITY;
stateChangeTime = millis();
}
lastButtonPress = millis();
}
// Reset system if both buttons pressed simultaneously
if (digitalRead(BUTTON_BIKE) == LOW && digitalRead(BUTTON_CAR) == LOW) {
resetSystem();
lastButtonPress = millis();
}
}
break;
case SHOW_AVAILABILITY:
// Display slot availability
displaySlotAvailability();
// Change back to vehicle question after 2 seconds
if (millis() - stateChangeTime >= DISPLAY_CHANGE_TIME) {
currentState = ASK_VEHICLE_TYPE;
}
break;
case UPDATE_OCCUPANCY:
// This state is for internal updates if needed
currentState = ASK_VEHICLE_TYPE;
break;
}
// Always update the reference display with current status
updateReferenceDisplay(currentWidth);
// Short delay to prevent excessive processing
delay(50);
}
// Function to display "Which is your vehicle?"
void displayVehicleQuestion() {
userLCD.clear();
userLCD.setCursor(0, 0);
userLCD.print("Which is your");
userLCD.setCursor(0, 1);
userLCD.print("vehicle?");
}
// Function to display slot availability
void displaySlotAvailability() {
userLCD.clear();
userLCD.setCursor(0, 0);
userLCD.print("Slot #17: ");
userLCD.setCursor(0, 1);
// Check if slot is available
if (remainingWidth >= BIKE_WIDTH_MAX) {
userLCD.print("Available");
} else {
userLCD.print("FULL");
}
}
// Function to update reference display with detailed information
void updateReferenceDisplay(int currentWidth) {
referenceLCD.clear();
referenceLCD.setCursor(0, 0);
// First line shows occupancy status
if (carParked) {
referenceLCD.print("Car Parked");
} else if (bikeCount > 0) {
referenceLCD.print(bikeCount);
referenceLCD.print(" Bike");
if (bikeCount > 1) referenceLCD.print("s");
referenceLCD.print(" Parked");
} else {
referenceLCD.print("Slot Empty");
}
// Second line shows width information
referenceLCD.setCursor(0, 1);
referenceLCD.print("Rem:");
referenceLCD.print(remainingWidth);
referenceLCD.print("cm");
if (currentWidth > 0) {
referenceLCD.print(" W:");
referenceLCD.print(currentWidth);
}
}
// Function to measure distance with error checking
int getDistance(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Measure the response time
long duration = pulseIn(echoPin, HIGH, 30000); // Added timeout
// Check for invalid readings
if (duration == 0) {
return 400; // Return max distance if timeout
}
// Calculate and return distance in centimeters
int distance = duration * 0.034 / 2;
// Sanity check on the distance value
return (distance > 0 && distance < 400) ? distance : 400;
}
// Function to reset the system
void resetSystem() {
occupiedWidth = 0;
remainingWidth = TOTAL_SLOT_WIDTH;
bikeCount = 0;
carParked = false;
currentState = ASK_VEHICLE_TYPE;
Serial.println("System reset - slot now empty");
}