Listing 5 enthält ein Beispielprogramm, mit dem Sie alle Motoren des Modells für eine Sekunde laufen lassen. Dabei zählen Sie die Impulse der Geber. Womöglich wirkt die Python-Syntax etwas kompakt, aber so nimmt der Code weniger Platz beim Druck in Anspruch.
Listing 5
geber_test.py
import time
import board
import RPi.GPIO as GPIO
from adafruit_motorkit import MotorKit
PULSE_M1=16;PULSE_M2=19;PULSE_M3=20;PULSE_M4=21
GPIO.setmode(GPIO.BCM)
GPIO.setup(PULSE_M1, GPIO.IN)
GPIO.setup(PULSE_M2, GPIO.IN)
GPIO.setup(PULSE_M3, GPIO.IN)
GPIO.setup(PULSE_M4, GPIO.IN)
m1=0;m2=0;m3=0;m4=0
def handler_M1(channel): global m1;m1=m1+1
def handler_M2(channel): global m2;m2=m2+1
def handler_M3(channel): global m3;m3=m3+1
def handler_M4(channel): global m4;m4=m4+1
GPIO.add_event_detect(PULSE_M1, GPIO.FALLING,callback=handler_M1)
GPIO.add_event_detect(PULSE_M2, GPIO.FALLING,callback=handler_M2)
GPIO.add_event_detect(PULSE_M3, GPIO.FALLING,callback=handler_M3)
GPIO.add_event_detect(PULSE_M4, GPIO.FALLING,callback=handler_M4)
kit = MotorKit(i2c=board.I2C())
kit.motor1.throttle = 1.0
kit.motor2.throttle = 1.0
kit.motor3.throttle = 1.0
kit.motor4.throttle = 1.0
time.sleep(1)
kit.motor1.throttle = 0
kit.motor2.throttle = 0
kit.motor3.throttle = 0
kit.motor4.throttle = 0
print("M1={} M2={} M3={} M4={}".format(m1,m2,m3,m4))
Wenn Sie das Programm starten, achten Sie bitte darauf, dass das Modell keinen Unfall oder Absturz erleiden kann. Eine Möglichkeit das zu vermeiden, besteht in einem Podest für das Fahrzeug. So können sich die Räder frei drehen. Die Ausgabe zeigt an, wie viele Impulse während der Fahrt erzeugt wurden.
Wie Sie sehen, bewegt sich das Fahrzeug zur Seite, obwohl sämtliche Motoren in eine Richtung drehen. Das liegt daran, dass die Motoren in unterschiedlichen Ausrichtungen verbaut sind. Zusätzlich sind die Omniwheels durch ihren Aufbau ebenfalls ein Stück weit für dieses Verhalten verantwortlich.
Im nächsten Schritt werden wir das Fahrzeug einen kleine Strecke zurücklegen lassen. Damit das Beispielprogramm ohne Anpassung zum Einsatz kommen kann, müssen Sie die Motoren und die Impulsgeber zwingend wie auf Abbildung 2 anordnen und anschließen. Die Motoren müssen sich so drehen, dass das Fahrzeug vorwärts fahren würde. Falls das bei Ihrem Aufbau nicht der Fall ist, passen Sie bitte die Verdrahtung dementsprechend an. Um zu testen, welcher Motor sich an welcher Position befindet, kommentieren Sie der Reihe nach drei Motoren im Programm (Listing 5) aus und schauen, welcher sich noch dreht.

Abbildung 2: Die Motoren müssen unbedingt richtig angeschlossen sein, damit das Beispielprogramm funktioniert.
Komplexeres Beispiel
Das Beispielprogramm in Listing 6 lässt das Fahrzeug ein Quadrat abfahren. Dabei wird das Fahrzeug allerdings nicht in die Fahrtrichtung gedreht, stattdessen verwendet es die Omniwheels, um sich seitwärts zu bewegen. Zum Zählen der Impulse für einen Streckenabschnitt, fragen Sie den Impulsgeber vom Motor M1 ab. Hier ist gut zu erkennen, dass unterschiedliche Programmteile über gemeinsame Variablen miteinander kommunizieren. Sobald ein Grenzwert erreicht ist, gehen Sie in die nächste Bewegung über.
Wir haben zwei Konstanten definiert, um das Programm an die Mechanik des Fahrzeugs anzupassen. Da ist zum Einen S (Zeile 33) für die Geschwindigkeit der Motoren und zum Anderen PDM (Zeile 34) für die nötigen Pulse, um 10 Zentimeter zurückzulegen.
Ein weiterer interessanter Programmteil liegt in der Prozedur blink (Zeile 21). Wie Sie bestimmt schon ahnen, lässt sie die LEDs blinken, solang das Fahrzeug sich bewegt. Dabei wird blink in einem extra Thread gestartet und läuft damit unabhängig vom Hauptprogramm. In Python lassen sich Threads nicht von außen beenden. Daher dient hier die Variable run dazu, blink am Ende des Programms ebenfalls zu beenden.
Listing 6
Kompexeres Beispiel (beispiel.py)
import time
import board
import RPi.GPIO as GPIO
from adafruit_motorkit import MotorKit
from rpi_ws281x import PixelStrip, Color
from threading import Thread
PULSE_M1=16;PULSE_M2=19;PULSE_M3=20;PULSE_M4=21
GPIO.setmode(GPIO.BCM)
GPIO.setup(PULSE_M1, GPIO.IN)
GPIO.setup(PULSE_M2, GPIO.IN)
GPIO.setup(PULSE_M3, GPIO.IN)
GPIO.setup(PULSE_M4, GPIO.IN)
m1=0;m2=0;m3=0;m4=0
def handler_M1(channel): global m1;m1=m1+1
def handler_M2(channel): global m2;m2=m2+1
def handler_M3(channel): global m3;m3=m3+1
def handler_M4(channel): global m4;m4=m4+1
leds = PixelStrip(4,10,800000,10,False,32,0)
leds.begin()
run=True
def blink(l):
i=1
while(run):
l.setPixelColor(i%4, Color(0,255,0))
l.setPixelColor((i-1)%4, Color(0,0,0))
i=i+1;l.show();time.sleep(0.2)
Thread(target=blink, args=(leds,)).start()
GPIO.add_event_detect(PULSE_M1, GPIO.FALLING,callback=handler_M1)
GPIO.add_event_detect(PULSE_M2, GPIO.FALLING,callback=handler_M2)
GPIO.add_event_detect(PULSE_M3, GPIO.FALLING,callback=handler_M3)
GPIO.add_event_detect(PULSE_M4, GPIO.FALLING,callback=handler_M4)
kit = MotorKit(i2c=board.I2C())
S=1.0
PDM=63
kit.motor1.throttle=S;kit.motor2.throttle=S;kit.motor3.throttle=S;kit.motor4.throttle=S
m1=0
while(m1<PDM*2): pass
kit.motor1.throttle=S;kit.motor2.throttle=-S;kit.motor3.throttle=-S;kit.motor4.throttle=S
m1=0
while(m1<PDM*2): pass
kit.motor1.throttle=-S;kit.motor2.throttle=-S;kit.motor3.throttle=-S;kit.motor4.throttle=-S
m1=0
while(m1<PDM*2): pass
kit.motor1.throttle=-S;kit.motor2.throttle=S;kit.motor3.throttle=S;kit.motor4.throttle=-S
m1=0
while(m1<PDM*2): pass
kit.motor1.throttle=0;kit.motor2.throttle=0;kit.motor3.throttle=0;kit.motor4.throttle=0
run=False
Verbesserungspotential
Die gezeigten Codebeispiele kommen ein wenig komprimiert daher, um die Programme nicht ausufern zu lassen. Das können Sie in ihren eigenen Projekten definitiv besser machen. Darüber hinaus ergäbe es durchaus Sinn, alle Funktionen rund um das Fahrzeug in eine eigene Bibliothek auszulagern. Sie könnte dann sämtliche Funktionen bereitstellen, um die Steuerung zu vereinfachen.
Wir haben in unseren Beispiel keinen der Sensoren verwendet – diese spannende Aufgabe überlassen wir Ihnen. Zusätzlich ließe sich überlegen, die Daten des Fahrzeugs zwecks Visualisierung an einen Rechner mit Monitor zu übertragen. Außerdem interessant: den RasPi mit einer Kamera ausstatten, um beobachten zu können, wo sich das Fahrzeug aktuell befindet.
Bei unseren einfachen Beispielprogrammen fiel es nicht sonderlich auf, aber die Motoren weisen immer leicht unterschiedliche Drehzahlen auf. Für einen perfekten Gleichlauf, müssten die Motoren über eine Drehzahlregelung verfügen. Programmiertechnisch müssen Sie sich im Rahmen solcher Aufgaben allerdings definitiv mit Parallelprozessing und Interprozesskommunikation beschäftigen.
Fazit
Sie haben jetzt alle Werkzeuge in der Hand, um basierend auf dem Testaufbau weitere eigene Projekte aufzusetzen. Beispielsweise könnten Sensoren das Gefährt in eine mobile Messstation umwandeln. Ihrer Fantasie sind dabei keine Grenzen gesetzt.





