Build a Miniature Parking Tower That Parks Cars by Itself!
Meet Levo — a 3-level Arduino parking tower that reads a car's RFID tag, lifts it up on an elevator, and rotates it into an empty bay. Tap the same tag again, and Levo brings your car right back down!
🏗️ Say hi to Levo, your automated parking tower!
What Is an Automated Parking Tower, Anyway?
In big cities, automated parking towers save space by stacking cars vertically instead of spreading them across a big lot. A robotic elevator lifts each car to an open level, and a mechanism slides it neatly into a bay — no driving around searching for a spot! In this project, Levo shrinks that whole idea down to a desktop-sized model using RFID tags to identify each toy car and motors and servos to move it into place.
What You'll Need
Gather these parts before you start building your parking tower!
Arduino Uno
The brain that tracks every car and controls the elevator.
RC522 RFID Reader + Tags
Identifies each toy car by its unique tag.
DC Gear Motor + L298N Driver
Raises and lowers the elevator platform between levels.
IR Break-Beam Level Sensors
Tell the Arduino exactly when the elevator reaches each floor.
SG90 Micro Servo Motors
One per level, rotating cars into and out of their parking bay.
LEDs (one per level)
Lit when that level's bay is occupied.
Small Buzzer
Beeps to confirm parking, retrieval, or a full tower.
Cardboard or 3D-Printed Tower Frame
Holds the 3 levels, elevator shaft, and bays.
Breadboard + ~25 Jumper Wires
Connects every sensor, motor, and servo.
The Circuit Diagram
The RFID reader, elevator motor, level sensors, and three parking-bay servos all connect to one Arduino Uno.
Step-by-Step Build Instructions
We'll build the tower frame first, then wire the electronics level by level. Work with an adult on the elevator mechanism!
Build the tower frame
Construct a 3-level open-frame tower from cardboard, foam board, or a 3D-printed kit, with a vertical shaft down the middle for the elevator platform.
Install the elevator
Attach a small platform to a pulley-and-string or rack-and-pinion system driven by the DC gear motor, so it can travel smoothly up and down the shaft.
💡 Tip: Test the elevator's up/down movement by hand first before connecting the motor, to make sure it slides freely.Add the level sensors
Mount one IR break-beam sensor at each floor (Ground, Level 1, Level 2) so the Arduino always knows exactly when the elevator arrives at a level.
Build the parking bay servos
At each level, mount a servo with a small pushing arm that can slide a car sideways off the elevator platform into an empty bay, and pull it back for retrieval.
Mount the RFID reader and LEDs
Place the RFID reader at the tower's entrance where cars "tap in." Add one LED per level to show at a glance which bays are occupied.
Attach an RFID tag to each toy car
Stick a small RFID tag underneath each toy car so it can be identified the moment it's placed on the elevator platform.
Wire everything and test
Connect the motor driver, sensors, servos, and buzzer exactly as shown in the circuit diagram, upload the code, and tap a car's tag to watch Levo park it automatically!
The Arduino Code
This code needs the MFRC522 and Servo libraries. Copy it in, adjust motor directions to match your wiring, then click Upload.
// 🚗🤖 Levo the Automated Parking Tower — Arduino RFID Robotics Project // Identifies cars by RFID, lifts them by elevator, and parks them in a free bay #include <SPI.h> #include <MFRC522.h> #include <Servo.h> #define SS_PIN 10 #define RST_PIN 9 MFRC522 rfid(SS_PIN, RST_PIN); // ---- Elevator motor (via L298N) ---- const int enaPin = 3, in1Pin = 4, in2Pin = 5; const int levelSensorPins[3] = {2, 6, 7}; // Ground, Level 1, Level 2 // ---- Bay servos + occupied LEDs ---- Servo baySer[3]; const int servoPins[3] = {A0, A1, A2}; const int ledPins[3] = {A3, A4, A5}; const int buzzerPin = 8; // ---- Parking memory ---- bool occupied[3] = {false, false, false}; byte parkedUID[3][4]; int currentLevel = 0; void setup() { SPI.begin(); rfid.PCD_Init(); pinMode(enaPin, OUTPUT); pinMode(in1Pin, OUTPUT); pinMode(in2Pin, OUTPUT); for (int i = 0; i < 3; i++) { pinMode(levelSensorPins[i], INPUT); baySer[i].attach(servoPins[i]); baySer[i].write(0); // bay arm retracted pinMode(ledPins[i], OUTPUT); } pinMode(buzzerPin, OUTPUT); Serial.begin(9600); } void loop() { if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return; int knownSlot = findParkedSlot(); if (knownSlot != -1) { retrieveCar(knownSlot); } else { int freeSlot = findFreeSlot(); if (freeSlot != -1) { parkCar(freeSlot); } else { alertFull(); } } rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); } // Moves a new car up to a free level and rotates it into the bay void parkCar(int level) { moveElevatorTo(level); baySer[level].write(90); // push car into bay delay(600); for (int i = 0; i < 4; i++) parkedUID[level][i] = rfid.uid.uidByte[i]; occupied[level] = true; digitalWrite(ledPins[level], HIGH); moveElevatorTo(0); // send elevator back to ground tone(buzzerPin, 1500, 200); } // Brings a known car back down to the ground floor void retrieveCar(int level) { moveElevatorTo(level); baySer[level].write(0); // pull car back onto elevator delay(600); occupied[level] = false; digitalWrite(ledPins[level], LOW); moveElevatorTo(0); tone(buzzerPin, 1000, 300); } // Drives the elevator motor until it reaches the target level's sensor void moveElevatorTo(int targetLevel) { bool goingUp = targetLevel > currentLevel; digitalWrite(in1Pin, goingUp ? HIGH : LOW); digitalWrite(in2Pin, goingUp ? LOW : HIGH); analogWrite(enaPin, 180); while (digitalRead(levelSensorPins[targetLevel]) == LOW) { delay(10); // keep driving until the level sensor triggers } analogWrite(enaPin, 0); // stop the motor currentLevel = targetLevel; } // Checks if this scanned card matches a car already parked int findParkedSlot() { for (int level = 0; level < 3; level++) { if (!occupied[level]) continue; bool match = true; for (int i = 0; i < 4; i++) { if (rfid.uid.uidByte[i] != parkedUID[level][i]) match = false; } if (match) return level; } return -1; } // Finds the first empty parking level int findFreeSlot() { for (int level = 0; level < 3; level++) { if (!occupied[level]) return level; } return -1; } // Plays a warning pattern when the tower has no free bays void alertFull() { for (int i = 0; i < 3; i++) { tone(buzzerPin, 400, 150); delay(200); } }
How Does Levo Actually Work?
Here are the big robotics ideas hiding inside this project:
Position Feedback
Rather than guessing how far the motor has spun, the level sensors give Levo real feedback — it drives until the sensor confirms it has actually arrived.
Remembering Where Each Car Went
The parkedUID array acts like a parking log, storing exactly which car's RFID tag is in which level, so it can be found again later.
Two Outcomes, One Scan
A single RFID tap does double duty: if the car is already parked, Levo retrieves it; if not, it looks for a free spot — smart branching logic in action.
Motor Direction Control
Sending different HIGH/LOW patterns to the motor driver's two input pins is what makes the elevator motor spin one way to go up, and the other way to come down.
🧑🔬 Safety First!
- Build with an adult, especially when wiring the motor driver and assembling the elevator mechanism.
- Keep fingers clear of the elevator shaft and pulley system while it's powered on.
- Use only lightweight toy cars — check your motor and pulley can safely lift the weight before full testing.
- Double-check all wiring against the circuit diagram before connecting power.
- This is a scaled-down learning model, not a certified parking system for real vehicles.
Frequently Asked Questions
What if the elevator doesn't stop exactly at a level?
Adjust the physical position of each IR level sensor slightly, or lower the motor speed in moveElevatorTo() so it responds more precisely when a sensor triggers.
Can I add more than 3 levels?
Yes! Just add more entries to the levelSensorPins, servoPins, ledPins, occupied, and parkedUID arrays, and update the loop limits from 3 to your new number of levels.
Why compare all 4 bytes of the RFID UID?
Each RFID tag's ID is made of several bytes — checking every byte (not just one) makes sure Levo never confuses two different cards that might share a similar first number.
What age group is this project good for?
Because it combines a mechanical elevator, RFID, and multiple servos, this project is best suited for kids around age 10+ working closely with an adult.

Comments
Post a Comment