[自キ]磁気キーボードを作りたい。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電源連動、各ポート電源スイッチつき、ぐらいはしたいですね。

コメント

タイトルとURLをコピーしました