Release 2017.4.20 / Update 2017.10.22

ロータリーエンコーダを使うpart 2 : Non-Click type

前回、ロータリーエンコーダの効率的な読み方について書きましたが、あくまで「クリック付き」タイプについてのものでした。

今回は「クリックなし」のエンコーダを使って、分解能を4倍に引き上げた読み取りに挑戦します。勿論、スケッチ上だけの処理です。

今回紹介するものは「完璧」ではないので、それを求めるなら、「アブソリュート型」といった高級で精度の高いパーツや、回路を使用することをオススメします。ただ、自分的には、これだけ出来れば充分なレベルかな、と。

この記事の更なる改善版スケッチは Part 3へ (2017/10/22)

回路図

「クリックなし」タイプのロータリーエンコーダ。あと、なくても構いませんが、確認用にLEDを1つ。いつも通り、エンコーダAB相はArduino内部プルアップ接続です。

ロータリーエンコーダ

一般的にロータリーエンコーダは、4つのずれた接点が並んでいて、今の組み合わせと、前回の組み合わせを照合することで、「進んだ」、「戻った」の判断をします。そして、「クリックあり」のタイプは、4つの組み合わせを1クリックとして認識させています。例えば、20クリックのエンコーダなら、1回転で80回接点が切り替わっているわけです。

それを全部拾えたとしたら、エンコーダをもっと細かくコントロールできるはず。つまり、「分解能が上がる」ことになります。これがやることの今回の目的です。

「クリックなし」タイプのロータリーエンコーダは普通に手に入ります。

ただし、これらは1回転あたりのクリック数が低いものが多く、そうでないものを探すのは大変です。そこで、クリック付きで多いものを選び、物理的に「クリック」を外してやる方法があります。

エンコーダの改造

改造は自己責任で行ってください。

この分解能を上げる方法は、この「クリック無しへの改造」の記事を読んだのがきっかけです。

クリックの仕組みは中の回転台にデコボコと突起が噛み合って発生していますが、その突起と絡まないようにすればクリック「付き」が「なし」になります。

自分が見つけたもので一番クリック数のあるエンコーダはこちらですが、今回の説明では、手元で遊んでいたこのエンコーダを使います。

このエンコーダは1回転24クリックです。つまり、全部拾えれば1回転で96の分解能になります。

土台を繋ぎとめているカシメを外す
切り離すと、エンコーダの原理部分である接点が見える
更につまみと切り離すと、クリックを与える機構が見える。この金属部分を引っかからなくなるよう曲げてやれば、クリックがなくなる

多分、エンコーダごとに細かい仕組みが違うと思うので、あくまで参考です。

スケッチ

スケッチにミスがあったので修正し(Ver1.1)、多少読み取りが改善しました(2017/10/16 追記)
更なる改善版は Part 3へ(2017/10/22 追記)

このスケッチは“外部割り込み”ではなく、「MsTimer2」ライブラリを使って、“タイマー割り込み”動作をしています。IDEにインストールされていなければ「ライブラリを管理」から入手してください。

このプロジェクトファイルをダウンロードするか、

Sketch:High Resエンコーダ

下記のコードをコピペして使ってください。

うまくコンパイル出来ない場合、こちらを読んでください。

ダウンロードのプロジェクトファイルの方が、タブでセクション分けしているので、自分のプロジェクトに合ったコードを付け足していきやすいと思います。

使い方は簡単で、ENC_COUNT()関数に任意の変数を投げれば、エンコーダの変化を反映した値が帰ってきます。

スケッチの“void Loop”内に書かれているサンプルでは、変数valをシリアルモニタしているので、数値が確認できると思います。

また、シリアルプロットで見ると、視覚的に動作を確認できます。(Ctrl+Shift+M)

早い動きでは、やはり取りこぼしがありますが、数値が明後日の方向へ飛んでしまう極端な振る舞いはしないと思うので、そこそこの速さなら、かなり安定した操作が出来ると思います。

取りこぼすとギザギザになる

現段階では他のルーチンと合わせてプログラムを組んでいないので、大きなスケッチになってきた時、どれだけ対応できるかは保障できません。なので、試した方は感想や状況なんかをコメントに残して置いていただけると嬉しいです。

最後にどういう考え方で書いたか解説を書いておきます。気になる方はどうぞ。

解説

まずはチャタリングがどれだけ起きるのか、実際に確認してみる必要があります。

チャタリングを見る

外部割込みを使って、ピンの変化を記録、表示します。外部割込み中にシリアルプリントしてしまうと、表示にかかる遅延で正確に見れないと思うので、「ピンの変化」と「経過時間」を大きな配列で用意しておき、落ち着いたらまとめて表示するようにしています(ちょっと配列の入れ方が間違っているので、最初と最後が正確ではありません)。

シリアルモニタには、チャタリングで安定していないモノも含めた変化の流れが帰ってきます。アルファベット「A~D」が2つのピンのパターンなので、1目盛分の動きでかなり行ったり来たりしているのが分かります。

その回数はバラつきがあって、素直に一回で変わる時もあれば、100回以上繰り返している時もあります。早く回すと、どこが切り替わりのポイントか分かりません。

方法論

上記の検証から、外部割込みをしたところで、正確な変更を拾える保障はありません。

そこで、いっそのことタイマー割り込みで頻繁に読み取り更新をかけ、おなじみの“ゲージ判定”で、位置が変わったのかどうかを判断するような仕組みにします。

  • 確定している位置“Home” Position
  • 最新の読み取り位置“Current” Position

これらを比較して、動きの判断をします。

“ゲージ判定”を使った、スイッチ読み取りライブラリを作ってみました。(2017.6.26 追記)

HomeとCurrentが違う位置を示せば、「エンコーダが動き始めたかもしれない」ことを判断する“Trigger”が入り、その合図きっかけで、集中的にABピンの読み取りを繰り返します。

動いたか、動いていないかのgaugeを2つ用意し、天秤にかけ、先に既定値(ENC_JUDGE)に到達したほうを採用。動いていれば、“Home”を更新してカウンターを増減、そうでなければ破棄します。どちらに転んでも、判定が終われば“gauge”と“Trigger”はリセットし、次の変化を待つ。

これの繰り返しでエンコーダを読んでいきます。

関数など

エンコーダのパターンは2bitで表現できるので、1byteのグローバル変数「enc_status」を作り、エンコーダのピン状態はここにまとめて織り込みます。各ビットの配置は以下の通り。

これらはビット演算子で簡単に書き換えられるようにします。まず、そのための関数を作ります。

次に、ピン状態を読む関数を作ります。

タイマー割り込みさせるのはENC_GAUGE()関数です。ここで繰り返し読み込みの判定、カウンターの増減、諸々のリセットをしています。

変更されたカウントはすぐに反映するのではなく、ENC_COUNT()のカウンターで管理させることで、数値のやりとりにすれ違いを出させなくし、また、色んな変数へ柔軟に代入できるようになります。

調整

今回のスケッチはArduinoUno用に書きましたが、使うマシンによって処理スピードが変わってくるので、反応が変わってくるかと思います。その場合、いくつか定数をいじることで改善するかもしれません。

  • ENC_JUDGE
  • TIM::set(1, ENC_GAUGE);

ENC_JUDGEはTriggerON時の、ピン読み取りの繰り返し回数と既定値に絡んでいます。ここを変更すると切り捨て度合いが変わってくるので、うまくいかない場合はいじるといいかもしれません。

また、タイマー割り込みは1msに設定されています。これ以下には出来ませんが、反応が早過ぎるときは、逆に落とすとうまく作用するかもしれません。

こうやって一行ずつ解説を書くと、試行錯誤していく中で意味が無くなってしまった部分もあったりするなあ、と。前回分とか、チャージのビットとか。まあ、そこら辺は気になれば消して使ってください。

参考リンク

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください