去抖动摇杆按钮输入
我有一个用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
有很多方法可以处理按钮的抖动问题。一个简单且不阻塞的方法是:
- 定期检查按钮的状态,...
- ...如果按钮的“瞬时”状态不是我们认为的“有效”状态,...
- ...就增加一个计数器,...
- ...如果计数器达到某个设定值,就切换按钮的“有效”状态。
- 每当“瞬时”状态和“有效”状态相同时,计数器应该重置。
当然,这种方法需要定期进行检查,因为反应时间是由 频率 * 阈值
决定的。
编辑:我没有硬件来实际运行这个,但处理抖动的方法应该类似于:
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
是你根据公式按钮反应时间 = 抖动处理频率 * 阈值
定义的常量。
希望这些信息对你有帮助!