Keyboard (2.4 GHz) als Fernsteuerung nutzen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
whleupold
User
Beiträge: 2
Registriert: Mittwoch 14. August 2019, 18:49

Hallo, ich bin ganz neu hier und brauche dringend Unterstützung.
Mit einem Keyboard (Rii Mini i8+/2.4 GHz) möchte ich auf meinem Raspberry 3B+ 2 Servos fernsteuern und ein Roboterauto bewegen. Dazu muss ich feststellen, welche Taste gedrückt wird. Das schaffe ich, auch bei Sondertasten, die eigntlich für Lautstärke- und Videosteuerung vorgesehen sind.
Mein Problem liegt aber darin, dass ich die Variablen, die für die sukzessive Bewegung der Servos vorgesehen sind, nicht ändern kann.
Der Programmcode funktioniert nur, wenn ich feste Werte eingebe, nicht wenn ich die Variablen ändere.
Im folgenden Python-Code sind die Zeilen, die einen Abbruch-Fehler hervorrufen deaktiviert (##).
Hat jemand eine Idee, was ich falsch mache?
Danke für jeden zielführenden Hinweis.

Anbei der Python-Code:

from __future__ import division
import sys, tty, termios, os, readchar

import pynput
from pynput import keyboard

import time
import pygame
pygame.init()

# Import the PCA9685 module.
import Adafruit_PCA9685

Taste = ""

servo_lr_akt = 400
servo_lr_min = 130
servo_lr_max = 730

servo_hr_akt = 400
servo_hr_min = 130
servo_hr_max = 730

currentlyRunning = True

# Initialise the PCA9685 using the default address (0x40).
pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm(0, 0, servo_lr_akt)
pwm.set_pwm(0, 0, servo_lr_akt)

def set_servo_pulse(channel, pulse):
pulse_length = 1000000 # 1,000,000 us per second
pulse_length //= 60 # 60 Hz
print('{0}us per period'.format(pulse_length))
pulse_length //= 4096 # 12 bits of resolution
print('{0}us per bit'.format(pulse_length))
pulse *= 1000
pulse //= pulse_length
pwm.set_pwm(channel, 0, pulse)

def on_press(key):
try:
print('Key {0} pressed'.format(key.char))

except AttributeError:
print('Key {0} pressed'.format(key))

def on_release(key):
print('{0} released'.format(key))
print(key)
Taste = str(key)
print(Taste)

if Taste.find("269025046") == True:
##servo_lr_akt = servo_lr_akt + 5
pwm.set_pwm(0, 0, servo_lr_akt)
sleep(1)
print("rechts")
return True

if Taste.find("269025047") == True:
##servo_lr_akt = servo_lr_akt + 5
pwm.set_pwm(0, 0, servo_lr_akt)
sleep(1)
print("links")
return True

if Taste.find("269025041") == True:
##servo_hr_akt = servo_hr_akt + 5
pwm.set_pwm(1, 0, servo_hr_max)
sleep(1)
print("hoch")
return True

if Taste.find("269025043") == True:
##servo_hr_akt = servo_hlr_akt + 5
pwm.set_pwm(1, 0, servo_hr_akt )
sleep(1)
print("runter")
return True

if Taste.find("269025044") == True:
#servo_lr_akt = servo_lr_akt + 5
pwm.set_pwm(0, 0, servo_lr_akt)
pwm.set_pwm(1, 0, servo_hr_akt)
print("stop")
return True

if key == keyboard.Key.esc:
pwm.set_pwm(0, 0, servo_lr_akt)
pwm.set_pwm(1, 0, servo_hr_akt)
return False

# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Du importierst termios, tty, readchar und pygame, ohne sie zu benutzen. Es ist gut, wenn Du verschiedene Sachen ausprobierst, aber dann solltest Du sie auch wieder restlos entfernen, wenn es nicht geklappt hat. Warum hat pygame nicht geklappt? Es greift deutlich weniger in System ein als pynput, wäre also die bessere Wahl.

Auch wenn Du Sondertasten benutzt, die in keyboard.Key nicht definiert sind, solltest Du sie ähnliich behandeln, also eine Konstante definieren und key direkt vergleichen, anstatt eine Zahl in einen String zu verwandeln diesen mit find in einen Wahrheitswert zu überführen und dann noch explizit mit True zu vergleichen.

Dein Problem ist, dass pynput mit Threads arbeitet, und Du die ganze Arbeit in enem Callback erledigst. Das kann zu verschiedenen seltsamen Problemen führen, nicht nur, dass Du keine Variablen über zwei Aufrufe hinaus speichern kannst. Besser ist es daher, im Callback nur eine Queue zu füttern, und das eigentliche Abarbeiten im Hauptthread zu machen.

Code: Alles auswählen

from __future__ import division
from functools import partial
from pynput.keyboard import Key, Listener
from Queue import Queue
import time
import Adafruit_PCA9685

XF86_AUDIO_LOWER_VOLUME = 0x1008FF11
XF86_AUDIO_MUTE = 0x1008FF12
XF86_AUDIO_RAISE_VOLUME = 0x1008FF13
XF86_AUDIO_PLAY = 0x1008FF14
XF86_AUDIO_STOP = 0x1008FF15
XF86_AUDIO_PREV = 0x1008FF16
XF86_AUDIO_NEXT = 0x1008FF17


def servo_init(servo_lr_akt, servo_hr_akt):
    pwm = Adafruit_PCA9685.PCA9685()
    pwm.set_pwm(0, 0, servo_lr_akt)
    pwm.set_pwm(1, 0, servo_hr_akt)
    return pwm	

def set_servo_pulse(pwm, channel, pulse):
    pulse_length = 1000000    # 1,000,000 us per second
    pulse_length //= 60      # 60 Hz
    print('{0}us per period'.format(pulse_length))
    pulse_length //= 4096     # 12 bits of resolution
    print('{0}us per bit'.format(pulse_length))
    pulse *= 1000
    pulse //= pulse_length
    pwm.set_pwm(channel, 0, pulse)

def on_press(key):
    try:
        print('Key {0} pressed'.format(key.char))
    except AttributeError:
        print('Key {0} pressed'.format(key))

def on_release(key, queue):
    print('{0} released'.format(key))
    if key in (XF86_AUDIO_PREV, XF86_AUDIO_NEXT, XF86_AUDIO_LOWER_VOLUME,
        XF86_AUDIO_RAISE_VOLUME, XF86_AUDIO_PLAY):
        queue.put(key)
        return True	
    elif key == keyboard.Key.esc:
        queue.put(key)
        return False	
		
def main():
    servo_lr_akt = 400
    servo_lr_min = 130
    servo_lr_max = 730

    servo_hr_akt = 400
    servo_hr_min = 130
    servo_hr_max = 730
    pwm = servo_init(servo_lr_akt, servo_hr_akt)

    queue = Queue()
    with keyboard.Listener(
            on_press=on_press,
            on_release=partial(on_release, queue=queue)) as listener:
        while True:
            key = queue.get()
            if key == XF86_AUDIO_PREV:
                servo_lr_akt = servo_lr_akt + 5
                pwm.set_pwm(0, 0, servo_lr_akt)
                sleep(1)
                print("rechts")
            elif key == XF86_AUDIO_NEXT:
                servo_lr_akt = servo_lr_akt + 5
                pwm.set_pwm(0, 0, servo_lr_akt)
                sleep(1)
                print("links")
            elif key == XF86_AUDIO_LOWER_VOLUME:
                servo_hr_akt = servo_hr_akt + 5
                pwm.set_pwm(1, 0, servo_hr_max)
                sleep(1)
                print("hoch")
            elif key == XF86_AUDIO_RAISE_VOLUME:
                servo_hr_akt = servo_hlr_akt + 5
                pwm.set_pwm(1, 0, servo_hr_akt )	
                sleep(1)
                print("runter")
            elif key == XF86_AUDIO_PLAY:
                servo_lr_akt = servo_lr_akt + 5
                pwm.set_pwm(0, 0, servo_lr_akt)
                pwm.set_pwm(1, 0, servo_hr_akt)
                print("stop")
            elif key == keyboard.Key.esc:
                pwm.set_pwm(0, 0, servo_lr_akt)
                pwm.set_pwm(1, 0, servo_hr_akt)
                break	
            
if __name__ == '__main__':
    main()
Eingerückt wird übrigens immer mit 4 Leerzeichen pro Ebene, nicht Tabs und Leerzeichen mischen!
whleupold
User
Beiträge: 2
Registriert: Mittwoch 14. August 2019, 18:49

Vielen Dank für die sehr ausführliche Hilfe. Ich bin begeistert!
Leider habe ich bei der Ausführung des Programms immer noch Probleme. Nach dem Start erscheint sofort folgende Fehlermeldung:

Traceback (most recent call last):
File "testprog.py", line 96, in <module>
main()
File "testprog.py", line 60, in main
with keyboard.Listener(
NameError: global name 'keyboard' is not defined

Ich beschäftige mich erst seit kurzer Zeit mit Python und stehe wirklich auf dem Schlauch.
Gerne würde ich mich auch, wie vorgeschlagen, nur auf pygame einlassen, konnte jedoch online keine Beispiele für mein Problem mit den Sondertasten finden.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

So muß es bei mir richtig sein

Code: Alles auswählen

with Listener(
und natürlich auch

Code: Alles auswählen

elif key == Key.esc:
Antworten