Dozen0を組み立てた

はじめに

Dozen0を組み立てたので記録を残しておきます。

ミスったところを書いておきます。

Dozen0とは

booth.pm

akiba-pc.watch.impress.co.jp

Dozen0を購入した動機

  • 組み立て後もスイッチの交換ができる。
  • キースイッチを実際に動作させて試すことができる。
  • 自作キーボードキットに使うキースイッチの選定に使えそう。 

組み立ててみた後の印象

  • キースイッチソケットのはんだ付けは独特だけど、難しくない。
  • 組み立て後は隠れちゃうけど、ボトムプレートPCBにも◤◢◤◢◤◢◤◢がワンポイントではいっててカッコいい。
  • はんだ付け箇所が少なく、キースイッチの選定に使えるので、これから自作キーボードをはじめようっていう人におすすめ。

あったほうが良い工具

Dozen0の組み立てに必要な工具は公式のビルドガイドの通りですが、 個人的にあったほうが良いと思う工具

  • 先の細いこて先
    • ソケットのコの字型の部分に先端が入るやつであれば何でもOK
    • 白光 こて先 1.6D型 T18-D16
  • 逆動作ピンセット
    • ソケットがPCBから浮かないように押さえるのに使いました。
    • goot TS-16
  • LED付きヘッドルーペ
    • ソケット部分にちゃんとハンダが流れてるのかとかProMicroのはんだ付けちゃんとできてるかとか、はんだ付け作業をしながら確認できます。
  • キースイッチ引き抜き工具

組み立て記録

難しいところはありませんでしたが、 あんまり難しくないだろうとナメてかかってたのでミスりました。

ソケットのはんだ付け

ソケットを逆動作ピンセットで挟んで固定して、はんだ付けしました。

f:id:cnaos:20190321101613j:plain
逆動作ピンセットでソケットを固定

ソケットのコの字型の部分にコテ先を入れて、十分に加熱してからハンダを入れます。 いつもの270度の設定で、2,3秒くらい温めてという感じでやりました。

f:id:cnaos:20190321101728j:plain
ソケットの端子の加熱

コの字部分の底にスリットが空いていて、加熱が十分だとここからハンダが流れて PCBのパッドと接合するみたいです。

やらかし1:ロープロファイルのキースイッチと普通のキースイッチが混載できるんだと思ってた。

これは私の完全な思い込みだったんですが、 最初こんな感じでロープロファイルのキースイッチ(右下の3つ, choc系スイッチ)と通常のキースイッチ(Cherry MX系スイッチ)を混載してみたんですが、

f:id:cnaos:20190321105907j:plain

こうなりました。 ロープロファイルの方のキースイッチの端子がソケットに届いてません。 Dozen0自体は両方に対応していますが、混載はできません。

f:id:cnaos:20190321105901j:plain

気を取り直して全部Cherry MX系のスイッチに切り替えました。 その後、プレートに取り付けたキースイッチをソケットのついたPCBに 全体を均等に少しづつ押し込んでいったんですが、 別の理由でうまくはまらない箇所がありました。

やらかし2:ソケットの方向を間違えてはんだ付けしていた

ソケットのはんだ付け方向を間違えていました。 これによってPCBの真ん中の穴が塞がれ、スイッチがPCBにちゃんとはまりませんでした。

f:id:cnaos:20190321110502j:plain
ソケットの取り付け方向を間違えた

ハンダ吸い取り線ではんだを除去。 ハンダを吸い取っただけだとソケットが取り外せないので、 はんだごてでソケットの端子を加熱しつつ、ピンセットで交互にちょっとずつ浮かしてソケットを取り外しました。

f:id:cnaos:20190321110953j:plain
ソケット取り外し後

f:id:cnaos:20190321111323j:plain
修正後

うまく行ってよかった。

ファームウェアを書き込んで動作チェック

最初はQMK Toolbox(mac版)を使おうとしたんですが、うまく扱えなかったので、 QMKのビルド環境を作ってファームウェアを書き込みました。

macでのビルド環境の作り方 https://docs.qmk.fm/#/getting_started_build_tools?id=macos

qmkのファームウェアをクローンしてくる

git clone https://github.com/qmk/qmk_firmware.git

Dozen0のファームウェアのビルドとインストール

Dozen0をPCに接続して、以下のコマンドを実行。

cd qmk_firmware;
make dozen0:default:avrdude

Detecting USB port, reset your controller now.......

と表示され始めたらDozen0のリセットスイッチを1回または2回連続で押す。

Dozen0の動作チェック

以下のサイトをつかってキー入力のテストを行いました。

www.keyboardtester.com

keyboardchecker.com

動作チェックしてたんですが、反応しないキーがある。 いったん全部スイッチを外して、ソケットのついたPCBを眺めてみました。 はんだ付けは問題なさそうです。

PCBを明かりに透かしてみると、ソケット部分の端子がやたらと大きく開いてるのがある。 原因はこれっぽい。

やらかし3: ソケット端子がキースイッチの端子に接触してない

たぶん、ソケットのはんだ付け方向を間違えたせいで、ソケットの端子に無理な力がかかったんでしょう。 ソケット内部の端子が広がりすぎてスイッチの端子に接触してない状態になっていました。

問題の起きたソケット内部の端子を壊さないように、 ドライバーセットの千枚通しのようなしっかりした先の細いやつでこじって広がった端子を狭めました。 これもうまく行って良かった。

※精密ピンセットはこういう力のかかる用途に使ってはいけません。 先を曲げてだめにしてしまいます。

キースイッチソケット、意外と繊細ぽいので注意しよう。

完成

もういっかい組み直して無事完成しました。

f:id:cnaos:20190321111604j:plain
キースイッチとProMicroの組み込み完了

f:id:cnaos:20190321112411j:plain
化粧プレートつけた

f:id:cnaos:20190406211533j:plain
キーキャップつけて完成

マスキングテープを使って、安全にProMicroのモゲ対策をする

はじめに

ProMicroのmicroUSBコネクタには穴が空いており、コネクタのモゲ対策で接着剤を盛ろうとすると容易にコネクタ内に接着剤が侵入します。

マスキングテープを使うことで安全に接着剤を盛ることができたので紹介します。

f:id:cnaos:20190315221932j:plain

ProMicroのmicroUSBコネクタの穴1

f:id:cnaos:20190315222023j:plain

ProMicroのmicroUSBコネクタの穴2

作業に必要なもの

  • マスキングテープ
  • 先が細い精密ピンセット

microUSBコネクタ内に突っ込めるくらい先が細いピンセットが必要です。

今回使ったのはgootのTS-10です。

f:id:cnaos:20190316143433j:plain

精密ピンセット

マスキングテープでコネクタの穴を塞ぐ

上面に2つ、左右の下側に2つ穴が空いているので、これらをマスキングテープで塞ぎます。

※コネクタ内部のmicroUSBの端子部分を壊さないように注意してください。

  1. マスキングテープを適当な大きさに切ります。
  2. 粘着面を外側にして二つ折りにします。
  3. ピンセットでマスキングテープをつまみコネクタ内に入れます。
  4. マスキングテープをコネクタの一番奥まで突っ込みます。
  5. ピンセットの先端でマスキングテープをコネクタの内側から外側に向かって押しつけてマスキングテープを貼り付けます。
  6. コネクタの穴がちゃんとふさがっているか、マスキングテープとコネクタの間に隙間ができていないか確認します。

f:id:cnaos:20190315222828j:plain

マスキングテープで塞いだところ1

f:id:cnaos:20190315222902j:plain

マスキングテープで塞いだところ2

f:id:cnaos:20190315222851j:plain

マスキングテープで塞いだところ3 コネクタ内部の様子

反対側の穴も同様にマスキングテープで塞ぎます。

f:id:cnaos:20190315223123j:plain

両方の穴をマスキングテープで塞いだところ

f:id:cnaos:20190315223113j:plain

両側の穴を塞いだあとのコネクタ内部の様子

スルーホールの保護

スルーホール内に接着剤が侵入すると困るので、
スルーホールにもマスキングテープを貼って保護します

f:id:cnaos:20190315225556j:plain

microUSBコネクタ近くのスルーホールにもマスキングテープ

接着剤をmicroUSBコネクタ周辺に盛る

あとは接着剤をmicroUSBコネクタ周辺に盛るだけです。

f:id:cnaos:20190315230551j:plain

microUSBコネクタに接着剤を盛る

スルーホールのマスキングテープの上に接着剤がかかってしまった場合は、
接着剤がゴム状に半分固まったくらいになってから
マスキングテープを剥がして接着剤を整え、スルーホールが塞がらないようにします。

接着剤が固まったらマスキングテープを剥がして完成です。

 

Mint60にロープロファイルピンヘッダ使ってみた

自作キーボードキット Mint60でProMicro用のピンヘッダを、秋月電子で売ってたロープロファイルピンヘッダに変えてみたら、余ったピンヘッダを切る必要がなくなって、ケースとの干渉もなく最高だったので、記録を残しておきます。

 

 普通のピンヘッダとロープロファイルピンヘッダの違いはこんな感じ。

f:id:cnaos:20190209142149p:plain

ピンヘッダの比較

 
Mint60の基板につけてみた場合の違い 

f:id:cnaos:20190209142158p:plain

普通のピンヘッダの場合

買ったロープロファイルピンヘッダは14ピンあったので、2ピン分余ってます

f:id:cnaos:20190209142114p:plain

ロープロファイルピンヘッダの場合

ロープロファイルピンヘッダを2ピン分切って12ピンにして基板に挿した

f:id:cnaos:20190209142126p:plain

はんだ付け前

f:id:cnaos:20190209142136p:plain

はんだ付け後

ケースとの干渉も無く問題ありません。

f:id:cnaos:20190209142144j:plain

ケースとの間隔

  

eucalyn.hatenadiary.jp

akizukidenshi.com

 

isaax勉強会#24(ラズパイでオムロン環境センサを使ってみる)に参加してきた

isaaxug.connpass.com

参加しようと思ったきっかけ

自室の温度とか湿度の記録を取りたいなと思っていて、 ウェザーニュースのWxBeacon2(オムロンの環境センサーのOEM)と Raspberry Pi 3B+を買ってたんだけど、 放置したままだったので、これはまさにぴったりの勉強会ではないかと思って参加してみました。

isaaxについての知識はありませんでした。

ハンズオンの中身

ハンズオンで使ったテキストは以下で公開されています。

オムロン環境センサ・Ambient・isaaxハンズオン – Isaax Camp

ハンズオンで利用するプログラム(Pythonスクリプト)はすでにgithubに用意されていて、 それをforkして使いました。

GitHub - isaaxug/envsensor-ambient

全体のシステム構成はこんな感じだと思います。 f:id:cnaos:20190126153252p:plain

sshraspberry piに入って、isaaxdのプロセスとかディレクトリを見てたら、 isaaxdがgithubからraspberry piで動かすPythonスクリプトをダウンロードしてきて実行してました。

事前に用意されていたのは、以下の2つのPythonスクリプトでした。

  • オムロンの環境センサーからBLEでデータ読み出しをするもの(sample1.py)
  • それに可視化サービスambientへデータを送信する部分が追加されたもの(sample2.py)

コードを書く部分はあまりなくて、 isaax, github, ambientなどの連携や設定がほとんどでした。

githubに上げられない秘匿情報はisaax側に保存しておいて、環境変数として参照できるみたいです。

f:id:cnaos:20190126153514p:plain
isaaxの管理画面

多少のトラブルがあったものの、 環境センサーから取得したデータをambientに送って可視化することができました。

f:id:cnaos:20190126153606p:plain
環境センサーから読み取ったデータをグラフ化

勉強会をふりかえってみて

isaaxむっちゃ便利!!

家でも使おうと思う。

これまで趣味でraspberry piをちょこちょこいじってたんだけど、 raspberry pi上でプログラムを動かすとなると、

  1. PC上でraspberry pi上で動かすプログラムのソースコード書く
  2. raspberry pi上に転送
  3. raspberry pi上で実行
  4. 必要ならサービスの作成

とまあ、わりとめんどくさい手順が必要だったんだけど、 isaaxを使えば、

  1. PC上でソースコード書いてgithubに上げる
  2. isaaxの管理コンソールからプログラムをリスタートすれば反映される

という風にすごく楽にプログラムの修正と反映ができる。

個人が趣味で使っている分には、raspberry piが手元にあるので、 実感できる便利さはこの程度なんだけど、 isaaxの真価はインターネットにつながってさえいれば、 リモートでプログラムの更新ができるところにあるらしい。

swiftでQRコードジェネレータを作ってみた

だいぶ前だけど、swiftでQRコードジェネレータを作ってみた

bitbucket.org

今回はSwiftとRxSwiftを使ってみようということで、
またしてもMac上で動くQRコードジェネレータを作ってみた。

QRコードのエンジン部分にはQRCoderを使った。

QRCoder on CocoaPods.org

 

f:id:cnaos:20190126112303g:plain

動的にQRコードが変わる様子

 

テキストボックスと、スライダーの両方を監視して、
どちらかに変更があったらQRコード画像を生成し直すっていう処理が比較的少ないコード量で書ける。

ただ、RxSwiftの参考書などを見ずにやってたから、このくらいだったら大丈夫だけど、もっと複雑なことをやろうとしたら大変そうだなって感触。

あとMacOS用のRxSwiftはRxCocoaというサブセットで、
サポートされているGUI部品がiOS用のものとだいぶ違うらしい。
たとえば、MacOSだとテーブルはNSTableViewを使うんだけど、
このあたりのサポートがなかったりする。

 

 

griffonでQRコードジェネレータを作ってみた

macQRコードを生成するツールZebraがあって、
便利に使ってたんだけど、URLを変更するときにいちいち別の画面を開かないといけないのが面倒だったんで、QRコードジェネレータを作ってみた。
Zebraでもショートカットキーをつかえば簡単にできるけどね。

バイナリはここから
https://bitbucket.org/cnaos/quickqrgen/downloads/qucickQrGen-0.1-jar.zip

ソースコードはここに。
https://bitbucket.org/cnaos/quickqrgen/src


参考にしたのはこのあたり。

QRコードジェネレータ部分はgoogleのzxingを使いました。
GitHub - zxing/zxing: ZXing ("Zebra Crossing") barcode scanning library for Java, Android


結構作るのに手間取ったけど、
groovyのswing builderの使い方とか、
Javaのswingのあたりの基礎力が足りないんだろうな。

jerseyのサロゲートペアに関するバグ

現象

POSTするテキストなどにU+10000以上のUTF-8文字(サロゲートペアに変換される文字)が含まれると、OAuthのSHA-1署名が不正なものになる。

まずは、OAuthの署名をやってるメソッドのコード*1です。

OAuthSignature.java

78  public class OAuthSignature {

90 public static String generate(OAuthRequest request,
91 OAuthParameters params, OAuthSecrets secrets) throws OAuthSignatureException {
92 return getSignatureMethod(params).sign(elements(request, params), secrets);
93 }

105 public static void sign(OAuthRequest request,
106 OAuthParameters params, OAuthSecrets secrets) throws OAuthSignatureException {
107 params = (OAuthParameters)params.clone(); // don't modify caller's parameters
108 params.setSignature(generate(request, params, secrets));
109 params.writeRequest(request);
110 }

122 public static boolean verify(OAuthRequest request,
123 OAuthParameters params, OAuthSecrets secrets) throws OAuthSignatureException {
124 return getSignatureMethod(params).verify(elements(request, params), secrets, params.getSignature());
125 }

jerseyのOauthモジュールで署名を扱ってるのはこのOAuthSignatureクラスなんですが、sign(), verify()メソッドから呼ばれているelementsメソッドで、URIとかリクエストの中身を正規化しています。

230  private static String elements(OAuthRequest request,
231 OAuthParameters params) throws OAuthSignatureException {
232 // HTTP request method
233 StringBuilder buf = new StringBuilder(request.getRequestMethod().toUpperCase());
235 // request URL, see section 3.4.1.2 http://tools.ietf.org/html/draft-hammer-oauth-10#section-3.4.1.2
236 buf.append('&').append(UriComponent.encode(constructRequestURL(request).toASCIIString(),
237 UriComponent.Type.UNRESERVED));
239 // normalized request parameters, see section 3.4.1.3.2 http://tools.ietf.org/html/draft-hammer-oauth-10#section-3.4.1.3.2
240 buf.append('&').append(UriComponent.encode(normalizeParameters(request, params),
241 UriComponent.Type.UNRESERVED));
243 return buf.toString();
244 }

このあたりには問題がなくて、UriComponent.encode()メソッドが問題。

UriComponent.java

252  public static String encode(String s, Type t, boolean template) {
253 return _encode(s, t, template, false);
254 }

274  private static String _encode(String s, Type t, boolean template, boolean contextualEncode) {
275 final boolean[] table = [t.ordinal()];
277 StringBuilder sb = null;
278 for (int i = 0; i < s.length(); i++) {
279 final char c = s.charAt(i);
280 if (c < 0x80 && table[c]) {
281 if (sb != null) sb.append(c);
282 } else {
283 if (template && (c == '{' || c == '}')) {
284 if (sb != null) sb.append(c);
285 continue;
286 } else if (contextualEncode) {
287 if (c == '%' && i + 2 < s.length()) {
288 if (isHexCharacter(s.charAt(i + 1)) &&
289 isHexCharacter(s.charAt(i + 2))) {
290 if (sb != null)
291 sb.append('%').append(s.charAt(i + 1)).append(s.charAt(i + 2));
292 i += 2;
293 continue;
294 }
295 }
296 }
298 if (sb == null) {
299 sb = new StringBuilder();
300 sb.append(s.substring(0, i));
301 }
303 if (c < 0x80) {
304 if (c == ' ' && (t == .)) {
305 sb.append('+');
306 } else {
307 appendPercentEncodedOctet(sb, c);
308 }
309 } else {
310 appendUTF8EncodedCharacter(sb, c);
311 }
312 }
313 }

こいつがU+10000のUnicode文字つまり、java内でサロゲートペアに変換される文字を考慮してないんですな。

まあ、中身が正しいかどうかはわからんけど、サロゲートペアが含まれる場合は、以下のようにStringのlength()をそのまま使うと、U+10000以上のコードポイントの1文字が2文字に分割されてるので、バグります。


for (int i = 0; i < s.length(); i++) {

実際にgroovyで確認

ではそれを実地で確認してみましょう。javaだとjersey持ってきたりコンパイルするのがたるいので、goovyのコードです。groovyConsoleから実行するのが楽です。

@Grapes(
    @Grab(group='com.sun.jersey', module='jersey-core', version='1.14')
)
import java.net.URLEncoder;

def text="\ud83c\udc00\ud83c\udc01\ud83c\udc02"

println "text="+text
println "----"

def encoded = com.sun.jersey.api.uri.UriComponent.encode(text, com.sun.jersey.api.uri.UriComponent.Type.UNRESERVED)
println "UriComponent.encode="+encoded

def utf8andurlencoded = URLEncoder.encode(text, "UTF-8");
println "utf8andurlencoded="+utf8andurlencoded;

なにをやってるかというと、unicodeの U+1F000, U+1F001, U+1F002の3文字(unicodeで)をサロゲートペア化したテキストを用意して、JerseyのUriComponent.encodeとjava標準のURLEncodeでそれぞれUTF-8エンコード&URLエンコードした結果を表示しています。

で、結果はこれ。

text=🀀🀁🀂
      • -
UriComponent.encode=%3F%3F%3F%3F%3F%3F utf8andurlencoded=%F0%9F%80%80%F0%9F%80%81%F0%9F%80%82

jerseyの使ってるクラスのほうがエンコード失敗してますね。

というわけで、jerseyのOAuth署名処理にはコードポイントでU+10000以上の文字が含まれる場合に、リクエストパラメタの正規化のためのURLエンコードが正しく行われない問題があり、結果としてOAuth署名が正しく行われないのでした。

jersey2のほうでもまだ修正されてないみたいね。
jersey/UriComponent.java at master · jersey/jersey · GitHub

jersey2で確認するときはGrapeのところ次のように書き換えます。

@Grapes(
     @Grab(group='org.glassfish.jersey', module='project', version='2.0-m08-1')
)

*1:grepcodeの奴が見やすいので、そっちを貼ったけど、状況はjerseyの1.14でも同じ。