[自キ]磁気キーボードを作りたい①ホールセンサ触ってみる

キーボード

ちょこちょこ進捗をまとめたいなと思います。
完全無知状態なので見れた内容ではないダイジェストですがひとしきり終わったら備忘録を別途作成したいですね。

磁気キーボードを作りたい

 こういうゲーミングキーボードが欲しいので基板を起こして作ろうと思うと、曲面だとfpc基板で作らなければなりません。しかしホットスワップソケットではどんなにうまく固定したとしてもキーの抜き差しで破損の不安があります。
 自分用なら手配線で作ってしまえば一日とかからずできてしまうのではありますが、そこは別の話ということで。

 というところでちょっとめんどくさいなと思っていたのですが、磁気キーボードはスイッチと基板とが非接触で入力を行うことができます。上記のようなリスクとは無縁というわけです。おまけに磁気キーボード用のスイッチはKS-20と規格化されたスイッチがたくさん販売されています。

 ラピトリで精度が0.01mmでとかはちょっとよくわからないのですが、こうした立体形状のキーボードには非接触入力できる方式があっており、丁度磁気スイッチが入手性もよく、マッチしているので作りたいなと思った次第です。
 目標としては自分用に磁気スイッチのゲーミングキーボードを作る。自分用でいいのでarduinoを使ってサクッと作りたいなと思っています。

ホールセンサ

 digikeyでホールセンサについて調べてみます。

リニア、コンパス(IC)- digikey

 x,y,z軸あって最大3軸検知できるものもあるようです。すごい。スイッチを押すだけですから1軸シングルでよいですね。
 多軸のものは出力の関係からデジタルでi2cやspi出力のものも多いですね。

TMAG5273C1QDBVR

 出力形式ですが、まずオンオフの判定のものは適していないでアナログ値を出力するものである必要があります。
 形式としては電圧、電流、PWM、i2c、spi等があるようです。磁気キーボードのイメージですとアナログ電圧が一般的でよさそうですね。
 デジタル出力のものもありこれも使いやすそうではあります。マイコンにはADCピンがそんなについていないことが多いですからデジタル出力の方が直接接続する場合はよいのかもしれない。もっともアナログ電圧出力のものでもpicやattiny等使用すれば同じことができそうではあります。
 標準的なアナログ電圧出力をマルチプレクサで増やすのが簡単そうなのでこれでやろうと思います。

 実装方法は面実装とスルーホールありますが当然面実装です。

 温度補正機能がついているものも多いですね。これは実際に試してみたいところです。

 そんなところでTexas InstrumentsのDRV5053シリーズを買ってみました。理由としては上記条件でソートし、安めだったこととモデルがいくつかあり、感度違いで試してみようと思ったからです。
 磁気スイッチの磁力がどんなもんなのかもわかっていないので。

 +と-がありますが、磁石にS極N極ありますからそれです。+のタイプではホールセンサに対して上からS極を近づけると出力電圧が大きくなりN極を近づけると電圧が小さくなります。
 KS-20スイッチはN極が下側にあります。通常ホールセンサの下からN極が近づくので、+感度の製品を使用していそうです。

 電源ラインに0.1uFのコンデンサが必要なので、それも一緒に買います。基板はブレッドボードに刺せそうな感じでJLCに発注しました。

読み取ってみる

 まずは+45mV/mT (EA)で試してみます。

 pi picoでarduinoを使いホールセンサの出力を読み取ってみます。
 電源3.3VとGND、あとはホールセンサの出力をpi picoのADC端子につなぎます。

void setup() {
  // シリアル通信を初期化
  Serial.begin(115200);
  // ADCピンの設定 12ビット分解能(0~4095)
  analogReadResolution(12);
}

void loop() {
  // GP26(ADC0)からアナログ値を読み取り
  int A0Value = analogRead(A0);


  Serial.print(“A0,”);
  Serial.println(A0Value);

  delay(100);
}

 シリアルモニタにホールセンサの出力電圧を12ビットで表示されます。

基板のみの状態12801280/4095*3.3でおよそ1V出力されています。
スイッチを載せた状態1640およそ1.3V
スイッチを押した状態2560およそ2.06V
裏にスイッチを載せた350およそ0.28V
裏にスイッチを押した65およそ0.05V

 データシートに磁石ない時は1Vと書いてありますからその通りです。

 出力は0.2V~1.8Vのようです。arduinoでは0.05V~2.05Vで読みとられています。0.05Vのオフセットが入っているのかしら。
 使用範囲が0.2V~1.8Vに収丸用にするべきなのでしょうか。また表裏でスイッチを押したときホールセンサの出力が振り切ってしまっているのがわかります。EAの45mV/mTでは感度が高すぎるようです。もっと範囲の広いホールセンサを使用する必要があります。

 読み取り値をグラフにしてみました。
 基板のみ→スイッチを載せる→押す→裏にスイッチを載せる→押す

 結構値が揺れていることがわかります。これでは既製品でいっている精度0.01mmとか土台無理ですよね。電源と一緒に見てみたりしましたが、電源と連動して揺れているわけでもなさそうです。
 思うに想像ですが、カタログスペックの強いものはアナログ測定精度がものすごいんじゃなくて、スキャンレートを上げて、データ処理して、精度を向上してたりするんでしょうか。オンオフしかないキーボードごときでスキャンレート数百MHzなんだろと思っていましたがそういうのなんですかね。

 また、隣のスイッチから干渉したりしないのかと思っていましたが近くの磁力にしか反応しないようです。これは干渉を気にせずありがたい反面、できるだけホールセンサとスイッチは近く配置し可能な限り感度の高いホールセンサを使用する必要がありそうです。

感度

 スイッチと基板の間に追加でスペーサとして基板を挟み遠ざけて値を読み取ってみました。スイッチと基板の距離での感度の変化を見てみます。横軸が追加で設けた距離で縦軸が読み取り値(押し込み量0→4mm時の読み取り差分)です。

 0mmの時、先述のように頭打ちになってしまっていますから実際はもっと大きな数字を取っているはずです。スペーサ1~4枚を見てみると、線形ではないことがわかります。指数関数というか2次関数というかそういう感じです。距離が離れるごとに感度が悪くなっています。できるだけ近づけることは重要そうです。
 となると使用するホールセンサの感度ももう倍ぐらいのものが必要そうでしょうか。

平均

 値が揺れすぎていてなんもわからん状態なので平均を取ってみます。
 一回の読み取りに0.5ms程度で、直近50程度で平均を取ると揺れが収まってくる様子です。1000Hzのキーボードを作るとしたら1msに50回はスキャンしないとというところですね。

const int numSamples = 50;  // サンプル数
int A0Values[numSamples];
int A1Values[numSamples];
int sampleIndex = 0;
bool filled = false;

unsigned long lastPrintTime = 0; // 最後にシリアル出力した時間

void setup() {
  Serial.begin(2000000);
  analogReadResolution(12); // 12ビット分解能
}

void loop() {
  int A0Value = analogRead(A0);
  int A1Value = analogRead(A1);

  A0Values[sampleIndex] = A0Value;
  A1Values[sampleIndex] = A1Value;
  sampleIndex++;

  if (sampleIndex >= numSamples) {
    sampleIndex = 0;
    filled = true;
  }

  // ここで現在時間を取得
  unsigned long currentTime = millis();

  // 0.5秒(500ミリ秒)経ってたら出力
  if (filled && (currentTime – lastPrintTime >= 10)) {
    long sumA0 = 0;
    long sumA1 = 0;
    for (int i = 0; i < numSamples; i++) {
      sumA0 += A0Values[i];
      sumA1 += A1Values[i];
    }
    int averageA0 = sumA0 / numSamples;
    int averageA1 = sumA1 / numSamples;

    int timeMicro = micros();
    Serial.print(“time,”);
    Serial.print(timeMicro);
    Serial.print(“,A0,”);
    Serial.print(averageA0);
    Serial.print(“,”);
    Serial.print(“A1,”);
    Serial.println(averageA1);

    lastPrintTime = currentTime; // 最後に出力した時間を更新
  }
}

 平均をとるようにして個体差を確認してみました。

 ホールセンサの実装基板を複数用意し比べてみましたが差はADCの値1程度の差しかありませんでした。多少の実装精度、ホールセンサの個体差はそこまで深く考えなくてもよさそうです。
 一方でスイッチの個体差はADCの値で20程度はあり、結構差があるのかなあという感じ。スイッチを取り換えた際はキャリブレーションを実施したい気になりますね。またこの差はオフセットすることで解消できそうなので、割と単純かもしれない。

 また直近50の平均を取ってスイッチを押したり話したりしてみました。一回の読み取りが0.5ms程度だったので過去25ms間の平均なのでだいぶ遅延はありますが移動平均を取ると割ときれいに読めていますね。

とりあえずホールセンサの値を読むことができました。ただadcピンを読み取るだけなので単純であります。

 DRV5053は出力が0-2Vでしたが、0-3.3Vで出力してくれる例えばdrv5055とかの方がSNも解像度も上がってよさそうです。
 45mV/mTではクリップしてしまったため適切な感度のものを選ぶ必要があります。
 読み取り値が揺れまくるので、マイコンもスキャンレートをより早くできるものを実戦では使う必要がありそうです。

 ホールセンサの買いなおしとデータ処理の仕方など検討する必要があります。マイコンボードもより高速なものを使いたいですね。とりあえず安いのでpipico2でしょうか。
 ホールセンサの向きも考えなくては。どうせケース下に基板を配置するのならば-感度にした方がスイッチとセンサーの距離が近くすることができます。

コメント

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