Sonntag, 11. Oktober 2015

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


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.


PWM GPIO Pin


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.



Roboter bewegen für Fortgeschrittene

Keine Kommentare:

Kommentar veröffentlichen