Ampelprojekt – Phase 3: Programmierung

Dem Aufbau des Modells folgt die abstrakte Modellierung, die Beschreibung der Ampel mit Methoden der Informatik. Das ist die Voraussetzung für die Implementierung als Programm.

Einfache Ausgaben – Testprogramm A

Zunächst soll der Aufbau getestet werden. Gelingt es eine LED an- und auszuschalten?

import RPi.GPIO as GPIO, time

print("""
==========================
==    TEST 1 LED        ==
==========================""")

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(8, GPIO.OUT, initial=GPIO.LOW)    #aa gr
GPIO.setup(10, GPIO.OUT, initial=GPIO.LOW)   #aa g
GPIO.setup(12, GPIO.OUT, initial=GPIO.LOW)   #aa r

GPIO.setup(3, GPIO.OUT, initial=GPIO.LOW)    #fa r
GPIO.setup(5, GPIO.OUT, initial=GPIO.LOW)    #fa gr

GPIO.output(8, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(8, GPIO.LOW)
time.sleep(0.5)

print("done.")

Testprogramm B

Gelingt es alle LEDs an- und auszuschalten?

import RPi.GPIO as GPIO, time

def onoff(pin, t):  # (***)
    GPIO.output(pin, GPIO.HIGH)
    time.sleep(t)
    GPIO.output(pin, GPIO.LOW)
    time.sleep(t)

print("""
==========================
==    TEST alle LEDs    ==
==========================""")

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(8, GPIO.OUT, initial=GPIO.LOW)    #aa gr
GPIO.setup(10, GPIO.OUT, initial=GPIO.LOW)   #aa g
GPIO.setup(12, GPIO.OUT, initial=GPIO.LOW)   #aa r

GPIO.setup(3, GPIO.OUT, initial=GPIO.LOW)    #fa r
GPIO.setup(5, GPIO.OUT, initial=GPIO.LOW)    #fa gr

liste = [8,10,12,3,5] # (*)

for led in liste:     # (**)
    onoff(led, 0.5)

print("done.")

Das Programm B unterscheidet sich in drei Punkten von Programm A: Eine Liste enthält alle Pins (*) und wird in einer Schleife abgearbeitet (**). In der Schleife wird eine Funktion aufgerufen, die auf einen Pin Strom gibt und ihn wieder abschaltet (***).

Video 5: Testprogramm B, Ampel 01

Abfrage von Eingaben an Tastern

Das Ampelsystem ändert seinen Zustand nach dem Drücken des Knopfes an einer der beiden Ampeln. Diese Zustandsänderung soll immer verfügbar sein, d.h. sie soll immer wieder ausgelöst werden können.

Abbildung 7: Zustandsdiagramm – Zustandsübergang ausgelöst durch Drücken der Taste an der Ampel.

Um den Zustandsübergang von Zustand 1 zu Zustand 2 auszulösen, braucht das Ampelsystem eine Eingabemöglichkeit ähnlich der echten Ampel: Wenn ein bestimmter Knopf gedrückt wird, schaltet die Ampel um. Der Übergang von Zustand 2 zu Zustand 1 erfolgt dagegen zeitgesteuert: Wenn die Fußgänger genug Zeit hatten, um die Ampel zu überqueren, wird das Signallicht zurückgestellt.

Programm 02 führt dazu drei Änderungen ein. Zentral ist die Endlosschleife (*) mit der Abfrage (**) der Pins 16 bzw. 18. Als Grundlage dafür werden die beiden Pins 16 und 18 als Eingaben konfiguriert (***).

import RPi.GPIO as GPIO, time

#===============================#
# FUNCTION                      #

def onoff(pin, t):
    GPIO.output(pin, GPIO.HIGH)
    time.sleep(t)
    GPIO.output(pin, GPIO.LOW)
    time.sleep(t)

#===============================#
# CONFIG / SETUP                #

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

lights = [8,    # autoampel gruen
          10,   # aa gelb
          12,   # aa rot
          3,    # fussgaengerampel rot   
          5     # fa gruen
          ]

for led in lights:
    GPIO.setup(led, GPIO.OUT, initial=GPIO.LOW)

GPIO.setup(16, GPIO.IN) # input 1     (***)
GPIO.setup(18, GPIO.IN) # input 2

#===============================#    
# HAUPTPRG                      #

print("""prg: ampel 02
==========================
==    TEST              ==
==========================""")

while True:                              # (*)
    if GPIO.input(16) or GPIO.input(18): # (**)
        for led in lights:
            onoff(led, 0.5)

Die Endlosschleife bewirkt, dass die nachfolgende Abfrage immer wieder geprüft wird. Im Effekt werden jedes Mal nach dem Drücken des ersten oder des zweiten Tasters alles LEDs einmal durchgeschaltet. Im Vergleich mit der fertigen Ampel fehlt jetzt noch die Logik der Signale.

Video 6: Programm Ampel 02

Bedingte Signalschaltung

Programm 03 bringt die Endlosschleife, die Abfrage der Pins und die bedingte Ausführung der Funktionen fussgaenger() bzw. autofahrer() in eine logische Folge. Dabei stellt die Funktion fussgaenger() Zustand 2 her (*), die Funktion autofahrer() stellt danach zeitbedingt Zustand 1 her (**).

Video 6: Programm Ampel 03
import RPi.GPIO as GPIO, time

#==============================================#
# CONFIG / SETUP                               #

# globale Variablen: verfuegbare Pins
aa_gruen =  8 # Output: LEDs
aa_gelb  = 10
aa_rot   = 12
fa_rot   =  3
fa_gruen =  5

in_1     = 16 # Input: Taster
in_2     = 18

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(aa_gruen, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(aa_gelb,  GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(aa_rot,   GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(fa_rot,   GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(fa_gruen, GPIO.OUT, initial=GPIO.LOW)

GPIO.setup(in_1, GPIO.IN) # input 1
GPIO.setup(in_2, GPIO.IN) # input 2

#==============================================#
# FUNKTIONEN                                   #

def fussgaenger():
    # fussgaenger rot und autofahrer gruen
    GPIO.output(fa_rot, GPIO.HIGH)
    GPIO.output(aa_gruen, GPIO.HIGH)
    time.sleep(3)
    # autofahrer gelb
    GPIO.output(aa_gruen, GPIO.LOW)
    GPIO.output(aa_gelb, GPIO.HIGH)
    time.sleep(3)
    # autofahrer rot
    GPIO.output(aa_gelb, GPIO.LOW)
    GPIO.output(aa_rot, GPIO.HIGH)
    time.sleep(3)        
    # fussgaenger gruen
    GPIO.output(fa_rot, GPIO.LOW)
    GPIO.output(fa_gruen, GPIO.HIGH)    

def autofahrer():
    # fussgaenger rot
    GPIO.output(fa_gruen, GPIO.LOW)
    GPIO.output(fa_rot, GPIO.HIGH)
    time.sleep(3)        
    # autofahrer rot und gelb
    GPIO.output(aa_gelb, GPIO.HIGH)
    time.sleep(3)
    # autofahrer gruen
    GPIO.output(aa_gelb, GPIO.LOW)
    GPIO.output(aa_rot, GPIO.LOW)
    GPIO.output(aa_gruen, GPIO.HIGH)

def aus():
    GPIO.output(fa_rot, GPIO.LOW)
    GPIO.output(aa_gruen, GPIO.LOW)

#==============================================#  
# HAUPTPRG                                     #

print("""
================================================
==   PROGRAMM AMPEL 03                        ==
================================================
""")

while True:
    
    aus()
    
    if GPIO.input(in_1) or GPIO.input(in_2):
        # autoampel auf rot; fussgaenger gruen
        fussgaenger()     # (*)
        # zwischenzeit
        time.sleep(10)
        # autoampel auf gruen; fussgaenger rot
        autofahrer()      # (**)
        time.sleep(10)
            

Ampelprojekt – Phase 2: Aufbau des Modells

Das Modell des Straßenübergangs mit Fußgängerampel besteht aus der Basisplatte, den einzelnen elektronischen Teilen, dem Raspberry Pi und der Programmierung. Auf der Basisplatte werden alle Teile montiert und die LEDs, Widerstände und Kabel verlötet. Die Elektronik wird anschließend mit den Pins des Raspberry Pi verbunden.

Basisplatte

Die Basisplatte kann aus Sperrholz, Pappe oder ähnlichen Materialien gefertigt werden. Sie dient zu Befestigung der Ampeln. Im Grunde könnte man auch eine Steckplatine verwenden.

Abbildung 5: Skizze zum Aufbau des Modells

Mit Leim oder Heißkleber lassen sich die einzelnen Schichten fixieren. Die Ampeln können auch von unten durch die Basisplatte gesteckt und befestigt werden. Der entsprechende Durchlasss in der Mitte der Platte wird am Ende durch das Tonpapier für die Straße verschlossen.

Verkabelung

Nach dem Zusammenbau müssen die Kabelverbindungen verlötet werden.

Abbildung 6: Schaltplan der LEDs, Widerstände und Taster

Bei der Schaltung muss beachtet werden, dass jede LED durch einen Widerstand abgesichert ist. Beim Anschluss an den Raspberry Pi sollten 100 Ohm genügen. Oftmals liest man, dass 220 oder 330 Ohm verwendet werden.

Der Taster wird zusammen mit einem Pulldown-Widerstand angeschlossen. Beim Aktivieren des Tasters erzeugt das später einen Stromeingang, der von der Programmierschnittstelle des Raspberry Pi als Wert 1 erkannt wird.

Die Ampeln im Detail

Die einzelnen Ampeln wurden von der Unterseite der Platte mit Heißkleber fixiert und mit dünnen mehradrigen Kabelbändern verbunden. Die Kathoden der LEDs werden mit dem Schutzwiderstand verbunden. Die Taster wurden wegen der Stabilität auf ein kleines Platinenstück gelötet und dort mit dem Pulldown-Widerstand beschaltet. Alle Kabel werden zunächst auf die Unterseite der Basisplatte und von dort vor dem Raspberry Pi nach oben geführt. Die Steckverbindung zum Raspberry Pi lässt sich lösen, damit man den Einplatinenrechner mehrfach verwenden kann.

Weiter: Programmierung >>

Ampelprojekt – Phase 1: Testaufbau

Testaufbau am Steckbrett

Um sich dem Ampelsystem anzunähern wird zunächst eine Testschaltung aufgebaut. Dabei werden einzelne LEDs mit Pins des Raspberry verbunden und jeweils mit einem Schutzwiderstand von 100 Ohm abgesichert.

Abbildung 3: Schaltplan des Testaufbaus

Programmierung

Zunächst zeigt Programm 01, ob grundlegende Konzepte funktionieren: Läuft der Raspberry Pi? Funktioniert der Anschuss der Pins an das Steckbrett? Sind die Teile alle ganz?

import RPi.GPIO as GPIO
import time

print("prgO1.py")

# KONFIGURATION / SETUP
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
# Eine rote LED wird am physikalischen Pin 16 angeschlossen.
GPIO.setup(16, GPIO.OUT, initial=GPIO.LOW)

# LICHT AN / AUS
GPIO.output(16, GPIO.HIGH)    # "Rot an!"
time.sleep(0.5)               # 0,5 Sek. warten
GPIO.output(16, GPIO.LOW)     # "Rot aus!"

Am schnellsten erstellt man das Programm auf dem Raspberry Pi selbst mit der Python IDLE oder einem vorinstallierten Editor.

Programm 02 führt eine einfache For-Schleife ein, und zeigt damit, dass der elektronische Output fortlaufend wiederholbar ist. Das ist insofern wichtig, als die spätere Ampel selbstständig laufen soll und nicht nur dann, wenn die Maus auf der OS-Oberfläche des Raspberry Pi das Programm startet.

Video 2: Programm 02
import RPi.GPIO as GPIO
import time

print("prgO2.py")

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(16, GPIO.OUT, initial=GPIO.LOW)

for n in range(5):
    print("Durchgang: "+str(n+1))

    GPIO.output(16, GPIO.HIGH)
    print("rot an")
    time.sleep(1)
    GPIO.output(16, GPIO.LOW)
    print("rot aus")
    time.sleep(1)

Programm 03 zeigt, wie LEDs im Wechsel an- und ausgeschaltet werden können. Die Ampel folgt dann später dem typischen Phasenmodell, erfordert also über den reinen Wechsel hinaus noch die Logik der Signalabfolge.

Video 03: Programm 03
import RPi.GPIO as GPIO
import time

print("prgO3.py")
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT, initial=GPIO.LOW) #gelb
GPIO.setup(13, GPIO.OUT, initial=GPIO.LOW) #rot

for n in range(5):
    print("Durchgang: "+str(n+1))
    GPIO.output(11, GPIO.HIGH)
    GPIO.output(13, GPIO.LOW)
    print('gelb')
    time.sleep(1)
    GPIO.output(11, GPIO.LOW)
    GPIO.output(13, GPIO.HIGH)
    print('rot')
    time.sleep(1)
    
# alles aus
GPIO.output(11, GPIO.LOW)
GPIO.output(13, GPIO.LOW)

Phasen einer Ampel

Ampeln für den Straßenverkehr mit drei Signalleuchten schalten in Phasen nach immer derselben Logik.

Abbildung 4: Traffic lights 4 states; public domain, eingebettet von Wikimedia Commons.

Programm 04 setzt die Phasenschaltung der Verkehrsampel in einem imperativen Python-Skript um.

Video 4: Programm 04
import RPi.GPIO as GPIO, time

print("prgO4.py")
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(10, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(12, GPIO.OUT, initial=GPIO.LOW)
GPIO.output(8, GPIO.HIGH)
GPIO.output(10, GPIO.LOW)
GPIO.output(12, GPIO.LOW)
time.sleep(1)
GPIO.output(10, GPIO.HIGH)
time.sleep(1)
GPIO.output(8, GPIO.LOW)
GPIO.output(10, GPIO.LOW)
GPIO.output(12, GPIO.HIGH)
time.sleep(10)
GPIO.output(12, GPIO.LOW)

Weiter: Modell >>

Ampelprojekt mit dem Raspberry Pi

Abbildung 1: Im Vordergrund mittig die Ampel für Autofahrer und Fußgänger, etwas rechts davon der Taster zum Anfordern des Signals. Im Hintergrund rechts der Raspberry Pi4 mit dunklem Miuzei-Gehäuse.

Die Ampel ist ein beliebtes Beispiel im Informatikunterricht zur Zustandsmodellierung. In diesem Beitrag wird ausgehend von einem Raspberry Pi ein Ampelmodell entwickelt und programmiert. Das Projekt wird in drei Phasen entwickelt:

Voraussetzungen

Die Basis bildet der Raspberry Pi. Er ist mit Python einfach zu programmieren, verfügt über eine gute Anschlussfähigkeit dank der GPIO-Pins und über einen HDMI-Ausgang, den man beim Einsatz im Unterricht mit einer Dokumentenkamera oder direkt mit einem Beamer verbinden kann. Eine USB-Tastatur und Maus oder eine Bluetooth Multimedia-Tastatur ergänzen die Hardware. Geladen wird als Betriebssystem Rasberry Pi OS (früher Raspian). Das OS lässt sich frei herunterladen und auf eine Micro-SD-Karte schreiben. Kleine Ampeln lassen sich mit dem 3D-Drucker herstellen. Vorlagen gibt es zum Beispiel bei Thingiverse. Alternativ gibt es fertige Ampeln zum Bestellen. LEDs, Taster und Widerstände sind nicht besonders teuer und können bei verschiedenen Anbietern über das Internet bestellt werden.

Ziel

Abbildung 2: Die gesamte Ampelanlage.

Die gesamte Ampelanlage ist auf ein Sperrholzbrett montiert, die Straße aus Tonpapier ausgeschnitten und aufgeklebt. Die Verdrahtung erfolgt auf der Unterseite des Brettes: Die beiden Ampel für die Autofahrer sind parallel geschaltet, ebenso die Ampel für die Fußgänger. Es gibt zwei Taster, die mit einem Pull-Down-Widerstand als Input zur Anforderung des Fußgängersignals funktionieren. Programmierseitig werden sie mit einer ODER-Logik verbunden.

Video 1: Das fertige Ampelmodell

Weiter: Testaufbau am Steckbrett >>

Creative Commons Lizenzvertrag Dieses Werk ist lizenziert unter einer Creative Commons Namensnennung 4.0 International Lizenz.