Raspberry Pi Gleichstrommotor mit Motortreiber L293D und Pulsweitenmodulation
In dieser Anleitung wird auf die Grundlagen der Steuerung kleiner Gleichstrommotoren (DC Motoren) mit dem Raspberry Pi eingegangen. Dabei findet der gängige Motortreiber L293D Verwendung. Nachdem der Motor gesteckt und getestet wird, regeln wir die Drehzahl mittels Pulsweitenmodulation. Bestelllinks zu allen verwendeten Komponenten finden sich unten auf dieser Seite.
Der Motor |
![]() |
Der verwendete Gleichstrommotor (DC Motor) des chinesischen Herstellers Zhaowei dreht sich mit ca. 6 min-1 (U/min). Auf der Welle befindet sich eine angefräste Fläche für formschlüssige Welle-Nabe-Verbindungen (Kraftübertragung durch verkantete Formen). In der Regel verwendet man bei solchen Verbindungen Flachkeile nach DIN 6883, um das Drehmoment auf die Nabe (das durch die Motorwelle angetriebene Außenteil) zu übertragen. In unserem Fall ist das Nennmoment mit 16,08 Ncm (0,161 Nm) so gering, dass zur Kraftübertragung eine (Kugeldruck-)Schraube ausreichend wäre. Der Motor kann zwischen 3 V und 7,5 V betrieben werden. Der Arbeitspunkt liegt bei 6,5 min-1 (U/min). [Datenblatt/Technische Zeichnung]
Die Batterie |
![]() |
Die Batterie (oder eine vergleichbare Stromquelle) ist erforderlich, da der Raspberry Pi weder in der Lage ist, die 6 V, geschweige denn die 600 mA zu speisen. Unsere Batterie weist eine Ladung von 1600 mAh auf. Wenn der Motor konstant mit maximalem Stromverbrauch von 600mA fahren würde, reicht die Zeit:
L293D Motortreiber |
![]() |
Da der Raspberry Pi den Motor nicht direkt betreiben kann (Aufgrund unzureichender Spannungs- und Stromniveaus) wird ein zusätzlicher IC (Integrated Schaltkreis) benötigt. Diese Aufgabe übernimmt der L293D. Mit seinen vier integrierten Halb-H-Brücken ist er fähig, zwei Motoren mit bis zu je 600 mA unabhängig voneinander zu steuern. Die Versorgungsspannung darf dabei in einem Rahmen von 4,5 V bis 36 V liegen.
Der Pin 1 (Enable 1, violett) des ICs L293D wird verwendet, um die Schaltung für den ersten Motor zu aktivieren. Alternativ kann er auch für Pulsbreitenmodulation genutzt werden. Dafür benutzen wir allerdings der Einfachheit halber einen anderen Pin. Pin 9 (Enable 2) hat dieselbe Funktion für einen zweiten Moto. Pin 2 (In 1, orange) und 7 (In 2, orange) werden mit dem GPIO des Raspberry Pi verbunden. Je nachdem welcher der beiden Pins bestromt wird, dreht sich der Motor in die entsprechende Richtung. Werden beide Pins gleichzeitig bestromt, dreht der Motor sich nicht, genauso als würde kleiner von beiden bestromt. Über diese Pins werden wir auch später ergänzend die Pulsweitenmodulation durchführen. Äquivalente Funktionen erfüllen Pin 15 (In 4) und 10 (In 3) für einen zweiten Motor. Pin 3 (Out 1, gelb) und 5 (Out 2, grün) werden mit dem Motor verbunden. Pin 14 (Out 4) und 11 (Out 3) würden mit einem zweiten Motor verbunden. Die Pins 4,5,13,12 sind Masse-Pins (Ground, blau), welche mit einem Masse-Pin des Raspberry Pi, als auch mit dem der Batterie verdrahtet werden! Pin 8 (+Vmotor, rot) wird mit dem Pluspol (+, rot) der Batterie verbunden, hierüber erhält der Motor (die Motoren) seinen (ihren) Strom. Pin 16 (+V, violett) wird mit dem Strom des Raspberry Pi (5 V) verbunden, welcher für den Betrieb des L293D erforderlich ist.
PWM Geschwindigkeitssteuerung |
![]() |
Die Geschwindigkeit kleiner Gleichstrommotoren wird in der Regel über die Spannung gesteuert. Je größer die Spannung, desto schneller dreht sich die Welle des Motors. Allerdings verfügt der Raspberry Pi, als auch der Verwendete L293D Motor Treiber nur über digitale Ausgänge, welche einzig die Werte 0 (aus) und 1 (an) annehmen können. In unserem Fall bedeutet dies, dass entweder 0 V oder 6 V emittiert würden. Spannungen zwischen diesen beiden Werten sind nicht regelbar. Dennoch lässt sich die Geschwindigkeit des Motors mit einem Trick variieren: Mit der Pulsweitenmodulation (PWM). Innerhalb einer vorgegebenen Periodendauer T wird ein Rechteckimpuls mit variabler Zeitausprägung t erzeugt.
t
kann minimal 0 ms (Millisekunden) betragen und maximal den Wert von T
haben. Angegeben wird im Code allerdings das Verhältnis von t
zu T
. Dieses Verhältnis wird Tastgrad (engl. Duty Cycle) genannt und in % angegeben. In diesem Beispiel wäre es:
Die Schaltung |
![]() |
Um Beschädigungen an jeglichen Komponenten zu vermeiden, ist es erforderlich zunächst alle Masse (Ground) Pins korrekt zu verbinden! Erst nach mehrfacher Kontrolle sollten alle anderen Verbindungen getätigt werden!
In der Mitte der Steckplatte ist eine Teilung vorhanden, die verhindert, dass Strom von der linken Lochreihe zu der rechten- und umgekehrt fließt. Darüber wird der Motortreiber L293D platziert. Zudem ist drauf zu achten, dass er richtig herum platziert wird, damit die Pins nicht vertauscht werden. Deshalb befindet sich auf der vorderen Seite eine Einkerbung. Aus ihrer Höhe beginnt die Pinnummerierung auf der linken Seite mit 1.
Die Masse des Raspberry Pi (hier: Board-Pin 6) ist mit dem Breadboard (Steckplatine) über das blaue Jumperkabel verdrahtet. Über eine Brücke (blau) auf dem Steckbrett sind beide Massereihen miteinander verbunden. Eine weitere Verbindung (blau) von der Masse führt zum schwarzen Kabel der Batterie.
Der Motortreiber wird über die orangenen Kabel mit zwei Pins, außer natürlich jenen zur Stromversorgung bzw. als Masse gedachten, des GPIO verbunden. In diesem Beispiel: BCM-Pin 21 und 25.
Die Stromversorgung für den Treiber erfolgt über einen 5V Pin des Raspberry Pi (violett). Auch hier gibt es eine Brücke (violett) zur anderen Seite der Platine. An die 5V Stromversorgung wird der Pin 1 und 16 des L293D mit hier violett dargestellten Kabeln verknüpft.
Motor Testen |
![]() |
Erstmals verwenden wir UTF-8 Kodierung, die es uns erlaubt in Kommentaren und Variablen Umlaute (ä, ö, ü) zu verwenden (und auch sämtliche weitere Sonderzeichen).
#coding: utf8
Anschließend werden standardmäßig die erforderlichen Bibliotheken für die verwendeten Befehle importiert:
import RPi.GPIO as GPIO import time
Nun folgen ein paar, bereits aus den vorherigen Anleitungen bekannten Standardeinstellungen:
# Konvention für Pinnummerierung festlegen (BCM bzw. Board) GPIO.setmode(GPIO.BCM) # Warnungen, die das Ausführen des Programms verhindern, wenn # Ausgang bereits als OUT deklariert wurde ignorieren GPIO.setwarnings(False) # Pins als Ausgänge deklarieren GPIO.setup(21, GPIO.OUT) GPIO.setup(25, GPIO.OUT)
Die Frequenz (50 HZ) der Pulsweitenmodulation (PWM) wird zusammen mit der (BCM-)Pinnummer als Variable der Richtung des entsprechenden Pins deklariert, in die die Welle des Motors rotieren soll. Ein Pin steht dabei für eine Richtung.
# PWM für Richtungen mit Frequenz festlegen uhrzeigersinn = GPIO.PWM(21, 50) gegen_uhrzeigersinn = GPIO.PWM(25, 50)
Die beiden Pins werden mit einem Tastgrad von 0% initialisiert.
# PWM mit Tastgrad 0% initialisieren uhrzeigersinn.start(0) gegen_uhrzeigersinn.start(0)
Nur zum Testen:
Zunächst soll der Motor mit 100% Geschwindigkeit (Tastgrad) im Uhrzeigersinn für zwei Sekunden fahren, dann für die gleiche Dauer in die andere Richtung.
uhrzeigersinn.ChangeDutyCycle(100) time.sleep(2) uhrzeigersinn.stop() gegen_uhrzeigersinn.ChangeDutyCycle(100) time.sleep(2) gegen_uhrzeigersinn.stop()
Hier noch einmal der komplette Code:
#coding: utf8 # Erforderliche Bibliotheken importieren import RPi.GPIO as GPIO import time # Konvention für Pinnummerierung festlegen (BCM bzw. Board) GPIO.setmode(GPIO.BCM) # Warnungen, die das Ausführen des Programms verhindern, wenn # Ausgang bereits als OUT deklariert wurde ignorieren GPIO.setwarnings(False) # Pins als Ausgänge deklarieren GPIO.setup(21, GPIO.OUT) GPIO.setup(25, GPIO.OUT) # PWM für Richtungen mit Frequenz festlegen uhrzeigersinn = GPIO.PWM(21, 50) gegen_uhrzeigersinn = GPIO.PWM(25, 50) # PWM mit Tastgrad 0% initialisieren uhrzeigersinn.start(0) gegen_uhrzeigersinn.start(0) uhrzeigersinn.ChangeDutyCycle(100) time.sleep(2) uhrzeigersinn.stop() gegen_uhrzeigersinn.ChangeDutyCycle(100) time.sleep(2) gegen_uhrzeigersinn.stop()
Motor beschleunigen und bremsen lassen |
![]() |
Nun haben wird den Motor getestet. Er sollte dabei einmal in die eine- und kurz danach in die andere Richtung gefahren sein.
Der Code wird jetzt um eine Funktionalität erweitert, die den Motor in eine Richtung beschleunigen und anschließend wieder bremsen lässt. Danach wird in die entgegengesetzte Richtung beschleunigt und gebremst. Danach wiederholt sich der Prozess. Wir verrichten dies mit der for
-Zählschleife.
Dabei verwenden wir die range
-Funktion. Sie beinhaltet folgende Parameter:
# range(Startwert, Endwert, Schrittweite)
Im Folgenden Beispiel gilt i
als Zählvariable und kann beliebig benannt werden. Sie wird bei jedem Schleifendurchlauf (hier) um 2 erhöht.
Als Beispiel:
for i in range(0, 8, 2): print(i)
Die Ausgabe liefert:
0 2 4 6
Der Code in seiner vollen Gänze |
![]() |
Nun zum endgültigen Code: Verschachtelt in einer Endlosschleife, gekennzeichnet durch while True
, beschleunigt und bremst der Motor jeweils zunächst in die eine Richtung und anschließend in die andere. Beendet werden kann diese Ausführung durch die Tastenkombination [STRG] + [C]
#coding: utf8 # Erforderliche Bibliotheken importieren import RPi.GPIO as GPIO import time # Konvention für Pinnummerierung festlegen (BCM bzw. Board) GPIO.setmode(GPIO.BCM) # Warnungen, die das Ausführen des Programms verhindern, wenn # Ausgang bereits als OUT deklariert wurde ignorieren GPIO.setwarnings(False) # Pins als Ausgänge deklarieren GPIO.setup(21, GPIO.OUT) GPIO.setup(25, GPIO.OUT) # PWM für Richtungen mit Frequenz festlegen uhrzeigersinn = GPIO.PWM(21, 50) gegen_uhrzeigersinn = GPIO.PWM(25, 50) # PWM mit Tastgrad 0% initialisieren uhrzeigersinn.start(0) gegen_uhrzeigersinn.start(0) ''' Hoch- und Herunterfahren mit anschließendem Richtungswechsel ''' # try ermöglicht das Abbrechen des Programms mit der # Tastenkombination [Strg] + [C] try: print("Programm gestartet. Beenden mit [Strg] + [C]!") # While True - Endlosschleife while True: #---Im Uhrzeigersinn--- # Tastgrad von 0 % auf 100 % mit Schrittweite 2 erhöhen for i in range(0, 100, 2): # Tastgrad auf i [%] ändern uhrzeigersinn.ChangeDutyCycle(i) time.sleep(0.02) # Tastgrad von 100 % auf 0 % mit Schrittweite 2 erniedrigen for i in range(100, 0, 2): # Tastgrad auf i [%] ändern uhrzeigersinn.ChangeDutyCycle(i) time.sleep(0.02) #---Gegen den Uhrzeigersinn--- # Tastgrad von 0 % auf 100 % mit Schrittweite 2 erhöhen for i in range(0, 100, 2): # Tastgrad auf i [%] ändern gegen_uhrzeigersinn.ChangeDutyCycle(i) time.sleep(0.02) # Tastgrad von 100 % auf 0 % mit Schrittweite 2 erniedrigen for i in range(100, 0, 2): # Tastgrad auf i [%] ändern gegen_uhrzeigersinn.ChangeDutyCycle(i) time.sleep(0.02) except KeyboardInterrupt: uhrzeigersinn.stop() print("Programm beendet")
Verwendete Bauteile |
![]() |