LoginSignup
0
0

More than 1 year has passed since last update.

Raspberry Pi に Xbox のコントローラーを Bluetooth 接続して Python で使う

Last updated at Posted at 2023-02-22

Xbox のコントローラーを Raspberry Pi と Bluetooth 接続して Python から使う方法をまとめます。Python 実行時は pygame を使用しますが GUI は使用せずに実行可能です。本プログラム内では十字キーと B ボタンにのみ反応するようになっています。

まず Xbox のコントローラーを ペアリングモード にして Raspberry Pi の Bluetooth のアイコンをクリックし Add Device... をクリックします。

bluetooth1.png

Xbox Wireless Controller と表示されるので選択して Piar ボタンを押します。Raspberry Pi と Xbox コントローラーが Bluetooth で無事接続されると Connection successfully と表示されるので OK ボタンを押します。

bluetooth2.png

再度 Bluetooth アイコンをクリックすると Xbox Wireless Controller の左にチェックマークが表示され現在接続中であることが確認できます。

bluetooth3.png

CLI で接続されていることを確認するには bluetoothctl コマンドを使います。Bluetooth 接続自体も CLI で行いたい場合は ここここ などを参照してください。因みに後者では xboxdrv や joystick のインストールを行っていますが Raspberry Pi OS (bullseye) を使用し且つ Python の pygame から使用する範囲内では特にインストールせずに動作するようです。

$ bluetoothctl paired-devices
Device C8:3F:26:60:22:6A Xbox Wireless Controller

次に pygame がインストールされているか確認します。以下のコマンドの実行結果から該当の環境では pygame 1.9.6 がインストールされていることが確認できます。インストール方法は 本家 などを参照してください。

$ python3 -c "import pygame; print(pygame.version.ver)"
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
1.9.6

pygame を使用した Python の例は以下のようになります。

import sys, os

os.environ["SDL_VIDEODRIVER"] = "dummy"
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"

import pygame

def joy_event(joy):

    hat = joy.get_hat(0) # Get status of cross key

    if hat[0] == 0 and hat[1] == 1: # Up key pressed
        print("up")
    elif hat[0] == 0 and hat[1] == -1: # Down key pressed
       print("down")
    elif hat[0] == -1 and hat[1] == 0: # Left key pressed
       print("left")
    elif hat[0] == 1 and hat[1] == 0: # Right key pressed
       print("right")


def main():

    pygame.init()

    try:
        joy = pygame.joystick.Joystick(0)
        joy.init()
        print('Joystick Name: ', joy.get_name())
        print('Number of buttons: ', joy.get_numbuttons())

    except pygame.error:
        print('Joystick 0 is not connected.')
        sys.exit(1)

    try:
        while True:
            event = pygame.event.wait() # Wait until getting event from queue

            btn_b = joy.get_button(1) # B button to exit
            if btn_b == 1:
                break

            joy_event(joy)

            #print(event)

    except KeyboardInterrupt:
        print("Program interrupted by user")

    joy.quit()
    pygame.quit()

    print("Exit")

    return

if __name__=="__main__":
    main()

プログラムを実行するとまずコントローラーの名前とボタンの数が表示されます。続いて Xbox コントローラーの十字キーを押すとそれに応じた出力がターミナル上に表示されます。B ボタンを押すとプログラムが終了します。

$ python3 ./test.py
Joystick Name:  Xbox Wireless Controller
Number of buttons:  15
up
left
right
down
Exit

pygame.event.wait() でイベント (ここではコントローラのボタンが押される) を待ちイベントが発生した場合 joy_event() を呼び出しています。joy_event() 内で joy.get_hat(0) を呼び出し十字キーのステータスを取得しています。joy.get_hat() は 2 つの要素を持つタプルを返し例えば上が押された場合は (0, 1)、なにも押されていない場合は (0, 0) を返します。

print(event) をコメントから外すと以下のようにキーに対応した番号が取得できます。例えば A を押した際に以下のような出力となり 0 が対応していることがわかります。

<Event(10-JoyButtonDown {'joy': 0, 'button': 0})>
<Event(11-JoyButtonUp {'joy': 0, 'button': 0})>

アナログスティックは joy.get_axis() を呼び出すと x 軸方向や y 軸方向などの傾きに対応した値を -1.0 から 1.0 の範囲で得られるようです。詳しくは ここ などを参照してください。例はいろいろと web に転がっていますが最近では ChatGPT 先生 に聞くのが良いかもしれません。。

<Event(7-JoyAxisMotion {'joy': 0, 'axis': 0, 'value': 0.9060335093234047})>

一点要調査なのは Ctrl-C で以下の個所が思った通りに動かないことです。。pygame.event.wait() 内で待ってるからだと思いますが ChatGPT 先生に聞いても今のところ答えは分かりませんでした。。なのでプログラムは B ボタンを押して終了する必要があります。

    except KeyboardInterrupt:
        print("Program interrupted by user")

アナログスティックの傾きの値を得る場合はこんな感じ。

def joy_event(joy):

    du = joy.get_axis(0) # Joy stick Down(+1.0)/Up(-1.0)
    rl = joy.get_axis(1) # Joy stick Right(+1.0)/Left(-1.0)

    print("D(+1.0)/U(-1.0): " + str(du) + ", R(+1.0)/L(-1.0): " + str(rl))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0