自作キーボード2号機

自作のキーボード1号機テンキーパッドの経験を生かし、キーボード2号機を作成しました。

作成に使用した asoovu usb用のファームウェア キースイッチ取り付け用のQCADデータ 感光基板用のkicadデータ GitHubで公開しています。

  • 失敗メモ
    3キー同時押しを取りこぼす場合がある(Ctrl,A,S,D,F,Gキー)。
    実用上問題無いので放置。

1号機との主な違いは以下です。

  • 修飾キーが標準サイズになった(スタビライザ使用)
  • 感光基板の使用で配線がスッキリ

以下、比較写真。上が1号機、下が2号機。修飾キーが標準サイズに。

上が1号機、下が2号機。配線がスッキリ…したのか?

作業工程

アルミ板加工

けがき線を引いて下穴を空ける。

けがき線に沿って穴空け。

穴が開いたらキースイッチとスタビライザーを取り付け。

回路作成

プリンタの都合で基板が2枚になりました。

QCADで回路図を作成、プリンタで出力。しっかり感光させる。

現像、エッチング後、カットして穴を空ける。
分割は既存のエルゴノミクスキーボードを参考にしました。特に意味はありません。

組み立て

基板を取り付け。位置が合わない場合は穴を広げて対応。

部品を半田付け。ダイオードとジャンパ線(回路図上は抵抗)を間違わないように注意。

マイコンと接続。

キーキャップを付けて完成。

CherryとCostarのスタビライザ比較

自作テンキーパッドではCherryのスタビライザ(stabilizer)を使用しましたが、ちまたではCostarのスタビライザも多く見受けられます(というかCherryMXスイッチ使用のキーボードのほとんどがCostarのような………)。
というわけでwasdkeyboardsでCostarスタビライザを購入し厚紙(1.5mm)に取り付けてみました。
Costarスタビライザの加工寸法はgeekhackの記事を参考にしました。
以下、取り付け画像です(左がCostar、右がCherry)。

加工穴↓

上面↓

下面↓

横面↓

どちらがいい?

わかりません……が、以下の理由でCostarかな?(あくまで自作目的目線)

  • 取り付け穴の加工が簡単
  • キースイッチとスプリングの干渉が起きにくそう(←自作テンキーパッドで失敗した)
  • 基板面(下面)の部品が少ないのでキースイッチと基板実装部品との干渉が起きにくそう(←自作テンキーパッドで失敗した)

肝心の鍵打感は実際に使用して比べてみるしかないですね。

テンキーパッドのようなもの自作

f:id:ukasiad:20140427210528j:plain

テンキーパッドのようなものを作成しました。
実用目的では無く自作キーボード2号機作成に向けて、

  • cherryキーのスタビライザー取り付け
  • プリント基板作成

の練習です。
今回作成したQCAD、kicad、MPLAB Xプロジェクトはgithubに置いてありますが、問題が多々あります。以下の失敗メモの部分を参照してください。

Cherryキー用スタビライザー取り付け

スタビライザーは自作1号機では取り付けを見送った部品です。 今回はQCADを使用して加工用図面を作成ました。加工手順は自作1号機と同じです。

  • 失敗メモ:スイッチ固定部分とスタビライザーのメタルパーツが接触して滑らかに動かない。
    →メタルパーツ固定部側に穴を広げて対応

プリント基板作成

自作1号機では空中配線を行いましたが耐久性と生産性を考えいるとプリント基板を作れた方が良さそうです。
今回はサンハヤト 感光基板製作入門キット PK-11を使い、これに入っている取り扱い説明書に習って作業しました。

パターン作成

パターン作成にはkicadを使用しました。

  • メモ:回路図など書いた事がなかったが、チュートリアルを参考にすればなんとかなった。
    ※"download file"リンクからDLできる。日本語版もあるが少し古い?
  • メモ:Cherryキースイッチのkicad用フットプリントを公開してくれている方がいたので使わせてもらった→geekhack-org/kicad-library
    ※基板取り付け用の穴は今回必要なかったので削除して使用。
  • メモ:PK-11の説明書には空きパターンを塗りつぶす(銅箔を残す)ことを薦める旨の記述があるが個人的には要らない部分は無いほうが作業しやすいような気がする。
  • メモ:PcbnewへQCADで書いたdxfファイルを読み込みたかったが、やり方が分からなかった。
    →QCADでbitmapで保存してkicadのBitmap2ComponentでPcbnewへ読み込んだ。この際、寸法が合わなかったので画像を適度に拡大保存する必要があった。
    ※一度Pcbnewへ読み込んで寸法ツール(Add dimensionボタン)で実寸法と画像寸法を比較するのが手っ取り早い。
  • 失敗メモ:図面をこねくり回しているうちにダイオードが直列つなぎになった。
    →通過するダイオードの数が多いほど電流が小さくなってしまうがとりあえず動いたのでOKとした。
  • 失敗メモ:スタビライザーとダイオードが接触した。
    ダイオードを銅箔側へ取り付け。

↓↓↓ダイオードがキー部品と接触するので銅箔側へ取り付け↓↓↓

露光

感光基板に光を当ててパターンを焼きつけます。(エッチング工程で光が当たった部分の銅箔が取り除かれます)
露光には自作のケミカルランプを使用しました。

  • 失敗メモ:基板とOHPフィルムとの間に隙間が出来て必要な部分にまで光があたってしまった。
    →とにかく密着させることを心がけ。

現像

慣れないと完了がわかりにくい工程です。WEB上の写真などで予めできあがり状態を確認しておくといいかもしれません。

  • 失敗メモ:現像液の温度が高すぎて必要な部分の感光剤まで取り除かれてしまった。
    →適正温度(30℃)は守ろう。

エッチング

感光部分の銅を薬液で溶かします。 ここまでうまく行っていればエッチングはそう難しい作業ではないと思います。時々引き上げてテスタで確認するといいかもしれません。

  • 失敗メモ:3箇所ほど露光不足でショートしていた。
    →先の細いヤスリで削って修正した。

なんやかんや失敗して5枚目にやっと成功しました(ヽ´ Д `)。

↓↓半田付け完了後↓↓

コントローラ

今回は秋月電気通商で販売されているPIC18F14K50使用USB対応超小型マイコンボードを使用しました。 自作1号機で使用したASOOVU USB(PIC18F2550)と似たようなマイコンですが、今回のはROMライタ(PICプログラマ)が必要なので併せてマイクロチップ PICkit3も購入しました。

  • メモ:今後の開発環境はMPLAB X IDEXCコンパイラになっていく模様。
  • 失敗メモ:IOピンのアナログ入力設定がONになっていて入力が取れなかった。
    →OFFにして対応。

※回路図にはありませんがnumlock状態を知らせるLEDをつけてます。

さくらのクラウドAPI1.1をJavaで使う

Javaさくらのクラウド環境を操作してみました。
APIのドキュメント→さくらのクラウドAPI1.1

  • メモ
    さくら公式のNode.jsのモジュールnode-sacloudがある。

環境

Vine Linuxです。

$ cat /etc/vine-release 
Vine Linux 6.2 (Haut Bailly)
$ java -version
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.1) (vine-4.b22vl6-i386)
OpenJDK Server VM (build 19.0-b09, mixed mode)
  • メモ
    Vine Linux 6.2ではデフォルトキーストアとして
    /usr/lib/jvm/jre-1.6.0-openjdk/lib/security/cacerts
    が使用されているが、このキーストアは空っぽ。
    なんとなく、
    /etc/pki/java/cacerts
    が代わりに使えそうなので、これをシンボリックリンクにして使用した。
    $ cd /usr/lib/jvm/jre-1.6.0-openjdk/lib/security/
    $ sudo mv cacerts cacerts.backup
    $ sudo ln -s /etc/pki/java/cacerts

ソースコード

SSHキー関連のAPIのGET, POST, PUT, DELETEをテストです。
API_URL_PRE, ACCESS_TOKEN, ACCESS_TOKEN_SECRET は各自の値を設定。

package com.example.SakuraCloudApiTest;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;

public class Main {
  // 石狩第1ゾーン
  // private static final String API_URL_PRE = "https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/";
  // 石狩第2ゾーン
  public static final String API_URL_PRE = "https://secure.sakura.ad.jp/cloud/zone/is1b/api/cloud/1.1/";

  public static final String ACCESS_TOKEN = "YOUR_ACCESS_TOKEN";

  public static final String ACCESS_TOKEN_SECRET = "YOUR_ACCESS_TOKEN_SECRET";

  public static void main(String[] args) {
    try {
      // SSHキー一覧を取得
      sshkeyGet(null);

      // 該当IDのSSHキー情報を取得
      // sshkeyGet(your sshkeyid);

      // SSHキーを作成
      // sshkeyPost("testkey1", "description1", "ssh-rsa test key1");

      // SSHキーを更新
      // sshkeyPut(your sshkeyid, "TESTKEY1", "DESCRIPTION1", "ssh-rsa TEST KEY1");

      // 該当IDのSSHキーを削除
      // sshkeyDelete(your sshkeyid);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static class BasicAuthenticator extends Authenticator {
    private String password;
    private String user;

    public BasicAuthenticator(String user, String password) {
      this.password = password;
      this.user = user;
    }

    protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(user, password.toCharArray());
    }
  }

  private static String getSshkeyJson(String name, String description,
      String publicKey) {
    StringBuilder sb = new StringBuilder();
    sb.append("{");
    sb.append("SSHKey:{");
    sb.append("Name:");
    sb.append("\"" + name + "\"");
    sb.append(",");
    sb.append("Description:");
    sb.append("\"" + description + "\"");
    sb.append(",");
    sb.append("PublicKey:");
    sb.append("\"" + publicKey + "\"");
    sb.append("}"); // SSHKey: {
    sb.append("}");
    return sb.toString();
  }

  public static void sshkeyGet(String sshkeyId) throws Exception {
    String path = "sshkey";
    if (sshkeyId != null) {
      path += "/" + sshkeyId;
    }
    _http("GET", path, null);
  }

  public static void sshkeyPost(String name, String description,
      String publicKey) throws Exception {
    _http("POST", "sshkey", getSshkeyJson(name, description, publicKey));
  }

  public static void sshkeyPut(String sshkeyid, String name,
      String description, String publicKey) throws Exception {
    _http("PUT", "sshkey" + "/" + sshkeyid,
        getSshkeyJson(name, description, publicKey));
  }

  public static void sshkeyDelete(String sshkeyid) throws Exception {
    _http("DELETE", "sshkey" + "/" + sshkeyid, null);
  }

  private static void _http(String method, String path, String body)
      throws Exception {
    HttpURLConnection conn = null;
    InputStream in = null;
    OutputStream out = null;
    try {
      URL url = new URL(API_URL_PRE + path);
      conn = (HttpURLConnection) url.openConnection();
      conn.setDoOutput(true);
      conn.setUseCaches(false);
      conn.setRequestMethod(method);
      // conn.setRequestProperty("X-Sakura-API-Beautify", "1");
      Authenticator authenticator = new BasicAuthenticator(ACCESS_TOKEN,
          ACCESS_TOKEN_SECRET);
      Authenticator.setDefault(authenticator);
      if (body != null) {
        out = conn.getOutputStream();
        byte[] b = body.getBytes("UTF-8");
        out.write(b);
      }

      conn.connect();
      in = conn.getInputStream();
      ByteArrayOutputStream bout = new ByteArrayOutputStream();
      int d = -1;
      while ((d = in.read()) > -1) {
        bout.write(d);
      }

      System.out.println(bout.toString());

    } catch (Exception e) {
      throw e;
    } finally {
      if (in != null) {
        in.close();
      }
      if (out != null) {
        out.close();
      }
      if (conn != null) {
        conn.disconnect();
      }
    }
  }
}

「さくらのクラウド」でサーバ作成してSSHなどを設定した

 会社でお付き合いのあるSAKURA Internetさんから『「さくらのクラウド」無料券』なる物を頂ました.さくらのクラウドを2万円分使用できるクーポン券です(使用開始から一年間の期限付き).
 さくらのクラウドは最小構成でCPU1コア/メモリ1GB/ディスク20GB(SSD)が月額1,900円です.
 個人(自分)が使うとすればお試し環境構築といった用途になるかなぁ.上記最小構成なら1時間9円,1日95円です.個人使用で常時運用するなら同じSAKURA InternetでもVPSの方が使いやすいかな.

使い勝手は・・・

 他のクラウドサービスを使ったことがないので何とも言えません.
 一番安いプランでCentOS 6.4 64bitでサーバ作成してみましたが3分もかからずサーバ作成完了.グローバルIPが割り当てられておりrootでsshでログイン可能な状態で起動します.
 サーバ削除も試してみましが,こちらはすぐに完了します.

初期状態

 サーバ作成直後はディスクとメモリはこんな感じ.

# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/vda3              18G  1.4G   16G   9% /
tmpfs                 499M     0  499M   0% /dev/shm
/dev/vda1              98M   28M   65M  31% /boot
# free -m
             total       used       free     shared    buffers     cached
Mem:           996         99        896          0          7         34
-/+ buffers/cache:         57        938
Swap:         2048          0       2048

SSH関連の設定を行なう

 具体的な用途は無いですが,とりあえずssh関連の設定を行なっておきます.
 設定する項目は以下です.

  • ssh認証変更
    • rootユーザログイン禁止
    • 公開鍵認証(秘密鍵パスワードなし)
    • パスワード認証禁止
  • sshdポート変更
  • iptablesでsshのみ接続許可

ユーザ追加してsudo設定

 まずはユーザ追加,パスワード設定,sudo設定.

# useradd ukasiad
# passwd ukasiad
# visudo
...省略...
ukasiad ALL=(ALL) ALL        # 追加
...省略...

鍵ペアを用意(クライアント側作業)

 自分はクライアントとしてWindows7cygwinを使用しました.すでに鍵がある場合は飛ばしてOK.
 ホームディレクトリに移動,~/.sshフォルダが無ければ作成。

cygwin$ cd ~
cygwin$ mkdir .ssh
cygwin$ chmod 700 .ssh

 ssh-keygenでsakura1_id_rsaという名前で鍵ペアを作成します.途中の "Enter passphrase" で何も入力しません.

cygwin$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa): sakura1_id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in sakura1_id_rsa.
Your public key has been saved in sakura1_id_rsa.pub.
The key fingerprint is:
... 省略 ...

 鍵ペア生成確認,秘密鍵の権限を変更,秘密鍵を.sshへ移動.

cygwin$ ls
sakura1_id_rsa  sakura1_id_rsa.pub
cygwin$ chmod 600 sakura1_id_rsa
cygwin$ mv sakura1_id_rsa .ssh/

.ssh/configに以下を追記.

host sakura1
    user ukasiad
    hostname ***.***.***.***
    port 22
    identityfile ~/.ssh/sakura_id_rsa

公開鍵(sakura1_id_rsa.pub)をサーバへコピー.

cygwin$ scp sakura1_id_rsa.pub ukasiad@***.***.***.***:~/

メモ
秘密鍵から公開鍵を作るコマンド
ssh-keygen -y -f 秘密鍵ファイル

サーバ側作業

 ホームディレクトリ権限変更(忘れがち),~/.ssh フォルダが無ければ作成.

$ chmod 755 /home/ukasiad
$ mkdir .ssh
$ chmod 700 .ssh

 公開鍵を鍵ファイルに追加.

$ cat sakura1_id_rsa.pub >> .ssh/authorized_keys
$ chmod 600 .ssh/authorized_keys

メモ
公開鍵(sakura1_id_rsa.pub)は削除してもかまわない。秘密鍵から再作成可能。

sshd設定

 sshdで公開鍵認証を有効にして再起動.

$ sudo vi /etc/ssh/sshd_config
...省略...
PubkeyAuthentication yes
...省略...
$ sudo service sshd restart

 クライアントからssh sakura1でパスワードなしでログイン出来れば成功.

sshdポート変更など

 sshdのポートを*****に変更(クライアント側~/.ssh/configのポート番号変更も必要),rootログイン禁止,パスワードログイン禁止,チャレンジレスポンス認証禁止.fail2banのsshdポートの変更.

$ sudo vi /etc/ssh/sshd_config
...省略...
Port *****
...
PermitRootLogin no
...
PasswordAuthentication no
...
ChallengeResponseAuthentication no
...省略...

$ sudo vi /etc/fail2ban/jail.conf
...省略...
[ssh-iptables]

enabled  = true
filter   = sshd
action   = iptables[name=SSH, port=*****, protocol=tcp]
           sendmail-whois[name=SSH, dest=root, sender=fail2ban@example.com]
logpath  = /var/log/secure
maxretry = 5
...省略...
$ sudo service sshd restart
$ sudo service fail2ban restart
$ sudo service iptables restart

メモ
fail2banはデフォルトでパスワード認証失敗しか対応していない?

iptables設定

 外からはssh接続しか許可しない.

$ sudo vi /etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport ***** -j ACCEPT
COMMIT
$ sudo iptables -L

メモ
設定を間違ってssh接続が出来なくなった場合,さくらクラウドコントロールパネルのコンソールで接続して修正.

メモ
パケットフィルタなる物がコントロールパネルで用意されているが使い勝手はどうなんだろう.

その他

 yumパッケージを更新.200個ほどの更新あり.

$ sudo yum -y update

 とりあえずサーバ再起動.

$ sudo shutdown -r now

自作キーボードのキートップ換装

自作キーボードキートップを換装しました.

1.0倍キーはダイヤテックオンラインショップ 「Majestouch専用無刻印キートップ 104英語(コーティングあり」 を購入↓↓
f:id:ukasiad:20131027220329j:plain
1.5倍キーはWASD Keyboardsで購入↓↓
f:id:ukasiad:20131027220401j:plain

ダイヤテックオンラインショップは3日くらい、WASD Keyboardsは1週間くらいで商品が届きました。

キートップを外すときはマイナスドライバーでキースイッチを押さえながら慎重に引き抜きます。
今回の構造だと普通にキートップを引き抜こうとするとキースイッチ自体が外れて配線がちぎれてしまいます。
f:id:ukasiad:20131027220447j:plain

キートップを全て外した状態↓↓
f:id:ukasiad:20131027220523j:plain

キートップ換装後の状態↓↓
1.25倍キーで代用していた部分の隙間がなくなっています.
f:id:ukasiad:20131027220600j:plain

これでこのキーボードはひとまず完成.
2号機の構想を練るかぁ.

Nキーロールオーバーとは何の事か分からん

 キーボードにおけるNキーロールオーバーとは全キー同時押下が可能な事だと思ってました.
 が,どうも違うらしい.

'N'とは何か(私見です)

 ネットでいろいろ調べましたがNキーロールオーバーの'N'が何を意味するのかが分かりませんでした.私見ですが PS/2時代 USB時代 で言葉の意味が変わっているような印象を受けました.

  • PS/2時代のNキーロールオーバー
     全キー同時押下可能の意味.
     たとえばAキーロールオーバー対応と言った場合,キーボードでA個のキーが押下されている状態で,A+1個目のキーが押下されたとき,A+1個目のキーを検出可能である機能. この時,既に検出状態にあるキーで押下検出が最も早かったキー情報が捨てられる(未押下状態となる).結果,PCはA個の押下状態を検出した状態となる(ところてん方式).
     Aに変数の意味での'N'を使用した場合,Nはどんな値もとりうる,すなわち全キー同時押下検出可能なキーボードと言うことになる.

  • USB時代のNキーロールオーバー
     キーボードで何らかのキーを押下検出した状態から新たにキーを押下した場合,このキーを検出できる機能.つまりNに数値的な意味は無い.
     PS/2時代で言うところの6キーロールオーバーに該当するキーボードをNキーロールオーバーとうたっていることが多いような・・・

自作キーボードは

 先日自作したキーボード(中西Type1)では6キー分の送信用バッファを用意し,押下を検知した順にキーを追加していく方式をとっています.
 なので7キー以上同時押下した状態では,ハードウェア的にスキャンが早い順に6つのキーがPCに送られます. よって 6キー同時押下可能でロールオーバーの機能は有していない と言うことになります.