Neuigkeiten    Das Projekt    Technik    RoboSpatium    Unterstützung    Stichwortverzeichnis    Download    Reaktionen    Spiele    Kauftipps    Kontakt   




<<< Python: GPIOs schalten         Python: Hintergrundaktivität >>>

Python: Pulsweitenmodulation

Der Schaltplan zum Kapitel

Schalten von LEDs mit Hilfe von Python
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.
Ansteuern eines Servos mit Hilfe von Python
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

Ansteuerung Servo per Pulsweitenmodulation
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  
    # Script ends after that section.  
    print ("...keyboard interrupt detected\n")  
    



<<< Python: GPIOs schalten         Python: Hintergrundaktivität >>>


Neuigkeiten    Das Projekt    Technik    RoboSpatium    Unterstützung    Stichwortverzeichnis    Archiv    Download    Reaktionen    Spiele    Verweise    Kauftipps    Kontakt    Impressum   





Twitter YouTube Hackaday Patreon TPO