log.fstn

技術よりなことをざっくばらんにアウトプットします。

Let's Split Build Log

f:id:foostan:20171212143419p:plain

自作キーボードに興味を持ったのでまずは入門編だと思って、日本語の情報が多い Let's Split を作ったのでその作業ログを共有します。

Let's Split とは

調べるとたくさん出てくるので特に詳しく説明しませんが、40%キーボードであり、分離型、またキー配列が格子型になっているが特徴です。 40%キーボードだとPlanckが割りと人気のようですが、それを真っ二つにしたのがこれです。

組み立てのガイドはGitHubで公開されています。

https://github.com/nicinabox/lets-split-guide:embed:cite:w500

このキーボードは基本的にはPCB(基盤)とキースイッチ、Pro Micro(Arduino Leonardo互換)、で構成されているとてもシンプルなものです(そもそも大体のキーボードはこれぐらいシンプルなものですが)。 Pro MicroにはGitHub上に公開されているファームウェアを書き込んで利用します。

github.com

材料調達

f:id:foostan:20171213024912p:plain:w500

値段は購入当時のものなので変動している可能性があります。 また、注文から届くまでの期間についても購入当時のものですので状況によって変わると思います。

パーツ 購入場所 値段 送料 注文日 到着日 (関東) コメント
Black Let's Split PCB Set MEHKEE $8.99 $5.71 11/15 11/25
TRRS Jacks MEHKEE $2.99 上記 同上 同上
Gateron Red / PCB-mount (5 pin) - 10 switches x 7 MEHKEE $16.80 $9.28 11/20 12/02 AliExpressで注文したが発送が遅かったのでMEHKEEで注文
1N4148TR - 100 Diodes MEHKEE $3.29 上記 同上 同上
ProMicro x 2 AliExpress $3.65 $0.84 11/16 11/30
XDA blank keycaps AliExpress ¥3,269 ¥0 11/29 12/08
ケース(Top and bottom plate) x 4 (2台分) Ponoko $6.67 $31.59 11/24 12/05 初回注文で本体代が$20割引
4極ケーブル Amazon ¥880 ¥0 12/02 12/03
Micro USB ケーブル Amazon ¥999 ¥0 12/02 12/03
M3ネジ Amazon ¥998 ¥0 12/02 12/03
ゴム足 Amazon ¥373 ¥0 12/09 12/10

合計で¥17,000ぐらいかかりました。 ただ、MEHKEEへの注文を2回に分けていたりキースイッチやケーブル、ケース等を余計に買っているので計画的に買えばもっと安く収まるはずです。MEHKEEの Full Kits が買えれば1万円弱で済みそうです。

組み立て

ProMicroの下処理

ProMicroのUSB部分はとても貧弱でよくもげるそうです。 ハンダ付け後にもげると悲惨なのでエポキシ系接着剤で強化します。

f:id:foostan:20171213025520p:plain:w400

f:id:foostan:20171213025525p:plain:w400

ダイオードの取り付け

予め足を折っておくと綺麗にできます。

f:id:foostan:20171213030348p:plain:w400

ダイオードには向きがあるので注意(PCBの □ にダイオードの | が来るようにする)

f:id:foostan:20171213030548p:plain:w400

あとは無駄な足を切ってからハンダ付けすればOK。

TRRSジャックの取り付け

下記のとおりにジャンプさせる必要があります。 f:id:foostan:20171213031009p:plain:w400

Pro Microのピンヘッダの取り付け

まずはピンヘッダだけです。ここでPro Microを付けてしまうとキースイッチが付けられなくなるので注意です。

f:id:foostan:20171213031751p:plain:w400

一部のキースイッチと上プレートの取り付け

動作確認をするためにまずはProMicroの上に来るスイッチのみを取り付けます。 上プレートがある場合は忘れずに。

f:id:foostan:20171213031938p:plain:w400

ProMicroの取り付けと動作確認

ProMicroの初期不良があり得るので、はんだ付けする前にファームウェアを書き込みます。

github.com

キーマップをカスタマイズする場合は、keymaps/default からコピーします。

qmk/qmk_firmware > cp -a keyboards/lets_split/keymaps/default keyboards/lets_split/keymaps/USER_NAME
qmk/qmk_firmware > vim keyboards/lets_split/keymaps/USER_NAME/keymap.c # 適当に編集
qmk/qmk_firmware > make lets_split/rev2:USER_NAME
qmk/qmk_firmware > make lets_split/rev2:USER_NAME:avrdude # 途中でProMicroのリセットを求められます。今回購入したProMicroの場合リセットを素早く2回押す必要がありました(RSTとGNDを導線でショートさせた)。

ファームウェアが無事に書き込めたらProMicroを取り付けます(左右で向きが異なるので注意です)。 ProMicroが付いたら実際にPCにつなげてみてペンチなどで通電させて文字が入力できるか確認するとよさそうです。

キースイッチ取り付け

残りのキースイッチを全て付けます。

f:id:foostan:20171213034039p:plain:w400

ネジ・スペーサーの選択と下プレートの取り付け

今回購入したネジには6mm、8mm、10mm、12 mm、15 mm、20 mmのスペーサーが付属していました。 なるべく高さを出したくないのでギリギリはまる 10mm を利用します。

ちなみに下プレートを加工してProMicroとジャックをむき出しにすれば 6mm のスペーサーが入ります。

f:id:foostan:20171213034908p:plain:w400

f:id:foostan:20171213035004p:plain:w400

6mm と 10mm の比較

f:id:foostan:20171213035345p:plain:w400

たかが 4mm ですが、実際に使ってみるとかなり感覚が変わります。 10mm だとパームレストが欲しくなりますが、6mm だとなくてもいけます。

完成

f:id:foostan:20171213040819p:plain:w500

黒のキーキャップもいい

f:id:foostan:20171213035226p:plain:w500

黒のProMicroなので黒のPCBに似合います

f:id:foostan:20171213035258p:plain:w500

20mmのスペーサーを利用して Kinesis Freestyle2 っぽくしてみた

f:id:foostan:20171213035319p:plain:w500

特に意味はないけど立ててみた

f:id:foostan:20171213035418p:plain:w500

keymapはまだ定まっていない

f:id:foostan:20171213040417p:plain:w500

机が広々しました(間にドリンク置ける)

f:id:foostan:20171213035457p:plain:w500

Jenkinsの無秩序なジョブをDigdagで再定義する

ということで Jenkins のジョブを Digdag に置き換えて Git で管理すると最高なので、今困っている人はやりましょう。1日あれば多分終わります。 今回試したのは CI のジョブですが、どんなジョブでも応用できると思います。

詳しく

こないだ Rebuild 152 聴いていたらその会話の中に「Jenkinsおじさん」ってワードが出てきたんですよ。

rebuild.fm

Jenkinsをそれなりの規模で使っている人ならお馴染みだと思うんですが、Jenkinsって自由度が高くてジョブの編集も簡単にできるから気をつけないとジョブがカオスな状態になってきて、 管理できる人が限られてしまいます。ジョブを編集したいと思ったらその「管理している人」に許可を取って、これでいいですかね?ってジョブの内容を確認してもらってWeb上から直接ジョブを書き換えると… いわゆるこの「管理している人」が「Jenkinsおじさん」なわけですが、この管理方法だとJenkinsおじさんにとってもその他の利用者にとってもジョブの編集が怖くなってくるんですよね。 あと、経験上こういうフローで編集したジョブってだいたい初回はちゃんと動かなくて結局みんなに迷惑かけちゃいます。つらい。

脱 Jenkins おじさん

まずは Git で管理

とりあえずジョブは Git で管理できるようにして、GitHub とかでちゃんと Pull Request 作ってレビューしてもらう体制を整えたいです。Git で管理するようにすれば過去の変更は全て追えるようになるし、何か問題が起きたときは特定しやすくなります。Pull Request を利用したレビューも普段から使い慣れているので同じようにやるだけですね。

これだけでカオスな状態になりにくい環境になると思います。

次に肝心のジョブの定義についてですが、いくつか方法があると思います。

現在のジョブをそのままファイルに書き出す

レポジトリにシェルスクリプトのファイルを置くだけです。 あとは Jenkins ジョブ上でこのファイルを実行すればOK。 単純でかつ簡単にできますが、そもそもシェルスクリプトの内容が複雑になってきてそろそろ書き換えたかったので今回はパス(シェルスクリプトが苦手ってのもある)。

Jenkins2 にして Jenkinsfile を記述する

Jenkins2には既にしてあったので最初はこれが最有力な選択肢でした。 ただ検証してみたら Jenkinsfile を書くための学習コストが結構高かったのと、GitHub pull request builder plugin が Pipeline ジョブに未対応( Jenkinsfile を使うには Pipeline への対応が必要)だったのでやめました。

GitHub pull request builder plugin 使わないのであれば、Pipeline、Multiple Pipeline、Github Organization あたりのジョブで Jenkinsfile が使えるので良いと思います。 またこれらのジョブはステップ毎の実行結果や実行時間を表示してくれていい感じなので試してみるのをおすすめします。 新しいUIとして Blue Ocean というものも出てきてるのでついでに見てみるのもいいです(現在はベータ版ですがプラグインとしてインストールできます)。

Digdag を使う

Rebuild 152 でも話題になってましたが Digdag が今回の用途としては筋が良さそうでした。 Digdag はざっくり説明するとシェルスクリプトPythonRubyなどで記述したタスクを yaml(正確には yaml を拡張した dig ファイル) で定義したフローで実行するシンプルなワークフローエンジンです。 詳しくはドキュメント読んだり、検索すれば関連記事が沢山出てくるのでそれらを参照してもらうと良いと思います。

Jenkins のジョブを Digdag で再定義する

対象のアプリケーションは Rails で、フロントエンドのテストとバックエンドのテストが独立しているとします。 また、バックエンドのテストの一環として RSpec の他に Rubocop を実行することとします。 なお、フロントエンドのテストは js ファイルが変更された場合、バックエンドのテストは rb ファイルが変更された場合のみ実行させるとします。

この場合 Digdag では以下のように定義することが出来ます。

test.dig

timezone: UTC

_export:
  rb:
    require: 'tasks/test'

+setup:
  rb>: Test.setup

+test:
  +frontend:
    if>: ${diff_js}
    _do:
      rb>: Test.frontend

  +backend:
    if>: ${diff_rb}
    _do:
      +setup:
        rb>: Test.setup_for_backend

      +backend_test:
        +execute_rubocop:
          rb>: Test.execute_rubocop

        +execute_rspec:
          rb>: Test.execute_rspec

下記はタスクの例です。

tasks/test.rb

class Test
  def setup
    Digdag.env.store(diff_js: diff?('.js'))
    Digdag.env.store(diff_rb: diff?('.rb'))
  end

  def frontend
    # 省略
  end

  def setup_for_backend
    run "bundle install"
  end

  def execute_rubocop
    # 省略
  end

  def execute_rspec
    run 'bundle exec rspec'
  end

  private

  def diff?(file)
    # 省略
  end

  def run(command)
    start_time = Time.now
    puts "run `#{command}`".blue
    system command
    finished_time = Time.now

    if $?.success?
      puts "finished `#{command}` in #{(finished_time - start_time).round 2} seconds".blue
    else
      raise "failed `#{command}` in #{(finished_time - start_time).round 2} seconds".blue
    end
  end
end

class String
  def blue; "\e[34m#{self}\e[0m" end
end

Jenkins側のジョブは

digdag run test.dig -a --project .jenkins

だけで大丈夫です( .jekinstest.dig がある場合)。

小ネタですが def run のところで実行時間を測っておくと

00:00:31.677 finished `bundle install` in 3.45 seconds

のように出力されるので便利です。

おわりに

Digdag でフローを定義することによってジョブの見通しがよくなりました。 Digdag なら Jenkins 以外の Circle CI や Travis CI などの SaaS でも普通に動くはずのなのでサービスの選択肢が広がっていいですね。

学習コストも低く1日あれば試せるのでJenkinsおじさん問題で困っている方は検討してみてはいかがでしょうか。