HOME >> 鉄道模型実験室 > ロータリエンコーダを使ってみた その1
以前から注目していたロータリエンコーダについて、触ってみることにしました。使い方やArduinoでの処理の方法などを学び、何に使えるのかも考察することにしよう。
■ 使用するエンコーダについて
取り扱うロータリエンコーダは特別に入手したわけではありません。「μ特性を測定しよう 測定装置の検討」(2025/8/30)にて入手したエンコーダ付きのギヤードモータに装着してあったもので、このエンコーダを使ってみることにしたのです。製品は、
このエンコーダボードは、磁気ディスクの回転を感知する2個のセンサを備えており、そのAとBの両チャンネルのによってモータシャフト1回転あたり12カウントの分解能となる直交エンコーダ仕様なのです。磁気ディスクとセンサ処理基板を下に示します。
モータに取り付けた状態を下に示します。
配線は、センサ部の+5とGND、およびパルス出力端子AおよびBに加えて、モータ給電用の別回路の2本を含めて、合計6本必要です。パルス出力は整形済みで出力されるので、Arduinoのポートに直接接続可能です。楽々ですね。
■ エンコーダのパルスカウント方法
始めて使用するので、使い方をネットで調べました。色々な解説がありましたが、直交エンコーダ仕様を使用した4倍方式の処理方法をトライしてみます。この方法はA相とB相の二つのパルスをもとに、回転方向の判別と共に、分解能も4倍となる方法だそうです。二つのパルスは位相が90度ずれているので “直交” 方式と言うそうですがこれが制御のポイントとなると理解しました。
今まで自分が実施してきたパルスカウント方法は、白黒マークをフォトセンサで読み取り、パルス成形後にカウンタICを使ってカウントさせます。カウントが指定回数まで達する経過時間を使用して回転数を計測していました。
このエンコーダでは、出力されたパルスをコンピュータの割込み処理を使用して、インクリメンタル方式で直接カウントさせるのですが、 “直交” 方式に対応するするロジックを使用して処理を実施していました。そのロジックは色々な解説がありましたが、理解するには紹介されていたスケッチの内容を読み取って行く必要があり、半日程度かかってしまいました。変換テーブルの意味やビット操作など、頭の優秀な先人さんが工夫したようです。脱帽です。
応用させていただいたスケッチの内容は下に示しますが、変換テーブルの意味や内容についてはネットの解説記事を参照にしてください。ちなみに自分が参考にしたサイトは、 〜廃材連盟〜 “Arduino でロータリエンコーダを使う” です。
■ 実験のねらいと実験装置
今回使用するエンコーダはモータと一体となっていますので、このモータを使って実験することになります。実験の第1のねらいはエンコーダの勉強ですので、処理回路を含めてなるべく簡単な実験とすることにしました。
そこで、電気回路が最も簡単なモータの逆起電力を測定する回路にしました。この測定は、モータの端子はオープンとし、この端子に発生する電圧だけを測定すれば良いのです。当然ながらモータの回転数を測定する必要があるので、そのために、エンコーダを使用します。実験の様子を下に示します。
モータ周りの様子を下に示します。
// Moter-Measure-8-1 2026/2/5
// モータ特性測定 エンコーダ使用
// 割込み D2 D3
#define PIN_A 2 //割り込みA
#define PIN_B 3 //割り込みB
#define START_PIN 7 //スタートスイッチ
#define vol_pin 0 //電圧測定アナログ
const int8_t ENCODER_TABLE[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
//参照用テーブル
volatile bool StatePinA = 1; //true か false の値をもつ
volatile bool StatePinB = 1; //true か false の値をもつ
volatile uint8_t State = 0; //State変数を8ビット整数とする
volatile long Count = 0;
unsigned long value;
void setup() { //セットアップ
pinMode(PIN_A, INPUT_PULLUP);
pinMode(PIN_B, INPUT_PULLUP);
pinMode(START_PIN,INPUT);
attachInterrupt(0, ChangePinAB, CHANGE); //割込発生時に実行する関数を指定
attachInterrupt(1, ChangePinAB, CHANGE); //割込発生時に実行する関数を指定
Serial.begin(9600);
}
void loop() { //メインループ
int start;
int vol;
unsigned long t1;
start = digitalRead(START_PIN);
while (start == HIGH) { // スタートスイッチを待つ
start = digitalRead(START_PIN);
}
t1 = millis(); //測定時刻を読む
update_value(); //カウント数を読む
vol = analogRead(vol_pin); //電圧を読む
String buf = String(t1)+","+String(value)+","+String(vol); //文字列作成
Serial.println(buf); //シリアル通信送信
delay(1); //時間調整:
}
void ChangePinAB(){ //割込み処理関数
StatePinA = PIND & 0b00000100; //D2ポートの値を読む
StatePinB = PIND & 0b00001000; //D3ポートの値を読む
State = (State<<1) + StatePinA; //左に1ビットシフトして加算
State = (State<<1) + StatePinB; //左に1ビットシフトして加算
State = State & 0b00001111; //下位4ビットだけ有効にする
Count += ENCODER_TABLE[State]; //テーブルのState番目の値をCountに加算
}
void ChangePinAB()){ //パルスカウントを読む
noInterrupts(); //割込み無効
value = Count; //カウント数を読み取る
interrupts(); //割込み有効
}
● 実験方法
逆起電力はモータ軸を強制的に回転させ、その時にモータ端子に発生する電圧を測定して、回転数と電圧の関係を求めることにより算出可能です。この時の装置の配置を下に示す。

まず、駆動部はタミヤのテクニクラフトシリーズNO.5 の6速ギヤボックスHE を使用しました、ギヤ比は、76.5:1 の設定にしました。この駆動部とギヤドモータをタミヤのユニバーサルジョイントで写真のように連結しています。
駆動モータは安定化電源の電圧を変化させて回転数を調整します。ギヤドモータの端子は、アナログ入力端子とGND端子に直接接続して電圧を測定し、ロータリエンコーダの出力端子は割り込み処理が可能なD2トD3ポートに連結しています。電源はArduinoの+5を使用しました。
さらに、測定実行の指令を操作するため、ON/OFFスイッチを追加しています。何時ものプルアップ回路としています。
● スケッチの内容
Arduinoに書き込んだプログラムを右に示します。メインループには、参照したスケッチに測定時の時刻と電圧値を取り込んで、パルスカウント数と共に、コンマ区切りのデータとしてシリアル通信で送信するようにしました。
また、このメインループのサイクルタイムを調整できるようにdelay() 関数を挿入しています。
void ChangePinAB() は、割込み処理時に実行するサブルーチンで、void ChangePinAB()は、割込み処理で計算されたカウントを読みに行くサブルーチンです。
この割込み処理時に実行するサブルーチンは、変換テーブルの意味やビット操作などの意味を理解する必要がありましたが、その工夫には脱帽です。左に1ビットシフトという事は、その数値を2倍することであるに気が付いたのが取っ掛かりでしたね。
■ 通信データの受信と処理方法
さて、準備ができたのですが、データの受取り方法を検討しました。今まで実施してきた方法は、システムの状態が一定の状態である時に測定を実施する、即ち静特性値を計測する方法でしたので、1〜3秒かけて計測していました。
しかし、今回はミリ秒オーダーでの計測にも挑戦しようとしています。これは、変化する回転状態を計測しようと欲張っているからです。
このためには、
を検討しておく必要があります。
● サイクルタイム の計測
まず、簡単な方法として、シリアルモニタにて受信データを表示させ、コピー/ペーストによってデータをExcel に張り付ける方法にてサイクルタイムを調べてみました。送られてきたデータの中の、測定時刻を読み取った t1 の値の差を行ごとに計算し、その値を調べたのですが、delay(1) の場合でも 15msec もかかっていました。そんな馬鹿なと考えて、delay() の値を色々変えて、送信されてくる時間間隔(タイム)をグラフに表示したのが下左のグラフです。

なんと、びっくりですね! delay(15) 辺りで直線が変化しています。送信されてくる時間間隔(タイム)の単位はmsec ですが、その差は、0〜2msec の範囲です。これはプラグラムが非常に正確にサイクルを刻んでいることを示しています。そして、グラフは、これらの50個近くのデータの平均を取って表示しています。
右上がりの直線部分のデータより近似直線のY切片の値が、本来のサイクルタイムと睨んでいるので、下の方の横一線の範囲は、プログラム処理以外、即ちハード部分の要因で時間遅れが発生しているのではないかと推定しました。
その要因は、シリアル通信の通信速度によるのではないかと考えて、通信レートを 9600 bps から 115200 bps に上げて実験したのが右のグラフです。
横一線の範囲が消えています!
自己流の推定として、CPUの処理は 0.7msec のサイクルタイムで処理を終わっているが、通信ハード系の処理に時間がかかるため、待たされているのではないかと考えました。通信速度を早くすると処理時間が追い付いてくるので、横一線の範囲は発生しないのでは無いかと考えられます。とにかく、処理速度を早くしたい場合には、通信速度も考慮する必要があると言うことですね。
この件に関して、ネットで調べてみました。すると、“シリアルのBAUDレートは実行速度に影響しますか?”の質問に対して明快な回答が寄せられいました。Arduinoにあるシリアルバスのバッファに溜まったデータの処理時間が関係するとのことでした。
● 受信データの記録方法
つぎに、受信データの記録方法を検討する必要があります。上記のシリアルモニタのデータをコピー/ペーストでデータを記録する方法では対応できないのは明らかです。かといって、今までのように、Excel シートに直接書き込んで行く方法では時間的に間に合いません。
などがリストに上がりました。そこで、もっとも簡単そうな Data Streamer を使う方法についてトライしてみることにします。
■ ロータリエンコーダでのデータ取得状況
ところで、本来の目的であるロータリエンコーダによるデータ取得状況を見てみましょう。その報告は次回のその2で報告します。
************************************************
2026/2/8