目的
(下書きでずーっと保持してるのもアレなので雑すぎる情報だけど発行)
2020年10月にゲーム配信を始めてもうすぐ2年.配信で英語の練習のために英語もまれにしゃべる中,字幕の翻訳入力言語を切り替える必要があった*1.
ゲーム中は,もちろん両手が塞がっていて,あまっているのは足! 既存のフットスイッチはなんか弱々しいので,もう作っちゃお! そういうこと.
本記事で紹介するおもな環境は下表のとおり:
名称 | 規格 | 製造会社 | 備考 |
---|---|---|---|
フットスイッチ (3本ペダル) |
SP-34 | CASIO | 購入時5,733JPY, Amazon.co.jpのURL |
マイコン | Seeeduino XIAO | Seeed Studio | 購入時580JPY, 秋月電子通販コードM-15178 |
フットスイッチ用コネクター (PS/2コネクター) |
JPCB-PS/2-2P | aitendo | 購入時39JPY, aitendoのURL |
炭素皮膜抵抗 | 2.2kΩ | 不明 |
また,GitHubのリポジトリーは以下: github.com
結果
動くものは,現状,以下の感じ(このツイートを追っていくと製作までの流れが見える).
音出るので注意
— AKETO, Tomu (@so2akt) November 17, 2021
こうなりました.1発目が位置ズレするのは直前に動かしたマウスのせいっぽい.ゆえにプライマリーディスプレイ内での絶対座標にしたほうがよさそう~ pic.twitter.com/xYyQtdVocQ
要求・要件
- 足の操作で,マウスクリック相当をしたい
- ON/OFFの2値とする
設計(書きかけ)
実装(書きかけ)
ハードウェア
ブレッドボード上で運用してて,接触悪くなってきたのでユニバーサル基板へ実装!
表面 | 裏面 |
---|---|
一応,絶縁的なサムシングを施して以下が現状2022/07/18最終形とした:
ソフトウェア
#include "HID-Project.h" #include <TimerTC3.h> #define SERIAL_BAUDRATE (115200) #define TC3_INT_COUNT (10 * 1000) // microsecond #define AD_RESOLUTION (10) #define HORIZ_POS_ADJ (1920) #define VERT_POS_ADJ (1760) #define BTN_POS_DIFF (720) #define MOUSE_MOVE_ITR (5) #define DAMPER_PEDAL_UNPUSHED (642) #define DAMPER_PEDAL_PUSHED (374) #define SOSTENUTO_PEDAL_UNPUSHED (1023) #define SOSTENUTO_PEDAL_PUSHED (180) #define SOFT_PEDAL_UNPUSHED (1023) #define SOFT_PEDAL_PUSHED (160) #define PIN_IN_DAMPER_PEDAL (1) #define PIN_IN_SOSTENUTO_PEDAL (2) #define PIN_IN_SOFT_PEDAL (3) #define NUM_OF_EDGE (1) #define NUM_OF_DEBOUNCE (3) #define NUM_OF_POLLING (NUM_OF_EDGE + NUM_OF_DEBOUNCE) // buttons name on Yukarinette Connector Voice Recognition Window typedef enum TAG_BUTTON_NAME { LANG_1ST, // 1st language: Japanese (default) LANG_2ND, // 2nd language: English US (default) LANG_3RD, // 3rd language: Chinese Mainland (default) LANG_MAX }button_number_t; typedef enum TAG_PEDAL_NUMBER { PEDAL_DAMPER, // right pedal PEDAL_SOSTENUTO, // middle pedal PEDAL_SOFT, // left pedal PEDAL_MAX }pedal_number_t; typedef enum TAG_PEDAL_COND { PEDAL_COND_DONT_CARE, // unpushed or continuing pushed PEDAL_COND_PUSHED_EDGE, // detect pushed edge PEDAL_COND_PUSHED, // pushed PEDAL_COND_MAX }pedal_cond_t; typedef struct TAG_ANALOG_PEDAL { uint32_t ulPinIndicator; // indicator led output: ON when pedal pushed uint32_t ulPinPedal; // pedal analog input uint16_t usThresholdPushed; // pedal threshold when pedal pushed uint16_t usThresholdUnpushed; // pedal threshold when pedal unpushed bool bIsPushedPoll[NUM_OF_POLLING]; // debounce polling pattern: true when pedal pushed pedal_cond_t kPedalCond; // pedal condition uint8_t ucPushedCount; // number of pushed uint8_t ucPollCount; // polling counter: 0 to NUM_OF_POLLING -1 }analog_pedal_t; analog_pedal_t kPedal[PEDAL_MAX] = { { // damper pedal (right pedal) setting PIN_LED, PIN_IN_DAMPER_PEDAL, DAMPER_PEDAL_PUSHED, DAMPER_PEDAL_UNPUSHED, {false, false, false, true}, // 4th element prevents from PUSHED detection when started with pedal pushing PEDAL_COND_DONT_CARE, 0, 0 }, { // sostenuto pedal (middle pedal) setting PIN_LED2, PIN_IN_SOSTENUTO_PEDAL, SOSTENUTO_PEDAL_PUSHED, SOSTENUTO_PEDAL_UNPUSHED, {false, false, false, true}, // 4th element prevents from PUSHED detection when started with pedal pushing PEDAL_COND_DONT_CARE, 0, 0 }, { // soft pedal (left pedal) setting PIN_LED3, PIN_IN_SOFT_PEDAL, SOFT_PEDAL_PUSHED, SOFT_PEDAL_UNPUSHED, {false, false, false, true}, // 4th element prevents from PUSHED detection when started with pedal pushing PEDAL_COND_DONT_CARE, 0, 0 } }; void MouseMoveAndClick(button_number_t); void vPedalDiscriminant(pedal_number_t, button_number_t); void vInputPoll(void); void setup() { SerialUSB.begin(SERIAL_BAUDRATE, SERIAL_8N1); // default SERIAL_8N1 while(!SerialUSB) { ; // wait for SerialUSB enabled } SerialUSB.print("serial com opened as "); SerialUSB.print("baudrate: "); SerialUSB.print(SERIAL_BAUDRATE); SerialUSB.println(", data bit: 8, parity bit: none, stop bit: 1"); pinMode(kPedal[PEDAL_DAMPER].ulPinIndicator, OUTPUT); SerialUSB.print("set damper pedal indicator OUTPUT #"); SerialUSB.println(kPedal[PEDAL_DAMPER].ulPinIndicator); pinMode(kPedal[PEDAL_SOSTENUTO].ulPinIndicator, OUTPUT); SerialUSB.print("set sostenuto pedal indicator OUTPUT #"); SerialUSB.println(kPedal[PEDAL_SOSTENUTO].ulPinIndicator); pinMode(kPedal[PEDAL_SOFT].ulPinIndicator, OUTPUT); SerialUSB.print("set soft pedal indicator OUTPUT #"); SerialUSB.println(kPedal[PEDAL_SOFT].ulPinIndicator); pinMode(kPedal[PEDAL_DAMPER].ulPinPedal, INPUT); SerialUSB.print("set damper pedal analog INPUT #"); SerialUSB.println(kPedal[PEDAL_DAMPER].ulPinPedal); pinMode(kPedal[PEDAL_SOSTENUTO].ulPinPedal, INPUT); SerialUSB.print("sostenuto pedal analog INPUT #"); SerialUSB.println(kPedal[PEDAL_SOSTENUTO].ulPinPedal); pinMode(kPedal[PEDAL_SOFT].ulPinPedal, INPUT); SerialUSB.print("soft pedal analog INPUT #"); SerialUSB.println(kPedal[PEDAL_SOFT].ulPinPedal); analogReadResolution(AD_RESOLUTION); // default 10-bit on Seeeduino XIAO SerialUSB.print("set A/D converter resolution: "); SerialUSB.print(AD_RESOLUTION); SerialUSB.println(" bits"); AbsoluteMouse.begin(); SerialUSB.println("absolute positioning mouse started"); Mouse.begin(); SerialUSB.println("relative positioning mouse started"); TimerTc3.initialize(TC3_INT_COUNT); TimerTc3.attachInterrupt(vInputPoll); } void loop() { ; } void MouseMoveAndClick(button_number_t kButtonNumber) { AbsoluteMouse.moveTo(SHRT_MAX - HORIZ_POS_ADJ, VERT_POS_ADJ + kButtonNumber * BTN_POS_DIFF); for(int i = 0; i < MOUSE_MOVE_ITR; i++) { Mouse.move(SCHAR_MAX, 0); } Mouse.click(); return; } void vPedalDiscriminant(pedal_number_t pedal_idx, button_number_t button_idx) { uint8_t ucPollCountPrev = (kPedal[pedal_idx].ucPollCount + NUM_OF_POLLING - 1) % NUM_OF_POLLING; uint32_t ulPedalVal = analogRead(kPedal[pedal_idx].ulPinPedal); kPedal[pedal_idx].bIsPushedPoll[kPedal[pedal_idx].ucPollCount] = (ulPedalVal < kPedal[pedal_idx].usThresholdPushed) ? true : false; switch (kPedal[pedal_idx].kPedalCond) { case PEDAL_COND_DONT_CARE: if ((!kPedal[pedal_idx].bIsPushedPoll[ucPollCountPrev]) && (kPedal[pedal_idx].bIsPushedPoll[kPedal[pedal_idx].ucPollCount])) { kPedal[pedal_idx].kPedalCond = PEDAL_COND_PUSHED_EDGE; kPedal[pedal_idx].ucPushedCount = 1; } break; case PEDAL_COND_PUSHED_EDGE: if (kPedal[pedal_idx].bIsPushedPoll[kPedal[pedal_idx].ucPollCount]) { if (NUM_OF_DEBOUNCE == ++kPedal[pedal_idx].ucPushedCount) { kPedal[pedal_idx].kPedalCond = PEDAL_COND_PUSHED; } } else { kPedal[pedal_idx].kPedalCond = PEDAL_COND_DONT_CARE; } break; case PEDAL_COND_PUSHED: MouseMoveAndClick(button_idx); default: kPedal[pedal_idx].kPedalCond = PEDAL_COND_DONT_CARE; kPedal[pedal_idx].ucPushedCount = 0; break; } kPedal[pedal_idx].ucPollCount = (kPedal[pedal_idx].ucPollCount + 1) % NUM_OF_POLLING; return; } void vInputPoll(void) { vPedalDiscriminant(PEDAL_DAMPER, LANG_1ST); vPedalDiscriminant(PEDAL_SOSTENUTO, LANG_2ND); vPedalDiscriminant(PEDAL_SOFT, LANG_3RD); return; }
改訂履歴
# | 日付 | 内容 |
---|---|---|
1 | 2022/07/18 | ユニバーサル基板での実装写真を掲載 |
参考URL
- Seeed Seeeduino XIAO を使ってみた(USBデバイス編): K.H.WEBLOG
- フットスイッチコントローラの作り方 - Qiita
- マウスポインタを絶対画面座標に移動するためのArduinoLeonardo / Micro用ライブラリ。 - wenyanet
- Seeeduino XIAO(Arduinoと互換)の開発環境を作る | スマートライフを目指すエンジニア
- Seeeduino Xiao - Anyone got the part? - parts help - fritzing forum
*1:当たり前(?)ながら,日本語の翻訳入力で英語をしゃべると正しく翻訳されないため.