Roboter bewegen für Fortgeschrittene
In meinem Artikel „Roboter bewegen für Fortgeschrittene“ zeige ich euch wie ihr das Python Skript für die Navigation eures Roboters aus dem früheren Artikel „Roboter bewegen für Anfänger“ weiter verfeinert. Diesmal kommt die Geschwindigkeit hinzu. Diese wird beim Raspberry Pi über den PWM GPIO Pin gesteuert.
Roboter bewegen für Fortgeschrittene
Im vorangegangenen Anfängerartikel habe ich euch ja bereits ein fertiges Skript präsentiert über dieses man den Roboter bereits mit der Tastatur – wahlweise auch über SSH – in die 4 Richtungen steuern konnte. Das Problem war die Geschwindigkeit. Das Roboter Board besitzt 2 Pins über die man die Geschwindigkeit der Räder links und rechts Regeln kann. Diese Geschwindigkeit wird über ein analoges Signal eingestellt. Der Raspberry Pi hat jedoch nur digitale Pins, weshalb nur zwei Einstellungen möglich sind:
- 1: maximale Geschwindigkeit
- 0: Stillstand
Im ersten Moment könnte man meinen das ist nun mal so und man muss sich damit abfinden. Glücklicherweise gibt es einen Pin der GPIO Schnittstelle, der PWM unterstützt. Das ist der Pin mit der Nummer 12 beziehungsweise GPIO 18.
PWM Theorie
Unter PWM versteht man die schnelle Änderung der Spannung. Bei dem PWM Pin kann man angeben wie oft er ein- und ausgeschaltet wird. Das geschieht innerhalb kürzester Zeit sehr oft. So oft, dass manche Geräte wie Servo Motoren dieses Signal als analoges Signal interpretieren. Je nach Geschwindigkeit, also der Häufigkeit der Umschaltvorgänge ist das analoge Signal unterschiedlich stark. Genau das benötigen wir für die Ansteuerung des Motors um eine bestimmte Geschwindigkeit zu setzen.
WiringPi kommt ins Spiel
Vor einiger Zeit habe ich euch die WiringPi2 Bibliothek vorgestellt, die unter anderem auch für Python portiert wurde. Mit dieser kann man recht einfach mit der GPIO Schnittstelle arbeiten. Als besonderes Feature stellt diese Bibliothek auch eine Funktion bereit um ein PWM Signal zu erzeugen.
wiringpi.pwmWrite(18, 550)
Die Funktion pwmWrite hat 2 Parameter. Das ist zum einen die Nummer des GPIO Pins (18 ist die einzig mögliche Eingabe!) und einen Wert für die Frequenz. Dieser muss zwischen 0 und 1024 liegen.
Anpassungen an der Hardware
Die schlechte Nachricht zuerst: wir müssen eine Modifikation an der Verkabelung vornehmen. Die gute Nachricht: es wird sogar etwas einfacher! Bis jetzt verwendeten wir 2 Pins für die Geschwindigkeit der linken und der rechten Seite. Dazu auch 2 Kabel (grün und gelb). Diese werden nun entfernt. Ersetzt werden diese durch einen einzigen Pin – wir erinnern uns: es gibt nur einen PWM Pin am Raspberry Pi. An diesen müssen wir nun 2 Kabel hängen und mit dem Roboterboard verbinden. Zu diesem Zweck benötigen wir ein Steckbrett – alternativ kann man diese Kabel auch zusammen löten.
Wie man gut sehen kann sind nun über den Umweg vom Steckbrett beide lila Drähte direkt mit dem PWM Pin verbunden.
Anpassungen an der Software
Bevor man mit Änderungen an der Software durchführen kann muss WiringPi installiert werden. Wie das funktioniert habe ich bereits in einem der letzten Artikel zu WiringPi gezeigt.
Auch bei der Software können wir vereinfachen. Statt 2 Pins und Outputs benötigen wir nun pro Bewegungsaktion nur einen. Der Unterschied zum Anfängerskript ist nun, dass wir den PWM Pin nicht über die Standard GPIO Bibliothek ansprechen sondern über die WiringPi2 Bibliothek. Der vollständige Code sieht wie folgt aus:
import RPi.GPIO as GPIO import wiringpi2 as wiringpi import time #pins M1 = 40 #rot PWM = 18 #rot-lila M2 = 36 #weiss FULLSPEED = 1024 #between 0 and 1024 LOWSPEED = 450 TURNSPEED = 460 GPIO.setmode(GPIO.BOARD) wiringpi.wiringPiSetupGpio() #also setup GPIO for wiringpi GPIO.setup(M1, GPIO.OUT) GPIO.setup(M2, GPIO.OUT) wiringpi.pinMode(PWM, 2) #also set Pinmode for WiringPi PWM Pin def move(): GPIO.output(M1, True) GPIO.output(M2, True) wiringpi.pwmWrite(PWM, FULLSPEED) #full speed def reverse(): GPIO.output(M1, False) GPIO.output(M2, False) wiringpi.pwmWrite(PWM, LOWSPEED) #half full speed def left(): GPIO.output(M1, True) GPIO.output(M2, False) wiringpi.pwmWrite(PWM, TURNSPEED) #quarter full speed def right(): GPIO.output(M1, False) GPIO.output(M2, True) wiringpi.pwmWrite(PWM, TURNSPEED) #quarter full speed def stop(): GPIO.output(M1, False) GPIO.output(M2, False) wiringpi.pwmWrite(PWM, 0) #engine off def init(): stop() 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 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() time.sleep(0.5) GPIO.cleanup()
Neu ist die Importzeile für WiringPi2:
import wiringpi2 as wiringpi
Bei der Definition der Variablen wurden die zwei PWM Zeilen entfernt und durch eine einzelne PWM Zeile plus drei unterschiedlichen Geschwindigkeitsvariablen ersetzt:
PWM = 18 #rot-lila ... FULLSPEED = 1024 #between 0 and 1024 LOWSPEED = 450 TURNSPEED = 460
Die Nummer des PWM Pins ist 18. Das ist wie bereits erwähnt die einzig korrekte Nummer. Bei der Geschwindigkeit gibt es die Höchstgeschwindigkeit und danach zwei Werte für den Rückwärtsgang und dem Drehen des Roboters.
Für WiringPi muss genau wie für die normale GPIO Schnittstelle in einer Initialisierung gesagt werden, wie die Pins durchnummeriert sind.
wiringpi.wiringPiSetupGpio() #also setup GPIO for wiringpi
Für den PWM Pin müssen wir dann auch noch definierten ob er ein INPUT, OUTPUT oder PWM_OUTPUT Pin ist. Die 2 steht für PWM_OUTPUT:
wiringpi.pinMode(PWM, 2) #also set Pinmode for WiringPi PWM Pin
Zuletzt gibt es noch in jeder der 4 möglichen Richtungsfunktionen eine Änderung. Die beiden PWM Pins sind weg und durch einen einzelnen PWN Aufruf ersetzt worden. Der Funktion pwmWrite übergibt man neben der Nummer des GPIO Pins auch noch die Geschwindigkeit.
wiringpi.pwmWrite(PWM, FULLSPEED) #full speed
Fazit
Mit nur kleinen Änderungen verbessert man das Bewegungsskript für den Roboter sehr stark. Der Faktor Geschwindigkeit lässt den Roboter viel schöner bewegen. Dieser steuert sich realistischer und vor allem durch die niedrigere Umdrehungsgeschwindigkeit auch deutlich präziser.