ArduinoでHID
肢体不自由者がPCを操作する際にキーボードやマウスの代替として、外部スイッチで入力できるインターフェースを使う選択肢があり、市販もされている。
これまではジョイスティックの基板からスイッチのバイパスを取り、フリーソフトで機能を割り当てて使っていたが、浅田先生(北神戸スイッチルーム)がHID機能をもったスイッチBOXを作られた。この方法はWindows、iOsにかかわらず使用できるので汎用性が高い。
そこでわたしも作ってみた。今回初めてHID機能を持つ32U4を積んだArduinoProMicro(Leonardo)を使用した。
併せてこれまで採用してきたジョイスティックの基板とフリーソフトの組み合わせによる方法を記録として残す。(他の選択肢→自作)
パーツ
Arduino Pro Micro(AliExpress、送料込み691円)
タクトスイッチ、ジョイスティック(デジットのジャンク品)など
回路
写真の通り。使用ポートの詳細はsketchを参照のこと。
実装
(救急車のサイレンは愛敬ということで。。)
スケッチ
ほとんどサンプルスケッチそのままである。ライブラリに感謝!
/* HID_for_Pro_Micro_04.ino
Arduino Pro Micro
TX/1・ ・RAW
RX/0・ ・GND
GND・ ・Reset
GND・ ・VCC *PWM
SDA/2・ ・21/A3
SCL/3* ・20/A2
left --> A6/4・ ・19/A1 <== y_Axis
up --> 5* ・18/A0 <== x_Axis
down --> A7/6* ・15/SCLK <== mouseButton
space --> 7・ ・14/MISO <-- LED
right --> A8/8・ ・16/MOSI <-- bs
return --> A9/9* *10/A10 <-- tab
*/
#include <Keyboard.h>
#include <Mouse.h>
const int LED = 14;
const int up = 5;
const int down = 6;
const int right = 8;
const int left = 4;
const int tab = 10;
const int space = 7;
const int bs = 16;
const int enter = 9;
const int mouseButton = 15; // mouse button
const int x_axis = A0; // joystick X axis
const int y_axis = A1; // joystick Y axis
int mouse_x = 0;
int mouse_y = 0;
int range = 12; // output range of X or Y movement
int threshold = range / 4; // resting threshold
int center = range / 2; // resting position value
int responseDelay = 10; // response delay of the mouse, in ms
int lastSwitchState = LOW; // previous switch state
void setup() {
pinMode(LED, OUTPUT); // for switch indicater
pinMode(up, INPUT_PULLUP);
pinMode(down, INPUT_PULLUP);
pinMode(right, INPUT_PULLUP);
pinMode(left, INPUT_PULLUP);
pinMode(tab, INPUT_PULLUP);
pinMode(space, INPUT_PULLUP);
pinMode(bs, INPUT_PULLUP);
pinMode(enter, INPUT_PULLUP);
pinMode(mouseButton, INPUT_PULLUP);
Serial.begin(9600);
Keyboard.begin();
Mouse.begin();
}
void loop() {
mouse_control();
mouse_button_control();
keyboard_control();
delay(responseDelay);
}
void mouse_control() {
mouse_x = readAxis(x_axis);
mouse_y = readAxis(y_axis);
Mouse.move(mouse_x, mouse_y, 0);
Serial.print("mouse position : ");
Serial.print(mouse_x, DEC);
Serial.print(" , ");
Serial.println(mouse_y, DEC);
}
int readAxis(int thisAxis) { // analog input to mouse pointer output
int reading = analogRead(thisAxis);
reading = map(reading, 0, 1023, 0, range);
int distance = reading - center;
if (abs(distance) < threshold) {
distance = 0;
}
return distance;
}
void mouse_button_control() {
if (digitalRead(mouseButton) == LOW) {
if (!Mouse.isPressed(MOUSE_LEFT)) {
Mouse.press(MOUSE_LEFT);
digitalWrite(LED, HIGH);
}
} else {
if (Mouse.isPressed(MOUSE_LEFT)) {
Mouse.release(MOUSE_LEFT);
digitalWrite(LED, LOW);
}
}
}
void keyboard_control() {
if (digitalRead(up) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_UP_ARROW);
delay(10);
Keyboard.releaseAll();
while (digitalRead(up) == LOW);
}
if (digitalRead(down) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_DOWN_ARROW);
delay(10);
Keyboard.releaseAll();
while (digitalRead(down) == LOW);
}
if (digitalRead(right) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_RIGHT_ARROW);
delay(10);
Keyboard.releaseAll();
while (digitalRead(right) == LOW);
}
if (digitalRead(left) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_LEFT_ARROW);
delay(10);
Keyboard.releaseAll();
while (digitalRead(left) == LOW);
}
if (digitalRead(tab) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_TAB);
delay(10);
Keyboard.releaseAll();
while (digitalRead(tab) == LOW);
}
if (digitalRead(space) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(0x20);
delay(100);
Keyboard.releaseAll();
while (digitalRead(space) == LOW);
}
if (digitalRead(bs) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_BACKSPACE);
delay(10);
Keyboard.releaseAll();
while (digitalRead(bs) == LOW);
}
if (digitalRead(enter) == LOW) {
digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW);
Keyboard.press(KEY_RETURN);
delay(10);
Keyboard.releaseAll();
while (digitalRead(enter) == LOW);
}
}
その他の選択肢
自作 (→ 代替マウスとしてのスイッチボックス)
手順
USB対応のジョイスティックをバラして基板から各スイッチのバイパスを取りだす。(ジョイスティックはアマゾンで数百円で買える)
基板には動作確認用の露出部があり、念のためピンセットをあててショートさせて確認しながらバイパスを取る。(基板によっては対応するスイッチがプリントされている)作業が単調なのでビールを飲みながらハンダ付けしたら火傷をしたことがあった(笑)
スイッチへの機能の割り当てはJoyToKeyやjoypointerなどのフリーソフトを使う。これらのソフトはゲーマー用に開発されたもので非常に高性能であり、設定も簡便である。Windowsでしか使えないのは残念だ。
REVIVE USB
市販の基板である。12ポート、各ポートへの機能の割り付けは付属のアプリをダウンロードして行う。アプリはWindows用だが、設定してしまえば他のOSでも使える。
らくらくマウス
市販品。現在はテクノツールが引き継いでいるが、以前は基板の販売もあった。
テクノツールに移譲前に注文製作を依頼したことがあった。ボタンの配置、ケースの選定から始まり、防水対策、外部スイッチ用のジャックの追加の提案など非常に丁寧に良心的に対応して戴いた。
できマウス。
市販。4ポート。8ポートに拡張も可。
サイトに上がっている優れもののアプリたちには大変お世話になりました。ありがとうございました。
ver.2 を作った
各スイッチの機能割り当てが変更出来るようになった。