由於想增加第八個鼓面,朋友原先的電路感覺不容易新增與維護
於是選擇了用 pyboard 去做改接 (可以直接模擬成電腦搖桿的 Arduino 板不知丟哪去了 Q_Q)
每個鼓面下面都是蜂鳴片(壓電元件),並上 1M ohm 電阻後,
一端接地,一端接 AD輸入[1][2][3]
pyboard 提供了可以當成電腦鍵盤的功能 (接上USB時,電腦辨識成鍵盤)
當成電腦鍵盤時,同時可模擬按壓六個按鍵 [4][5]
pyboard 的USB連接到電腦時,可以是 [6]
互動執行 + 隨身碟(儲存裝置) 或
互動執行 + HID裝置 (可以為滑鼠或鍵盤)
隨身碟模式方便把寫好的程式拷到板子上跑,HID鍵盤裝置是最終要玩打鼓遊戲的設置
一開始先測試 pyboard 的 AD [7]
先連續讀值並把數值丟出來看(如下),冒號右邊為保值的最大值
37 22 25 24 30 28 27 20 : 49 1179 120 40 42 62 46 30
34 23 27 22 27 32 23 13 : 49 1179 120 40 42 62 46 30
35 24 24 22 28 25 20 15 : 49 1179 120 40 42 62 46 30
上面分別為八個鼓面的 AD輸出與最大值的保值
多試個幾次去記錄最大值,以此值做 閥值的參考
當讀值超過閥值時,才當成有輸入
測試過程中可以發現透過鼓架傳遞震動,有時敲 A 鼓,B也有反應,但輸出較小,持續時間也較短
於是加入第二個判斷,當超過閥值時,計數陣列值+1
如下為 3 與 4 鼓面同時被判定有輸入,持續時間達 7 ms 與 2ms (使用每 1ms 讀一批次AD)
[0, 0, 7, 2, 0, 0, 0, 0]
當持續發生有輸入時,送出對應的按鍵值給電腦
電腦對按鍵的辨識,間距要 10ms 以上,不然會出錯
以下程式,其中 main 裡面放了
changetMode() 方便切換 Storage 與 HID
modify_threshold() 方便修改閥值(在HID模式時)並儲存
ma() 使用前要關掉 timer 中斷( tim2.deinit());用來查看連續的AD讀值
boot.py
# boot.py -- run on boot-up# can run arbitrary Python, but best to keep it minimal
import machine
import pyb
#pyb.main('main.py') # main script to run after this one
#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device
#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
pyb.usb_mode('CDC+HID',hid=pyb.hid_keyboard)
main.py
#hardware platform: pyboard V1.1import time
import os
import struct
import micropython
import machine
import pyb
def changetMode(m='f'):
'''
parameter mode
m = 'f' : flash
m = other: HID_KB
'''
# from HID_KB mode return to Flash mode
f=open('boot.py', 'r')
boot=f.readlines()
f.close()
if m == 'f' and len(boot)>8: # USB to flash mode
print('back to flash mode, will reset')
boot.pop(-1)
f=open('boot.py', 'w')
for i in range(len(boot)):
f.write(boot[i])
f.close()
machine.reset()
else: # USB to HID KB mode
print('change to KB mode')
f=open('boot.py', 'w')
for i in range(len(boot)):
f.write(boot[i])
f.write(b"pyb.usb_mode('CDC+HID',hid=pyb.hid_keyboard)")
f.write('\n')
f.close()
machine.reset()
hid=pyb.USB_HID()
# byte 0 Modifier keys
# byte 1 Reserved
# byte 2 Keycode 1
# byte 3 Keycode 2
# byte 4 Keycode 3
# byte 5 Keycode 4
# byte 6 Keycode 5
# byte 7 Keycode 6
# max 6 keys send at the same time
def release_key():
global hid
buf = bytearray(8) # report is 8 bytes
#buf[2] = 0
hid.send(buf) # key released
pyb.delay(10) #must delay 10ms
def press_key(key = [0]):
global hid
buf = bytearray(8) # report is 8 bytes
for i in range(len(key)):
buf[i+2] = key[i]
#buf[i+3] = 40 # Enter; for Note test
hid.send(buf) # key released
pyb.delay(10) #must delay 10ms
X1 = pyb.ADC(pyb.Pin('X1')) # set X1 for analog input
X2 = pyb.ADC(pyb.Pin('X2')) # set X2 for analog input
X3 = pyb.ADC(pyb.Pin('X3')) # set X3 for analog input
X4 = pyb.ADC(pyb.Pin('X4')) # set X4 for analog input
X5 = pyb.ADC(pyb.Pin('X5')) # set X5 for analog input
X6 = pyb.ADC(pyb.Pin('X6')) # set X6 for analog input
X7 = pyb.ADC(pyb.Pin('X7')) # set X7 for analog input
X8 = pyb.ADC(pyb.Pin('X8')) # set X8 for analog input
AD = [X1, X2, X3, X4, X5, X6, X7, X8]
KBKEY = [30, 31, 32, 33, 34, 35, 36, 37] # mapping HID KB 1 ~ 8
# Timer 1 ~ 14
#Timer 3 is reserved for internal use, and 5 and 6 are used for servo and ADC/DAC control
import threshold as th
threshold = th.threshold
DRUM = [0]*8 #
AVG = [0]*8 # for average
ADV=[0]*8 # store read AD value
flg20ms = 0
hisstat=[0]*8 # history of DRUM status
# if DRUM 0 -> 1, do nothing
# if DRUM 1 -> 0, set 1 (button up trigger)
flg_doeven = 0
def Timer2callback(t):
global AD
global ADV
global DRUM
global threshold
global hisstat
global flg_doeven
global flg20ms
if flg20ms > 0:
flg20ms = flg20ms - 1
for i in range(8):
ADV[i] = AD[i].read()
if ADV[i] > threshold[i]:
DRUM[i] = 1
hisstat[i] += 1
else:
DRUM[i] = 0
if hisstat[i] > 2:
if flg20ms == 0:
print(hisstat)
flg20ms = 20
flg_doeven = 1
def modify_threshold(threshold):
f = open('threshold.py', 'w')
f.write('threshold = [')
for i in threshold:
f.write(str(i))
f.write(', ')
f.write(']')
f.close()
def ma(op = 0):
global AVG
global ADV
global DRUM
MAXV = [0]*8
while(1):
AVG = [0]*8
for j in range(20):
for i in range(8):
ADV[i] = AD[i].read()
AVG[i] += ADV[i]
for i in range(8):
AVG[i] //= 20
if AVG[i] > MAXV[i]:
MAXV[i] = round(AVG[i])
if op == 0:
print('{:>4} {:>4} {:>4} {:>4} {:>4} {:>4} {:>4} {:>4}'.format(ADV[0], ADV[1], ADV[2], ADV[3], ADV[4], ADV[5], ADV[6], ADV[7]))
elif op == 1:
print('{:>4} {:>4} {:>4} {:>4} {:>4} {:>4} {:>4} {:>4}'.format(DRUM[0], DRUM[1], DRUM[2], DRUM[3], DRUM[4], DRUM[5], DRUM[6], DRUM[7]))
else:
for i in range(8):
print('{:>5} '.format(round(AVG[i])), end='')
print(':', end='')
for i in range(8):
print('{:>3} '.format(MAXV[i]), end='')
print()
tim2 = pyb.Timer(2, freq=1000)
tim2.callback(Timer2callback)
#tim2 = pyb.Timer(2, freq=1000, callback=Timer2callback) # 1ms
flg_release = 0
while True:
if flg_doeven == 1:
PK=[]
for i in range(8):
if hisstat[i] > 3:
PK.append(KBKEY[i])
for i in range(8):
hisstat[i] = 0
press_key(PK)
flg_doeven = 0
flg_release = 1
else:
if flg_release == 1:
flg_release = 0
release_key()
pyb.delay(10)
threshold.py
threshold = [700, 1700, 1500, 1800, 650, 350, 400, 130]參考:
[1] 极客DIY:利用Arduino制作电子鼓 https://www.freebuf.com/news/topnews/60389.html
[2] Arduino Leonardo/Micro As Game Controller/Joystick https://www.instructables.com/id/Arduino-LeonardoMicro-as-Game-ControllerJoystick/
[3] [ Arduino ] Arduino電子鼓 – Arduino Drum using Hairless MIDI + pizeo disk https://yoyotechnology.wordpress.com/2015/07/15/arduino-arduino%E9%9B%BB%E5%AD%90%E9%BC%93-arduino-drum-using-hairless-midi-pizeo-disk/
[4] 什麼是 N-key 與按鍵衝突?原理說明、改善技術、選購注意完全解析https://www.techbang.com/posts/10235-keyboard-triggers-do-not-bomb-almighty-from-the-matrix-to-the-circuit-n-key-conflict-with-the-keys-in-the-end-is-what-computer-king-75-fully-understood?page=4
[5] 【micropython】用python來進行BadUSB的USB-HID測試(含無線控制) https://codertw.com/ios/58229/
[6] http://docs.micropython.org/en/latest/library/pyb.html?highlight=usb_mode#pyb.usb_mode
[7] ADC performance of MicroPython boards https://forum.micropython.org/viewtopic.php?t=2682
注意:
1. timer 中斷裡不能使用浮點數除法,若要做移動平均,要用 // 做整數除法
2. 雖然有 14 個 timer (1~ 14),但是系統用的 (3, 5, 6)
要避開 http://docs.micropython.org/en/v1.9.4/pyboard/pyboard/tutorial/timer.html?highlight=timer