首页 > 解决方案 > Python-无线控制器和加数/值列表

问题描述

硬件: RPi4 4GB,SteelSeries Stratus Duo WiFi/BTLE 无线控制器

长期目标:使用无线控制器执行多项任务(即,移动/归零工具头,启动/暂停/停止程序等),无线控制器将与运行控制 CNC 路由器的服务器的 RPi 接口。

短期目标:确定按下了哪些按钮组合,而不使用过多的if/elif语句。

摘要:我已经弄清楚如何使用 PyUSB 读取无线控制器的输出。我已经更改/添加了 PyUSB 中包含的代码,以产生一些人类可读的结果。输出格式为列表,每个项目的值由某种按钮组合确定。(我知道它说的是“数组”,但 Python 似乎将它视为一个列表。)

这是未按下按钮时的输出(默认):

array('B', [0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

前两个值 ( ...[0, 20,...]) 似乎是某种标识符,它们永远不会改变。然而,多个按钮在列表中使用相同的索引位置。它们都有不同的值,并在同时按下时相加。任何按钮值的组合都不会为索引位置生成相同的输出。例子:

按钮 A:array('B', [0, 20, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

左上方:array('B', [0, 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

左上角和A:array('B', [0, 20, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

这是我当前的程序,你可以看到 if/elif 语句开始有点失控了:

#!/usr/bin/python
from __future__ import division

import usb.core
import usb.util
import time
import os
import sys
#import csv

USB_IF      = 0 # Interface
USB_TIMEOUT = 5 # Timeout in MS

USB_VENDOR  = 0x1038 # SteelSeries
USB_PRODUCT = 0x1430 # Stratus Duo

dev = usb.core.find(idVendor=USB_VENDOR, idProduct=USB_PRODUCT)

endpoint = dev[0][(0,0)][0]

if dev.is_kernel_driver_active(USB_IF) is True:
    dev.detach_kernel_driver(USB_IF)

usb.util.claim_interface(dev, USB_IF)

while True:
    control = None

    try:
        control = dev.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, USB_TIMEOUT)
        CtrlA = control[2]      #Directional Pad, Start/Select, L/R Stick Press
        CtrlB = control[3]      #Top Left/Top Right, Center, A, B, X, Y
        CtrlC = control[4]      #Left Trigger (0-255)
        CtrlD = control[5]      #Right Trigger (0-255)
        CtrlEH = control[6:10]  #Left Stick
        CtrlIL = control[10:14] #Right Stick
        print control
        if CtrlA ==0:
            print "No Input"
        elif CtrlA == 1:
            print "Directional Pad: Up"
        elif CtrlA == 2:
            print "Directional Pad: Down"
        elif CtrlA == 4:
            print "Directional Pad: Left"
        elif CtrlA == 8:
            print "Directional Pad: Right"  
        elif CtrlA == 16:
            print "Right Center Button"
        elif CtrlA == 32:
            print "Left Center Button"
        elif CtrlA == 64:
            print "Left Stick Pressed"
        elif CtrlA == 128:
            print "Right Stick Pressed"
        elif CtrlA == 192:
            print "Right & Left Sticks Pressed"
        else:
            break

        if CtrlC == 0:
            print "Left Trigger: No Input"
        elif 1 <= CtrlC <=254:
            print "Left Trigger: " + "{:.0%}".format(CtrlC/255)
        elif CtrlC == 255:
            print "Left Trigger: Max"
        else:
            break


        if CtrlD == 0:
            print "Right Trigger: No Input"
        elif 1 <= CtrlD <=254:
            print "Right Trigger: " + "{:.0%}".format(CtrlD/255)
        elif CtrlD == 255:
            print "Right Trigger: Max"
        else:
            break

except:
pass

#Let Ctrl+C actually exit.
time.sleep(0.01)

同样,我想要的结果是让程序确定被按下的按钮的组合 - 例如,如果值为control[3]17有没有办法有效地让程序确定它是161( “A”按钮和“左上”按钮)?

我已经研究过可能使用 CSV 文件、itertools(排列、组合等)、嵌入式列表和其他此类可能的解决方案。乍一看,所有这些似乎都在我想做的事情的大致范围内。不幸的是,这些(至少它们本身)似乎都无法实现目标。对我来说,这是一个完全未知的编程领域,任何指导将不胜感激。

标签: pythonarrayslistwireless

解决方案


如果 control[3] 的值为 17,有没有办法有效地让程序确定它是 16 和 1 的分配值的组合

这是这个问题的有趣之处。答案是“是”。您可能已经注意到各个值 (1, 2, 4, 8, 16, 32, 64...) 是 2 的幂(2**1, 2**2, 2**3...)。这意味着可以将组合值视为二进制数字。因此,如果我给你 40,那么使用 2 的幂表示的唯一方法是 32 + 8。在二进制中,这是 101000。如果你想在 Python 中得到这个(至少在 Python3 中)你可以这样做bin(40),它会打印字符串“0b10001”。

至于如何充分利用这一点,我将听从 art-solopov 的回答。


推荐阅读