Abbildung 1:
Die LED Beispielschaltung für dieses Kapitel.
Alles zum korrekten Anschließen von LEDs an GPIOs gibt's im Kapitel zu LEDs mit Hilfe von GPIOs schalten.
Welche Pins welche Funktion haben, ist im Kapitel zur Hardware des Raspberry Pi nachzulesen.
Abbildung 2:
Das Servo muss wie in dieser Abbildung gezeigt, angeschlossen werden. Es empfiehlt sich ein Microservo, oft auch als 9g Servo bezeichnet, zu verwenden, da diese keinen allzu hohen Strom ziehen.
Endlos Blinken in schneller Abfolge
Im vorherigen Kapitel haben wir gelernt, GPIOs ein- und auszuschalten. Somit leuchtet eine an diesen Pin angeschlossene LED entweder mit maximaler Helligkeit oder überhaupt nicht. Wir haben in dem Beispiel die LED aber auch einmal lang und dreimal kurz blinken lassen, bevor das Programm beendet wurde. In dem folgenden Beispiel lassen wir die LED ständig blinken, das Python Skript läuft endlos weiter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python
import RPi.GPIO as GPIO # needed to switch GPIOs
from time import sleep # needed to make command "sleep" available
# Choose BOARD pin numbering
GPIO.setmode(GPIO.BOARD)
# Set GPIO number 16 to output mode
GPIO.setup(16, GPIO.OUT)
# If a skript has to be stopped by 'ctrl+c', we must permanentely
# watch for such an event, which is done be the 'try:' statement.
try:
# Turn on LED with maximum brightness
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(2.0) # Do nothing for 2.0 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(1) # Do nothing for 1 second
# The statement (1 == 1) is true forever!
# With that, the while loop and so the skript never ends.
# You must press 'ctrl + c' to abort the script execution.
while (1 == 1):
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.1) # Do nothing for 0.1 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.9) # Do nothing for 0.9 seconds
except KeyboardInterrupt:
# This is the code section executed after 'ctrl+c' is pressed
# Script ends after that section.
print ("...keyboard interrupt detected\n")
GPIO.cleanup()
In der while-Schleife wird die LED immer für 0.1s eingeschaltet und bleibt dann für 0.9s ausgeschaltet. In einer Sekunde leuchtet die LED 0.1s lang. Die benötigte Zeitdauer, um die Schleife einmal abzuarbeiten, beträgt eine Sekunde. Die benötigte Zeit von etwa 0.00001s = 10μs pro Schaltvorgang für einen GPIO lassen wir dabei einfach mal unter den Tisch fallen. Die Zeidauer zum Durchlaufen der while-Schleife wird als Periodendauer (T) bezeichnet, die Einschaltzeit der LED als Pulsweite (t1). Die Pulsweite im Verhältnis zur Periodendauer wird als Tastgrad bezeichnet und meist in Prozent angegeben. Für obiges Beispiel erhalten wir einen Tastgrad von:
100 * 0.1s / (0.1s + 0.9s) = 100 * 0.1s / 1s = 10%
Läuft das Skript, so ist zu sehen, wie die LED zunächst 2 Sekunden leuchtet und dann immer kurz aufblitzt, während die while-Schleife durchlaufen wird. Das Blinken wird erst durch Drücken der Tastenkombination 'ctrl + c' beendet. Verkürzen wir nun die Periodendauer der while-Schleife um den Faktor 2:
28
29
30
31
32
while (1 == 1):
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.05) # Do nothing for 0.05 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.45) # Do nothing for 0.45 seconds
Die LED blitzt in kürzeren Intervallen. Die Periodendauer beträgt nun nur noch 0.05s + 0.45s = 0.5s, der Tastgrad ist mit 100*0.05/0.50 = 10% jedoch gleich geblieben. Verkürzen wir die Periodendauer nun deutlich um den Faktor 100 im Vergleich zum ersten Versuch:
28
29
30
31
32
while (1 == 1):
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.001) # Do nothing for 0.001 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.009) # Do nothing for 0.009 seconds
Mit einer Periodendauer von T = 0.001s + 0.009s = 0.01s bei nach wie vor 100 * 0.001s / 0.010s = 10% Tastgrad sind nun mit dem bloßen Auge die einzelnen Schaltvorgänge der LED nicht mehr auszumachen. Zu sehen ist, dass die LED nach Starten des Skripts für 2 Sekunden mit der maximalen Helligkeit leuchtet und mit Beginn der while-Schleife die Helligkeit deutlich abnimmt. Je höher der Tastgrad:
28
29
30
31
32
while (1 == 1):
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.003) # Do nothing for 0.003 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.007) # Do nothing for 0.007 seconds
um so heller leuchtet die LED und je niedriger der Tastgrad:
28
29
30
31
32
while (1 == 1):
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.005) # Do nothing for 0.005 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.005) # Do nothing for 0.005 seconds
um so dunkler erscheint diese. In verschachtelten While-Schleifen können wir die Helligkeit der LED variieren:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/env python
import RPi.GPIO as GPIO # needed to switch GPIOs
from time import sleep # needed to make command "sleep" available
# Choose BOARD pin numbering
GPIO.setmode(GPIO.BOARD)
# Set GPIO number 16 to output mode
GPIO.setup(16, GPIO.OUT)
try: # Watch for interrupt events
# Turn on LED with maximum brightness
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(2.0) # Do nothing for 2.0 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(1) # Do nothing for 1 second
while (1 == 1): # This while loop runs forever
loopCount = 0
while (loopCount < 150): # Loop runs 150*(0.001s+0.009s)=1.5s
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.001) # Do nothing for 0.001 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.009) # Do nothing for 0.009 seconds
loopCount = loopCount + 1
loopCount = 0
while (loopCount < 150): # Loop runs 150*(0.003s+0.007s)=1.5s
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.003) # Do nothing for 0.003 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.007) # Do nothing for 0.007 seconds
loopCount = loopCount + 1
loopCount = 0
while (loopCount < 150): # Loop runs 150*(0.005s+0.005s)=1.5s
GPIO.output(16, GPIO.HIGH) # Turn LED ON
sleep(0.005) # Do nothing for 0.005 seconds
GPIO.output(16, GPIO.LOW) # Turn LED OFF
sleep(0.005) # Do nothing for 0.005 seconds
loopCount = loopCount + 1
except KeyboardInterrupt:
# This is the code section executed after 'ctrl+c' is pressed
# Script ends after that section.
print ("...keyboard interrupt detected\n")
GPIO.cleanup()
Startet ihr das Skript, so ändert sich die Leuchtkraft der LED alle 1.5s.
Die Pulsweitenmodulation ist ein gängiges Verfahren zum Dimmen von LEDs oder allgemein zur Leistungssteuerung der an einen GPIO angeschlossenen Verbraucher. Daher gibt es in Python eine Funktion, die genau das macht, was wir in den verschachtelten while-Schleifen abarbeiten. Als Parameter wird hierbei allerdings nicht die gewünschte Periodendauer des Pulsweitensignals übergeben, sondern die Frequenz (f). Diese ist der Kehrwert der Periodendauer:
f = 1 / T
Für das vorangegangene Beispiel erhalten wir f = 1 / (0.003s + 0.007s) = 1 / 0.01s = 100Hz.
Die in den folgenden Beispielen verwendete Python Funktion baut auf dem Softwarepaket "pigpio" auf, das auf den aktuellen Versionen von RaspianOS vorinstalliert ist. Sollte das nicht der Fall sein, so kann das Paket nachinstalliert werden:
sudo apt-get update
sudo apt-get install pigpio
Auf jeden Fall muss der sogenannte pigpio Daemon vor Ausführen des Skripts gestartet werden:
sudo pigpiod
Dieser Daemon kann automatisch beim Bootvorgang gestartet werden:
sudo systemctl enable pigpiod
Unter Verwendung der Funktionen kommt das Skript mit deutlich weniger Befehlszeilen aus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python
from time import sleep # needed to make command "sleep" available
from gpiozero import Device, PWMLED # needed to switch LED with pwm signals
# The older Raspberry Pi 1 or Pi Zero require to set the pin factory
from gpiozero.pins.pigpio import PiGPIOFactory
try: # Watch for interrupt events
# Pin factory for older Raspberry Pi models
Device.pin_factory = PiGPIOFactory()
# Set GPIO 16 to pwm mode with a base frequency of 100Hz
# Duty cycle is between 0.0 (=OFF) and 1.0 (=fully ON)
# For example 0.105 equals 10.5% duty cycle
# Initial duty cycle is 0.0
pwm16 = PWMLED("BOARD16", True, 0, 100)
while (1 == 1): # This while loop runs forever
pwm16.value = 0.1 # Set LED to 10% duty cycle
sleep(1) # Do nothing for 1 second
pwm16.value = 0.205 # Set LED to 20.5% duty cycle
sleep(1) # Do nothing for 1 second
pwm16.value = 0.4 # Set LED to 40% duty cycle
sleep(1) # Do nothing for 1 second
pwm16.value = 1.0 # Set LED to 100% duty cycle
sleep(1) # Do nothing for 1 second
except KeyboardInterrupt:
# This is the code section executed after 'ctrl+c' is pressed
# Script ends after that section.
print ("...keyboard interrupt detected\n")
Eine Mini-Leuchtshow mit zwei pulsierenden LEDs erhalten wir mit dem folgenden Skript, das zu erkunden ich euch selbst überlasse:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python
from time import sleep # needed to make command "sleep" available
from gpiozero import Device, PWMLED # needed to switch LED with pwm signals
# The older Raspberry Pi 1 or Pi Zero require to set the pin factory
from gpiozero.pins.pigpio import PiGPIOFactory
try: # Watch for interrupt events
# Pin factory for older Raspberry Pi models
Device.pin_factory = PiGPIOFactory()
pwm16 = PWMLED("BOARD16", True, 0, 100)
pwm22 = PWMLED("BOARD22", True, 0, 100)
# Define varying duty cycles for the LEDs
dutyCycle16 = 0.0
dutyCycle22 = 0.0
while (1 == 1): # This while loop runs forever
# Raise dutycycles
dutyCycle16 = dutyCycle16 + 0.01
dutyCycle22 = dutyCycle22 + 0.02
# Make sure that dutycycles are never greater than 1.0 (=100%)
if (dutyCycle16 > 1.0):
dutyCycle16 = 0.0 # start over with 0% duty cycle
if (dutyCycle22 > 1.0):
dutyCycle22 = 0.0
pwm16.value = dutyCycle16
pwm22.value = dutyCycle22
sleep(0.05) # Do nothing for 0.01 seconds
except KeyboardInterrupt:
# This is the code section executed after 'ctrl+c' is pressed
# Script ends after that section.
print ("...keyboard interrupt detected\n")
Servo
Abbildung 3:
Die Ansteuerung von Servos erfolgt ebenfalls per Pulsweitenmodulation:
Die Frequenz muss dabei 50Hz entsprechen und der Tastgrad im Bereich zwischen 5% (=-45° und 10% (=+45°) liegen. Die Mittelstellung entspricht einem Tastgrad von 7.5%
Mehr dazu gibt's im Kapitel zu Servos.
Da Servos recht gebräuchliche Antriebe sind, gibt es in Python darauf abgestimmte Funktionen, welche die Grundfrequenz von 50Hz vorgeben. Die Stellung des Servohebels wird nicht in Grad oder direkt in der Pulsweite angegeben, sondern variiert von -1.0 (=-90°) bis +1.0 (=+90°), wobei 0.0 der Mittelstellung entspricht:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python
from time import sleep # needed to make command "sleep" available
from gpiozero import Device, Servo # Needed for Servo control signals
# The older Raspberry Pi 1 or Pi Zero require to set the pin factory
from gpiozero.pins.pigpio import PiGPIOFactory
try: # Watch for interrupt events
# Pin factory for older Raspberry Pi models
Device.pin_factory = PiGPIOFactory()
# Control line of Servo connected to pin 1_12 on Raspberry Pi
servo12 = Servo("BOARD12")
# Create variable for servo angle
servoAngle = -1.0
while (1 == 1): # This while loop runs forever
# Set servo angle
servo12.value = servoAngle
# Raise servo angle
servoAngle = servoAngle + 0.1
# Make sure that servoAngle doesn't get greater than 1
if (servoAngle > 1.0):
servoAngle = -1 # start over with -1
sleep(1.0) # Give the servo arm some time to settle
except KeyboardInterrupt:
# This is the code section executed after 'ctrl+c' is pressed