Arduinoでエンコーダ付きDCモータを操作する方法

この記事で学習できること

  • エンコーダ付きDCモータ(SGM25-370)をArduino UNO R3に接続して操作します。操作の過程でエンコーダ周辺回路、エンコーダの仕組み、そしてエンコーダ出力の計測方法を学習します。

エンコーダ付きDCモータのメリット

  • エンコーダ付きDCモータを採用する主なメリットを一言で言えば「モータの状態をリアルタイムで把握し、正確に制御できること」にあります。通常のDCモータは電圧をかければ回転しますが、負荷の状態によって回転速度が変わってしまい、正確な位置で止めることも困難です。エンコーダはその課題を解決します。

DCモータ(SGM25-370) DC:6V RPM: 130の仕様

● 直径25mmのDCモータに減速ギヤとエンコーダを加えたモータは色々な種類が販売されています。電圧6V、減速後の出力が130RPMのモータを購入しました。

諸元特性/仕様
定格電圧6V
回転方向時計方向/反時計方向
シャフト径φ4mm (D外形部 3.5mm)
シャフト長さ12mm (D外形部 8mm)
重量約 100g
ギヤ比 (減速比)45:1
エンコーダーホールエフェクト式の磁気エンコーダ2相(A相・B相)
エンコーダ出力モーター1回転あたり 11 パルス

● エンコーダのパルス数はギア出力を通すと 11 × 減速比(45:1) ≒ 495 パルス/回転 となります。

1. DCモータの外観

● 全長は約74mm

— SG25-370 外観 —

2. DCモータのコネクタピン配置

  • エンコーダ部に6ピンのコネクタが実装されており、モータ端子およびホー素子ICに接続されています。
  • DCモータのシャフトにSNに着磁された磁石が取付られており、ホール効果ICが磁界の変化を検出します。
エンコーダ部の外観
— エンコーダ部の外観 —

3. エンコーダ出力を作る仕組み

  • エンコーダの出力を作るためにホール効果が使われています。ホール効果は、「電流が流れている物質に磁場をかけると、電流と磁場の両方に垂直な方向に電圧が発生する」という現象です。
ホール効果
— ホール効果 —
  • ホール効果ICはホール効果による電圧変化を増幅して出力します。DCモータのシャフトに取り付けられた磁石はSNを交互に着磁してあり、ホール効果ICは磁界の変化を電圧変化で出力します。
ホール効果ICの外観とブロック図
— ホール効果ICの外観とブロック図 —
  • Honeywell社のSS400シリーズの仕様書を参照しています。
  • ホール効果ICの出力はオープンコレクタになっています。エンコーダ部のPCBにはプルアップ抵抗(510Ω)が実装してあり、シャフトに取り付けられた磁石が回転すれば、コネクタからは方形波が出力されます。

4. エンコーダ出力例

  • ホール効果ICから出力されるA相とB相の出力をオシロスコープで観察しました。A相、B相ともに方形波で出力されています。また、DCモータを正回転と逆回転にした場合で、A相とB相の位相がずれているのが解ります。
  • A相とB相の出力の数から、DCモータの回転数が解り、A相とB相の位相からDCモータの回転方向が解ります。
エンコーダー出力 DCモータ正回転時
— エンコーダー出力 DCモータ正回転時 —
エンコーダー出力 DCモータ逆回転時
— エンコーダー出力 DCモータ逆回転時 —

DCモータ(SGM25-370)を駆動する部品

部品機能個数
Arduino UNO R3CPUボード1 個
SGM25-370エンコーダ付きDC モータ1 個
TB6612FNGのDIP化基板 モータードライバ1 個
1.5V単4電池(4本)モータ用電源(6V)1 個
ブレッドボード、ジャンパ線配線用部材(必要数)

DCモータ(SGM25-370)を駆動する回路と接続

  • Arduino UNO R3、DCモータ(SGM25-370)、TB6612FNGおよびDCモータ用の電源6V(1.5V単4電池4本)の接続図をFritzingで描いています。
— SGM25-370 駆動回路 —
  • SGM25-370とArduino UNO R3、TB6612FNG(DIP化基板)の接続
SGM25-370接続先端子
モーター端子TB6612FNGAO1
GNDArduino UNO R3GND
ホール素子 A相Arduino UNO R3Digital 2ピン ※
ホール素子 B相Arduino UNO R3Digital 4ピン
VccArduino UNO R35V
モーター端子TB6612FNGAO2

※ ホール素子A相は割込み機能のあるDigital 2ピンに接続します。

  • TB6612FNGのDIP化基板、Arduino UNO R3、モーター用電池(6V)の接続
TB6612FNG(DIP化基板)接続先端子
PWMAArduino UNO R3Digital 9ピン
AIN1Arduino UNO R3Digital 8ピン
AIN2Arduino UNO R3Digital 7ピン
VCCArduino UNO R35V
GNDArduino UNO R3とドライバ電源GND
STBYArduino UNO R35V
VMドライバ電源6V

DCモータPWM駆動関数と割込み信号処理関数

1. ArduinoのPWM駆動機能

  • ArduinoでDCモータを制御する場合は、PWMによる駆動がデジタルとの親和性が良く便利です。スケッチにArduinoからPWM波形を出力する関数が提供されています。スケッチでその関数を呼び出せば、設定したポートからPWM波形が出力されます。
  • PWM出力のできるArduino UNO R3の端子とPWM周波数です。目視で解るようにボードにポート番号が印刷されています。PWM波形が出力できるポート番号の前に’~’が加えられています。
PIN 番号PWM 周波数
3, 9, 10, 11490 Hz
5, 6980 Hz
  • PWMを出力する関数は、analogWrite(pin, value) です。
  • pinでPWMを出力するpin番号を設定します。変数を使う場合は、int型です。
  • valueでデューティ-サイクルを設定します。0~255の数値で設定し、0の場合はデューティ-サイクルが0%、255の場合はデューティ-サイクルが100%になります。
analogWrite(9, 128);
  • analogWrite(9, 128)はArduino UNO R3の9pinにデューティ-サイクルが50%の波形を出力した例です。

2. Arduinoの割り込み機能

  • Arduino UNO R3には、割込み関数を呼び出すトリガー信号を受けることのできるピンがあります。デジタルポートの、2または3ピンになります。割り込みポートの0または1ピンになります。(ピン番号が紛らわしいので注意が必要です。) スケッチは割込み関数を呼び出す設定が準備されており書式に従って記述すれば割込みで信号処理が可能です。
  • 一般的に割込み関数中の処理は、メインの処理の中断を避けるためにできるだけ少なくすべきです。
  • 割り込みを有効にする関数は、attachInterrupt(digitalPinToInterrupt(pin), isr, mode) です。
  • digitalPinToInterrupt(pin),は割込み処理に使えるピン番号です。デジタルポートの、2または3ピンになります。
  • isr,に割込み関数の名前を設定します。割込み関数はvoid型でなければなりません。
  • mode、で波形のどのような状態で割り込みをするかの設定になります。RISINGの場合は、波形が立ち上がった時に割り込みが発生します。
attachInterrupt(0,isr,RISING)
  • detachInterrupt(digitalPinToInterrupt(pin))関数を使って、割り込みを無効にする設定をします。割り込みで取得した値を使って計算する期間は、割り込みが発生しても、割り込み処理をしないようにします。
detachInterrupt(digitalPinToInterrupt(0));
  • 割込み関数をstr()として定義した例です。割込み関数はvoid型でなければなりません。
void isr()     

3. 割り込み関数を使ってエンコーダの波形を計数する具体例

  • エンコーダ出力を割込み関数を利用して計数する処理に係るスケッチコードの一部です。
// エンコーダA相 (Interrupt)
const int ENC_A = 2;   // エンコーダA相 (Interrupt)

//A相の立ち上がりエッジで割り込み
attachInterrupt(digitalPinToInterrupt(ENC_A), countPulse, RISING);

// エンコーダカウント用
volatile long pulseCount = 0; 
  
// --- 割込み関数 ---
void countPulse() {
  pulseCount++;
}  
  • エンコーダのA相を割込み機能を持つArduino UNO R3のデジタル2ピンに割り当てます。
  • attachInterrupt(),関数に、ピンを割り当て、割込み関数countPulseを指定し、エンコーダ出力の立上がりで割込み関数を呼び出すように設定します。
  • エンコーダの出力係数用の変数pulseCounを定義し初期値を0とします。
  • 割込み関数countPulse()が呼ばれたら、変数pulseCounに1を加算します。
  • この処理によってエンコーダA相の波形の立ち上がりごとにcountPulse()が呼ばれて変数pulseCountにエンコーダ出力の数が計数されます。
(参考) 割込み機能を使って回転数を測定した記事

割込み関数を使っての連続サーボモータの回転数を測定しました。記事 [連続回転サーボモーターの回転速度を測定しました]にまとめています。

SGM25-370のエンコーダ出力を計数するスケッチ

  • SGM25-370をTB6612FNGからのPWM波形で回転させエンコーダ出力を計数します。
    • 出力をPWMの設定を32ステップ刻みで変化させる。
    • PWMの各ステップごとに正回転、逆回転でそれぞれ30秒間エンコーダ出力を計数する。
    • シリアルモニタに計測結果を出力する。
/*
 * Arduino UNO R3 + TB6612FNG + SGM250-370
 * モーター特性計測用スケッチ (PWM vs RPM)
 */

// --- デバッグレベル設定 ---
// 0: 表示なし, 1: 計測結果(Count/RPM), 2: プロッタ用出力
#define DEBUG_LEVEL 1 

// --- ピン割り当て ---
const int PIN_PWMA = 9;
const int PIN_AIN1 = 7;
const int PIN_AIN2 = 8;
const int PIN_ENCA = 2; // 外部割り込み(INT0)
const int PIN_ENCB = 4;

// --- 定数 ---
const float PULSES_PER_REV = 495.0;           // 1回転あたりのパルス数
const unsigned long MEASURE_TIME_MS = 30000;  // 計測時間(30秒)

// --- グローバル変数 ---
int currentPWM = 0;
bool isFinished = false;
volatile long pulseCount = 0;

// --- 割り込みサービスルーチン ---
void countPulse() {
  pulseCount++;
}

void setup() {
  pinMode(PIN_PWMA, OUTPUT);
  pinMode(PIN_AIN1, OUTPUT);
  pinMode(PIN_AIN2, OUTPUT);
  pinMode(PIN_ENCA, INPUT);
  pinMode(PIN_ENCB, INPUT);

  Serial.begin(115200);
  
  // プログラム開始メッセージの出力
  Serial.println("========================================");
  Serial.println("Motor Measurement Program Start");
  Serial.println("Wait for 5 seconds...");
  Serial.println("========================================");

  // A相の立ち上がりエッジでカウント
  attachInterrupt(digitalPinToInterrupt(PIN_ENCA), countPulse, RISING);

  // 5秒間待機
  stopMotor();
  delay(5000);
}

void loop() {
  if (isFinished) return;

  // 正回転 30秒
  executeMeasurement(true);

  // 5秒停止
  stopMotor();
  delay(5000);

  // 逆回転 30秒
  executeMeasurement(false);

  // 5秒停止
  stopMotor();
  delay(5000);

  // PWM加算処理
  if (currentPWM >= 255) {
    isFinished = true;
    Serial.println(">> Measurement Completed.");
  } else {
    currentPWM += 32;
    if (currentPWM > 255) currentPWM = 255; // 255を超えた場合は255に固定
  }
}

// --- モーター制御・計測コア関数 ---

void executeMeasurement(bool forward) {
  pulseCount = 0;
  moveMotor(forward, currentPWM);

  unsigned long startTime = millis();

  while (millis() - startTime < MEASURE_TIME_MS) {
    #if DEBUG_LEVEL == 2
      // A相とB相の状態をプロッタ形式で出力 (0V/5V付近で分離表示)
      Serial.print(digitalRead(PIN_ENCA) * 5); 
      Serial.print(" ");
      Serial.println(digitalRead(PIN_ENCB) * 2); 
    #endif
  }

  // 停止後の計算と表示
  #if DEBUG_LEVEL == 1
    // RPM = (総パルス / 495) * (60秒 / 30秒)
    float rpm = (pulseCount / PULSES_PER_REV) * (60.0 / (MEASURE_TIME_MS / 1000.0));
    
    Serial.print(forward ? "[FORWARD] " : "[REVERSE] ");
    Serial.print("PWM: "); Serial.print(currentPWM);
    Serial.print(" | Count: "); Serial.print(pulseCount);
    Serial.print(" | RPM: "); Serial.println(rpm, 2);
  #endif
}

void moveMotor(bool forward, int speed) {
  if (forward) {
    digitalWrite(PIN_AIN1, HIGH);
    digitalWrite(PIN_AIN2, LOW);
  } else {
    digitalWrite(PIN_AIN1, LOW);
    digitalWrite(PIN_AIN2, HIGH);
  }
  analogWrite(PIN_PWMA, speed);
}

void stopMotor() {
  digitalWrite(PIN_AIN1, LOW);
  digitalWrite(PIN_AIN2, LOW);
  analogWrite(PIN_PWMA, 0);
}
  • シリアルモニタに、回転方向、PWM値、エンコーダ出力数、そしてRPMが表示されます。モータの仕様で説明したように495パルスでシャフトが1回転します。測定は30秒間のカウント数ですから、このカウント数を2倍して495で割ればRPM値になります。

● シリアルモニタの出力例です。

========================================
Motor Measurement Program Start
Wait for 5 seconds...
========================================
[FORWARD] PWM: 0 | Count: 0 | RPM: 0.00
[REVERSE] PWM: 0 | Count: 0 | RPM: 0.00
[FORWARD] PWM: 32 | Count: 1097 | RPM: 4.43
[REVERSE] PWM: 32 | Count: 1324 | RPM: 5.35
[FORWARD] PWM: 64 | Count: 3232 | RPM: 13.06
[REVERSE] PWM: 64 | Count: 3326 | RPM: 13.44
[FORWARD] PWM: 96 | Count: 5306 | RPM: 21.44
[REVERSE] PWM: 96 | Count: 5381 | RPM: 21.74
[FORWARD] PWM: 128 | Count: 7818 | RPM: 31.59
[REVERSE] PWM: 128 | Count: 7962 | RPM: 32.17
[FORWARD] PWM: 160 | Count: 10965 | RPM: 44.30
[REVERSE] PWM: 160 | Count: 11209 | RPM: 45.29
[FORWARD] PWM: 192 | Count: 14763 | RPM: 59.65
[REVERSE] PWM: 192 | Count: 15138 | RPM: 61.16
[FORWARD] PWM: 224 | Count: 19099 | RPM: 77.17
[REVERSE] PWM: 224 | Count: 19690 | RPM: 79.55
[FORWARD] PWM: 255 | Count: 22664 | RPM: 91.57
[REVERSE] PWM: 255 | Count: 23349 | RPM: 94.34
>> Measurement Completed.
  • 測定結果をグラフ化しました。
— PWM デューティ-サイクルとSGM25の回転数(RPM)の関係 —

よくあるトラブルと対処法

モーターが動かない配線の確認、駆動ICの制御ピンの操作を確認
逆回転しない駆動ICの制御ピンの操作を確認
エンコーダ値が取得できないモータへの配線の確認
電源が落ちる電源の配線を確認

まとめ

  • DCモータ(SGM250-370)のエンコーダ部の構造を理解しました。そしてTB6612FNGでDCモータをPWM駆動して、エンコーダ出力の実際の波形を確認しました。Arduino UNO R3で受信し波形数を割込み関数で計測する方法が学習できました。また計測したエンコーダの数からシャフトの回転速度(RPM)が測定できました。エンコーダの出力を検出しながらモータ駆動すれば、例えば、倒立振子・自己バランスロボットの車輪の回転制御の精度が向上するはずです。

ご質問、誤植の指摘などありましたら。「問い合わせ 」のページからお願いします。