[Rails] Active Record Transactions の requires_new
transactionをネストしたときに、子のtransaction内でActiveRecord::Rollback
を投げてもロールバックされない。
irb(main):059:0> User.transaction do irb(main):060:1* User.create(username: 'Kotori') irb(main):061:1> User.transaction do irb(main):062:2* User.create(username: 'Nemu') irb(main):063:2> raise ActiveRecord::Rollback irb(main):064:2> end irb(main):065:1> end (0.1ms) begin transaction User Create (0.7ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Kotori"], ["created_at", "2019-07-18 14:31:50.104487"], ["updated_at", "2019-07-18 14:31:50.104487"]] User Create (0.1ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Nemu"], ["created_at", "2019-07-18 14:31:50.106418"], ["updated_at", "2019-07-18 14:31:50.106418"]] (1.7ms) commit transaction => nil irb(main):066:0> User.all.pluck(:username) (0.1ms) SELECT "users"."username" FROM "users" => ["Kotori", "Nemu"]
requires_new: true
とすると子のtransaction内だけロールバックする。
irb(main):073:0> User.transaction do irb(main):074:1* User.create(username: 'Kotori') irb(main):075:1> User.transaction(requires_new: true) do irb(main):076:2* User.create(username: 'Nemu') irb(main):077:2> raise ActiveRecord::Rollback irb(main):078:2> end irb(main):079:1> end (0.1ms) begin transaction User Create (0.3ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Kotori"], ["created_at", "2019-07-18 14:33:44.891135"], ["updated_at", "2019-07-18 14:33:44.891135"]] (0.0ms) SAVEPOINT active_record_1 User Create (0.1ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Nemu"], ["created_at", "2019-07-18 14:33:44.892205"], ["updated_at", "2019-07-18 14:33:44.892205"]] (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 (1.5ms) commit transaction => nil irb(main):080:0> User.all.pluck(:username) (0.1ms) SELECT "users"."username" FROM "users" => ["Kotori"]
ちなみに、普通に例外を投げると親のtransactionもロールバックする。普通。
irb(main):087:0> User.transaction do irb(main):088:1* User.create(username: 'Kotori') irb(main):089:1> User.transaction do irb(main):090:2* User.create(username: 'Nemu') irb(main):091:2> raise irb(main):092:2> end irb(main):093:1> end (0.1ms) begin transaction User Create (0.8ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Kotori"], ["created_at", "2019-07-18 14:36:22.828138"], ["updated_at", "2019-07-18 14:36:22.828138"]] User Create (0.2ms) INSERT INTO "users" ("username", "created_at", "updated_at") VALUES (?, ?, ?) [["username", "Nemu"], ["created_at", "2019-07-18 14:36:22.830153"], ["updated_at", "2019-07-18 14:36:22.830153"]] (1.4ms) rollback transaction Traceback (most recent call last): 3: from (irb):87 2: from (irb):89:in `block in irb_binding' 1: from (irb):91:in `block (2 levels) in irb_binding' RuntimeError () irb(main):094:0> User.all.pluck(:username) (0.1ms) SELECT "users"."username" FROM "users" => []
参考
[Ruby] 再帰的group_by
やりたいこと
こういうデータ↓を
[ { prefecture: '埼玉県', city: '深谷市', town: '北根', address: '3-5' }, { prefecture: '埼玉県', city: '深谷市', town: '北根', address: '3-7-19' }, { prefecture: '埼玉県', city: '深谷市', town: '堀米', address: '1-11-14' }, { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新中里', address: '1-2-17' }, { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新都心', address: '1-6-13' }, { prefecture: '東京都', city: '品川区', town: '西中延', address: '3-5' }, ]
こう↓したい
{ "埼玉県"=> { "深谷市"=> { "北根"=>["3-5", "3-7-19"], "堀米"=>["1-11-14"] }, "さいたま市中央区"=> { "新中里"=>["1-2-17"], "新都心"=>["1-6-13"] } }, "東京都"=> { "品川区"=> { "西中延"=>["3-5"] } } }
再帰的group_by
参考:
module Enumerable def recursive_group_by(*props, &block) groups = group_by{ |e| e[props.first] } next_props = props.drop(1) if next_props.empty? block_given? ? block.call(groups) : groups else groups.transform_values do |e| e.recursive_group_by(*next_props, &block) end end end end data = [ { prefecture: '埼玉県', city: '深谷市', town: '北根', address: '3-5' }, { prefecture: '埼玉県', city: '深谷市', town: '北根', address: '3-7-19' }, { prefecture: '埼玉県', city: '深谷市', town: '堀米', address: '1-11-14' }, { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新中里', address: '1-2-17' }, { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新都心', address: '1-6-13' }, { prefecture: '東京都', city: '品川区', town: '西中延', address: '3-5' }, ] new_data = data.recursive_group_by(:prefecture, :city, :town) do |groups| groups.transform_values do |v| v.map { |x| x[:address] } end end pp data puts '--' pp new_data
結果
[{:prefecture=>"埼玉県", :city=>"深谷市", :town=>"北根", :address=>"3-5"}, {:prefecture=>"埼玉県", :city=>"深谷市", :town=>"北根", :address=>"3-7-19"}, {:prefecture=>"埼玉県", :city=>"深谷市", :town=>"堀米", :address=>"1-11-14"}, {:prefecture=>"埼玉県", :city=>"さいたま市中央区", :town=>"新中里", :address=>"1-2-17"}, {:prefecture=>"埼玉県", :city=>"さいたま市中央区", :town=>"新都心", :address=>"1-6-13"}, {:prefecture=>"東京都", :city=>"品川区", :town=>"西中延", :address=>"3-5"}] -- {"埼玉県"=> {"深谷市"=>{"北根"=>["3-5", "3-7-19"], "堀米"=>["1-11-14"]}, "さいたま市中央区"=>{"新中里"=>["1-2-17"], "新都心"=>["1-6-13"]}}, "東京都"=>{"品川区"=>{"西中延"=>["3-5"]}}}
JSONからフットプリントを自動配置するスクリプトを作った
前置き
キーボードを作ろう!と思い立ち、キーマトリクス回路を理解して、KiCadのEeschemaでスイッチとダイオードを結線して、フットプリントを関連付けして、pcbnewを開いて、「うわメンドクサイ」と思った経験はありませんか?僕は毎回思います。
なので、フットプリントを自動配置するスクリプトを作りました。
Keyboard Layouter Plugin
Keyboard Layout Editor (KLE) のJSONからスイッチのフットプリントを自動配置します。
インストール
keyboard_layouter.py をダウンロードし、以下のディレクトリに置くだけです。
- Windowsの場合
- %APPDATA%/Roaming/kicad/scripting/plugins
- macOSの場合
/Applications/KiCad/kicad.app/Contents/SharedSupport/scripting/plugins- ~/Library/Preferences/kicad/scripting/plugins
- Linuxの場合
- ~/.kicad/scripting/plugins
Quick Start
簡単に試せるようにJSONと回路のサンプルを用意しました。
これをダウンロードしてKiCadを起動し、pcbnewを開くと以下のようになっていると思います。
「ツール」→「外部プラグイン」→「Keyboard Layouter」を選択します。
KLEで作成したJSONを指定します1。ここではErgoDoxのJSONファイルを選びました。
スイッチを移動させたいときは"Switch"のチェックボックスにチェックを入れます。 ダイオードも一緒に移動させたいときは"Diode"にもチェックを入れます。スイッチの原点からどれだけオフセットを持たせて配置させるか、表裏反転させるかを設定することができます。設定が終わったら、最後に"Run"ボタンを押します。
それっぽく配置されました🎉
制限事項
- 1uのキー間隔は19.05mmです
- 対応しているスイッチのフットプリントはkicad-footprints/Button_Switch_Keyboard.prettyのCherry MX Switchのみです。
- 使えるスイッチのサイズは以下の通りです。これ以外のサイズ、例えば1 x 1.5などは現状では扱えませんが、1.5 x 1を90度回転させることはできます
- 1.00u (1 x 1)
- 1.25u (1.25 x 1)
- 1.50u (1.5 x 1)
- 1.75u (1.75 x 1)
- 2.00u (2 x 1, 1 x 2)
- 2.25u (2.25 x 1)
- 2.75u (2.75 x 1)
- 6.25u (6.25 x 1)
- ISO Enter
- 使えるスイッチのサイズは以下の通りです。これ以外のサイズ、例えば1 x 1.5などは現状では扱えませんが、1.5 x 1を90度回転させることはできます
最後に
まだまだバグがあるかもしれません。ご使用の際は自己責任で、目視確認を!(Issue, PRいただけると喜びます)
皆様のキーボードづくりの一助になれば幸いです。
参考
- Documentation/development/pcbnew-plugins.md · f0ef18fb9e24ac94d6f595f87ded98aa41925ba0 · KiCad / KiCad Source Code / kicad · GitLab
- KiCad用のPythonスクリプト ~ ほぼ回路図の配置通りにフットプリントを予備配置する - Qiita
- KiCadのPython scripting機能を使ってみる : 東京工業大学 ロボット技術研究会
- KiCAD PCBnew マクロ - N->N->N
- ruiqimao/qmkbuilder: Online GUI for QMK Firmware
- ijprest/keyboard-layout-editor: Web application to enable the design & editing of keyboard layouts
- wxPython | Python-izm
-
左上の凡例をスイッチのリファレンス番号にする必要があります。↩
[tmux] Ctrl-dでexitするのをやめる
環境
$ bash --version bash --version GNU bash, バージョン 4.4.23(1)-release (x86_64-apple-darwin17.5.0) Copyright (C) 2016 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $ tmux -V tmux -V tmux 2.7
やったこと
.bashrcでignoreeof
を設定
set -o ignoreeof
.tmux.confでデタッチをunbind
unbind -T root C-d
参考
Python EDAで論理式を簡単化する
『CPUの創りかた』に載っているデコーダをPython EDAを使って簡単化してみた。
真理値表
OP3, OP2, OP1, OP0, CFlagが入力。B, A, ~LOAD0, ~LOAD1, ~LOAD2, ~LOAD3が出力。
OP3 | OP2 | OP1 | OP0 | CFlag | B | A | ~LOAD0 | ~LOAD1 | ~LOAD2 | ~LOAD3 |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | X | 0 | 0 | 0 | 1 | 1 | 1 |
0 | 0 | 0 | 1 | X | 0 | 1 | 0 | 1 | 1 | 1 |
0 | 0 | 1 | 0 | X | 1 | 0 | 0 | 1 | 1 | 1 |
0 | 0 | 1 | 1 | X | 1 | 1 | 0 | 1 | 1 | 1 |
0 | 1 | 0 | 0 | X | 0 | 0 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | X | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 1 | 0 | X | 1 | 0 | 1 | 0 | 1 | 1 |
0 | 1 | 1 | 1 | X | 1 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | X | 0 | 1 | 1 | 1 | 0 | 1 |
1 | 0 | 1 | 1 | X | 1 | 1 | 1 | 1 | 0 | 1 |
1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 |
1 | 1 | 1 | 0 | 1 | X | X | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | X | 1 | 1 | 1 | 1 | 1 | 0 |
入力側のdon't careを0, 1になおして、入力の欠けている部分も補ったのが↓。
OP3 | OP2 | OP1 | OP0 | CFlag | B | A | ~LOAD0 | ~LOAD1 | ~LOAD2 | ~LOAD3 | 追加 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | |
0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | |
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | |
0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | |
0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | |
0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | |
0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | |
0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | |
0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | |
0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | |
0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | |
0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | |
1 | 0 | 0 | 0 | 0 | X | X | X | X | X | X | ← |
1 | 0 | 0 | 0 | 1 | X | X | X | X | X | X | ← |
1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | |
1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | |
1 | 0 | 1 | 0 | 0 | X | X | X | X | X | X | ← |
1 | 0 | 1 | 0 | 1 | X | X | X | X | X | X | ← |
1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | |
1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | |
1 | 1 | 0 | 0 | 0 | X | X | X | X | X | X | ← |
1 | 1 | 0 | 0 | 1 | X | X | X | X | X | X | ← |
1 | 1 | 0 | 1 | 0 | X | X | X | X | X | X | ← |
1 | 1 | 0 | 1 | 1 | X | X | X | X | X | X | ← |
1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | |
1 | 1 | 1 | 0 | 1 | X | X | 1 | 1 | 1 | 1 | |
1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
Python EDA
from pyeda.inter import * X = ttvars('x', 5) b = truthtable(X, '00 00 11 11 00 00 11 11 -- 00 -- 11 -- -- 1- 11'.replace(' ', '')) a = truthtable(X, '00 11 00 11 00 11 00 11 -- 11 -- 11 -- -- 1- 11'.replace(' ', '')) load0 = truthtable(X, '00 00 00 00 11 11 11 11 -- 11 -- 11 -- -- 11 11'.replace(' ', '')) load1 = truthtable(X, '11 11 11 11 00 00 00 00 -- 11 -- 11 -- -- 11 11'.replace(' ', '')) load2 = truthtable(X, '11 11 11 11 11 11 11 11 -- 00 -- 00 -- -- 11 11'.replace(' ', '')) load3 = truthtable(X, '11 11 11 11 11 11 11 11 -- 11 -- 11 -- -- 01 00'.replace(' ', '')) bm, am, load0m, load1m, load2m, load3m = espresso_tts(b, a, load0, load1, load2, load3) print('b =', bm) print('a =', am) print() print('load0 =', load0m) print(expr2truthtable(load0m)) print('load1 =', load1m) print(expr2truthtable(load1m)) print('load2 =', load2m) print(expr2truthtable(load2m)) print('load3 =', load3m) print(expr2truthtable(load3m))
出力が↓。OP3, OP2, OP1, OP0, CFlagがそれぞれ、x[4], x[3], x[2], x[1], x[0]に割り当てられる。
b = x[2] # OP1 a = Or(x[1], x[4]) # OP0 + OP3 load0 = Or(x[4], And(x[3], ~x[4])) # OP3 + (OP2・~OP3) = OP2 + OP3 x[4] x[3] 0 0 : 0 0 1 : 1 1 0 : 1 1 1 : 1 load1 = Or(x[4], And(~x[3], ~x[4])) # OP3 + (~OP2・~OP3) = ~OP2 + OP3 x[4] x[3] 0 0 : 1 0 1 : 0 1 0 : 1 1 1 : 1 load2 = Or(x[3], And(~x[3], ~x[4])) # OP2 + (~OP2・~OP3) = OP2 + ~OP3 x[4] x[3] 0 0 : 1 0 1 : 1 1 0 : 0 1 1 : 1 load3 = Or(~x[3], And(x[3], ~x[4]), And(x[0], ~x[1])) # ~OP2 + (OP2・~OP3) + (CFlag・~OP0) # = ~OP2 + ~OP3 + (CFlag・~OP0) x[4] x[3] x[1] x[0] 0 0 0 0 : 1 0 0 0 1 : 1 0 0 1 0 : 1 0 0 1 1 : 1 0 1 0 0 : 1 0 1 0 1 : 1 0 1 1 0 : 1 0 1 1 1 : 1 1 0 0 0 : 1 1 0 0 1 : 1 1 0 1 0 : 1 1 0 1 1 : 1 1 1 0 0 : 0 1 1 0 1 : 1 1 1 1 0 : 0 1 1 1 1 : 0
- B, Aは本に載ってるのと同じものが得られた
- ~LOAD0, ~LOAD1, ~LOAD2, ~LOAD3は分配律
(x + yz) = (x + y)(x + z)
を使えば同じ形
RaspberryPi Helix
この記事は自作キーボード #2 Advent Calendar 2018 - Adventarの25日目の記事です。 昨日は@zeriyoshiさんの ALPS メカニカルキースイッチとその歴史でした。
TL;DR
- HelixのコントローラとしてRaspberry Pi Zero Wを使った
- Bluetoothキーボードをエミュレートした
- LEDを制御した
デモ
構成
リポジトリ
以下、作業メモです。
Raspberry Pi Zero Wのセットアップ
上記の記事がとても丁寧に書かれているので、これに従って設定していきます。以下に要点をメモっておきます。
OSイメージのダウンロード
今回使ったイメージは2018-11-13-raspbian-stretch-lite.img
です。
イメージのインストール
$ sudo ./install 2018-11-13-raspbian-stretch-lite.img
設定
$ touch /Volumes/boot/ssh # ssh有効化 $ vi /Volumes/boot/cmdline.txt # "modules-load=dwc2,g_ether"を追記 $ echo "dtoverlay=dwc2" >> /Volumes/boot/config.txt
インターネット共有
$ ssh pi@raspberrypi.local
Wifiの設定
$ sudo sh -c 'wpa_passphrase "wifi_ssid" < wifi_password >> /etc/wpa_supplicant/wpa_supplicant.conf' $ sudo wpa_cli reconfigure
ここまででラズパイが使えるようになりました。
Bluetoothキーボードのエミュレート
次はこの記事に従ってラズパイをBluethoothキーボードとして使えるようにします。
ツールのインストール
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install python-gobject bluez bluez-tools bluez-firmware python-bluez python-dev python-pip python-gtk2 $ sudo pip install evdev
元記事からpython-gtk2
を追加しています。
Bluethoothデーモンの設定
$ sudo /etc/init.d/bluetooth stop $ sudo /usr/sbin/bluetoothd --nodetach --debug -p time
一度Bluethoothデーモンを止めて、立ち上げ直します。
ソースコードのクローン
元記事のソースをクローンしてきます。
$ git clone https://github.com/yaptb/BlogCode.git
DBUSの設定
$ cd BlogCode/btkeyboard/dbus $ sudo cp org.yaptb.btkkbservice.conf /etc/dbus-1/system.d
Bluetoothデバイスの有効化
$ sudo hciconfig hcio up
sudo hciconfig hcio
でBluetoothデバイスアドレスをメモっておき、BlogCode/btkeyboard/server/btk_server.py
のMY_ADDRESS
を書き換えます。
エミュレーターサーバーの起動
$ cd BlogCode/btkeyboard/server $ sudo python btkserver.py
ペアリング
$ sudo /usr/bin/bluetoothctl # agent on # default-agent # scan on # discoverable on
パスキーの確認が出たらyes
とタイプしてペアリング完了。
文字を送信してみる
$ cd BlogCode/btkeyboard/keyboard $ sudo python send_string.py hello_bluetooth!
ここまででラズパイをBluetoothキーボードとして使えるようになりました。
ラズパイとHelixをつなげる
あとはHelixとラズパイを配線し、キーマトリクスの状態をGPIOで読み出してやればオーケーなはずです。
配線図
Colは左右で共用しています。VCC, GNDは省略しています。
ファームウェア
LEDの制御
せっかくなのでLED制御もします。Helixに使われているLEDはSK6812MINIですが、
これでググっても情報が出てこないのでws2812 raspberry pi
などでググります。1
すると、しっかりとライブラリがあったので、次はこの記事をなぞります。
ツールのインストール
$ sudo apt-get install build-essential scons swig
ライブラリのインストール
$ git clone https://github.com/jgarff/rpi_ws281x.git $ cd rpi_ws281x && sudo scons && cd python && sudo python setup.py install
元記事はwgetを使っていますが、gitで。
配線
VCC, GNDは省略しています。
サンプルプログラムの実行
ピンとLED数を修正してrpi_ws281x/python/examples/strandtest.py
を実行します。
まとめ
- ファームはすごい適当ですが、思ったよりもちゃんと動いていた
- レイヤー機能がないです。ちゃんと使うなら必要
- LEDのパターンを増やしていきたい
この記事はpakbdを使って書かれました。
おまけ:うまくいかなかったこと
USB HIDデバイス化
最初は有線でラズパイをHIDデバイスとして使うことを考えていました。試して見ましたがうまくいきませんでした。OSのアップデートが原因っぽい?
スマートキーボード化
- 好きな言葉で呼びかけられるGoogle HomeをDIYする - Qiita
- Raspberry Pi にGoogle Assistant SDKを搭載して「OK Google」してみる。 - Qiita
Google Assistant SDKを動かして"OK Helix!"とやりたかったんですが、 やってみるとAssistant単体では動くんですが、キーボードのファームに組み込むとLEDが光らなくなりうまくいきませんでした。
ライブラリ内部で使っている何かが競合しているのか、単にタイミングの問題なのか、まだよくわかってないです。
-
QMKのファームを読んでみたら
ws2812
と書いてあったのを見つけました↩
pakbdについて。つまり僕の好きなキーボードについて
pakbd rev1
Row-Staggered
自作キーボードではOrtholinearと呼ばれる格子状の配列や、 Column-Staggerdと呼ばれる縦方向にキーがずれて配置されているレイアウトが多いですが1、 僕は一般的によく目にするタイプのキー配列、Row-Staggeredと呼ばれているレイアウトが好きです。 このレイアウトに慣れているからという単純な理由だけですが。
なので自分で0から自由にキーボードを作れるとしても、よくあるキーボードレイアウトと大きく変わる変更は極力避けるようにしました。 矢印キーやBackspace, Deleteキーも自分としては必須なので省略しませんでした。 pakbdのレイアウトはこんな感じです。
よくあるレイアウトと違う箇所いくつかありますが、これらの差異はたとえ一般的でなくても自分にとって大きなメリットがあると思います。
左Shift
とEnter
が1.75u。(よくあるレイアウトでは2.25u)- スタビライザを使いたくなかったから。単純にパーツが増えるのが嫌だったのと、スタビライザはカチャカチャ音がうるさいし、タイプの感触が変わってしまうのも嫌でした
- 左下に
Ctrl
がない。Option
とCmd
の位置がよくあるレイアウトより右に配置されている- 自分は
A
の隣にCtrl
を配置しているから、左下のCtrl
は不要でした。Option
とCmd
の位置はMint60を参考にさせてもらいました。コピー(Cmd+C
)やペースト(Cmd+V
)のためにCmd
キーはもっと右にあるべきだと常々思っていた
- 自分は
pakbd rev1では4行バージョンも作れるようにしました。4行バージョンの想定レイアウトはこんな感じ。
Raise
キーを押すと一番上の行が数字行に入れ替わります。
6とBの問題
自分は文章中に出てくるB
は左手人差し指でタイプするんですが、Ctrl+B
(Emacsキーバインドで一文字戻る)のB
は右手人指し指でタイプする癖があるので、
左右両方に必要でした。
キーキャップ
DCS, SA , DSA, etc...いろんなプロファイルがありますが、自分はDCSが好きです。
pakbdではいくつかのキーを追加して、さらにいくつかのキーの長さを変えてしまったのでキーキャップの選択がすごく難しくなってしまいました。
普通のキーキャプセットにB
のキーは1つしか含まれていないし、1.75uのキーもcaps lockしか含まれてない。
さらにstep sculpture2なキーキャップは配置する行も決まっているので、
ほんとうに統一感のある見栄えにするには、同じキーキャップセットを2つ以上買わなきゃいけない。つらい。
キーキャップセットを2つ買ったり、grab bagの中からマシなキーキャップを見つけたりしました。
rev1で新しくやったこと
- スイッチソケット対応した
- スイッチがホットスワップできるようになった
- PCBに切れ目を入れて5行版と4行版に対応した
- カッターとアクリルカッターでPCBを削ったら、狙い通りに手で折ることができた
- ステンレスプレートの発注した
- きりいたドットコムに発注した。BUILD YOUR OWN KEYBOARDsを参考にさせてもらいました
- 自作ケーブルを作成した
- これはキーボードに直接関係ないですが、pakbdはケーブル端子が側面についているので両L字のケーブルが欲しかったので、秋葉原のオヤイデ電気に行って店員さんにパーツを選んでもらった
パーツとコスト
あんまりちゃんと勘定したことがなかったので今回はしっかりと単価を計算してみた。
次の表は写真の一番上にある紫色の4行キーボードを作るのに使った金額です。 いくつかgrab bagで手に入れたキーキャップを使っていますがそれは勘定に含んでいないし、送料も含んでいない。
部品 | 金額 | 単価 | 必要数 | 小計 | 備考 |
---|---|---|---|---|---|
Kailh Speed Switch Rose Pink | ¥400/10 | ¥40 | 55 | ¥2200 | https://yushakobo.jp/shop/kailh-speed/ |
GK64 XD64 DZ60 PBT keycaps | $30.00 | ¥3329 | 1 | ¥3329 | https://kbdfans.cn/products/gk64-xd64-dz60-keycaps |
スイッチソケット Kailh CPG151101S11 | ¥150/10 | ¥15 | 55 | ¥825 | https://yushakobo.jp/shop/a01ps/ |
ダイオード 1N4148W | ¥400/40 | ¥10 | 55 | ¥550 | http://akizukidenshi.com/catalog/top.aspx |
Pro Micro ATmega32U4 5V/16MHz/MicroUSB2(互換品) | ¥550 | ¥550 | 2 | ¥1100 | https://talpkeyboard.stores.jp/items/5b24504ba6e6ee7ec60063e3 |
チップ抵抗 4.7kΩ(1206) | ¥50/10 | ¥5 | 2 | ¥10 | https://www.sengoku.co.jp/index.php |
TRRSジャック MJ-4PP-9 | ¥50 | ¥50 | 2 | ¥100 | http://akizukidenshi.com/catalog/top.aspx |
PCB左側(149.6mm*101.2mm, 1.6, 2 Layers) | $37.00/5 | ¥863 | 1 | ¥863 | https://www.allpcb.com/ |
PCB右側(182.9mm*101.2mm, 1.6, 2 Layers) | $39.00/5 | ¥909 | 1 | ¥909 | https://www.allpcb.com/ |
アクリルプレート A4 3mm | ¥5600 | ¥5600 | 1 | ¥5600 | https://yushakobo.jp/lasercut/ |
ステンレスプレート左側(149.7mm*79.1mm) | ¥4770 | ¥4770 | 1 | ¥4770 | https://www.kiriita.com/ |
ステンレスプレート右側(178.2mm*79.1mm ) | ¥5690 | ¥5690 | 1 | ¥5690 | https://www.kiriita.com/ |
スタンドオフM2x5mm | ¥1030/100 | ¥10.3 | 12 | ¥124 | Amazon.co.jp: 100個雌ネジ柱真鍮スタンドオフスペーサーゴールドトーンM2x5mm: DIY・工具・ガーデン |
ネジ M2 x 5mm | ¥496/60 | ¥8.27 | 12 | ¥99 | Amazon.co.jp: uxcell ヘッドねじ ラウンド/パンヘッド 304ステンレス鋼 M2 x 5mm: DIY・工具・ガーデン |
ネジ M2 x 10mm | ¥100/12 | ¥8.33 | 12 | ¥100 | - |
合計 | ¥26269 |
このキーボードはプレートにステンレスを使ってみたので少し高級になった。
rev1の不具合
- PCBの左右が噛み合わない
- かみ合わせの凸凹を同じ幅にしてしまったから当然。幸いなことに少しヤスリを掛けるだけでうまく噛み合うようになった。アクリルも同じsvgを使ったんですが、こっちは最初からうまく噛み合った。カット時に溶けた分だけ小さくなったんだと思います
- ProMicroとソケットが接触する
- ProMicroの上にもキーを配置したのでPCBとProMicroの間にスイッチソケットが挟まる箇所が左右1箇所ずつあるんですが、ProMicroとソケットが接触してしまい、ProMicroが水平にはんだ付けできなかった
- PCBの固定方法を間違えた
- スイッチソケットを使わない場合は、プレートにスイッチをはめてスイッチをPCBにはんだ付けするとPCBは固定されていたんですが、ソケットを使う場合はPCBは別の方法でプレートと固定されなければならないと組み立ててから気づきました
最後に
11/3の天キーにスペースがあれば展示する予定です。見かけたらぜひカチカチしてやってください。