ProMicroでポインティングスティックを作った
動作
- ジョイスティックを傾けるとマウスポインタがその向きに動く
- 2番ピンのボタンを押すとジョイスティックの初期位置がリセットされる
- 3番ピンのボタンを押すとジョイスティックを傾けた方向にスクロールする
- 4番ピンのボタンでマウスの左クリック
配線図
使ってるジョイスティックがライブラリになかったため, テキトーに繋いでる。
コード
#include "Mouse.h" const int _UDPIN = A2; // UD入力 const int _LRPIN = A1; // LR入力 //const int _SWPIN = 7; // デジタルピン const int RESET_PIN = 2; const int CENTER_PIN = 3; const int CLICK_PIN = 4; int range = 12; int responseDelay = 20; int threshold = 1; int center = range / 2; int init_lr = 512; int init_ud = 512; char scroll_count = 0; void setup() { Serial.begin(9600); // pinMode(_SWPIN,INPUT) ; pinMode(RESET_PIN, INPUT_PULLUP); pinMode(CENTER_PIN, INPUT_PULLUP); pinMode(CLICK_PIN, INPUT_PULLUP); init_lr = analogRead(_LRPIN); init_ud = analogRead(_UDPIN); Mouse.begin(); } void loop() { if(digitalRead(RESET_PIN) == LOW) { init_lr = analogRead(_LRPIN); init_ud = analogRead(_UDPIN); } int ud = readAxis(_UDPIN, init_ud); int lr = -readAxis(_LRPIN, init_lr); Serial.print("UP-DOWN:"); Serial.print(ud, DEC); //DECは10進数フォーマットを表す Serial.print(" - Left-Rright:"); Serial.println(lr, DEC); // if (digitalRead(_SWPIN) == HIGH) { // Serial.println("switch on"); // } if(digitalRead(CENTER_PIN) == LOW) { if( scroll_count == 3) { Mouse.move(0, 0, -lr); scroll_count = 0; } else { scroll_count++; } } else { Mouse.move(ud, lr, 0); } // read the mouse button and click or not click: // if the mouse button is pressed: if (digitalRead(CLICK_PIN) == LOW) { // if the mouse is not pressed, press it: if (!Mouse.isPressed(MOUSE_LEFT)) { Mouse.press(MOUSE_LEFT); } } // else the mouse button is not pressed: else { // if the mouse is pressed, release it: if (Mouse.isPressed(MOUSE_LEFT)) { Mouse.release(MOUSE_LEFT); } } delay(responseDelay); } int readAxis(int pin, int init) { int reading = analogRead(pin); // reading = reading * range / 1023; // int distance = reading - center; int distance = NumLog( reading - init ); if( abs(distance) < threshold ) { distance = 0; } return distance; } int NumLog(int i) { int tei = 2; int sign = 1; if(i<0) { sign = -1; i = -i; } int j=0; for(; i>tei; j++) { i /= tei; } return sign*j; }
ちょっと長い区間の乗車券を買うことで往復割引の有効期間を延ばす
東京都区内から善通寺までは791kmで往復割引乗車券の有効期間が10日間になりギリギリ使えなかったが, あと9km付け足せば有効期間が12日に伸びて使うことができる。
さらに区間を秋葉原を通る経路で東京都区外側に伸ばせば秋葉原での下車を途中下車扱いにできる。600km超だと運賃計算のキロ数が40kmごとに区切られているので思いの外遠くまで同じ運賃で行くことができる。
今回は南浦和経由で南流山まで買うことにした。越谷レイクタウンや新三郷で途中下車できる。 時間があるかは別の問題
往復割引乗車券の有効期間が少し足りないときは乗車券の購入区間の延長を検討してみるといいと思う。
ツイートまとめ
東京都区内から実家最寄りまでが790kmなのであと10km足せば往復乗車券で帰省できることになる。丸亀―児島間の坂出経由を考慮しない計算特例を利用しなければ800kmになってちょうどいいんだが……
— 留年確定しました (@y_sni) 2017年12月14日
800km鉄道で移動するのが頭おかしいですね
— 留年確定しました (@y_sni) 2017年12月14日
松戸(東京都区外)発着の乗車券を買って東京や秋葉原で"""途中下車"""したいですね
— 留年確定しました (@y_sni) 2017年12月14日
600km超の長距離においては運賃が40kmごとに離散化されているので813kmの松戸駅からでも824kmの新三郷駅からでも同じ運賃で乗ることができる
— 留年確定しました (@y_sni) 2017年12月14日
乗車券で途中駅から乗れる規則は第148条3項でした。
— 留年確定しました (@y_sni) 2017年12月14日
JR東日本:旅客営業規則>第2編 旅客営業 -第4章 乗車券類の効力 -第1節 通則 https://t.co/SMcxofwgtv
840kmまでの範囲で南流山→南浦和→東京を追加できるらしい
— 留年確定しました (@y_sni) 2017年12月14日
Trinket M0でWebブラウズを便利にする
ハードウェアは前回と同じで, キーボードのふりをしてボタン操作でブラウザバック・上下スクロールができるようにします。
— 留年確定しました (@y_sni) 2017年12月8日
学び
ブラウザバックには0.2秒ほどスリープを入れないと戻りすぎた。 逆に上下スクロールは0.1秒毎にポーリングしないと遅すぎた。
懺悔
何も考えていないコピペだらけのクソコードでごめんなさい
参考
adafruit_hid.keycode — Adafruit HID Library 1.0 documentation
コード
from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS import board import digitalio import time back = digitalio.DigitalInOut(board.D0) back.direction = digitalio.Direction.INPUT back.pull = digitalio.Pull.UP up = digitalio.DigitalInOut(board.D4) up.direction = digitalio.Direction.INPUT up.pull = digitalio.Pull.UP down = digitalio.DigitalInOut(board.D2) down.direction = digitalio.Direction.INPUT down.pull = digitalio.Pull.UP kbd = Keyboard() layout = KeyboardLayoutUS(kbd) led = digitalio.DigitalInOut(board.D13) led.direction = digitalio.Direction.OUTPUT print("Waiting for button presses") while True: if not back.value: print("back") led.value = True kbd.press(Keycode.ALT, Keycode.LEFT_ARROW) time.sleep(0.1) kbd.release_all() led.value = False time.sleep(0.2) if not up.value: print("up") led.value = True kbd.press(Keycode.UP_ARROW) kbd.release_all() led.value = False if not down.value: print("down") led.value = True kbd.press(Keycode.DOWN_ARROW) kbd.release_all() led.value = False time.sleep(0.1)
Trinket M0 でマウスを作る
正直, 購入事例が少なくてバグの解決策を見つけづらいことからTrinket M0を買ったことを後悔している。 (まあ後でProMicroを買うからええやろ)
コードの内容
上下(vertical)と左右(horizontal)それぞれ1ボタンで, リバースボタンが押されていないとき右上に, リバースボタンが押されると左下に移動する。
気づいたこと
正しいmain.py
が書き込まれているときは仕様通りに書き込みに応じて新しいmain.py
ファイルが実行されるが, 誤ったmain.py
ファイルを書き込んだ後はいくら書き換えても実行されない。エラーメッセージも表示されない。リセットボタンを押すしかない。
誤ったmain.py
ファイルを書き込んだあとは, Blinkなどの確実に動くファイル(ライブラリを要求しないものがおすすめ)を書き込んでリセットボタンを押すと, 再度誤ったファイルを書き込んだときにエラーが表示されるようになる。
常にエラーメッセージが表示されるようになると嬉しいなあ。
コード
from adafruit_hid.mouse import Mouse import board import digitalio import time m = Mouse() v = digitalio.DigitalInOut(board.D0) h = digitalio.DigitalInOut(board.D4) r = digitalio.DigitalInOut(board.D2) buttons = [v, h, r] for button in buttons: button.direction = digitalio.Direction.INPUT button.pull = digitalio.Pull.UP print("Waiting for button presses") while True: if not v.value: if r.value: print("UP") m.move(y=-10) else: print("DOWN") m.move(y=10) if not h.value: if r.value: print("RIGHT") m.move(x=+10) else: print("LEFT") m.move(x=-10) time.sleep(0.02)
マイコン(Adafruit Trinket M0)を買った
マイコン道、始めます。 pic.twitter.com/BoWnx4KerX
— 留年確定しました (@y_sni) 2017年12月2日
マイコンでITF.した pic.twitter.com/v2ZHSiGqT1
— 留年確定しました (@y_sni) 2017年12月2日
テキストファイルを投げつけるだけで動くマイコン, 環境構築コストが0なので本当に入門者に最適という感じ (エラーメッセージを見づらいなどの問題はある)
— 留年確定しました (@y_sni) 2017年12月2日
ずっとPythonでやってる。
顛末
キーボードを自作したくてパーツについて調べていたらProMicroに行き着き, キーボード自作は断念したもののマイコンを使いたくて仕方がなくなったのでマイコンを買った
感想
- めっちゃ小さい
- もうピンを付けずにそのまま圧電スピーカーをハンダ付けしてオルゴールにしたらええんちゃうかという気分
- microUSBコネクタの抜き差しが怖い
- 組み込まないならArduinoのほうが良さそう
- 抜き差しで負荷がかからないUSB-Bを使っている
- ブレッドボードに挿すよりも基板にメスコネクタが生えていたほうが配線楽だよね
- GPIOの数が多い
- 配線に気を使う
- 3V(コイン電池)では動かない。基板の印刷には4〜6Vと書いてある
戻る/進む,クリック/右クリック,スクロールボタン付きポインティングスティックを作るにはデジタルインが5つ、アナログインが2つ必要だが、
— 留年確定しました (@y_sni) 2017年11月30日
買ったマイコンボードにはGPIOが5ポートしかない。
躓いた点と解決策
ブートローダーモードから出れない
ブートローダーを更新するためにリセットボタンをダブルクリックしてブートローダーモードにしたら, USBを挿し直そうとリセットボタンを押そうとブートローダーモードから出られなくなった。
Lastly, reload your code from Arduino or MakeCode or flash the latest CircuitPython core.
と書かれているとおり, Releases · adafruit/circuitpython · GitHub からCircuitPythonの実行環境(?)をダウンロードしてインストールしなおすと元通りPythonの実行環境になる。
コンソールを見れない
screen /dev/tty*
しても terminated するだけで何も表示されない。sudo
する必要があった。
ライブラリがない
CircuitPython PWM | Adafruit Trinket M0 | Adafruit Learning System にある simpleio
を使った作例を試そうとしても, main.py
を書いただけでは実行できない。
About CircuitPython Libraries | Adafruit Trinket M0 | Adafruit Learning System に書かれているとおり, lib/
にライブラリファイルを置く必要がある。デモプログラムに使用されているキーボード関係のライブラリは最初から入っている。
まとめ
- ちゃんとドキュメントを読もう
- ソフトウェア系の問題しか書いてないな
Magicforce smart 49key を使ってみて
他のキーボードを使うと困る点
- fが-にならない
- Tabの位置にCapsLockがある
- BackSpaceの位置に\がある
キーボードの配列は統一しましょう