簡體   English   中英

如何在Python中記錄xbox / gamepad控制器的狀態?

[英]How to record state of xbox/gamepad controller in Python?

我需要在特定時間知道xbox控制器的所有按鈕的值。 原因是我正在為神經網絡構建訓練集,並且試圖同時拍攝屏幕快照和拍攝控制器狀態的“快照”。 請注意,對於該項目的鍵盤版本,我能夠成功完成此操作,但是xbox控制器給我帶來了困難。

我所嘗試的是創建按鈕和值的字典,並在每次收到控制器事件時更新字典。 然后,我將圖像和字典另存為訓練數據的實例。 但是,輸入最終根本不與圖像同步。 我認為該問題可能與用於讀取控制器的軟件包之一中的線程或子進程有關,但是我不夠熟練,無法知道如何解決它。

下面是我的代碼。

from inputs import get_gamepad
import time
import cv2
import numpy as np
from mss.windows import MSS as mss

#Only track relevant inputs
gp_state = {#'ABS_HAT0X' : 0, #-1 to 1
             #'ABS_HAT0Y' : 0, #-1 to 1
             #'ABS_RX' : 0, #-32768 to 32767
             #'ABS_RY' : 0, #-32768 to 32767
             'ABS_RZ' : 0, #0 to 255
             'ABS_X' : 0, #-32768 to 32767
             'ABS_Y' : 0, #-32768 to 32767
             #'ABS_Z' : 0, #0 to 255
             'BTN_EAST' : 0,
             'BTN_NORTH' : 0,
             #'BTN_SELECT' : 0,
             'BTN_SOUTH' : 0,
             #'BTN_START' : 0,
             #'BTN_THUMBL' : 0,
             #'BTN_THUMBR' : 0,
             'BTN_TL' : 0,
             'BTN_TR' : 0,
             'BTN_WEST' : 0,
             #'SYN_REPORT' : 0,
             }

dead_zone = 7500

def screen_record(): 
    last_time = time.time()
    while(True):
        # 800x600 windowed mode
        printscreen =  np.array(ImageGrab.grab(bbox=(0,40,800,640)))
        last_time = time.time()
        cv2.imshow('window',cv2.cvtColor(printscreen, cv2.COLOR_BGR2RGB))
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break

def process_img(image):
    original_image = image
    processed_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    contrast = 1
    brightness = 0
    out = cv2.addWeighted(processed_img, contrast, processed_img, 0, brightness)
    return out

def main():

    #Give myself time to switch windows
    #Screen should be in top left
    for _ in range(4):
        time.sleep(1)

    controller_input = np.zeros(5)
    training_data = []
    training_files = 0

    with mss() as sct:
        while True:
            #Get screen and display
            bbox = (150,240,650,490)
            screen =  np.array(sct.grab(bbox))
            new_screen = process_img(screen)
            cv2.imshow('window', new_screen)
            new_screen = cv2.resize(new_screen, (100,50))

            #Map events to dictionary
            events = get_gamepad()
            for event in events:
                gp_state[event.code] = event.state

            #Set to zero if in dead zone
            if abs(gp_state['ABS_X']) < dead_zone:
                gp_state['ABS_X'] = 0 

            if abs(gp_state['ABS_Y']) < dead_zone:
                gp_state['ABS_Y'] = 0 

            #Set values to be between 0 and 1.
            controller_input[0] = (gp_state['ABS_X'] + 32768) / (32767 + 32768)
            controller_input[1] = gp_state['ABS_RZ'] / 255
            controller_input[2] = gp_state['BTN_SOUTH']
            controller_input[3] = gp_state['BTN_EAST']
            controller_input[4] = gp_state['BTN_TR']


            record = gp_state['BTN_NORTH'] #Record while holding y button
            if record:
                training_data.append(np.array([new_screen, controller_input]))
                print(controller_input)
                time.sleep(1)

            if len(training_data) % 500 == 0 and record:
                filename = f"training_data/rlb_XBOXtrain_{time.time()}.npy"
                np.save(filename, training_data)
                training_files += 1
                print(f"Trained {training_files} files!")
                training_data = []


            if cv2.waitKey(25) & 0xFF == ord('q'):
                cv2.destroyAllWindows()
                break

main()

我覺得我正在使這種方式變得比所需的更加困難。 但是,是否有一種更簡單的方法來僅在特定時間點獲取控制器的狀態?

請注意,我已經找到了一些適用於Linux的解決方案,但是我正在Windows 10中運行。這是Linux解決方案的示例: https : //github.com/FRC4564/Xbox

我覺得我正在使這種方式變得比所需的更加困難。

不,這實際上很難。 這很難,因為你不需要知道游戲手柄的狀態是在特定的時間什么,你也想知道哪個游戲手柄狀態被用於繪制特定幀。 采樣游戲手柄狀態的時間將始終早於繪制框架的時間,並且可能由於應用程序自身添加的延遲而延遲。 對於整個應用程序而言,增加的延遲可能是恆定的,或者在應用程序的不同部分之間可能有所不同。 這不是您可以輕松解決的問題。

您的python腳本會在接收到游戲手柄輸入后立即記錄它們,因此我希望它始終在屏幕捕獲之前至少運行一幀或兩幀。

我認為該問題可能與用於讀取控制器的軟件包之一中的線程或子進程有關,但是我不夠熟練,無法知道如何解決它。

這可能只是您正在測量的應用程序中游戲手柄輸入代碼所增加的延遲,而不是可以解決的問題。 大多數應用程序不會在收到游戲手柄輸入后立即做出任何嘗試,而是在每幀更新步驟中一次全部處理它們。 平均而言,這會增加等於幀速率一半的延遲。

如何解決這個問題? 我認為由於延遲問題,從另一個應用程序測量游戲手柄狀態將很困難。 如果可以的話,最好是對應用進行檢測,以在其主循環中記錄游戲手柄的狀態,這樣您就可以知道正在記錄的實際使用情況。 在Windows上,應該可以通過提供自己的XInput DLL版本來做到這一點,該版本可以在每次調用XInputGetState時記錄當前狀態。

TensorKart項目已經解決了這個問題: https : //github.com/kevinhughes27/TensorKart/blob/master/utils.py

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM