トラックボールを作る


これ、ジャンク屋で見つけました。知る人ぞ知るトラックボール。業務用映像機器で一世を風靡したテロッパー(※)のコントローラーです。通称「きりばり君」。一般的に出回る事が無く、一世を風靡したのが90年代と古いですので、かなりのレア物と言えます。衝動買いをしてしばらく眠らせていましたが、もったいないので、Pro Micro(Arduino Leonardo互換機)で現在のPCでも使えるようにしてみましょう。
(※テロッパー・・・テロップを入れる機械)
写真

中を開けてみると、手垢ですごい事になっていました。年季が入っています。うわーー。(拡大グロ注意)
写真 2013-04-20 17 22 56

部品をすべて外して、洗剤とエタノールでゴシゴシ洗って組み立てた結果。だいぶ綺麗になりました。
写真 2014-02-24 22 21 54

ボールの回転部を感知するロータリーエンコーダ部。エンコーダーで有名な多摩川精機製だということがわかります。
写真 2014-02-24 22 22 10

ボールを置くとこんな感じ。右側の2個のスイッチはそのまま、左右のクリックに使えそうです。
写真 2014-02-24 22 19 04

 

ハードウェア

D-subコネクタに繋がるピンアサインも控えておきます。回路図から起こしたピンアサインは、こんな感じ。回転を検知するエンコーダーからは、インクリメンタル型の信号が出ています。
写真 2014-02-24 23 26 43ピンアサイン

このD-subにつながるのが、前回作ったこのPro Microとケース。ようやく役に立つ日がきました。
Picture 32

配線図はこちら。INPUT_PULLUPを使って抵抗を無くすことで配線を簡略化しています。INPUT_PULLUPについて詳しい説明は(意外と知られていない?INPUT_PULLUP | スイッチサイエンス マガジン:
回路図

配線の完成写真。配線のみですっきりしています。
Picture 42

ソフトウェア

Arduino Leonardoは、簡単なソフトウェアを書くことで、USBのHID(ヒューマン・インタフェース・デバイス)としてパソコンから認識されるデバイスになります。つまり、USBマウスや、USBキーボードなどを作れるという事です。互換のPro Microにも当然同じ機能があります。詳しくはこのあたり(Guide/ArduinoLeonardo – スイッチサイエンス)(Arduinoリファレンス – Leonardo専用

プログラムは、ボタンからの信号をマウスクリックと、ロータリーエンコーダーからの信号をマウスの移動としてパソコンに送る2つの機能からなっています。

マウスクリックは、ボタンを押したらクリックON信号を出し、離したらクリックOFF信号を出すだけと簡単ですが、ボタンにはチャタリングという現象がありますので、それを考慮したプログラムになっています。チャタリングは、ボタンを押した瞬間に、接触の関係でON/OFFを繰り返すという現象で、そのままクリック信号にしてしまうと勝手にダブルクリックをしてしまうなどの現象になります。それを防ぐために、ボタンのONが安定したらクリックON信号を出すという事をしています。

 

マウスの移動はちょっと複雑です。
ロータリーエンコーダー1個から出てくる信号は、2bitです。信号を定期的に読み、0/0→1/0→1/1→0/1と変化するパターンが順方向と仮定し、反対だと逆方向に進んでいると読み取れます。

しかし、ロータリーエンコーダーが高速で回転している場合、正確に読み取れない事があります。

sam

実際に、考慮せずプログラムを書くとトラックボールを早く動かした時に、カーソルが止まってしまったり逆方向に動く事がありました。

解決方法として「エラー」となってしまった時には、前回動いている方向へ動かせば読み取り精度が2倍になり、「逆方向」となっている場合も活かせば3倍になります。そこで「変化無」から最初に動いた方向に向きを固定し、「エラー」でも「逆方向」でもその方向へ動かすようにしました。
最初の方向のサンプリングを読み間違いが多いと逆方向に全力で移動すると思いましたが、案外おかしな事にはならず、いい感じです。

以上の動作をすべて同時に動くようにプログラムしますが、マルチスレッドなど贅沢な制御はありません。そのため、例えばボタンONの信号が安定するまで待っている処理を書くと、その間マウスの移動が出来なくなってしまいます。

時間のかかる処理をどうするかというと、ある機能のタイマー関数を用意し+1して次の処理へ行き、10以上になったら信号を出すというような処理をしています。

フローチャート

できたプログラムがこちら。

プログラムは、共通部分が多いですが、あえてベタ書きしています。

「順方向」では1、「エラー」では2、「逆方向」では20 or 25の移動量と変則的に設定しています。それは、使いながら求めた値です。
水平の移動量と垂直の移動量を微妙に変えてあったり、微妙な調整が可能です。使っていると「あ、もうちょっとこうしたい」という事もあり、機械に自分を合わせるより、機械を自分に合わせられるのは、自作の醍醐味ですね。

写真4

作ってみて気が付いたのですが、私はトラックボールが好きなようで前にも作っています。イージス艦の戦闘指揮所にもトラックボールが使われているみたいなので、もし入手できたらUSB化を行ってみたいですね。


参考:橋本商会 » Arduino – ロータリーエンコーダ改:

9 コメント
  1. ひろ より:

    こんにちは。質問があるのでお手数ですが教えてもらえますでしょうか?

    ArduinoでオリジナルQWERTYの109キーボードを作りたいと思っています。
    Arduino Leonardを使用しています。

    いくつかサンプルスケッチを書き込んで実験しましたが、市販のキーボードと同様の動作「キーを押している間だけ文字入力される」という挙動ができませんでした。
    英数字キーはもちろん、スペースやエンターも押しっぱなしで、連続して入力するなどです。

    こちらのマウスのスケッチを試したところ、左クリックボタンでは、押している間のみクリック(キー入力≒信号の連続送信)ができているのを確認しました。

    キーボードでも同様の挙動ができるようにしたいのですが、スケッチの書き方を「Aキー」の入力だけで結構ですのでご指導頂けませんでしょうか?

    Keyboard.press()を使って、スイッチ離した時に、Keyboard.release()が処理されるような挙動がいいのですが実現できていません。
    109キーボードを再現したいので、アナログではなく、デジタルピンを使う必要があると思っています。

    よろしくお願いいたします。

    • ichirowo より:

      Keyboard関連は手馴れていないので想像で書いている部分がありますが、Keyboard.press()実行しっぱなしにした後に「1文字入力、ちょっと間があって連続入力」が出来ない、という事でしょうか?

      だとしたら、おそらくKeyboard.press()をONにし続けただけでは、本物のキーボードを押したように連続入力はしない仕様なのでしょう。

      スイッチの入力があった時にKeyboard.press()・delay(任意のm秒)・Keyboard.release()を実行し、まだ入力があった場合は秒数をカウントして、本物のキーボードのようなキー入力をシミュレートするようなタイミングで出力するプログラムを組むしかないと思います。(もちろんチャタリングを考慮したり、Shiftなど長押しキーはその挙動をしないようにプログラムを分岐します)

      ちょっとプログラムが面倒ですが、間の時間の設定が自分の思ったタイミングにできるなどメリットもあると思いますので、頑張ってください。

      >109キーボードを再現したいので、アナログではなく、デジタルピンを使う必要があると思っています。
      キーはON/OFFの情報しかありませんので、デジタルピンでの入力が必要かと思います。ただアナログピンもデジタル入力ピンとして使用できるので、使えなくもないと思いますが、109のキーを入力するにはピンが足りないと思います。

      キースキャンをする方法で多くのキーの入力ができると思いますが、そのあたりの知見がありませんので、すみません詳しくお答えできません。。。。

  2. ひろ より:

    ichirowoさま

    さっそくのご返答ありがとうございます。
    ちょっと問題と考えを整理したいと思います。
    後日またこちらで記載させて頂ければありがたいです。
    よろしくお願いします。

  3. ひろ より:

    >Keyboard関連は手馴れていないので想像で書いている部分がありますが、Keyboard.press()実行しっぱなしにした後に「1文字入力、ちょっと間があって連続入力」が出来ない、という事でしょうか?

    一般の文字入力されるノートパッドなどのソフト上ではそうなのですが、それぞれのキーに対し違う動作を当てているソフトもあります。

    テキスト入力のみであれば、おっしゃるようなプログラムを組むことで解決する部分があるのですが、
    汎用キーボードと同様の動作をさせる場合は、一文字記入し0.5秒後に毎秒10文字の文字を記入する仮想信号をキーボードから出すのではなく、
    キーボードからはキーを押している間のみキーの信号を送り続け、OSやソフトが上記の動作を決定させなくてはいけないと思います。

    >だとしたら、おそらくKeyboard.press()をONにし続けただけでは、本物のキーボードを押したように連続入力はしない仕様なのでしょう。

    スイッチを押した時にKeyboard.press()のONのコマンドは、ほぼ汎用のキーボードと同様の信号をArduinoから出ていると思えます。
    しかし、
    「デジタル回路にて、スイッチを離した時にKeyboard.release()を指示するコマンド」が見つかりません。
    結局、永遠にKeyboard.pressされるか、delayにより固定した間隔でのみのKeyboard.pressしか実現できていません。

    アナログ回路では、ある程度の電圧をかけた上で、
    スイッチonにより指定電圧以上となったらKeyboard.press
    スイッチoffにより指定電圧以下となったらKeyboard.release
    このようなプロブラムを組めそうなのですが、100以上のキーどころか26アルファベットすら困難だと思います。

    「デジタル回路にて、スイッチを離した時にKeyboard.release()を指示するコマンド」
    現在、ここが一番の壁に思えています。

    これに関しプログラムや回路配線上で解決することは難しいのでしょうか。
    もしご存知なら教えてもらえばありがたいです。

    よろしくお願いします。

    • ichirowo より:

      ちょっとしたプログラムを書いてみました。
      ハードウェアは、このトラックボールの左クリックボタンを使用しています。ボタンの先の詳細図面はブログ上にはありませんが、16PinがスイッチON状態だとGNDとショートする状態です。デジタル入力Pinです。

      —————————————-
      //入力ピン設定//////////////////////////////////////////
      #define LclickPin 16 //左クリック入力ピン

      void setup() {
          pinMode(LclickPin,INPUT_PULLUP);
          Keyboard.begin();
      }

      void loop() {
          if(digitalRead(LclickPin) == LOW){
              Keyboard.press(‘A’);
              
          }else{
              Keyboard.release(‘A’);
          }
      }
      —————————————-
      これだけで、ボタンを押し続けた場合「1文字入力、ちょっと間があって連続入力」が実現できますね。

      >だとしたら、おそらくKeyboard.press()をONにし続けただけでは、本物のキーボードを押したように連続入力はしない仕様なのでしょう。
      →という事はありませんでした。

      「デジタル回路にて、スイッチを離した時にKeyboard.release()を指示するコマンド」に関しては要件を満たしていると思いますが、こういった事でしょうか?
      もし、思い違いをしているのであれば、ご指摘ください。

  4. ひろ より:

    ichirowoさま

    サンプルのプログラムありがとうございます!
    思った通りの動作をしました。
    素晴らしいです。

    シフトキーとの組み合わせをした場合も大丈夫でした。

    もしかするとArduinoでは期待通りのインプットの挙動ができないのかと危惧していました。

    次はキーマトリクスのスケッチを頑張って書いてみようと思います。

    取り急ぎ、お礼まで。

    P.S.Twitterフォローさせて頂きました(^^)

コメントをどうぞ

*