去抖动摇杆按钮输入

1 投票
2 回答
4830 浏览
提问于 2025-04-16 20:50

我有一个用Python和gobject写的摇杆类,运行得很好,但有一个小问题。就是当我运行下面的代码时,按钮会出现抖动,导致每次按按钮时会被多次识别。请问我怎么才能把每次按按钮的消息减少到只发一次,而且准确度还不错呢?

''' 
Copyright 2009 Jezra Lickter 

This software is distributed AS IS. Use at your own risk. 
If it borks your system, you have  been forewarned. 

This software is licensed under the LGPL Version 3 
http://www.gnu.org/licenses/lgpl-3.0.txt 


for documentation on Linux Joystick programming please see 
http://www.mjmwired.net/kernel/Documentation/input/joystick-api.txt 
''' 

import gobject #needed for sending signals 
import struct #needed for holding chunks of data 

class Joystick(gobject.GObject): 
    '''The Joystick class is a GObject that sends signals that represent 
    Joystick events''' 
    EVENT_BUTTON = 0x01 #button pressed/released 
    EVENT_AXIS = 0x02  #axis moved  
    EVENT_INIT = 0x80  #button/axis initialized  
    #see http://docs.python.org/library/struct.html for the format determination 
    EVENT_FORMAT = "IhBB" 
    EVENT_SIZE = struct.calcsize(EVENT_FORMAT) 

    # we need a few signals to send data to the main 
    '''signals will return 4 variables as follows: 
    1. a string representing if the signal is from an axis or a button 
    2. an integer representation of a particular button/axis 
    3. an integer representing axis direction or button press/release 
    4. an integer representing the "init" of the button/axis 
    ''' 
    __gsignals__ = { 
    'axis' : 
    (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, 
    (gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_INT)), 
    'button' : 
    (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, 
    (gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_INT)) 
    } 


    def __init__(self,dev_num): 
        gobject.GObject.__init__(self) 
        #define the device 
        device = '/dev/input/js%s' % dev_num 
        #error check that this can be read 
        try: 
            #open the joystick device 
            self.device = open(device) 
            #keep an eye on the device, when there is data to read, execute the read         function 
            gobject.io_add_watch(self.device,gobject.IO_IN,self.read_buttons) 
        except Exception,ex: 
            #raise an exception 
            raise Exception( ex ) 

    def read_buttons(self, arg0='', arg1=''): 
        ''' read the button and axis press event from the joystick device 
        and emit a signal containing the event data 
        ''' 
        #read self.EVENT_SIZE bytes from the joystick 
        read_event = self.device.read(self.EVENT_SIZE)   
        #get the event structure values from  the read event 
        time, value, type, number = struct.unpack(self.EVENT_FORMAT, read_event) 
        #get just the button/axis press event from the event type  
        event = type & ~self.EVENT_INIT 
        #get just the INIT event from the event type 
        init = type & ~event 
        if event == self.EVENT_AXIS: 
            signal = "axis" 
        elif event == self.EVENT_BUTTON: 
            signal = "button" 
        if signal: 
            print("%s %s %s %s" % (signal,number,value,init) ) 
            self.emit(signal,number,value,init) 

        return True 

if __name__ == "__main__": 
    try: 
        j = Joystick(0) 
        loop = gobject.MainLoop() 
        loop.run() 
    except Exception,e: 
        print(e) 

2 个回答

0

通常情况下,在x、y和按钮接触点与地线(GND)之间各放一个1微法或10微法的电容器,可以帮助消除按钮按下时的抖动,这样就不需要写代码来处理这个问题了。

3

有很多方法可以处理按钮的抖动问题。一个简单且不阻塞的方法是:

  1. 定期检查按钮的状态,...
  2. ...如果按钮的“瞬时”状态不是我们认为的“有效”状态,...
  3. ...就增加一个计数器,...
  4. ...如果计数器达到某个设定值,就切换按钮的“有效”状态。
  5. 每当“瞬时”状态和“有效”状态相同时,计数器应该重置。

当然,这种方法需要定期进行检查,因为反应时间是由 频率 * 阈值 决定的。

编辑:我没有硬件来实际运行这个,但处理抖动的方法应该类似于:

if button_now() != button_state:
    debounce_counter += 1
    if debounce_counter == DEBOUNCE_THRESHOLD:
        button_state = not button_state
else:
    debounce_counter = 0

在上面的代码中:

  • button_now() 用来检查硬件状态(根据按钮电路是闭合还是打开返回 True/False),
  • button_state 是程序其余部分“看到”的按钮状态(同样是 True/False,表示按钮是按下还是抬起),
  • DEBOUNCE_THRESHOLD 是你根据公式 按钮反应时间 = 抖动处理频率 * 阈值 定义的常量。

希望这些信息对你有帮助!

撰写回答