Python-无线控制器和加数/值列表

Posted

技术标签:

【中文标题】Python-无线控制器和加数/值列表【英文标题】:Python- Wireless Controller & List of Addends/Values 【发布时间】:2020-05-30 10:26:54 【问题描述】:

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

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

短期目标:在不使用大量 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(排列、组合等)、嵌入式列表和其他此类可能的解决方案。乍一看,所有这些似乎都在我想做的事情的大致范围内。不幸的是,这些(至少它们本身)似乎都无法实现目标。对我来说,这是一个完全未知的编程领域,非常感谢任何指导。

【问题讨论】:

【参考方案1】:

这就是我要做的。

我会为每个按钮分配自己的位置和值元组,如下所示:

buttons = [
    ('dir_up', 2, 1),
    ('dir_down', 2, 2),
    ('dir_left', 2, 4),
    ('dir_right', 2, 8),
    # ... etc, other buttons here
]

然后你可以看到使用生成器实际按下了哪些按钮:

def pressed_buttons(control):
    for button in buttons:
        name, control_pos, value = button
        # To check if the button was pressed, perform a binary masking
        if control[control_pos] & value == value:
            yield button

P。 S. 为了更清楚起见,您可能会发现 namedtuples 甚至 enums 很有用。

【讨论】:

【参考方案2】:

如果 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 的回答。

【讨论】:

以上是关于Python-无线控制器和加数/值列表的主要内容,如果未能解决你的问题,请参考以下文章

CDlinux虚拟机怎么加载USB无线网卡

计算机网络实验(思科模拟器Cisco Packet Tracer)——无线路由和防火墙配置

无线开关原理

Micropython TPYBoard 控制无线加速度小车

iPhone12控制中心关闭无线局域网和蓝牙是真的关闭吗

在Airtest中如何使用无线模式控制手机