hyousi

  • Home
  • 一覧
  • [自キ]遊舎工房のレーザー加工サービス利用してみた

     最近レーザーカットしたいものが増えてきました。かといって家庭用のレーザー加工機は出力やサイズや値段やでいいバランスのものがなく外で加工するしかないかなあ。
     持ち込みで加工してくれたり貸し出しを行っているfab等がありますが億劫である。
     ということでyushakoboでレーザーカットサービスを利用してみました。

    yushakobo

     yushakoboでレーザー加工サービス (その2)というものが販売されており、今回はPORONの3mm厚を利用しようと思います。お得そうなのでサイズは500x300mmで。
     レーザー加工サービス デザインルールのページを確認します。Adobe Illustrator, Inkscape, Affinity Designer 2あたりのソフトを利用し作成するようです。以前セールで使い道もなくAffinity2を購入していたのでAffinity Designer 2を使用したデータ作成をしたいと思います。

     フォーマットとしては内側の抜きパターンと外形パターンとでRGBの色分け(加工順)と線幅を指定の細さにする必要があります。ここら辺はAffinityでの処理でしょうか。

     図形パスの連結と重複の禁止も行う必要があります。こちらはCADソフトで行おうと思います。Affinityに慣れている人は最初から最後までAffinityで完結したりするのでしょうか?
     無料のCADソフトだと連結機能が無いものも多いのでその場合はAffinityで連結処理を行う必要がありそうです。fusion360なんかもないですよね、そもそもfusionは2D図面作成に向いてなさすぎます。nanoCADという無料ソフトはポリラインを使えてかなりいいソフトだなと思いますおすすめです。重複の禁止は厄介な印象ですがどうなのでしょう。図形のbool演算行えるソフトがあるとmergeしてbreakするだけで楽そうですがそんなもの持っていない。
     KICADはフットプリント活用しつつポリライン作成できてDRCで重複も見れるのでこの用途だと割とバランスがいいのかもしれませんね、2D図面作成に向いているとは思わないですが。

     題材としては先日購入したphoton用のフォームを作ってみようかなと思います。フォームが必要かというと無いほうがらしいのですが試して遊ぼうと思います。

    KICAD

     基板を作るわけではないですがフットプリント活用してデザインできるのでKICADから図面作成してみます。
     スイッチプレート用のフットプリントを配列通りに並べ、図形ツールでスタビとスイッチの間などを調整します。狭すぎるところなど消してしまいます。
     トップケースねじ止め箇所やコントローラー部も抜きパターンとして図形を追加しています。

     スイッチの穴はレーザーカットのパスとしてそのまま四角で一筆書きできるのでいいですが図形が合わさっている所(2U~サイズや外形に接続する箇所)を一筆書きできるようにする必要があります。
     図形ツールにポリゴンという便利なものがあるのでポリゴンを使用して一筆書き図形を作成していきます。KICADのスナップは同レイヤーの各図形の頂点にしかスナップしない(図形同士の交点や中心点にスナップできない)と思うので、スナップしたい点には頂点を配置されるように図形の調整をしておきます。

     ポリゴンで2U~のスタビと外形部を作成し、ガイドとした図形は消しました。
     KICADはedge.cutsの重複があると3Dビュワーが正常に表示されず、一目で重複の確認ができるのが良いですね。DRCで位置もすぐ特定できます。
     3Dビュワー表示されました。よさそうです。

     後から線幅をまとめて変えたりできなさそうなのが不便ですね。そこはaffinityで行います。

     これ一つの作成だけなのでKICADで完結しましたが重い仕事量になるならフットプリント配置してdxf出力→cadで編集の方がイライラは少ないかもしれないですね。
     製造ガーバー出力からedge.cutsをsvg形式で出力します。

    Affinity Designer 2

     KICADから出力したsvgファイルをAffinity Designer 2で読み込みます。
     図形を選択すると上部のリボンから色と線幅を変更できるようです。デザインルールに合わせて変更しますが線幅が指定の細さだと見えなくなってしまったので0.3ptとしています。

     パスの連結はノードツール→カーブの連結で行えますが線の端同士がしっかりくっついていないとずれたり交差したりしそうですがどうなんでしょう。
     KICADで雑に並べたものを持ってきてカーブの連結、図形をまとめてしまってから不要なノードを消してポチポチするのでもいいかもしれないですね。

     svg単体で開いたのち、yushakoboからダウンロードしたテンプレートにコピーし配置しました。画面右下の変形タブで、選択図形の参照点を選んで動かせるので配置作業はしやすいですね。

     この編集した生ファイルをそのまま提出すればいいみたい。
     以前inkscape触ったときは使い方分からんとなって放置していましたがこれなら図面入れて色変えるだけでした。

    注文

     レーザーカットを注文後、受付メールが届くので、データを添付し発注完了でした。時期によるのでしょうが今回は注文から10日程度の納期でした。
     細い箇所も問題なくカットされています。

    おわり

     データのみの用意で注文できるので使いやすいサービスと思いました。0.2, 2, 3, 5mmのフォームであれば気軽に使っていきたいところです。
     他素材や厚みが欲しいこともあると思うので、他社サービスもいろいろ試してみたいと思います。


  • [自キ]磁気キーボードを作りたい。7週目

    ダイジェスト⑦

    磁気スイッチ触り

     photonに購入したり頂いたりしたphylina,kom,jadegaming,tiheをつけて打鍵比較してみました。

    ・トップアウト
    KOMは大きな音。トップアウトでポスポス鳴る。押さずにステムを揺らすとカシャカシャ鳴る
    次いでjadegamingもステムを揺らすとカシャつき、phylinaと続きtiheが良い感じ
    komとjadegamingは濁り、phylinaは高音より、tiheは低音より

    ・ボトムアウト
    ターンと強く押すとkomは濁った音に加えてトップアウトと同様パスっと音が出る。
    jadegamingはパチッと鋭い音が鳴り、phylinaモニタ傾向でやや高めの音
    カチカチ普通に押すとtiheとphylinaはカッカッと小気味よくなり、こちらはtiheの方が高い
    komは全体的にカシャカシャしている
    jadegamingじゃ強く押すとパチッとなるが普通に押すと低い地味で耳触りの良い音が出る

    ・ストローク
    jadegamingは擦れ感が強い。その点tiheとphylinaはスムーズで優秀
    komはばねがすげーカシャカシャする。ばねが強いため安定感はないもののスムーズ
    jadegamingはブレ感が気になる。
    このブレ感やスムーズさは所謂ラピトリ精度とかとはまた別の話です。

    ・返り
    komは押し込みが軽く帰りが早い
    jadegamingは過重変動少なく重め感で普通のリニアな感じ
    tiheは普通の軽めのリニア
    phylinaはなんか、

    tiheが総じて良く感じたがいい音と静音性はまた別の話ではある。
    以前はkomやjade系は全体的に打鍵感や打鍵音が絶賛されていた印象だがよくわからなかった。
    phylinaも絶賛されていた印象で買ってみたがタイピング体験としてもゲーム体験としても正直よくはな気がした。でも安いのでいいと思う。
    なんかでっかいステムのスイッチが多く出ているけれど、でっかいステム族自体がでっかいステム族のスイッチで分類できる気がして、tiheやastrolinkのような普通のタイプの方が好きかもしれない
    astrolinkもtiheと似たような感じだったがトップアウトがちょっとうるさい。

    精度がというのが大きな問題なのかもしれないが1umで動作するキーボードは持っていないのでわからない
    継続的に色々出てるから気が向いたらまた新しそうなの買ってみる

    ファームウェア作るぞ

     さて、ハードはいったん置いておいてキーボードとして動かすためのファームウェアにとりかかろうと思います。
     とりかかって大分たったのですが中々備忘録るやる気が出ずずるずると来ている

     結果としては、すべてをqmkに対応させたファームウェアで製作しようという方針になっています。そもそもでいうとゲーム用左手デバイスであればキーマップなどゲーム側でいじればよいのでありラピトリ設定のみいじれればいいのですからarduinoでそのまま作ってしまえばよいのであります。
     そうせずqmkでやろうというのは、自作磁気キーボードが普及すればいいなと思うためです。そのためにはゲームデバイスに限らずタイピングも行えるキーボードが必要で、タイピングを行うということはキーマップのまともな設定ソフトが必要で、それはqmkしかありません。
     なぜ自作磁気キーボードが流行らないのかというと誰も求めていないからというのが私の考えです。だってそうですよね、私自身立体形状筐体に限定して価値があるとして製作しているわけですから。つまりプログラムだの組み込みだのに一切経験も知識もない私には難しいのですが、自キで色々活動されている方からすれば自作磁気キーボードを作るのは緒ちょいのちょいなのでしょうけれど、無意味だからやっている人が少ない、というわけです。
     何もわからないのでハードに引き続き無料ai君頼りで進めます。

     さてではどのような構成でqmkに対応させようとするべきかというと、自作磁気キーボードをやってみようと思えるほど、簡単に準備ができることが必要です。そのためにはホールセンサやマルチプレクサ等のメカニカルにはなじみのない部品こそ使いますが安価で馴染みのあるrp2040を使用することです。rp2040zeroとかだな。もちろんゲーマーの方からすればrp2040でできあがるものにはいろいろな面で性能には足らないでしょうがそれはまた別畑の話でそのはるか先です。

     ゲーム用ならば設定など不要と言いましたが、タイピングも行う60%サイズなどの磁気キーボードを想定したとき、やはりソフトウェアはvial-qmkに対応していなければ使う気が起きません。私のように自作キーボードに取り組む一方ゲーミングデバイスにこだわりがあったりゲームを遊ぶという人は多くなくとも少なくもないと思うのです。
     そういう人、それこそ標準的な配列以外を好んでいる方はそこそこのラピトリ最高の設定ソフトor最高のラピトリそこそこの設定ソフトであれば間髪入れず前者を選ぶのではないかと思っています。

     というわけで誰でも簡単に自作磁気キーボードが作れるようにrp2040でqmkに対応させます。qmkのファイルも極力configをいじるだけで済ませられるようにします。その後、ラピトリ等の設定を行える別途ソフトウェアを作ります。という展望となります。

    qmkでADC入力

     今までqmkではただkeyboardjsonを書くだけのことしかしてきていないですが、ホールセンサでのアナログ出力から判定を行う必要があるのでscanをカスタムする必要があります。
     初めてのカスタムマトリクスです。そしてカスタムマトリクスの中でADC入力を受け取るように設定する必要があります。
     何がだるいってもはや写真など一枚も出てこずしばらく永遠に文字とアルファベットの羅列だけの内容になるのが書くのも見るのもキツイだろなんだこれ

     まずこの前のテスト基板どんな内容なのというところですが⑥から雑図を持ってきます。

     rp2040ボードのADCピンに2つのMUXが接続され、MUXにはホールセンサが複数接続されています。
     またMUXにはrp2040ボードのデジタル出力ピンがつながっています。

     マルチプレクサはrp2040からのデジタル出力により接続されたホールセンサから一つを選択あるいはオフにし、選択されたホールセンサからの電圧出力をrp2040のADC入力に通します。
     つまり使用しているADCピンは一つですがmuxにより今回だと8つのホールセンサ出力を受け取るように拡張されています。

     デジタル出力を制御することで電圧値を読みたいホールセンサを選択し、ADCで電圧を読むだけです。読んだ電圧値から判定を行いキーをオンオフするわけです。

     とりあえずラピトリどうこうでなくカスタムマトリクスの実装とADC入力の確認を行いたいので、まずは読みとったADC値をある閾値でオンオフ判定を行うようなものを作りたいです。

    カスタムマトリクス

     カスタムマトリクスというのはただ指定したピンでcol2rowだとかrow2colだとかdirectpinsじゃない方式でマトリクススキャンしたい時に自分で実装するというやつですね。二乗マトリクスとかなんとかそういうキー数いっぱい増やすやつで馴染みが深い気がしますが私は使ったことがありません。

    ドキュメント

     まずはqmkドキュメントのCustom Matrix項をgoogle翻訳して読んでます。https://docs.qmk.fm/custom_matrix

    QMK は、デフォルトのマトリックススキャン ルーチンを独自のコードで補足または置き換えるメカニズムを提供します。
    この機能を使用する理由は次のとおりです。
    キーボードのスイッチとMCUピンの間に追加のハードウェア
    I/Oマルチプレクサ

     このスイッチ以外のハードウェアを追加というのが今回ですね。

    カスタムマトリックスの実装には通常、追加のソースファイルのコンパイルが必要です。一貫性を保つため、このファイルは という名前にすることをお勧めしますmatrix.c。
    キーボード ディレクトリに新しいファイルを追加します。
    keyboards/matrix.c
    新しいファイルのコンパイルを設定するには、以下を追加しますrules.mk:
    SRC += matrix.c

     keyboard.jsonと同じディレクトリにmatrix.cというファイルを作成しその中に新規マトリクススキャンの中身を書きます。
     それを使用したファームウェアを作成するには一緒にコンパイルされるようにする必要があり、rule.mk内にSRC += matrix.cと書く必要があるようです。

    lite
    様々なスキャン関数のデフォルト実装を提供し、カスタムマトリックスを実装する際の定型コードを削減します。設定するには、以下を に追加します
    Full Replacement
    スキャンルーチンをより細かく制御する必要がある場合は、完全なスキャンルーチンを実装することもできます。設定するには、rules.mkに以下を追加します。

     カスタムマトリクスにはliteとfull replacementの2種類があるようです。
     両者で記述する関数が異なり、例えばfullでは”matrix_scan“ですがliteでは”matrix_scan_custom”となっています。fullの方が自由度が高そうでliteは一部だけ書き換えるような感じですが、調べてみます。
     qmkmsysでgrep -r “matrix_scan_custom”コマンドを実行します。該当するファイルを検索してくれるコマンドで色々調べるのによく使いまいしたので覚えました。

    quantum\matrix_common.cにヒット 見てみます。

    __attribute__((weak)) uint8_t matrix_scan(void) {
      bool changed = matrix_scan_custom(raw_matrix);
    #ifdef SPLIT_KEYBOARD
      changed = debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed) | matrix_post_scan();
    #else
      changed = debounce(raw_matrix, matrix, ROWS_PER_HAND, changed);
      matrix_scan_kb();
    #endif
      return changed;
    }

     matrix_scan関数の中でmatrix_scan_customが呼び出されており、その後デバウンス処理らしきものが行われています。
     fullはこのmatrix_scan全体を書き換え、liteはマトリクススキャン部分だけを書き換え、その後自動でデバウンス処理が行われる感じでしょうか。今回はアナログ入力でデバウンス処理は不要あるいは実装するとしても別の形なので、fullでよさそうです。
     attribute((weak))というのは他に同じものが定義していたら上書きする、のようなものらしい。今回のようにmatrix.cを実装する際はそちらを優先する感じでしょうか。

    Full Replacement設定するには、rules.mkに以下を追加します。
    CUSTOM_MATRIX = yes
    matrix.cキーボード フォルダー内のファイル
    に次の関数を実装します。
    matrix_row_t matrix_get_row(uint8_t row)
    void matrix_print(void)
    void matrix_init(void)
    uint8_t matrix_scan(void)

     rule.mkにCUSTOM_MATRIX = yesを書くことでfull replacementのカスタムマトリクスが有効になります。
     またmatrix.c内にはこのような関数を実装すればよいみたい。matrix_printはデバッグような感じなので置いておきます。基本的にはすでにあるデフォルトで読み込まれるものを見れば理解でき得るはずなので、参照しながら関数を一つ一つ見ていきます。マトリクススキャン部は基本的には下記ファイルにありそう

    quantum\matrix.h
    matrix.c
    matrix_common.c

     スキャン以外にも、qmkの機能的な部分はquantumフォルダ内のファイルを探すと情報がみつかりそうです。

    matrix_get_row

     matrix配列のrow番目を取得する関数のようです。

    inline matrix_row_t matrix_get_row(uint8_t row) {
    // Matrix mask lets you disable switches in the returned matrix data. For example, if you have a switch blocker installed and the switch is always pressed.
    ifdef MATRIX_MASKED
      return matrix[row] & matrix_mask[row];
    else
       return matrix[row];
    endif

    matrix_common.c

     matrix[]はというと、行数個の要素を持った配列で、デバウンス後のキー状態が格納されています。現在のキーボードとしての各キー入力状態といったところでしょうか
     先ほど見たmatrix_scanの中でdebounce関数の中にraw_matrix[]が引数となっていますから、きっとdebounce関数で処理されてmatrix[]になっているのでしょう。
     このキー状態配列はmatrix.c内で定義されているのでカスタムマトリクスでも同様に定義する必要がありそうです。

    /* matrix state(1:on, 0:off) */
    extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
    extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values

    matrix.c

     matrix_get_row[]やmatrix[]の型であるmatrix_row_tはmatrix.hにありました。列数に応じてサイズが変更されていますがこれは単に容量削減でしょうか。
     matrix_row_t型はcolに関係のある型と分かります。これはつまりマトリクスのある行のキー状態を表しているようです。

    if (MATRIX_COLS <= 8)
      typedef uint8_t matrix_row_t;
    elif (MATRIX_COLS <= 16)
      typedef uint16_t matrix_row_t;
    elif (MATRIX_COLS <= 32)

       typedef uint32_t matrix_row_t;
    else
      error “MATRIX_COLS: invalid value”
    endif

    matrix.h

     例えば4行5列のマトリクスを想定したとき、0がオフ、1がオンでこのような状態の時、matrix配列のrow番目にはrow行目の各colの状態がビット列で格納されている感じでしょうか。1次元配列にビット列を格納することで2次元マトリクスのデジタル状態がわかりますね。

    col4col3col2col1col0
    row001000matrix[0]=01000
    row100110matrix[1]=00110
    row200000matrix[2]=00000
    row300001matrix[3]=00001

     話は戻ってmatrix_get_row関数は指定した行のキー状態を渡していることがわかりました。知りませんが、スキャン後のqmkとしてのキーボード入力処理のところでこれを呼び出してキー状態を把握しているのでしょうかね。

     matrix mask?走らないので行わなくてよさそうですしキー状態を渡させるだけなので、ここは流用でよさそうです。

    matrix_init

     スキャンを開始する前にキーボード起動後諸々の初期化を行います。matrix_common.cにひとつ、ありますがこちらはカスタムマトリクスliteで使用するものなので無視します。

     matrix.cの中にもmatrix_initがあります。これが通常使用されるものでしょう。
     キー状態の初期化及び、ピンの初期化を行っています。

     matrix_init_pins関数でピンの初期化を行っています。matrix.c内でを追うと、スキャン方式でif分岐しています。確かにcol2rowとrow2colとdirectpinsとではピンの使い方が異なりますね。分岐するのもあってinitの外で定義されているのでしょうか。
     内容としては使用するピンをinput/output high状態にしています。directpinsは常にinput highにしてスキャンしますし、ダイオードのマトリクスでは任意の行or列をoutput high→lowにして対するinput highした列or行を呼んでlowになっているかどうかで判定するので、その通りですね。

    void matrix_init(void) {
    ifdef SPLIT_KEYBOARD
    ~ //分割用、割愛
    endif
    // ピンを初期化
    matrix_init_pins();
    //マトリクスを初期化、配列内全部0にしてすべてオフに
    memset(matrix, 0, sizeof(matrix));
    memset(raw_matrix, 0, sizeof(raw_matrix));

    //デバウンス初期化
    debounce_init(ROWS_PER_HAND);

    //ユーザー定義用
    matrix_init_kb();
    }

    matrix.c

     カスタムマトリクスする際は入出力ピンの状態と、スキャンする際に使用する配列等に初期状態、すべてオフなどを実装しておけばよさそうですね。
     磁気キーボードの場合はキャリブレーションやラピトリ設定値等のプロファイルを読み込んでおくのもここでしょうか。

    matrix_scan

     こちらもmatrix.c内にあるものを確認します。
     col2rowとrow2colとでif文分岐しています。これはmatrix[row]配列という形でrowごとにまとまりとしてキー状態を保存しているため向きが異なると順序が逆になるためです。

     col2row,directpins・・・行ごとに走査するためmatirx[row]を1桁ずつ埋めていけばよい
     row2col・・・列ごとに操作するため、桁ごとにmatrix[row]を選択し埋めていく

     matrix.c内のmatrix_read~関数を追うと結果としてcurr_matrixに現在のキー状態が格納されています。その後前回のキー状態raw_matrixと比較、変更があったらraw_matrixに反映しデバウンス処理。
     デバウンス処理した結果から帰り値としてのchanged判定とおおもとのmatrix配列更新を行っています。

    uint8_t matrix_scan(void) {
      //一時データを初期化
      matrix_row_t curr_matrix[MATRIX_ROWS] = {0};

    //directpins, col2rowの時
    if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
      // matrix_read_cols_on_rowで行ごとにスキャン
      for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
        matrix_read_cols_on_row(curr_matrix, current_row);
      }
    //row2colの時
    elif (DIODE_DIRECTION == ROW2COL)
      // matrix_read_rows_on_colでcolごとにスキャン
      matrix_row_t row_shifter = MATRIX_ROW_SHIFTER;
      for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++, row_shifter <<= 1) {
        matrix_read_rows_on_col(curr_matrix, current_col, row_shifter);
      }
    endif

    //raw(前)とcurr(今)を比較しchangedを判定
      bool changed = memcmp(raw_matrix, curr_matrix, sizeof(curr_matrix)) != 0;

    //状態変更があったらraw matrixを更新
      if (changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix));

    //デバウンス処理しmatrixに反映, changedもデバウンス込みで更新ありか判定
      changed = debounce(raw_matrix, matrix, ROWS_PER_HAND, changed);
      matrix_scan_kb();

    //キー状態変更通知
      return (uint8_t)changed;
    }

    amtrix.c

     磁気はデバウンス処理が必要ないので使用するmatrix[]配列は2で済みそうです。キー状態の変更があった場合changedで返すこと、matrix[]をみてその後処理されるので最新のキー状態を反映させること。がやらなければならないことです。

     また、これらのスキャンの中で使用していたgpioの関数は何をしているのでしょうか。次はそこから追ってみます。

    qmk進捗

     とりあえず今回で中身はないですがカスタムマトリクスが少し書けました。

    rule.mk
    rule.mk:
    CUSTOM_MATRIX = yes
    SRC += matrix.c
    matrix.c
    matrix.c:
    #include <stdint.h>
    #include <stdbool.h>
    #include <string.h>
    #include "util.h"
    #include "matrix.h"
    //#include "debounce.h"
    #include "atomic_util.h"
    
    //キー状態
    extern matrix_row_t raw_matrix[MATRIX_ROWS];//scanで更新
    extern matrix_row_t matrix[MATRIX_ROWS];//matrix_get_row受け渡し
    
    //初期化
    void matrix_init(void) {
    //スキャンで使用するピンや配列の初期化
    //キャリブレーションやラピトリ設定の読み込み
    }
    //マトリクススキャン
    uint8_t matrix_scan(void) {
    //スキャンしmatrix[], changedを更新する
    //変更通知
      return changed;
    }
    
    //キー状態受け渡し
    matrix_row_t matrix_get_row(uint8_t row) {
        return matrix[row];
    }
    
    //デバッグ用
    void matrix_print(void) {
    }

    おわり

     カスタムマトリクスが何なのかどうすりゃいいのかよくわからないなりにだらだらやっていますが終わる気配がない。しばらくqmkとかchibiosのコードを何やら追う内容になりそう。

     現時点でqmkのラピトリ実装と動作確認まではできているので、ちょこちょこダイジェスト進めて追いつきたい。
     現時点の考えですがキャリブレーションはソフトウェアの必要ないと思っていて、キャリブレーションモードの切り替わるトグルスイッチを設けてスイッチポチポチするだけでいいじゃんと思います。そのほか、速度精度度、ap,rp,ラピトリ値、スイッチストロークを設定する必要があるのでやはりソフトウェア自体は必要なのですが、それ自体も正直一度好きな値に設定したら正味変え無くね?と思うのです。
     ゲームで使用しないキーは速度重視かつaprpに余裕を持ち、ゲームで使用する部分のみ精度重視かつデッドゾーン0.1mmラピトリ0.05mmとかで十分と思うのだ。ライトゲーマーなので、、
     するとqmkmsysでmakeしてぶっこむことができる人は別途設定ソフトなくても困らないなと思ったり。
     ここら辺は割とすいすい行きそうなので、一番の課題はやはりスキャンの高速化だと思います。私はマウスカーソルみたいなアナログ信号でなく0,1のデジタル入力なのだから8kとか100kスキャンとか別にという人ですが、早いに越したことはないですからね。

     


  • NuPhy Berry Profile キーキャップ紹介

    NuphyのBerry Profile Dye-sub PBT Keycapsを紹介します。

     グレーのOblivionとピンクのPeach Blossomが公式サイト$49で販売されています。Oblivionはdigiartyushakoboyodobashiで国内でも販売されているようです。
     キーキャップは高価なものが多いので手に取りやすい価格ですね。

    NuPhy® x Oblotzky Oblivion
    NuPhy® x Kevin Ma Peach Blossom

     BerryプロファイルはCherryプロファイルを低背化したような形状で、ロープロファイルキーボードでもCherryプロファイルな使い心地を実現するためにデザインされたそうです。

     詳しくないですがロープロファイル向けのキーキャップは単一のプロファイルばかりの認識でしたので、それが苦手だった方には刺さりそうです。
     BerryプロファイルはCherryプロファイルよろしくシリンドリカルなステップスカルプチャーな形状です。シリンドリカルなものはKeychron等々あると思いますがステップスカルプチャーなものは私は初見です。
     低背CherryのようなものなのでロープロスイッチのみでなくMXスイッチで使用しても見栄えは悪くなさそうです。

    https://nuphy.com/products/oblivion?srsltid=AfmBOopr8xrHh_aMnqMmoq_zzFGIDEjW9Nvp5EbFvhO8ka25hsMIBmAJ

     NuphyのサイトからOblivionとPeach Blossomを購入してみました。
     パッケージは箱に3段で入ってました。OblivionはプラがテープでとまってたのですがPeach Blossomはとまってなくてガシャっとしてしまった。シール貼ってあったり貼ってなかったりするのか、

     キー数はぱっと見不自由なさそうで、コンベックスキーも入っている。内容数的には充実しており独自配列な自作キーボードにも対応できそう。
     Peach Blossomの方がでかいキーが多めに入っているのですね。

     Cherryとかと並べて
     ぱっと見Cherryぽい

     トップ高さはCherryより低く、ロープロキーキャップと同じぐらいに抑えられている
     ただしロープロスイッチに使用した際はステムが長い分飛び出し、ロープロキーキャップより高くなります。
     スカート下はロープロキーキャップより低くスイッチを覆いますが、cherryよりは若干高くなっています。
     DSAでかいね

     Cherryと比べるとR4なんかはだいぶ低くなっている。R3も若干低い
     Cherryよりも表面の傾斜が緩やかに
     ステップスカルプチャーであるものの高低差や角度は強くない。
    *斜めに撮ってるのでこれより高低差は少ないですR2がほぼ同じぐらい

     素材はPBTで印刷はdye-subだそうです。表面のテクスチャは触る分には感じずさらっとしてます。

     厚みは1.5~1.7mm、行数の記載があります。

     側面を見るとなるほどロープロ向けキーキャップなのだなと感じます。ステムがスカートから飛び出しています。触った感じだとgateronロープロスイッチやMXの逆向きとの干渉はそんな気にならなそうな感じ、choc v2は底ががっつり当たりフルストローク押し込めません。

     

     私はシリンドリカルステップスカルプチャー好きです。使っていてステップスカルプチャー感があり使いやすいと感じる反面、べったりしてるなと感じる部分もあります。
     個人的にはCherryでいいならCherryやOEMの方がはるかに打鍵しやすい。
     外観的に凸凹感のない見た目に仕上げたいときはよさそうです。

     そもロープロスイッチ用ならかなりよさそうに思います。キーキャップがネックで最近はロープロスイッチ触らなくなっていたので、また触ってもいいかなと思ったり。
     するとgateron lpスイッチは安いしberryで干渉しないのでchoc v2に対し明確な強みが出ますね。それ以外はchoc v2が強いのですけど、、

     単純に内容数十分かつ安価なのでとても使いやすそう。

     


  • CANNONKEYS Photon カスタムキーボード紹介

     ai03さんのデザインされたCANNONKEYSのベアボーン65%キーボードキットPhotonを買ったので紹介します。

    はじめ

     天キーで触って欲しいなと思っていましたが、公式で販売開始されると日本から購入されることを想定されていないような感じだったので断念していました。しかし2025年7月yushakoboで取り扱いが開始されこれはと購入しました。

    Photon-CANNONKEYS

     割と感動していて購入必死だろという気分でいましたが案外在庫残っているようです。触れる機会がイベントしかなかったですし、プラ筐体のガスケットマウントキーボード自体は選択肢豊富だからでしょうか。数年前はgas67なんか感触よくて安かった記憶がありますし、今は似た構成のEAVE65なんかが半額です。
     私自身カスタムキーボードに疎く他も持っていないのでそこらへんは考察できませんが天キーで惚れた意思は揺らぎません。カスタムキーボードが欲しかったのではない。Photonが欲しかったのだ。

    CANNONKEYS Photon-yushakobo

     舎で\16,500で販売されています。半透明黒のSmokeにしました。色が合っているなと思いdurockのスタビも一緒に買いました。

    DUROCK Screw-In Stabilisers V3-yushakobo

    PKG

     USB A2Cケーブルはロゴが入っています。
     ガスケットPORONはLE20でしょうか柔らかいです。
     バッテリーは1500mAhで6か月持つらしい。デスクトップはbt無く使わないので無しで組みます。会社用にするときは無線にしたいですが静音寄りにビルドするのももったいない感じがします。
     シリコンゴム足はハードでグリップもいい。どこかで売ってるかしら。
     両刀のプラ―は初めて手にしたので乗り換えようかと思いましたが、どちらも外しにくかったです、残念。
     プレートフォーク、スイッチはめる時にプレート陥没しないようにするらしい。

     PC射出成型のケース美しい
     基板はフレックスカットの入った1.6mm pcbです。右下のブロッカー下部表面にコントローラーがあります。なるほどいいですね。

     キーボード基板てベタがないことが多いですがなぜなんでしょう基板少しでも柔らかくするとかなんでしょうかね。誰か教えてください。

    組み立て

    Photon Build Guide-CannonKeys Documentation

     従い、viaで基板の動作確認。
     スタビライザールブして取り付けました。MOD等はしていません。

     プレート、キースイッチ、ガスケットを取り付けました。
     スイッチはストックしていたvertex v1を使用しました。
     ガスケットはとりあえず4点にしましたが今は9点すべて張り付けています。

     ケースをばらします。無線は使わないのでバッテリーは取り付けずカバーも外しました。
     フルPCなのでそうでなくては困るのですが、ボトムケースのみで平置きしてガタつきがなくよいです。金属プレートにボトムプラケースをねじ止めして歪みを矯正している製品を多く知っているので射出成型のボトムプレートはそういうもんなのかと思っていました。

     トップケースはガスケットの抑えと側面のカバーをしています。

     ケースのスタンドオフに基板およびプレートの避けたくぼみ部分8点をトッププレートとねじ止めするガスケットマウントです。
     トッププレートとボトムプレートにガスケットマウント用の隙間が空いています。

     ボトムケースに乗せた図

     トップケースに乗せた図

     ケースをねじ止めしキーキャップを付けました。
     キーキャップは色が合いそうで家にあったのでberry profile oblivionを使用しました。

    NuPhy® x Oblotzky Oblivion-NuPhy

     おお

     バックライトがついていますが上の写真はよく見えないです。Frostedだと映えるのかしら。下にクリアなデスクマットを敷く予定もないのでオフにしようと思います、

     左はPhoton, 右はGH60互換です。R0の高さが低くていいですね。リストレスト無しであればこういう方が打鍵体験が良いです。チルト角も少し大きめです。
     互換ケースは若干背が高いのが気に食わないとは思いながら使っているのですがこう比べるとやはり違いは大きいですね。60%サイズはそこらへん考慮した互換ケース作ったほうがQOL高いかもしれないなと感じました。

     押し込み時の開口は十分です。
     打鍵時に底まで押し込むことはあり得ないので何も問題はないですが、奥まで押し込むとセレクトスイッチはコツンと当たります。フカフカに沈み込ませるようなMODを施そうとするときは広げたりする方がいいかもしれない。
     スライドスイッチは有線、無線、デフォルトレイヤーを切り替えるそう。

     zmkstudioでキーマップ設定を行います。初zmkです。ロック解除が必要らしい。
     ロック解除含め初期状態でのショートカットはドキュメントに一覧があります。

    Photon User Guide-Shortcut guide

     ロック解除は右下のFn→Alt→Enterのようです。レイヤーキーでFnレイヤー→Controlレイヤー→Enter部にアンロックキーが登録されているようです。いじれば好きなキーでアンロックできそうです。

     マウスホイールなどは別途追加しないと使えなさそうでさょうか。zmkの中身は公開されてそうなのでカスタム自体はできそうです。zmk触ったことないのでわからん

    zmk-cannonkeys-keyboards/boards/arm/photon

     とりあえずCapsに全角半角だけ割り振って使ってみようと思います。
     65%って右の4キーをどう処理するのがいいのかよくわかっていません。

    おわり

     癖のないフィードバックに澄んだ打鍵音でキーボード側の味付けはあまりない印象です。

     他のプラガスケットに比べると高いけど周りを見ると買いやすい価格で所有欲満たされとてもよい。
     ガスケットマウントですがKeychronみたいな沈み込みのためではなくacousticな意図が大きそうです。今後ちょこちょこカスタムしつつ遊んでいきたいなと思います。機にスイッチやキーキャップもちょこちょこ試してみようかしら。

     一般にキーボードは重さと密度が正義という方が多いです。重さや密度による利点はもちろんありますが正解ではなくそれぞれが異なる方向性であることを軽量でシンプルな構成のphotonが教えてくれます。私自身そういった短絡的な風潮は体験としても否定的でしたし単純に重すぎるのは取り回しが悪いので好きでありませんので刺さった製品です。 まあ高級なカスキは触ったこともないので上を見れば軽量構成に限界があるのかもしれないですけど、

     


  • [自キ]磁気キーボードを作りたい。6週目

    ダイジェスト⑥

    テスト用の基板作る

     各部品の挙動がなんとなくわかったし部品も決まってきたのでxiao rp2040を使ったテスト用の基板を作りました。

     中身はこんな感じです。マイコンは家に余っていたxiaorp2040を使用します。
     ADCの拡張に8portのmuxを2つ使います。muxの出力は共通のADCピンに接続し、enableピンでそれぞれのmuxのオンオフ切り替えながらデータを取得します。
     各muxに4つのホールセンサを接続し、2×4のキーボードとしています。

     加えて用途は未定ですが余ったピンにdirect pinsでメカニカルスイッチ3つつけてます。

     キー数少ないのでxiaoの電源から各部品の電源を取っていますが、30キーとかに増やすと別途LDOをのっけた方がよさそうですね。

     arduinoでMUXを選択しポートを選択し8つのホールセンサから順に出力電圧を読み取り、シリアルポートに出力するように生成AIに作ってもらいました。

    // MUXセレクトピン
    const int S0 = 27;
    const int S1 = 28;
    const int S2 = 29;
    // MUX有効化ピン(LOWで有効)
    const int E0 = 7;  // mux1
    const int E1 = 6;  // mux2
    // ADCピン(MUXの出力読み取り)
    const int ADC_PIN = A0;
    // 各センサの選択順(対応するセレクトビット)
    const uint8_t selectOrder[4] = {2, 1, 0, 3};  // P2, P1, P0, P3
    //mux切替-読取遅延us
    const int muxdelay = 0;
    //mux平均サンプル数
    const float avenum = 10.0;
    void setup() {
      Serial.begin(9600);
      analogReadResolution(12);    // 12ビットADC
      // セレクトピン出力設定
      pinMode(S0, OUTPUT);
      pinMode(S1, OUTPUT);
      pinMode(S2, OUTPUT);
      // MUX enableピン出力設定
      pinMode(E0, OUTPUT);
      pinMode(E1, OUTPUT);
      // 初期状態ですべてオフ
      digitalWrite(E0, HIGH);
      digitalWrite(E1, HIGH);
    }
    void loop() {
      float keyValues[8];  // K1〜K8
      // === mux1 読み取り ===
      digitalWrite(E1, HIGH);  // mux2無効
      digitalWrite(E0, LOW);   // mux1有効
      for (int i = 0; i < 4; i++) {
        setMuxChannel(selectOrder[i]);
        delayMicroseconds(muxdelay);
        float sum = 0;
        for (int j = 0; j < avenum; j++) {
          sum += analogRead(ADC_PIN);
        }
        keyValues[i] = sum / avenum;
      }
      // === mux2 読み取り ===
      digitalWrite(E0, HIGH);  // mux1無効
      digitalWrite(E1, LOW);   // mux2有効
    
      for (int i = 0; i < 4; i++) {
        setMuxChannel(selectOrder[i]);
        delayMicroseconds(muxdelay);
        float sum = 0;
        for (int j = 0; j < avenum; j++) {
          sum += analogRead(ADC_PIN);
        }
        keyValues[i + 4] = sum / avenum;
      }
      digitalWrite(E1, HIGH);  // 最後にmux2も無効化
      // === 結果出力 ===
     // for (int i = 0; i < 8; i++) {
     //   float kval=keyValues[i];
      //  Serial.print(kval,0);
      //  if (i < 7) Serial.print(',');
      //}
     // Serial.println();
      //delay(1);
    }
    void setMuxChannel(uint8_t channel) {
      // 3bitのセレクトをS0~S2に設定
      digitalWrite(S0, (channel >> 0) & 1);
      digitalWrite(S1, (channel >> 1) & 1);
      digitalWrite(S2, (channel >> 2) & 1);
    }

     シリアルポートにADC読み取り値が出てきました。

     ずっとイライラしていたのはブレッドボードの不安定さだったので、そこらへんが解消されました。
     ちょっと触っただけで値が動いたりブレッドボードの接触抵抗が大きかったり、、、

    読み取り値は安定し、muxはポート切り替え後に鈍ることなく切り替わるようになりました。

    アイソレーションが

     一行目左から1~4, 2行目左から5~8とします。
     基板だけ(Vq)、スイッチ一つをそこにだけ載せる(top)、載せたスイッチを押す(bot)の時の各位置でのADC読み取り値です。使ったスイッチは同一のものです。
     Vq ホールセンサごとに今回でいうと2027~2062と電圧がばらついています。個体差があります。
     Vqが小さいとスイッチ乗せたときも小さい、大きい、の関係には完全には無いようです。ホールセンサ実装のズレ量とかなのでしょうかね。なんだろ

     載せた位置だけでなく、載せたときの他の場所がどうなっているかも見てみました。

     わかりづらいのでVqとの差分を取っていますね。
     黄色がスイッチを載せたところ、その行の緑がその隣、青は斜めの位置です。
     スイッチを載せると300ぐらい大きくなります。スイッチを押すと1500ぐらい大きくなります。この時周りの箇所で変化がなければ素晴らしいのですが、実際には隣のキーや斜めのキーの読み取り値に干渉しているようです。
     値がマイナスになっており、あるキーを押すとその隣や斜めのキーは実際よりも磁力が弱く、キーが離されて見えてしまいます。

     隣のホールセンサを貫く磁束が直下のホールセンサの逆向きなのでマイナスになるのは妥当な気がします。

     実際に使用する際はすべてキーを載せるので、8か所キーを載せてひとつづつ押し込んだ時の差分です。
     一つだけ載せたときは押し込んだ時隣が-8とか-9とかされていました。すべてキーを載せた状態では-3とか-4とかです。キースイッチを載せた分薄まっています。

     ちゃんとしようと思ったら、スキャンごとの判定に隣と斜めのキーの磁石に寄る干渉分も加味するべきと思います。
     しかしまあこの程度であればいったん無視してもいいかなと思っています。

    平均サンプル数

     muxのポート切り替え後に設ける遅延についてはブレッドボードでは2us程度欲しいという感じでしたが、ブレッドボードの抵抗分が原因でした。基板では遅延入れようが入れまいが変わらなかったです。arduinoのコード実行が遅いだけかもしれんので都度確認する必要はあると思いますがon抵抗の低いもの選んでおけば基本的に問題にはならなそう。

     読み取ったADCの値はバラバラして幅を持つので、既製品の0.001mmだとかいうような高感度にしようと思うとキーに触れなくともばらつき分で勝手にキー入力がされてしまいます。
     ので連続で何回か測定しその平均を取ることで安定したデータ取得を行おうと思います。その平均値をとるためのデータ取得数がいくつぐらいがいいのか見てみました。

     平均を取らず1個サンプルだと10程度ばらつきました。こんな取ってたらスキャンレートもったいないという感じですが50個サンプルだとばらつきは2程度に収まりました。平均を取ること速度を犠牲にはしますが有用そうです。

     グラフを見るに10ぐらい取っていれば十分かなと思います。
     実装する際は設定ソフトで平均サンプル数とスキャンレートのトレードオフで使用者に設定できるようにしとけばいいかなと思います。

    基板で磁力-距離特性測定

     マイクロメータ等での精細な測定でなく、3dpでスペーサを作り、ある高さでの磁力を測定してみます。
     スペーサは3種類、0, 1.8, 2.8mm+底上げ分 の高さのスペーサを作りました。

     これで楽にどのスイッチでも安定して測定できます。

     こんな感じです。先ほども言いましたがやはり各高さで各場所との関係は同じではないようです。

     KOMに加えJadeGamingでも見てみました。比べてみると3.8mm(top)では同じぐらいの値ですが0mm(bot)では100程度KOMの方が磁力が弱くなっています。
     Jadeの方がそこでの磁力は強い、が押さない時の磁力はKOMと同じ、なのでJadeはKOMより減衰度合いが大きい感じでしょうか。しらんけど
     そうとして振れ幅が大きい分botではJadeの方が精度よさそうですがそもそもbotは精度がいいです。topでは減衰度合いの小さいKOMの方が優秀そうです。

     また開封して磁石を見てみるとKOMの方が磁石が長かったです。磁石の磁力とか減衰度合いとかが何で決まるのか知らないですけど、そいう言うところでしょうか。そういえばzenaimの磁石はめちゃくちゃ長かったですね。減衰係数の小ささにも気を配っているのであれば素晴らしいですね。

     

     以前検討した簡単な逆二乗則でのfittingをこの3点で取得した値から行ってみます。
     KOMスイッチでのフィッティング結果です。d0が2.8, aが14000, y0が2000 程度となりました。

     こちらはJadegamingです。d0が3.4, aが23000, y0が1800 程度となりました。

     もともと現実に合わせたモデルではないし合っていないのでそこはいいのですが、スイッチごとに定数の差が大きすぎます。これを見ると既製品のソフトウェアのようにスイッチ(磁石)ごとにプロファイルを作成しておきたくなってきます。 もちろん既製品のスイッチプロファイルが何をどうするために使用されているのかは知らないのですけど。

     先ほども言ったように、減衰項を導入する必要があります。磁石ごとの減衰を補正しきると、y0=Vq磁石がない時の値になると思います。
     過去のマイクロメータの測定記録からy0=Vqと固定、減衰係数kを追加しフィッティングを行ってみます。

    $$ y-y_0=\frac{a (1-e^{k(d+d_0)})}{( d + d_0 )^2}=aX $$

     まずこれは減衰なし、y0=Vq固定での結果です。磁石とホールセンサの距離が離れると差が開いています。近似式は減衰を入れていないので実測よりも読み取り磁力が強いです。実際にはこの距離が短い実測点でもわずかな減衰は発生しているはずですがそこはいいです。

     そこに減衰の指数関数を加えてフィッティングしたものがこちら、完璧には合いませんがまあいい感じな気がします。

     ただ実際にこれをどうこうするかというとめんどくさくてやる気が起きないので、減衰は気にしないでy0=Vqとしてしまうのがいいかなと思ってきています。既製品のようにスイッチプロファイルを作成し適用するようにすればかなり一致度高くリニアな変換を行うことができますが、一生更新が必要ですし、ショートストローク化などいじっているスイッチでキャリブレーションを行うことができません。
     なので私はこの減衰による差は確かにあるのだけど、無視してしまう方向で行こうかなと今は思っています。というのも、正直ユーザーの言う精度というのは磁力-距離変換のリニアさ正確さではなく押し始めの感度の高さと誤入力の少なさであることは明らかですよね。であればこの減衰のたるみは中腹で強く出るのですから、誰も文句は言わないし何なら言わなければ気づかないでしょう。
     私は2mm押し込んだはずだが1.9mmしか押し込んだことになっていないからこれはどうだ、などという人はいなさそう。

    というわけでy0=Vqに固定し今回の基板のKOMとJadeとで再検討してみます。減衰は考慮しないので使用する値はtopとbotの2か所だけで計算を行います。その計算式と、1.8mm中腹での実測との差を見てみます。
     KOMでは中腹で0.1mm程度計算からずれています。Jadeでは中腹で0.3mm程度計算からずれています。ここではこのズレ量は磁石の減衰によるものと見ます。グラフのようにこのズレはtopからbotにかけてのたるみ具合となります。topやbotでの正確さはそんなに変わらないんじゃないかなと思っている。
     これであれば基板の校正はスイッチを載せずに値を読み取ったVqを保存し、スイッチの校正ではtopとbotの2点の値を与えてやれば得ることができます。そして減衰の少ない磁石を使用しているスイッチほど磁力-距離変換の正確さが出ます。
     という感じにしようかしら。

    おわり

     周囲のキーとのアイソレーション問題は美意識的には対応した方が良いのでしょうけど、誤動作起きないとは言い切れない大きさだけど、まあそこまで気にしなくてもいいレベルな気がする。
     ほんとのところは知らないですけどスイッチのプロファイルを既製品で読み込む必要があるのは確かになというところ、そしてzenaimはやはり強い。
     キャリブレーションの仕方、フィッティングの仕方、といろんなパターンを考えていたのですが、結局妥協ありで簡素なところに落ち着きそうです。すべてむだになった、、使う磁石各社そろえりゃいいのにね。それくらい
     arduinoのスキャンレートが思ってたより遅くて、そういう作り方はしなきゃなのかなと思ったり。qmkがどうなのか知らんけど。

     ブレッドボードで色々確認するのは大事だけども、ブレッドボードだから見れてないものも多いのかもしれない。面倒だし金もかかるけどブレッドボードはほんとの最初だけにして、すぐ都度テスト基板作る方がいいのかもしれん。小さな電圧変化見なきゃいけないものですものね

     いったんハード面は動作が確認できたのでいったん置いておいて、ソフトウェアの方に取り掛かりたいと思います。qmkに対応させたいのですが、根幹の部分は何もしなくていいのは楽なものの合わせながら実装しなければならないのでそこは面倒なところ。
     ハード面もいろいろ見なければならないのですけど今までやってきたことの繰り返しみたいなもの
     ここらで折り返し地点にしたいです。

     あとは数年前にも触っていましたが、磁気キーボードが電力食いなのでセルフパワーハブ必須なのでセルフパワーハブ作りましょう。そろそろ形にする。usbハブって不格好なものばかりじゃないですか。それがずっと納得いってないのですよね、、。DCプラグ給電、typeC接続、全ポートAとtypeC両対応、pc電源連動、各ポート電源スイッチつき、ぐらいはしたいですね。