Projektidee
Wir bauen gemeinsam ein kleines Parkplatzsystem mit Schranke. Es erkennt ankommende Autos, überprüft die Verfügbarkeit von zwei Parkplätzen und steuert eine Schranke sowie LEDs.
Ziele des Projekts
- Den Umgang mit Sensoren (Ultraschall, Lichtsensor) lernen
- Steuerung von LEDs und Servomotor verstehen
- Logisches Denken und Zustandslogik entwickeln
- Ein reales Problem (Parkplatz voll oder frei) technisch lösen
Benötigte Bauteile
- 1× Arduino Uno (oder kompatibel)
- 1× Ultraschallsensor (HC-SR04)
- 1× Servomotor (z. B. SG90)
- 2× Lichtsensoren (LDR oder Fotodiode) + Widerstände (z.B. 10kΩ)
- LEDs: je Parkplatz eine rote, eine grüne, eine Ankunfts-LED
- Vorwiderstände für LEDs (220–330 Ω)
- Steckbrett, Kabel, ggf. externe 5 V-Versorgung
Funktionsweise
Das System hat zwei Parkplätze. Mit den Lichtsensoren wird festgestellt, ob ein Platz frei oder belegt ist:
- Grüne LED: Parkplatz ist frei
- Rote LED: Parkplatz ist belegt
- Ankunfts-LED: Leuchtet, wenn der Ultraschallsensor ein Auto vor der Schranke erkennt.
Vor der Schranke erkennt ein Ultraschallsensor, ob ein Auto ankommt. Nur wenn mindestens ein Parkplatz frei ist, öffnet die Schranke. Sind beide Plätze belegt, bleibt sie geschlossen.
Schritt-für-Schritt Aufbau
- Verdrahte den Ultraschallsensor (TRIG, ECHO, VCC, GND) mit dem Arduino.
- Verbinde den Servomotor mit 5V, GND und einem digitalen Pin (z. B. D6).
- Baue die Lichtsensoren als Spannungsteiler mit Widerständen auf und schließe sie an A0 und A1 an.
- Setze LEDs mit Vorwiderständen ein und verbinde sie mit digitalen Pins.
- Prüfe jeden Teil einzeln: LEDs, Sensoren, Servo.
- Kombiniere danach die Logik: Schranke reagiert auf Auto + Parkplatzstatus.
Arduino-Code (C++)
Der Code ist stark kommentiert, um jeden Schritt verständlich zu machen, und verwendet die millis()-Funktion statt delay() für die Schrankensteuerung, damit das Programm reaktionsfähig bleibt.
/*
* Arduino-Projekt: Parkplatz mit Schranke
* Dieser Sketch steuert ein Parkplatzsystem mit zwei Plätzen.
* - Ein Ultraschallsensor (HC-SR04) erkennt ankommende Autos.
* - Zwei Lichtsensoren (LDRs) prüfen, ob die Parkplätze belegt sind.
* - LEDs (rot/grün) zeigen den Status jedes Parkplatzes an.
* - Eine Ankunfts-LED leuchtet, wenn ein Auto erkannt wird.
* - Ein Servomotor (SG90) steuert die Schranke.
*
* Die Schranke öffnet nur, wenn ein Auto ankommt UND mindestens ein Platz frei ist.
*/
// 1. Bibliotheken einbinden
#include <Servo.h> // Für die Ansteuerung des Servomotors
// 2. Pin-Definitionen (Konstanten)
// Ändere diese Pins, falls du eine andere Verdrahtung verwendest.
// Ultraschallsensor (Ankunft)
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
// Servomotor (Schranke)
const int SERVO_PIN = 6;
// Lichtsensoren (Parkplätze)
const int LDR1_PIN = A0; // Parkplatz 1
const int LDR2_PIN = A1; // Parkplatz 2
// LEDs
const int LED_GREEN1_PIN = 2; // Parkplatz 1 Frei
const int LED_RED1_PIN = 3; // Parkplatz 1 Belegt
const int LED_GREEN2_PIN = 4; // Parkplatz 2 Frei
const int LED_RED2_PIN = 5; // Parkplatz 2 Belegt
const int LED_ARRIVAL_PIN = 7; // Auto an Schranke erkannt
// 3. Schwellenwerte und Einstellungen (WICHTIG: Diese musst du anpassen!)
// Schwellenwert für die Lichtsensoren (0-1023)
// HINWEIS: Dieser Wert hängt stark von deiner Spannungsteiler-Schaltung
// und dem Umgebungslicht ab!
// Annahme: Spannungsteiler ist [5V] -- [10k Widerstand] -- [A0] -- [LDR] -- [GND]
// -> Mehr Licht = LDR Widerstand sinkt = Spannung an A0 sinkt
// -> Weniger Licht (Auto drüber) = LDR Widerstand steigt = Spannung an A0 steigt
// Teste die Werte mit dem Seriellen Monitor!
const int LDR_THRESHOLD = 500; // Beispielwert, wenn A0 > 500, dann "belegt"
// Schwellenwert für den Ultraschallsensor (in cm)
// Wenn ein Auto näher als dieser Wert ist, gilt es als "angekommen".
const int CAR_DISTANCE_THRESHOLD = 20; // z.B. 20 cm
// Positionen für den Servomotor (0-180 Grad)
const int SERVO_CLOSED_POS = 0; // Schranke zu
const int SERVO_OPEN_POS = 90; // Schranke offen
// Wie lange die Schranke offen bleiben soll, *nachdem* das Auto weg ist (in Millisekunden)
const long BARRIER_OPEN_DELAY = 5000; // 5 Sekunden
// 4. Globale Variablen
Servo myservo; // Servo-Objekt erstellen
// Zustandsvariablen für die Logik
bool spot1_occupied = false;
bool spot2_occupied = false;
bool car_at_gate = false;
bool barrier_is_open = false;
// Timer für die Schranke (verwendet millis())
unsigned long barrier_timer_start = 0;
// 5. Setup-Funktion (wird einmal beim Start ausgeführt)
void setup() {
Serial.begin(9600); // Seriellen Monitor starten (zum Testen der Sensorwerte)
// Pins für LEDs als AUSGANG definieren
pinMode(LED_GREEN1_PIN, OUTPUT);
pinMode(LED_RED1_PIN, OUTPUT);
pinMode(LED_GREEN2_PIN, OUTPUT);
pinMode(LED_RED2_PIN, OUTPUT);
pinMode(LED_ARRIVAL_PIN, OUTPUT);
// Pins für Ultraschallsensor
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// LDR-Pins sind standardmäßig Eingänge (analogRead)
// Servo initialisieren
myservo.attach(SERVO_PIN);
myservo.write(SERVO_CLOSED_POS); // Sicherstellen, dass die Schranke am Anfang zu ist
Serial.println("Parkplatzsystem gestartet.");
}
// 6. Loop-Funktion (wird ständig wiederholt)
void loop() {
// Schritt 1: Alle Sensoren auslesen und Zustände aktualisieren
checkParkingSpots();
checkCarArrival();
// Schritt 2: LEDs basierend auf den Zuständen steuern
updateParkingLEDs();
updateArrivalLED();
// Schritt 3: Die Schrankenlogik ausführen
controlBarrier();
// (Optional) Sensorwerte zur Kalibrierung ausgeben
// printSensorValues();
delay(50); // Kleine Verzögerung, um das System stabil zu halten
}
// 7. Hilfsfunktionen
/*
* Liest die beiden LDR-Sensoren aus und setzt die
* globalen 'spot1_occupied' und 'spot2_occupied' Variablen.
*/
void checkParkingSpots() {
int ldr1_value = analogRead(LDR1_PIN);
int ldr2_value = analogRead(LDR2_PIN);
// Logik umkehren, falls LDRs anders verschaltet sind!
// (z.B. < LDR_THRESHOLD)
spot1_occupied = (ldr1_value > LDR_THRESHOLD);
spot2_occupied = (ldr2_value > LDR_THRESHOLD);
}
/*
* Fragt den Ultraschallsensor ab und setzt
* die globale 'car_at_gate' Variable.
*/
void checkCarArrival() {
long duration;
int distance_cm;
// Impuls senden
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Impuls empfangen und Zeit messen
duration = pulseIn(ECHO_PIN, HIGH);
// Zeit in Distanz umrechnen (cm)
distance_cm = duration * 0.034 / 2;
// Prüfen, ob die Distanz innerhalb des Schwellenwerts liegt
if (distance_cm > 0 && distance_cm < CAR_DISTANCE_THRESHOLD) {
car_at_gate = true;
} else {
car_at_gate = false;
}
}
/*
* Steuert die rot/grün LEDs für beide Parkplätze.
*/
void updateParkingLEDs() {
// Parkplatz 1
digitalWrite(LED_GREEN1_PIN, !spot1_occupied); // Grün AN, wenn NICHT belegt
digitalWrite(LED_RED1_PIN, spot1_occupied); // Rot AN, wenn belegt
// Parkplatz 2
digitalWrite(LED_GREEN2_PIN, !spot2_occupied);
digitalWrite(LED_RED2_PIN, spot2_occupied);
}
/*
* Steuert die Ankunfts-LED.
*/
void updateArrivalLED() {
digitalWrite(LED_ARRIVAL_PIN, car_at_gate);
}
/*
* Hauptlogik: Steuert die Schranke (Servo).
* Verwendet millis() für eine nicht-blockierende Steuerung.
*/
void controlBarrier() {
// Prüfen, ob Plätze frei sind
bool spots_available = !spot1_occupied || !spot2_occupied;
if (car_at_gate && spots_available) {
// Fall 1: Auto ist da UND Plätze sind frei
if (!barrier_is_open) {
// Schranke öffnen, falls sie noch zu ist
myservo.write(SERVO_OPEN_POS);
barrier_is_open = true;
Serial.println("Schranke öffnet.");
}
// WICHTIG: Timer jedes Mal zurücksetzen, solange das Auto da steht
barrier_timer_start = millis();
} else if (car_at_gate && !spots_available) {
// Fall 2: Auto ist da ABER alles ist belegt
if (barrier_is_open) {
myservo.write(SERVO_CLOSED_POS);
barrier_is_open = false;
Serial.println("Parkplatz voll. Schranke schließt.");
}
} else if (!car_at_gate && barrier_is_open) {
// Fall 3: Kein Auto (mehr) da, ABER Schranke ist noch offen
// Prüfen, ob die Wartezeit (DELAY) abgelaufen ist
if (millis() - barrier_timer_start > BARRIER_OPEN_DELAY) {
// Zeit ist um -> Schranke schließen
myservo.write(SERVO_CLOSED_POS);
barrier_is_open = false;
Serial.println("Auto durchgefahren. Schranke schließt.");
}
}
// Fall 4: Kein Auto da, Schranke ist zu -> Nichts tun.
}
/*
* (Optionale) Debug-Funktion: Gibt Sensorwerte im Seriellen Monitor aus.
* Entferne die '//' vor 'printSensorValues();' in der loop(), um dies zu nutzen.
*/
void printSensorValues() {
Serial.print("LDR1: ");
Serial.print(analogRead(LDR1_PIN));
Serial.print(" (Belegt: ");
Serial.print(spot1_occupied);
Serial.print(") | LDR2: ");
Serial.print(analogRead(LDR2_PIN));
Serial.print(" (Belegt: ");
Serial.print(spot2_occupied);
Serial.print(") | Distanz: ");
Serial.print(getDistance()); // Ruft die Distanzmessung erneut auf
Serial.print("cm (Auto: ");
Serial.print(car_at_gate);
Serial.println(")");
}
// Kleine Hilfsfunktion, um die Distanz nur für das Debugging zu bekommen
int getDistance() {
long duration;
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
duration = pulseIn(ECHO_PIN, HIGH);
return duration * 0.034 / 2;
}
Wichtige Hinweise zum Programm
1. Kalibrierung der LDRs (Lichtsensoren)
Der wichtigste Schritt, damit das Programm funktioniert, ist die Einstellung des LDR_THRESHOLD.
- Lade den Code auf dein Arduino.
- Öffne den Seriellen Monitor (Werkzeuge -> Serieller Monitor).
- Entferne die Kommentarzeichen (
//) vor der ZeileprintSensorValues();in derloop()-Funktion und lade den Code erneut hoch. - Du siehst jetzt die Live-Werte deiner LDRs (0-1023).
- Notiere den Wert, wenn der Parkplatz frei ist (z.B. 350).
- Decke den Sensor ab (z.B. mit einem Spielzeugauto oder deiner Hand), um "belegt" zu simulieren. Notiere diesen Wert (z.B. 700).
- Dein
LDR_THRESHOLDmuss zwischen diesen beiden Werten liegen (z.B. 500). - Trage diesen Wert oben im Code bei
const int LDR_THRESHOLD = 500;ein.
checkParkingSpots() umdrehen: spot1_occupied = (ldr1_value < LDR_THRESHOLD);
2. Kalibrierung des Ultraschallsensors
Stelle einen Gegenstand (z.B. eine Schachtel) in der Entfernung vor den Sensor, in der ein Auto erkannt werden soll. Lies den "Distanz"-Wert im Seriellen Monitor ab und passe CAR_DISTANCE_THRESHOLD entsprechend an.
3. Stromversorgung des Servos (Wichtig!)
Wie im Projekttext erwähnt: Wenn dein Servo zittert oder sich nicht bewegt, reicht der Strom vom USB-Anschluss des Arduino nicht aus.
Lösung: Verwende eine externe 5V-Stromquelle (z.B. ein altes Handynetzteil mit abgeschnittenem Kabel oder ein Batteriepack).
- Verbinde +5V der externen Quelle mit dem + (rotes Kabel) des Servos.
- Verbinde GND der externen Quelle mit dem GND (braunes/schwarzes Kabel) des Servos UND mit einem GND-Pin am Arduino (das nennt man "gemeinsame Masse").
- Das Signalkabel (orange/gelb) des Servos bleibt am Arduino-Pin (z.B. D6).
Fragen zum Nachdenken
- Wie kann man verhindern, dass die LEDs bei schwankendem Licht flackern?
- Wie könnte man die Schranke länger offen lassen, wenn mehrere Autos nacheinander kommen? (Tipp: Der Code löst das bereits!)
- Welche Erweiterungen fallen euch ein? (z. B. Display mit „freie Plätze: 1“)
Mögliche Erweiterungen
- Anzeige der freien Plätze auf einem kleinen LCD
- Piezo-Buzzer, wenn die Schranke öffnet
- RFID-Chip, um die Einfahrt nur bestimmten Autos zu erlauben
Viel Erfolg bei eurem Projekt! 🚗