DS4 Controller (PS4) via BT an Raspberry Car

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
spiletty
User
Beiträge: 2
Registriert: Donnerstag 13. April 2017, 08:57

Hallo zusammen,
ich habe das Sunfounder Raspberry Video Car Kit.
Mittels vorgegebenem Code kann man das Auto über Wlan fernsteuern. Soweit - sogut.

Nun möchte ich das Video Car mittels einem Dual Shock 4 Controller über Bluetooth fernsteuern können.
Den entsprechenden DS4DRV habe ich installiert und der Controller wird auch als solcher erkannt.

Mit evdev lässt sich der Controller auslesen, BTN_B ist beispielsweise der X-Button:

Code: Alles auswählen

from evdev import InputDevice, categorize, ecodes, KeyEvent
gamepad = InputDevice('/dev/input/event1')

for event in gamepad.read_loop():
    if event.type == ecodes.EV_KEY:
        keyevent = categorize(event)
        if keyevent.keystate == KeyEvent.key_down:
            if keyevent.keycode[0] == 'BTN_B':
                    print ("Vorwärts"), forward_fun
Vorwärts wird übrigens ausgegeben.
Mein Problem: Ich bekomme es nicht auf die Reihe diesen Button mit der Funktion forward_fun (siehe unten) zu verbinden. Ich möchte nur dass wenn ich den X-Button drücke das Auto fährt.

Im vorgegebenen Code von Sunfounder wird beispielsweise zusätzlich die Tastatur als Steuerungseingabe angegeben:

Code: Alles auswählen

def forward_fun(event):
	print 'forward'
	tcpCliSock.send('forward')
# =============================================================================
# Bind buttons on the keyboard with the corresponding callback function to 
# control the car remotely with the keyboard.
# =============================================================================
top.bind('<KeyPress-w>', forward_fun)   # Press down key 'A' on the keyboard and the car will turn left.
top.bind('<KeyRelease-w>', stop_fun)
Ich kann gerne auch den kompletten Sunfounder Code online stellen falls das relevant ist - den gibt es frei im Netz.

Ja, ich bin Anfänger und wusste nicht ob ich hier nach dem Willkommensgruß der oben angepinnt ist überhaupt etwas schreiben soll, aber ich versuche hier wirklich mein Bestes das Problem darzustellen. Wenn mir jemand eine Hilfestellung geben könnte wäre ich sehr dankbar.

Viele Grüße

Vanessa
Zuletzt geändert von Anonymous am Freitag 14. April 2017, 13:14, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@spiletty: Du bildest in der letzten Zeile ein Tupel aus dem Rückgabewert der `print()`-Funktion und der Funktion `forward_fun()` und machst dann damit nichts. Wobei das ansich auch nicht so wild ist, denn das Tupel ist sowieso nicht sinnvoll. Also statt dieses Tupel zu bilden, solltest Du die `forward_fun()`-Funktion halt einfach aufrufen.
spiletty
User
Beiträge: 2
Registriert: Donnerstag 13. April 2017, 08:57

BlackJack hat geschrieben:@spiletty: Du bildest in der letzten Zeile ein Tupel aus dem Rückgabewert der `print()`-Funktion und der Funktion `forward_fun()` und machst dann damit nichts. Wobei das ansich auch nicht so wild ist, denn das Tupel ist sowieso nicht sinnvoll. Also statt dieses Tupel zu bilden, solltest Du die `forward_fun()`-Funktion halt einfach aufrufen.
Hi BlackJack,

so einfach und doch habe ich es nicht erkannt.
Mittlerweile habe ich die Buttons verteilt und es funktioniert auch!
Ein kleines Problem habe ich dennoch:

Unten sieht man, dass der Speed des Wagens ausgegeben wird. Ohne Ausgabe kein Speed und das Auto bewegt sich nicht.
Momentan geht leider nichts weil ich glaube, dass ich die Parameter irgendwie ausschließe oder von der Syntax her ein Fehler gemacht habe.

Code: Alles auswählen

from evdev import InputDevice, categorize, ecodes, KeyEvent
gamepad = InputDevice('/dev/input/event1')

for event in gamepad.read_loop():
    if event.type == ecodes.EV_KEY:
        keyevent = categorize(event)
        if keyevent.keystate == KeyEvent.key_down:
                if keyevent.keycode[0] == 'BTN_B':
                    forward_fun(event)
                elif keyevent.keycode == 'BTN_C':
                    backward_fun(event)
                elif keyevent.keycode == 'BTN_TL':
                    left_fun(event)
                elif keyevent.keycode == 'BTN_TR':
                    right_fun(event)
                elif keyevent.keycode == 'BTN_TR2':
                    x_increase(event)
                elif keyevent.keycode == 'BTN_TL2':
                    x_decrease(event)
                elif keyevent.keycode == 'BTN_THUMBL':
                    xy_home(event)
                elif keyevent.keycode == 'BTN_MODE':
                        quit_fun(event)

        elif keyevent.keystate == KeyEvent.key_up:
                if keyevent.keycode[0] == 'BTN_B':
                    stop_fun(event)
                elif keyevent.keycode == 'BTN_C':
                    stop_fun(event)
                elif keyevent.keycode == 'BTN_TL':
                    home_fun(event)
                elif keyevent.keycode == 'BTN_TR':
                    home_fun(event)
spd = 50

def changeSpeed(ev=None):
	tmp = 'speed'
	global spd
	spd = speed.get()
	data = tmp + str(spd)  # Change the integers into strings and combine them with the string 'speed'. 
	print 'sendData = %s' % data
	tcpCliSock.send(data)  # Send the speed data to the server(Raspberry Pi)

label = Label(top, text='Speed:', fg='red')  # Create a label
label.grid(row=6, column=0)                  # Label layout

speed = Scale(top, from_=0, to=100, orient=HORIZONTAL, command=changeSpeed)  # Create a scale
speed.set(50)
speed.grid(row=6, column=1)

def main():
	top.mainloop()

if __name__ == '__main__':
	main()
Erkennt das jemand? Danke nochmal.
Zuletzt geändert von Anonymous am Freitag 21. April 2017, 21:36, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@spiletty: Ob Du einen Syntaxfehler hast verrät Dir der Compiler der ja den Code verarbeitet bevor das Modul überhaupt ausgeführt wird. Und sollte ein Syntaxfehler enthalten sein, dann bekommst Du einen `SyntaxError`.

Der Code ist auf jeden Fall unvollständig. Und ist unübersichtlich. Code auf Modulebene sollte nur Konstanten, Funktionen, und Klassen definieren. Das Hauptprogramm steht üblicherweis ein der `main()`-Funktion. ``global`` hat in einem sauberen Programm nichts zu suchen. Und da man für ein GUI-Programm sowieso objektorientierte Programmierung (OOP) braucht, gibt's für ``global`` auch keine Ausrede.

Kryptische Abkürzungen wie `spd` (das waren doch die mit dem Martin Schulz, oder? ;-)) sollte man nicht verwenden.

Funktionsnamen beschreiben in der Regel eine Tätigkeit. Das da `*_fun()` am Ende steht ist überflüssig, denn man sieht ja schon am Aufruf, dass es sich um eine Funktion (oder etwas vergleichbares) handelt.

Mal wird das erste Element von ``keyevent.keycode`` mit einer Zeichenkette verglichen und mal ``keyevent.keycode`` selbst — eins von beidem ist mit ziemlicher Sicherheit falsch.

Das der Socket-Code bisher noch keinen Murks gemacht hat, ist wahrscheinlich Zufall, denn es ist nicht garantiert, dass `send()` auch wirklich alles sendet was als Argument übergeben wurde. Wie viele Bytes gesendet wurden verrät einem der Rückgabewert. Entweder muss man das in einer Schleife machen bis tatsächlich alle Bytes versendet wurden, oder man verwendet die `sendall()`-Funktion.

Ist das gewollt das zwischen 'speed' und der Zahl kein Zeichen steht? Und muss die Anweisung tatsächlich nicht irgendwie abgeschlossen werden? Woher soll der Empfänger sonst wissen ob schon alle Ziffern der Geschwindigkeit empfangen wurden, oder ob da noch etwas kommt?

Die Schleife von `evdev` dürfte so nicht zusammen mit der GUI-Hauptschleife funktionieren. Es kann ja immer nur eine von beiden laufen. Das musst man also irgendwie in die GUI-Hauptschleife integrieren.
Antworten