ProMicroでポインティングスティックを作った

動作

  • ジョイスティックを傾けるとマウスポインタがその向きに動く
  • 2番ピンのボタンを押すとジョイスティックの初期位置がリセットされる
  • 3番ピンのボタンを押すとジョイスティックを傾けた方向にスクロールする
  • 4番ピンのボタンでマウスの左クリック

配線図

使ってるジョイスティックがライブラリになかったため, テキトーに繋いでる。

f:id:y_sanagi:20180114233813p:plain

コード

#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ごとに区切られているので思いの外遠くまで同じ運賃で行くことができる。

今回は南浦和経由で南流山まで買うことにした。越谷レイクタウンや新三郷で途中下車できる。 時間があるかは別の問題

往復割引乗車券の有効期間が少し足りないときは乗車券の購入区間の延長を検討してみるといいと思う。

ツイートまとめ

Trinket M0でWebブラウズを便利にする

y-sni.hatenablog.com

ハードウェアは前回と同じで, キーボードのふりをしてボタン操作でブラウザバック・上下スクロールができるようにします。

学び

ブラウザバックには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)を買った

ずっとPythonでやってる。

顛末

キーボードを自作したくてパーツについて調べていたらProMicroに行き着き, キーボード自作は断念したもののマイコンを使いたくて仕方がなくなったのでマイコンを買った

感想

  • めっちゃ小さい
  • もうピンを付けずにそのまま圧電スピーカーをハンダ付けしてオルゴールにしたらええんちゃうかという気分
  • microUSBコネクタの抜き差しが怖い
  • 組み込まないならArduinoのほうが良さそう
    • 抜き差しで負荷がかからないUSB-Bを使っている
    • ブレッドボードに挿すよりも基板にメスコネクタが生えていたほうが配線楽だよね
    • GPIOの数が多い
  • 配線に気を使う
  • 3V(コイン電池)では動かない。基板の印刷には4〜6Vと書いてある

躓いた点と解決策

ブートローダーモードから出れない

ブートローダーを更新するためにリセットボタンをダブルクリックしてブートローダーモードにしたら, 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/ にライブラリファイルを置く必要がある。デモプログラムに使用されているキーボード関係のライブラリは最初から入っている。

まとめ

  • ちゃんとドキュメントを読もう
  • ソフトウェア系の問題しか書いてないな

価値とは

1万5000円のキーボードが提供する価値は1万5000円のパソコンでは提供できない。

5000円のキーボードが提供する価値は5000円の傘では提供できない。

レッドブル2本(380円)が提供する価値は380円の牛丼では提供できない。

それぞれまた逆も然り。

別の事象と比較することは無意味である。

共通尺度としての価格なのだろうけど。