Roboter bewegen für Anfänger
Im „Roboter bewegen für Anfänger“ Kurs geht es um die Basissoftware des Roboters. In einem Python Skript legen wir den Grundstein für alle folgenden Funktionen und Einsatzbereiche des Roboters. Ich zeige euch Schritt für Schritt was man alles machen muss. Als Ergebnis erhaltet ihr ein Programm über das man den Roboter über die Tastatur wie ein ferngesteuertes Auto steuern kann.
Roboter bewegen für Anfänger
Zugegeben, einen Roboter zu bewegen gehört zu den Paradedisziplinen des Programmierens. Man denke an das Google Driverless Car. Die Entwicklung solcher autonomer Systeme dauert Jahre und wird auf universitärer Ebene oder von großen Konzernen gemacht. Andere tolle Beispiele sind die Marsrover der Nasa. All diese Beispiele zeigen wie es geht.
Bewegungstheorie
Mein Roboter hat 4 Räder, zwei auf jeder Seite. Diese sind fix montiert und können sich nur in zwei Richtungen bewegen. Den Roboter können wir deshalb nicht wie ein Auto steuern, es fehlt die Lenkstange – dafür wäre ein fünfter Motor notwendig. Wir bewegen den Roboter deshalb wie folgt:
- vorwärts fahren
alle 4 Räder bewegen sich vorwärts. Das heißt alle 4 Motoren drehen sich in die selbe Richtung. Achtung: So trivial die Bewegung nach vorwärts auch erscheint, solange diese nicht funktioniert bracht man keine andere Bewegung implementieren. Warum? Die 4 Motoren müssen sich in die selbe Richtung bewegen aus der Sicht vom Chassis. Tatsächlich drehen sich die 2 Motoren links genau in die Gegengesetze Richtung als die beiden Motoren rechts, diese sind ja gespiegelt angebracht. - rückwärts fahren
die inverse Bewegung zum Vorwärts fahren. Man muss alle 4 Motoren einfach in die gegenteilige Richtung drehen. - Drehung nach links
Gedreht wird indem sich die Räder rechts und links in unterschiedliche Richtungen bewegen. Die linken bewegen sich rückwärts, die auf der rechten Seite vorwärts. Das Chassis wird gedreht. - Drehung nach rechts
die inverse Bewegung zur Drehung nach links. Die rechten Reifen bewegen sich rückwärts, die Reifen auf der linken Seite vorwärts. - Stopp
alle Motoren stehen still. Das Reset des Programms. Das muss immer als letztes Kommando im Programm ausgeführt werden, sonst kann es passieren, dass der Roboter trotz Programmabbruch weiter fährt.
Software
Meine erste Version der Software basiert auf dem Arduino Skript, dass vom Roboter Chassis Hersteller auf dessen Wiki Seite angeboten wird. Das der Raspberry Pi keine analogen Pins hat funktioniert das Skript nicht exakt gleich, man kann damit den Roboter aber schon sehr gut steuern. Das fertige Skript gibts auch als Download. Der Source Code schaut wie folgt aus:
import RPi.GPIO as GPIO
Wir benötigen lediglich Zugriff auf die GPIO Pins, deshalb wird nur diese Bibliothek eingebunden.
#pins M1 = 40 #rot M1_PWM = 37 #gruen M2_PWM = 38 #gelb M2 = 36 #weiss GPIO.setmode(GPIO.BOARD) GPIO.setup(M1, GPIO.OUT) GPIO.setup(M1_PWM, GPIO.OUT) GPIO.setup(M2, GPIO.OUT) GPIO.setup(M2_PWM, GPIO.OUT)
Wir legen uns Variablen an die wie am Board beschriftet heißen (damit man den Code auch Monate später noch versteht). Ich verwende die 4 letzten Pins des Raspberry Pi Modell B+, ihr könnt natürlich auch beliebig andere GPIO Pins verwenden. Die Verkabelung habe ich im ersten Teil bereits gezeigt. Alle 4 Pins werden als Ausgabepins initialisiert.
Nun wird es spannend. Wir legen 4 Funktionen an für die möglichen Bewegungsarten vorwärts, rückwärts, links und rechts und zusätzlich noch eine Stopp Funktion.
def move(): GPIO.output(M1, True) GPIO.output(M1_PWM, True) GPIO.output(M2, True) GPIO.output(M2_PWM, True) def reverse(): GPIO.output(M1, False) GPIO.output(M1_PWM, True) GPIO.output(M2, False) GPIO.output(M2_PWM, True) def left(): GPIO.output(M1, True) GPIO.output(M1_PWM, True) GPIO.output(M2, False) GPIO.output(M2_PWM, True) def right(): GPIO.output(M1, False) GPIO.output(M1_PWM, True) GPIO.output(M2, True) GPIO.output(M2_PWM, True) def stop(): GPIO.output(M1, False) GPIO.output(M1_PWM, False) GPIO.output(M2, False) GPIO.output(M2_PWM, False) def init(): stop()
Bei den Funktionen erkennt man schnell ein Muster. Alle PWM Pins sind immer True. Diese geben die Geschwindigkeit an. Da wir nur digitale Pins haben müssen diese klarerweise Spannung angelegt haben, sonst dreht sich der Motor nicht. Einzig bei der Stopp Funktion wird auf allen 4 Pins die Spannung abgeschaltet. Diese 4 Funktionen bilden die Basis der Bewegung. Wir benötigen jetzt nur noch Code der auf Tastenklick die korrekte Bewegungsfunktion aufruft.
In der ersten Version steuern wir den Roboter über die Tastatur. Über eine SSH Session wird der Code ausgeführt und über die Tasten werden Kommandos gegeben. Die gedrückten Tasten werden in der definierten getch() Funktion von der Tastatur geholt, ihr kennt vielleicht diese getch Funktion von C. Python hat so etwas nicht, deshalb müssen wir uns diese selber schreiben:
def getch(): import sys, tty, termios old_settings = termios.tcgetattr(0) new_settings = old_settings[:] new_settings[3] &= ~termios.ICANON try: termios.tcsetattr(0, termios.TCSANOW, new_settings) ch = sys.stdin.read(1) finally: termios.tcsetattr(0, termios.TCSANOW, old_settings) return ch
Damit sind wir mir der Definition der Variablen und der Funktionen fertig. Das restliche Programm ist recht einfach. Nach der Initialisierung wird in einer Endlosschleife mit getch() die Tastaturabfrage gemacht und abhängig der gedrückten Taste die gewünschte Bewegungsfunktion ausgeführt oder das Programm beendet.
init() loop = True _move = 0 _reverse = 0 _left = 0 _right = 0 while loop: c = getch() if c == 'a' and _left == 0: left() _left = 1 _right = 0 _move = 0 _reverse = 0 if c == 'd' and _right == 0: right() _left = 0 _right = 1 _move = 0 _reverse = 0 if c == 'w' and _move == 0: move() _left = 0 _right = 0 _move = 1 _reverse = 0 if c == 's' and _reverse == 0: reverse() _left = 0 _right = 0 _move = 0 _reverse = 1 if c != 'a' and c != 'd' and c != 'w' and c != 's': _move = 0 _reverse = 0 _left = 0 _right = 0 stop() if c == 'q': loop = False stop() GPIO.cleanup()
Ganz wichtig ist die letzte Zeile. Ohne dem cleanup() würden bei Programmabbruch die Motoren munter weiter laufen und der Roboter ohne Rücksicht auf Hindernisse oder Klippen weiter fahren. Ganz schlecht!
Konfiguration
Ob ihr alles richtig verkabelt habt könnt ihr beim ersten Testlauf feststellen. In diesem lasst ihr den Roboter am besten umgedreht nach vorne fahren. Bewegen sich alle 4 Räder in die korrekte Richtung habt ihr schon gewonnen. Falls sich manche Räder falsch bewegen, dann gehören die beiden Kabel vertauscht. Dies ist am Board recht einfach möglich und erfordert keinen großen Aufwand.
Fazit
Den Roboter bewegen ist gar nicht so schwierig. Mit dieser Basissoftware könnt ihr den Roboter nun bereits über die Tastatur manuell bewegen. Das macht richtig Spaß! Das Skript kann man übrigens als Basis für eine spätere autonome Navigation des Roboters nehmen. Durch Sensoren lernt der Roboter seine Umgebung kennen und kann auf Basis dieser Informationen navigieren, aber dazu in einem der nächsten Artikel mehr!
Das Skript ist alles andere als perfekt. Vor allem die Steuerung über die Tastatur funktioniert mit Python recht schlecht. Habt ihr dafür Optimierungen? Vorschläge wie das besser geht?
Teil 1 | Teil 2
Hallo,
ich möchte ein mit dem Handy ferngesteuertes Fahrzeug bauen. Mit Arduino/Bluetooth funktionierts, aber es gibt ständig Störungen und die Reichweite ist gering. Also möchte ich gern RaspPi über wlan benutzen, am liebsten auch über Internet und mit Kamera am Fahrzeug. Bis jetzt schaffe ich es aber nur, über ssh mit einfachsten C-Programmen LEDs ein und aus zu schalten. Kann man über ssh in einem auf dem RasbPi laufenden Programm Variablen verändern? Wenn ja, wie? Bin für jeden Tip dankbar.
Gruß
Werner 🙂
beispielsweise über eine Textdatei in der du Variablen abspeicherst und im Programm ausließt.
hallo,
ich habe nun das gleiche Setup wie auf den Bildern zu sehen ist.
nur leider wenn ich das programm starte dehen die 4 motoren an.
rechts bleibt nach 1 sek stehen, und rechts nach 2 sek, dann gehn die LED’s am Board aus, und man hört wie das Board wegen der Spannung pfeifft.
Der Pi läuft weiter nur das Board fällt aus.
Hat jemand eine Idee was das sein könnte?
ich hab sicherheits halter noch Bilder gemacht
http://postimg.org/image/rqstug9xn/
http://postimg.org/image/413e5rbkb/
http://postimg.org/image/6wghcmfkb/
http://postimg.org/image/4t624yfrf/
danke schon für Tipp’s
Hallo Herbert, ich habe mal die Bilder mit meinem Setup verglichen und sehe da im ersten Moment keinen Unterscheid. Mir fällt auf du verwendest einen Raspberry Pi 3, ich einen Pi 1 B+… ich werde das auch mal mit dem 3er probieren – es gab da ja ein Update der GPIO Schnittstelle. Hängt dein Pi an einer Powerbank oder direkt über einen Netzstecker an der Steckdose?
Hallo,
vielen Dank für die tollen Anleitungen! Eine Frage (und die Bitte um Hilfe 🙂 ): Wie kann es sein, dass bei mir auf der rechten Seite (d4 – d5) die Motoren sich nicht rückwärts, aber stattdessen vorwärts drehen, obwohl Output auf „false“ ist? Links klappt alles einwandfrei… Ich verwende folgende Verkabelung (PINs nach BCM, Raspi3):
d4: 26
d5: 12
d6: 13
d7: 6
Danke!
das Problem hatte ich anfangs auch! In dem Fall musst du am Roboter die Kabel zum Motor umdrehen. Das geht am einfachsten oben auf der Platine, dort wo du die Kabel an zum Beispiel M1 (siehe Bild im Artikel) angeschraubt hast. Also einfach die beiden Schrauben aufdrehen, Kabel raus ziehen, umdrehen und wieder rein stecken und Schrauben fest ziehen.
vielen Dank für den Tipp! Ich habe bei M3 und M1 die Kabel vertauscht, allerdings habe ich das Problem nun auf der anderen Seite. Es scheint mir, als könne der Motor nicht +/- tauschen…
du könntest alternativ noch mal probieren im Code mit den True und False herumzuspielen und diese zu ändern…
def right():
GPIO.output(M1, False)
GPIO.output(M1_PWM, True)
GPIO.output(M2, True)
GPIO.output(M2_PWM, True)
ich habe einige Anfragen mit dem Projekt weiter zu machen, leider liegt mein Roboter aktuell im Regal und setzt Staub an und ich habe noch jede Menge cooler Sensoren die ich da anbauen möchte. Ich werd schauen da zeitnah neue Artikel zu schreiben… um dein Problem zu lösen: schickst du mir mal deinen Code und Bilder deiner Verkabelung. Ich werd sehn was ich machen kann.
Hallo Werner,
der Quellcode: http://pastebin.com/TwEDDYWr
die Verkabelung: https://postimg.org/image/xybsqha6l/
Vielen Dank für deine Hilfe!
Endlich funktioniert der Roboter! 🙂 Vom Hersteller habe ich einen neuen Bausatz erhalten, da bei dem Board der Motortreiber defekt war.
sehr schön!
Guten Abend,
ich Steuere mit ihrem Programm und dem Raspi3 zum test vorerst nur 4 LED’s an.
Das funktioniert auch insofern das die LED’s angehen sobald ich die zugewiesene Taste drücke.
Die LED’s bleiben aber an. Ich kann lediglich das Programm über q beenden.
Ist es so vorgesehen das eine einmal aktivierte Richtung beibehalten wird?
Mein Ziel wäre es die Taste zu drücken -> LED leuchtet, die Taste loslassen -> LED erlischt.
Ich bin über jede informative Antwort sehr dankbar.
Hey, die digitalen Pins können den Status ein oder aus haben. Einmal auf 1 gesetzt bleiben sie auch in diesem Zustand bis du sie anders setzt oder ein cleanup machst. Ja, mein Roboter ändert den Zustand nur auf Knopfdruck, d.h. er fährt so lange vorwärts, bis ich eine andere Richtung will.
Was du brauchst sind onkeypress und onkeyrelease Events bei denen du immer den entsprechenden Status setzt. Sie mal dazu https://pythonhosted.org/pynput/keyboard.html
Hallo Herr Ziegelwanger,
Vielen Dank für Ihre ausführlichen und bildreichen Anleitungen.
Ich bin gerade dabei einen Roboter mit 2 Motoren aufzubauen. Dazu verwende ich Schrittmotoren, die über einen Motorkontroller gesteuert werden. Das ansteuern klappt bisher gut. Im nächsten Schritt möchte ich die Motoren durch Tastatureingaben steuern. Dazu habe ich versucht Ihre getch() Funktion zu übernehmen. Den Quellcode habe ich in die Thonny Python IDE kopiert in der ich meinen Code schreibe. Leider erhalte ich beim Ausführen einen Fehler, den ich weder zuordnen kann noch im Internet eine Erklärung finde, was er bedeutet.
Der Fehler lautet: „termios.error: (25, ‚Inappropriate ioctl for device‘).
https://ibb.co/cMuDEd
Ich hoffe Sie können mir weiterhelfen.
Viele Grüße, Dominik Rau
schon mal probiert das script mit root rechten (sudo) auszuführen? Sieht aus als ob die Terminal Eingabe nicht gelesen werden kann.
Coole Anleitung, vielen Dank.
Bei mir funktioniert „fast alles“ auf Anhieb. Einzig funktioniert die funktion „move“ nicht. Wenn ich ‚w‘ drücke, wird die Funktion ‚move‘ aufgerufen (habe ein print(„move called“) in die Funktion integriert), aber, die Räder drehen sich nicht.
Hat jemand Idee, woran es liegen könnte? Habe Raspberry Pi 3 B+ und verwende (wie in der Anleitung angegeben) die Pins 40, 38, 37 und 36.
Vielen Dank für jeden Tipp.