techno_memo

個人用の技術メモ。python・ROS・AI系のソフトウェア・ツールなどの情報を記載

pygameを用いたゲームパッド操作機能の実装

この記事の目的

 pythonのライブラリpygameを用いてゲームパッドでユーザーの入力を読み込む処理を実装する。

使用したゲームパッド


ゲームパッド Logicool ロジクール F310r 国内正規品 3年間メーカー保証

参考となるサイト https://glorificatio.org/archives/1398

pygame

pygameとは

pythonのゲーム制作用ライブラリ 2Dの画面描画/音楽再生機能/ユーザー操作入力(マウス/キーボード/ゲームパッド)が充実しており、ゲーム以外にも処理結果の描画やUIとして利用することができる。

wiki

ja.wikipedia.org

機能/使い方の詳細

aidiary.hatenablog.com

インストール

windows (anacondaの場合)

pip install pygame

Ubuntu mateの場合

sudo apt-get install python-pygame

GUI描画(Hello World) とキーボード読み込み

初期化処理でスクリーンサイズなどを設定したあとで、30msec間隔をあけながらキーボードの状態を取得して 赤丸の位置を動かす処理は、下記のように記述できる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys
 
SCREEN_SIZE = (640, 480)  # 画面サイズ (横/縦)
STEP = 10       #キーボード/ハットスイッチの反応の良さ

if __name__ == '__main__':
    # Pygameを初期化
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE)   # SCREEN_SIZEの画面を作成
    pygame.display.set_caption("window test")       # Windowタイトルの設定
    X_CENTER = int(SCREEN_SIZE[0]/2)
    Y_CENTER = int(SCREEN_SIZE[1]/2)
    [circle_x, circle_y] = [X_CENTER, Y_CENTER]     #円の初期位置を設定

    # 画面描画ループ
    while True:
        screen.fill((0,0,0))     # 画面を青色で塗りつぶす
        # イベント処理
        for event in pygame.event.get():    #×ボタンによる終了
            if event.type == QUIT:  # 終了イベント
                sys.exit()
        #  キーボード状態の取得
        pressed_keys = pygame.key.get_pressed()
        # 押されているキーに応じて画像を移動
        if pressed_keys[K_LEFT]:
            circle_x = circle_x - STEP
        if pressed_keys[K_RIGHT]:
            circle_x = circle_x + STEP
        if pressed_keys[K_UP]:
            circle_y = circle_y - STEP
        if pressed_keys[K_DOWN]:
            circle_y = circle_y + STEP

        #描画範囲の上下限チェック
        if circle_x< 0:
            circle_x = 0
        elif circle_x > SCREEN_SIZE[0]:
            circle_x = SCREEN_SIZE[0]

        if circle_y< 0:
            circle_y = 0
        elif circle_y > SCREEN_SIZE[1]:
            circle_y = SCREEN_SIZE[1]

        #描画
        pygame.draw.circle(screen, (255,0,0), (circle_x,circle_y), 10)
        pygame.display.update()  # 画面を更新
        pygame.time.wait(30)     # 30msec 待ち
        

コントローラの読み込み

ジョイスティックの初期化

下記処理を初期化部分に追加するとpygameジョイスティックを初期化できる。

    pygame.joystick.init()
    try:
        joy = pygame.joystick.Joystick(0) # create a joystick instance
        joy.init() # init instance
        print("Joystick Name: " + joy.get_name())
        print("Number of Button : " + str(joy.get_numbuttons()))
        print("Number of Axis : " + str(joy.get_numaxes()))
        print("Number of Hats : " + str(joy.get_numhats()))

F310の場合、軸やボタン数を下記のように取得できる。

Joystick Name: Controller (Gamepad F310)
Number of Button : 10
Number of Axis : 5
Number of Hats : 1

ジョイスティック(アナログバー)の読み込み

アナログバーは各軸について -1~1の小数値で得られる。 F310の場合axis(2)はLRキーの強さに対応する軸なので注意。 (下記は左スティックのみ有効としている)

            #ジョイスティック(アナログバー左スティック)状態の取得
            circle_x = int((joy.get_axis(0)+1) * X_CENTER)    #joystick(横軸)の方向キーはは-1~1の範囲で取得できる
            circle_y = int((joy.get_axis(1)+1) * Y_CENTER)    #joystick(縦軸)の方向キーはは-1~1の範囲で取得できる
            # axis(2)はL2/R2キーに対応
            #ジョイスティック(アナログバー右スティック)状態の取得
            #circle_x = int((joy.get_axis(3)+1) * X_CENTER)    #joystick(横軸)の方向キーはは-1~1の範囲で取得できる
            #circle_y = int((joy.get_axis(4)+1) * Y_CENTER)    #joystick(縦軸)の方向キーはは-1~1の範囲で取得できる

方向ボタン(ハットスイッチ)読み込み

方向ボタン(ハットスイッチ)は縦横軸それぞれを-1,0,1の離散値として取得できる

            #方向ボタン (ハットスイッチ)
            hat_input = joy.get_hat(0)

            if hat_input[0] == -1:  #
                circle_x = circle_x - STEP
            elif hat_input[0] == 1:
                circle_x = circle_x + STEP
            if hat_input[1] == 1:
                circle_y = circle_y - STEP
            elif hat_input[1] == -1:
                circle_y = circle_y + STEP

上記の3つの入力手段を切り替えることができるpygameスクリプトgithubに保存した。

github.com

次回は上記の処理をROSと結合して目標速度指令を送信し、turtlesimを動かす機能を実装する。