ギタコンの自作 試作2

ギタコン試作1で出たいくつかの問題を修正します。 (ギタコン作成のための環境構築が既に終わっているので、ここから先は楽ちんです)

試作1の問題点一覧

  1. 最初のキーアサイン時に、なぜかLEFTが自動設定されて、上入力が入りっぱなしになる
  2. 反応が悪い(反応が遅い)
  3. チャタリングする
  4. ボタン(スイッチ)が小さすぎて、使いにくい (これは試作3で対応します)
  5. ボタンが足らない (これも試作3で対応します)
  6. ピックをスティックにしたい (これも試作3で対応します)
  7. 配線が操作の邪魔 (試作4で対応します)
  8. コントローラーを動かしてのwailingができない (試作4で対応します)
  9. 筐体が無い (試作5で対応します)

ここでは、1~3について改善をしていきます。

最初のキーアサイン時の動作異常を改善する

「最初のキーアサイン時に、なぜかLEFTが自動設定されて、上入力が入りっぱなしになる」現象について。 これが発生する理由は、Joystick Libraryの仕様上、軸入力(X,Y,Z)が全部(中央値ではなく)0で初期化されるためです。 X軸の入力における0は左を、Y軸の入力における0は上を意味するため、 キーアサインの変更を始めた瞬間にまずX軸入力(0=左)が取り込まれてLEFTがアサインされ、 その後Y軸入力(0=上)に反応して上が入り続けます。

# 左も入りっぱなしになっていますが、キーアサインの画面で左を入力しても意味がない

この現象は、Joystick Libraryに「軸入力は使わない」ことを(Joysick_クラスのコンストラクタで)宣言することで、発生させなくすることができます。

具体的には、以下のようにします。

JoystickButton.ino のスケッチを開いて、14行目あたりを

Joystick_ Joystick();
から
Joystick_ Joystick(
  JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
  4, 0,                 // Buttons, Hat Switch Count ボタンの数を4から6に増やす
  false, false, false,  // X,Y,Z Axis
  false, false, false,  // Rx, Ry, Rz Axis
  false, false,         // rudder, throttle
  false, false, false   // accelerator, break, steering
);
に変更します。 これで、「ボタンを4つ使い、それ以外の軸入力は使わないジョイパッド」として動作するようになるため、 先の問題は発生しなくなります。

スケッチを修正したら、「検証」と「マイコンボードに書き込む」ことをお忘れなく。

また、このスケッチはこれまでとは別のファイル名で「名前を付けて保存」しておくのが良いです。 (これからの試作でこのスケッチをどんどん修正していくので、サンプルファイルとは別のファイルとして保存しておくべきです)

なお、一度スケッチをArduino Microに書き込んでしまうと、以後はCOMポートがPCに認識されなくなり、 書き込みに失敗するようになります。そのため、書き込みのタイミング(マイコンボードに書き込んでいます、と表示されたタイミング)でAruduino Microのリセットボタンを2連打してください。 するとしばらくの間だけCOMポートがPCに認識され、書き込みができるようになります。 ただ、この時にCOMポートの番号が以前と変わるようですので、一度リセットボタンを2連打してポート番号を確認してから 「ツール」 - 「シリアルポート」 を設定し直して、そのあとでもう1度リセットボタンを2連打して、書き込みを実行するとよいでしょう。

反応が悪いのを改善する

試作1のギタコンを使ってみてすぐにわかることは、ボタンの反応が悪いこと。

こうなる理由は簡単で、Arduino Microでのボタンのスキャン間隔が50msになっていることです。 (3フレーム描画する毎に1回、ボタンの入力をチェックしているような状態)

これも、スケッチの修正で対応できます。先ほど使ったスケッチを開いて、最後にある

  delay(50);

を、

  delay(1);
にします。これで、1ms毎にボタンがスキャンされるようになりました。簡単ですね。

チャタリングを改善する

チャタリングとは、簡単に言うと、ごく短時間の間にスイッチのON/OFFが連続して入ってしまう現象のことを指します。

具体的には・・・例えばスイッチを押してONにしたときの動作を考えてください。 金属の接点がつながって電流が流れるようになりスイッチがONになる・・・のですが、 このスイッチがつながる瞬間に、物理的に金属が振動して、ごく短い時間(数ms~数十ms)の間だけ、ONとOFFが数回切り替わってしまうのです。 人間はこの切り変わりが速すぎて気づきませんが、コンピュータはこの変化を検出して、コントローラーの入力としてのON/OFFを切り替えてしまいます。

ここまでの説明でお分かりかと思いますが、チャタリングが (入力がシビアな音ゲーで使う) ギタコンで発生するのは、致命的ですよね。

# ちなみに、試作1で使ったタクトスイッチの場合、この振動時間は最大5msとのことです。(同タクトスイッチの仕様書より。)

さて、それでは、この問題をどのように解決すればよいのでしょうか。

ソフトウェアでの解決策と、ハードウェアでの解決策があります。

ソフトウェアでの解決策は、「ボタンの状態が切り替わったら、以後数msの間は、万が一状態変化があっても無視する」ようにすることです。 これはArduino Micro側でスケッチを修正して対策してもよいし、DTXMania本体のソースコードを修正して対策してもよいです。

以下、Arduino Micro側のスケッチでチャタリング対策をした例を挙げます。具体的には、あるボタンの状態が変化したら(OFF→ONになったなど)、10msの間は状態を変化させないようにしています。(私はどう頑張っても20msより速くボタンを連打することができませんでした。そのため、その半分の10msで閾値を設定しておけば大丈夫かなと思いました。まる。)

(中略)

// Last state of the button
int lastButtonState[4] = {0,0,0,0};
unsigned long lastButtonChangedTime[4] = {0,0,0,0};

void loop() {

  // Read pin values
  for (int index = 0; index < 4; index++)
  {
    int currentButtonState = !digitalRead(index + pinToButtonMap);
    if (currentButtonState != lastButtonState[index])
    {
      unsigned long t = millis();

      if (t > lastButtonChangedTime[index] + 10)
      {
        Joystick.setButton(index, currentButtonState);
        lastButtonState[index] = currentButtonState;
        lastButtonChangedTime[index] = t;
      }
    }
  }

  delay(1);
}

なお、ハードウェアでの解決策は・・・RSフリップフロップ回路の追加やシュミットトリガ回路や・・・なんですが、「簡単さを最優先にしてギタコンを作る」というコンセプトから外れるため、ここでは説明を省略します。

なお、通常よく使われるチャタリング対策は、「ON/OFFの状態が安定するまで待つ」というものです。この場合、安定するまでの時間が入力遅延となります。一般的な用途では数十ms程度の入力遅延が許容されることが多いため、その方法で問題が出ないのですが、ギタコンでのチャタリング対策としては当然ながら使えません。ご注意ください。(例えば、「ハードウェアでの解決策」の例で挙げた「シュミットトリガ回路」は、遅延が発生します)

まとめ

試作2では、以下の改善を行いました。

  1. 最初のキーアサイン時に、なぜかLEFTが自動設定されて、上入力が入りっぱなしになる問題を修正
  2. 反応が悪い(反応が遅い) 問題を修正
  3. チャタリングする問題を修正。

試作2のスケッチ全体をダウンロードできるようにしました。ご活用ください。 gtcon-03_.zip

ご参考

チャタリングについては、この辺この辺が参考になりました。