DIY Raspberry Pi L293D Motorsteuerung (Teil 4)

tl;dr: Die DC Motoren werden über einen L293D gesteuert. Zwei GPIO Pins steuern die Richtung mit High/Low Outputs, ein dritter die Leistung per PWM. Folglich braucht man 3 Pins pro gesteuerten Motor.

...oder wie ich eine Gegensprechanlage baute (Teil 4)

Ja, die Projektrichtung hat sich etwas geändert: die Gegensprechanlage bekommt Räder. Nach dem letzten Teil über die IP Kamera kam mir die Idee, einen fahrbaren Untersatz zu ergänzen. Dann könnte man ein ferngesteuertes Auto bauen, dass man dank der IP Kamera ohne Sichtkontakt fahren könnte. Dazu später mehr. In diesem Artikel geht es ausschließlich um die Steuerung der Räder:

  • Wie kann ich ein Rad betreiben mit einem Raspberry Pi?
  • Wie kann ich die Geschwindigkeit und die Richtung ändern, insbesondere um Kurven zu fahren?

Natürlich kann man mit einem Arduino oder einem STM32 Blue Pill ganz ähnlich vorgehen.

Achtung! In Tutorials und Artikeln zu dem Thema schleichen sich bei aller Sorgfalt immer wieder kleine Fehler ein. Dieser Artikel ist keine Ausnahme. Fehlerhafte Schaltungen können zu Schäden an den Bauteilen, insbesondere an dem Raspberry Pi, führen. Folge nicht blind einer Anleitung. Ich gebe keine Garantien und übernehme keinerlei Haftung.

Der Motor

Zur Hand hatte ich nur einen Servomotor und einen Schrittmotor. Daraus könnte sicherlich ein Fahrzeug bauen, wenn man es unbedingt will. Einfacher wird es mit Gleichstrommotoren (DC Motor): schließt man eine Spannung an, dann dreht sich der Motor. Erhöht man die Spannung, dreht er sich schneller. Tauscht man die Pole, dreht er sich in die andere Richtung.

Für dieses Projekt habe ich mich für den Joy-it Roboter Fahrgestell Bausatz mit vier Getriebemotoren und Rädern entschieden. Ich bin zufrieden, aber die Qualität passt zum Preis. Den Bausatz kann man direkt zusammenbauen und ohne Raspberry Pi fahren lassen. Du brauchst noch 4 Mignons (AA) und einen Lötkolben. Interessanterweise liefern meine 4 1,2 V Akkus insgesamt sogar 5,5 V.

Die Motoren im Bausatz sind für eine Spannung zwischen 3 und 9 V ausgelegt bei einem Strom im Leerlauf von 160 bis 200 mA. Damit lässt sich der Motor definitiv nicht direkt mit dem Raspberry Pi betreiben, sondern könnte den Raspberry Pi beschädigen. Die GPIO Pins am Raspberry Pi liefern nur 0 V (low) oder 3,3 V (high) und maximal 16 mA pro Pin. Alle Pins zusammen liefern nicht mehr als 50 mA, wie in diesem Blog–Artikel ausführlich erklärt wird. Das reicht nicht annähernd für einen einzigen der vier Motoren in dem Bausatz, geschweige für alle vier.

Mit Schaltern und Tastern ließe sich allerdings ganz ohne Mikrocontroller ein Auto mit Kabelfernbedienung bauen.

Der L293D

Wir benutzen den Chip L293D quasi als Verstärker zwischen Raspberry Pi und Motoren. Praktischerweise kann man den Raspberry Pi über eine USB Powerbank und die Motoren über Mignons betreiben. Der Raspberry Pi steuert sozusagen den L293D, der die Motoren steuert. Der L293D hat die folgenden 16 Pins.

L293D Pins
L293D auf Breadboard

 

Mit der linken und der rechten Seite kann man jeweils einen Motor steuern. Der kleine Halbkreis markiert oben und ist auf dem Chip zu sehen.

An jeweils einen GPIO Pin vom Raspberry Pi kommen EN1, IN1 und IN2. Der Motor wird angeschlossen an OUT1 und OUT2. Entweder IN1 oder IN2 sind auf High (3,3 V) und geben die Richtung an, IN1 die eine Richtung IN2 die andere. Ein High auf EN1 schaltet den Motor an, ein Low aus.

Alle Beinchen mit 0V sind im L293D miteinander verbunden. Dort soll der negative Pol der Spannungsquellen der Motoren und GND vom Raspberry angeschlossen werden. An +V motor kommt der positive Pol der Spannungsquelle für die Motoren, an +V GPIO kommt die Spannung des Raspberry Pi. Die Spannungen sind nicht beliebig, wie man im Datenblatt nachlesen kann. Mehr dazu später.

Die Motorgeschwindigkeit steuert man über eine Pulsweitenmodulation (PWM) an EN1. EN1 wechselt dabei ständig zwischen High und Low. Je länger High und je kürzer Low ist, umso größer ist die Spannung zwischen OUT1 und OUT2 und umso schneller dreht sich der Motor.

Um den L293D etwas kennen zu lernen, habe ich ein kleines Test-Programm laufen lassen und die Spannungen zwischen OUT1 und OUT2 gemessen.

import RPi.GPIO as GPIO import time import sys print(""" This script is to get familiar with a L293D. It changes the EN1 output every few seconds so you can measure the resulting voltage between OUT1 and OUT2. """) En1Pin = 3 In1Pin = 5 In2Pin = 7 GPIO.setmode(GPIO.BOARD) GPIO.setup(En1Pin, GPIO.OUT) GPIO.setup(In1Pin, GPIO.OUT) GPIO.setup(In2Pin, GPIO.OUT) # see https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/ en1 = GPIO.PWM(En1Pin, 100) en1.start(0) en1.ChangeDutyCycle(0) for direction in [True, False]: print('running ' + ('foreward' if direction else 'backward')) # what is which direction depends on how the motor is wired GPIO.output(In1Pin, direction) GPIO.output(In2Pin, not direction) stepSize = 10 for x in range(int(100 / stepSize)): speed = stepSize * (x + 1) print('speed: {}'.format(speed)) sys.stdout.flush() en1.ChangeDutyCycle(speed) time.sleep(2) print('done') GPIO.output(In1Pin, False) GPIO.output(In2Pin, False) # stops anyway when en1 goes out of scope en1.ChangeDutyCycle(0) en1.stop() GPIO.cleanup()

Bei der Messung konnte ich sehen, dass die Spannung zwischen OUT1 und OUT2 linear mit der Pulsweite an EN1 steigt. Das Diagramm zeigt die Messpunkte und eine angenäherte Gerade bei 5,5 V an +V motor.  Die x-Achse zeigt die Spannung zwischen OUT1 und OUT2, die y-Achse die Pulsweite (DutyCycle).  Der Schaltplan für die Messung entspricht im wesentlichen dem Schaltplan im nächsten Abschnitt dieses Artikels.

Linear Output Voltage over Duty Cycle Chart

Laut Datenblatt erlaubt der L293D eine Motorspannung (+V motor) bis 36V und einen Strom von 600 mA pro "Channel" (also Beinchen?). Kurze Lastspitzen dürfen darüber liegen. Die Logikspannung (+V GPIO) muss mindestens 4,5 V betragen (3,3 V haben funktioniert, 5 V auch) und darf nicht über der Motorspannung liegen. Also reicht der Chip für den Bausatz völlig aus.

Die Schaltung

Der Bausatz hat vier Räder mit feststehender Achse und jeweils eigenem Motor. Eine Lenkung per Radstellung mit einem Servomotor benötigt bewegliche Achsen, weshalb ich vorhabe, das Fahrzeug über eine Geschwindigkeitsdifferenz zwischen linker und rechter Seite zu steuern: wenn sich die linken Räder vorwärts drehen und die rechten rückwärts, dreht sich das Auto auf der Stelle.

Der folgende Schaltplan zeigt, die Verdrahtung der Bauteile. Die Raspberry Pi Pins sind tatsächlich die ersten zwölf auf der Platine. Die Motoren auf jeder Seite sind parallel geschaltet und lassen sich nur gemeinsam steuern. Die Spannung liegt also an beiden Motoren voll an und der maximal Strom von 2x 200 mA (im Leerlauf) sollte das 600 mA Limit vom L293D nicht überschreiten.

Natürlich kann man auch andere Pins am Raspberry Pi verwenden. Alle Code–Beispiele in diesem Artikel beziehen sich auf diesen Schaltplan. Außerdem hilft es mir bei der Orientierung, wenn die Pins dicht zusammen liegen. Das Löten und Anschließen der Schaltung wird ebenfalls einfacher, mehr dazu gleich.

L293D Schaltplan

Erinnerung: die vier 0V Beinchen sind im L293D miteinander verbunden.

Ein paar Veränderungen an der Schaltung habe ich schon ins Auge gefasst:

  • eine höhere Spannung für die Motoren für mehr Tempo und mehr Geschwindigkeitsstufen
  • zusätzliche GPIO Pins für zBsp. Licht

Das Löten

Zum Löten finden sich sicher viele gute Tutorials, also gehe ich davon aus, du hast schon mal gelötet. Hier nur ein paar Stolperfallen von diesem speziellen Projekt.

Such dir ein Bezugssystem für die Richtung: die Drehrichtung vom Motor oder die Fahrtrichtung des Autos. Ich bin schnell durcheinander gekommen. Im Bild sieht man zwei Motoren der selben Seite. Der eine Motor wird quasi rückwärts eingebaut. Mir hat es sehr geholfen, rot und schwarz so anzulöten, dass schwarz mit schwarz und rot mit rot am L293D verlötet werden müssen.

DC Motoren im Fahrgestell

Das schwarze Bändchen ersetzt herausgebrochene Plastikhaken am Motorgehäuse. Das Material ist sehr spröde.

Für den Anschluss am Raspberry habe ich Kabelsteckbrücken verleimt zu einem großen Stecker. Die vielen Anschlüsse ständig zu Stecken ist mir zu fehleranfällig und zu riskant.

Raspberry Pi mit Kabelsteckbrücken

Den L293D habe ich direkt auf eine Platine mit einzelnen Lötstellen aufgelötet. Zwei Dinge würde ich jetzt anders machen:

1) Eine Platine mit Reihen wäre viel einfacher gewesen. 2) Den L293D direkt aufzulöten mit den Brücken zu den Nachbarbohrungen fand ich schwierig. Ich bin wenig geübt und gerade die 0V Beinchen fielen schwer, weil es die "heat sinks" sind. Einen Sockel hätte ich mir gewünscht.

Zu meiner Überraschung hat am Ende alles funktioniert. Der L293D ist nicht durchgebrannt, die Lötstellen sind ok und es sieht furchtbar aus. Deshalb ist das Foto von oben.

L293D auf Miniplatine

Das Raspberry Auto

Damit ist die Steuerung komplett. Im Moment lege ich Batterien, Powerbank und Raspberry einfach auf das Fahrgestell. Das folgende Script fährt das Auto vor- und zurück. Der Rest kommt ein anderes mal.

import RPi.GPIO as GPIO import time import sys print(""" This script let's the car drive around. """) class Wheel: """ wheel(s) on one side of the car """ def __init__(self, enPin: int, inForewardPin: int, inBackwardPin: int): GPIO.setup(inForewardPin, GPIO.OUT) self.inForewardPin = inForewardPin GPIO.output(inForewardPin, False) self.inBackwardPin = inBackwardPin GPIO.setup(inBackwardPin, GPIO.OUT) GPIO.output(inBackwardPin, False) GPIO.setup(enPin, GPIO.OUT) self.pwm = GPIO.PWM(enPin, 100) self.pwm.start(0) self.pwm.ChangeDutyCycle(0) def setSpeed(self, speed: int): """ speed might be -3, -2, -1, 0, 1, 2, 3 """ force = min(3, abs(speed)) isForewards = speed > 0 if (isForewards): GPIO.output(self.inBackwardPin, False) GPIO.output(self.inForewardPin, True) else: GPIO.output(self.inForewardPin, False) GPIO.output(self.inBackwardPin, force > 0) if force > 0: self.pwm.ChangeDutyCycle(70 + (10 * force)) else: self.pwm.ChangeDutyCycle(0) if __name__ == '__main__': GPIO.setmode(GPIO.BOARD) LeftWheels = Wheel(3, 5, 7) RightWheels = Wheel(8, 10, 12) try: while True: print('full stop') LeftWheels.setSpeed(0) RightWheels.setSpeed(0) time.sleep(2) print('full speed ahead') LeftWheels.setSpeed(3) RightWheels.setSpeed(3) time.sleep(2) print('full stop') LeftWheels.setSpeed(0) RightWheels.setSpeed(0) time.sleep(2) print('slowly backwards') LeftWheels.setSpeed(-1) RightWheels.setSpeed(-1) time.sleep(4) except KeyboardInterrupt: LeftWheels.setSpeed(0) RightWheels.setSpeed(0) GPIO.cleanup()
Auto mit Raspberry Pi

 

Wenn du bis hier gelesen hast, hat dir der Artikel wohl gefallen. Feedback ist sehr willkommen und viel Spaß beim Basteln.