XBOX Bluetooth Controller können nun direkt mit Powered Up Hubs verbunden werden (Pybricks)

Mit der neusten BETA-Version von Pybricks ist es nun möglich, XBOX Controller direkt mit Powered Up Hubs (Technic Control+ Hub, Mindstorms/SPIKE Prime Hub, SPIKE Essential Hub) zu verbinden. Der "City"-Hub und der Boost Move Hub werden wohl nicht unterstützt.
Pybricks kann kostenlos in Python oder kostenpflichtig mit einer Scratch-artigen grafischen Programmieroberfläche programmiert werden.

Kompatible Controller

TLDR: Die Tasten und "analogen" Eingabemethoden von Bluetooth XBOX-Controllern werden unterstützt.

Wie man dem Titel dieses Posts entnehmen kann, werden nur XBOX Controller unterstützt und davon nur solche, die Bluetooth unterstützen. Das sind alle XBOX Controller der XBOX One und XBOX Series Generation - bis auf den ersten XBOX One Controller und den ersten XBOX Elite Controller. Der XBOX Elite 2 Controller wird unterstützt.
Zu erkennen sind die Controller, die nicht kompatibel sind, daran, dass das Plastik um die XBOX-Taste das gleiche Stück wie bei den Triggern und nicht das große Plastikstück auf der Oberseite ist. Ungefähr seit 2016 unterstützen alle neuen XBOX Controller Bluetooth.
Quelle, nur der untere Controller-Typ kann Bluetooth
Neue XBOX Series Controller kosten um die 55€ bzw. im Angebot ab 45€.
Es ist gut möglich, dass in der Zukunft noch weitere Controller unterstützt werden. Auf absehbare Zeit werden jedoch wieder Nintendo Switch Controller, noch Playstation 4/5 Controller unterstützt. Das liegt daran, dass die meisten LEGO-Hubs nur BLE bzw. Bluetooth Low Energy unterstützen. Playstation und Nintendo Switch Controller nutzen jedoch BTC bzw. Bluetooth Classic, das nicht mit BLE kompatibel ist. Es wäre ein Controller-Update nötig, damit die Controller BLE unterstützen - wenn das überhaupt technisch möglich ist.
Zukünftige Controller, die unterstützt werden, müssen mit BLE kompatibel sein. Dazu zählen der Amazon Luna Controller, der 8Bitdo SNK NEOGEO Wireless Controller. Außerdem gibt es im mobilen Bereich einige Controller, die BLE unterstützen. Ein paar BLE-kompatible Controller wie der Google Stadia Controller und der Steam Controller werden nicht mehr hergestellt.

Kompatible Funktionen der Controller

Zurück zu den XBOX Controllern, die unterstützt werden. Es werden alle Inputs der Controller unterstützt, also alle Tasten, Trigger und Joysticks. Das sind insgesamt bis zu 16 Tasten plus Joysticks plus Trigger. Bewegungssensoren können nicht genutzt werden, weil die XBOX Controller keine enthalten.
Bei den Joysticks und Triggern, die "analoge" Eingabe ermöglichen, können die ganzen Stufen genutzt werden. Dadurch ist es z.B. bei Fahrzeugen möglich, den Trigger nur leicht rein zu drücken, damit das Fahrzeug nur langsam fährt.
Bei dem XBOX Elite 2 Controller können die Paddles auf der Rückseite einzeln abgefragt werden. Dafür sollte ein Profil ausgewählt werden, bei dem die Paddles nicht auf andere Tasten gelegt sind.
Was derzeit nicht unterstützt wird, ist die Steuerung der LED und der Rumble Motoren. Dadurch wären z.B. Annährungssensoren oder ein "piepen" beim Rückwärtsfahren möglich.
Ebenso können weder der Expansion Port, noch der Kopfhöreranschluss der Controller genutzt werden. Das liegt daran, dass sie von Controller Seite aus nicht per BLE genutzt werden kann. Die Chatpad-Tastatur kann nicht genutzt werden.

Vorbereitung

Es kann sein, dass der Controller zuerst aktualisiert werden muss. Das geht mit der XBOX Zubehör App für Windows und XBOX.
Außerdem werden XBOX Controller zum Zeitpunkt der Veröffentlichung dieses Posts nur in der BETA-Version von Pybricks unterstützt. Sie kann hier aufgerufen werden.

Verwendung

In der grafischen Programmieroberfläche kann der Controller im Setup mit dem "controller"-Block hinzugefügt werden. Die Eingabemöglichkeiten des Controllers können mit den Blöcken unter "Buttons and Force" abgefragt werden. Der Block "buttons center is pressed" ermöglicht die Abfrage der Tasten und der Block "controller left trigger" die Abfrage der analogen Eingabemethoden. Ihre Werte können im Fall der Sticks zwischen -100 und 100 bzw. im Fall der Trigger zwischen 0 und 100 liegen.
Bei der Nutzung von Python können Controller nach dem Import mit "from pybricks.iodevices import XboxController" mit dem Befehl "controller = XboxController()" genutzt werden. Die analogen Eingaben können beispielsweise mit "controller.triggers()[0]" abgefragt werden und die Tasten mit ""taste" in controller.buttons.pressed()".
Weitere Details zur Verwendung gibt es in der Dokumentation.

XBOX Controller haben die folgenden LED Modi:
  • Aus: Controller ist aus
  • langsam blinkend: Controller sucht nach gepairtem Gerät
  • schnell blinkend: Controller will sich pairen
  • dauerhaft leuchtend: Controller ist verbunden
Wenn das Programm auf dem LEGO Hub gestartet wurde, muss der Controller bei der ersten Verwendung gepairt werden. Dafür muss er durch langen Druck auf die XBOX-Taste erst eingeschaltet werden. Danach kann man auf die Sync-Taste neben dem USB-Anschluss des Controllers drücken, bis die LED schnell blinkt. Nach einigen Sekunden sollten sich Controller und Hub pairen.
Danach reicht es, nach dem Start des Programms den Controller einzuschalten. Er sollte nach einigen langsamen Blinken die Verbindung mit dem Hub aufbauen. Wird der Controller zwischendurch mit einem anderen Bluetooth-Gerät gepairt, muss er erneut mit dem Hub gepairt werden.

Beispielcode

Der folgende Beispiel-Code ist in Python für das "App-gesteuerte Transformationsfahrzeug" (42140) geschrieben. Außerdem sind Lampen an den Anschluss "C" angeschlossen, die mit der "A"-Taste am Controller ein- und ausgeschaltet werden können. Wenn diese Lampe nicht angeschlossen ist, müssen die folgenden 3 Zeilen entfernt werden: "light = Light(Port.C)", "light.off()" und "light.on(lightBrightness)".
Wenn das Programm läuft, kann die Geschwindigkeit des Fahrzeugs mit den Triggern gesteuert werden. Die Lenkung ist mit dem linken Stick möglich. Ebenso kann das Fahrzeug auf der Stelle drehen, indem nur der linke Stick zu einer Seite gedrückt wird.

from pybricks.hubs import TechnicHub
from pybricks.pupdevices import *
from pybricks.parameters import *
from pybricks.tools import wait
from pybricks.iodevices import XboxController

#Thanks to unbrickme for supplying the port configuration
#Thanks to profinerd for testing

hub = TechnicHub()
motor1 = Motor(Port.B)
motor2 = Motor(Port.A)
light = Light(Port.C)
light.off()
controller = XboxController()
lightBrightness = 0
hubOrientation = 1

#main loop
while True:
    #update pressed buttons information
    pressed = controller.buttons.pressed()

    #calculate a "motor factor" from joystick movement
    X_fact = controller.joystick_left()[0]
    if (X_fact < 0):
        right_fact = (100+X_fact)/100
        left_fact = 1
    elif (X_fact > 0):
        right_fact = 1
        left_fact = (100-X_fact)/100
    else:
        right_fact = 1
        left_fact = 1

    #update orientation of the hub
    if hub.imu.up() == Side.BOTTOM:
        hubOrientation = 0
    elif hub.imu.up() == Side.TOP:
        hubOrientation = 1

    #commands to drive
    #they depend on the orientation of the hub
    #for one side, motors are reversed and switched
    speed = controller.triggers()[1] - controller.triggers()[0]
    if hubOrientation == 0:
        hub.light.on(Color.ORANGE)
        if speed != 0:
            motor1.dc(-speed*left_fact)
            motor2.dc(speed*right_fact)
        else:
            motor1.dc(controller.joystick_left()[0])
            motor2.dc(controller.joystick_left()[0])

    elif hubOrientation == 1:
        hub.light.on(Color.BLUE)
        if speed != 0:
            motor2.dc(-speed*left_fact)
            motor1.dc(speed*right_fact)
        else:
            motor1.dc(controller.joystick_left()[0])
            motor2.dc(controller.joystick_left()[0])
           

    #Turn the hub off. Shamelessly copied from profinerd
    if ("MENU" in pressed):
        hub.system.shutdown()
   
    #Turn light on/off with A button
    if ("A" in pressed):
        if lightBrightness == 0:
            lightBrightness = 100
        else:
            lightBrightness = 0
   
    light.on(lightBrightness)

    wait(100)


Kommentare