つくって楽しい!ラボ

小さな「できた!」を、ゆっくり積み重ねていくモノづくりブログ。

【Arduino】エンコーダーを回してステッピングモータを自在に操ろう!

 

 

こんにちは!今回は「モノづくりのハードルを下げる」をテーマに、Arduinoを使った電子工作の記録をシェアします。

「ダイヤルを回した分だけ、正確にモーターを動かしたい」

そんな時に役立つのが、ロータリーエンコーダーステッピングモータの組み合わせです。初心者の方でも再現しやすいよう、構成を整理してみました。

今回作るものの概要

ダイヤル(エンコーダー)をカチカチと回すと、その動きに同期してステッピングモータが回転する仕組みを作ります。

使用部品

  • Arduino UNO(制御の心臓部)

  • ステッピングモータ (28BYJ-48)

  • ドライバ基板 (ULN2003)(モーターを力強く動かすため)

  • ロータリーエンコーダー(今回の操作部)

  • 電源モジュール / 9V電池

  • ブレッドボード・ジャンパー線

このブログでは ELEGOO(エレゴー)製の Arduino 互換品を使って実験しています。Arduino互換品と聞くと品質が心配になる方もいるかもしれませんが、ELEGOO の製品は「互換品とは思えない品質」 で、Arduino公式ボードと同じように問題なく使えます。それでいて 価格はかなりリーズナブル なのが魅力です。
特にスターターキットは、

  • Arduino互換ボード
  • モータ(DC,サーボモータ,ステッピングモータ)
  • 各種センサ
  • 電源モジュール
  • ブレッドボード
  • ジャンパーワイヤ

といった 電子工作で必要なパーツが一式そろっており、初めてでもすぐに実験を始められる 便利なセットになっています。

ロータリーエンコーダーって何?

ロータリーエンコーダの仕組み(原理)

最も一般的な「光学式」を例に説明します。

内部には、細かいスリット(溝)が入った円盤が入っています。この円盤が回転することで、光を「通す・遮る」を繰り返し、それをセンサーが読み取ってデジタル信号(パルス)に変換します。

  1. 発光素子(LED)から光を出す。

  2. 回転するスリット入りの円盤を光が通る。

  3. 反対側の受光素子が、光の点滅を検知する。

  4. 点滅の回数を数えることで「どれくらい動いたか」を、点滅の速さで「どれくらいの速度か」を判断する。

大きく分けて2つのタイプ

ロータリーエンコーダには、信号の出し方によって「インクリメンタル」と「アブソリュート」の2種類があります。ここが一番のポイントです。

① インクリメンタル形(相対角)

回転した「量」を測るタイプです。

  • 特徴:
    回転すると「ピ・ピ・ピ」とパルス信号を出します。その数をカウントして移動量を計算します。

  • メリット:
    構造がシンプルで安価。

  • デメリット:
    電源を切ると、それまでどこにいたか忘れてしまいます(原点復帰が必要)。

② アブソリュート形(絶対角)

回転した「位置(角度)」を測るタイプです。

  • 特徴:
    回転角ごとに固有のコード(住所のようなもの)が割り振られています。

  • メリット:
    電源を切っても、再起動した瞬間に「今どこにいるか」がすぐに分かります。

  • デメリット:
    構造が複雑で、価格が高め。

特徴 インクリメンタル形 アブソリュート形
位置の把握 前の位置からの「変化量」 常に「絶対的な位置」
停電時 現在地を忘れる 現在地を保持する
コスト 低い(リーズナブル) 高い
主な用途 一般的なモーター制御、つまみ 工作機械、ロボットアーム

回路と接続

配線は少し複雑に見えますが、一つずつ繋げば大丈夫です。

【回路図】

プログラム(コード)

以下のコードをArduino IDEに書き込みます。

#include "Stepper.h"
#define STEPS  32   // 内部シャフト1回転あたりのステップ数
                    // 外部シャフト1回転あたり2048ステップ
volatile boolean TurnDetected;  // 割り込みにはvolatileが必要
volatile boolean rotationdirection;  // 時計回りまたは反時計回りの回転
const int PinCLK=2;   // CLK信号を使用して割り込みを生成する
const int PinDT=3;    // DT信号の読み取り
const int PinSW=4;    // 読み取りプッシュボタンスイッチ
int RotaryPosition=0;    // ステッピングモーターの位置を保存
int PrevPosition;     // 前回の回転位置 精度を確認するための値
int StepsToTake;      // ステッパーをどれくらい動かすか
// モータードライバーピンの適切なシーケンス設定 // In1、In2、In3、In4 のシーケンスを 1-3-2-4 で設定 Stepper small_stepper(STEPS, 8, 10, 9, 11);
// CLKがHIGHからLOWに変わると割り込みルーチンが実行される void isr () { delay(4); // 最終操作を待つ if (digitalRead(PinCLK)) rotationdirection= digitalRead(PinDT); else rotationdirection= !digitalRead(PinDT); TurnDetected = true; }
void setup () { pinMode(PinCLK,INPUT); pinMode(PinDT,INPUT); pinMode(PinSW,INPUT); digitalWrite(PinSW, HIGH); // スイッチ用プルアップ抵抗 attachInterrupt (0,isr,FALLING); // 割り込み0は常にArduino UNOのピン2に接続されます } void loop () { small_stepper.setSpeed(700); //回転速度 if (!(digitalRead(PinSW))) { // ボタンが押されているかどうかを確認する if (RotaryPosition == 0) { // ボタンがすでに押されているかどうかを確認する } else { small_stepper.step(-(RotaryPosition*50)); RotaryPosition=0; // 位置をゼロにリセット } } // 回転が検出された場合実行 if (TurnDetected) { PrevPosition = RotaryPosition; // 前の位置を変数に保存する if (rotationdirection) { RotaryPosition=RotaryPosition-1;} // 位置を1つ下げる else { RotaryPosition=RotaryPosition+1;} // ポジションを1つ増やす TurnDetected = false; // 新しい回転が検出されるまでIFループを繰り返さない // ステッピングモーターをどの方向に動かすか if ((PrevPosition + 1) == RotaryPosition) { // モーターを時計回りに動かす StepsToTake=50; small_stepper.step(StepsToTake); } if ((RotaryPosition + 1) == PrevPosition) { // モーターを反時計回りに動かす StepsToTake=-50; small_stepper.step(StepsToTake); } } digitalWrite(8, LOW); digitalWrite(9, LOW); digitalWrite(10, LOW); digitalWrite(11, LOW); }

コード解説

全体のプログラム動作概要

このプログラムの主な目的は、「ロータリーエンコーダーの回転を検知し、その動きに合わせてステッピングモーターを回転させること」です。

具体的には以下のような動作を行います:

  1. 回転の検知:
    ダイヤルの「1カチ(1クリック)」を、Arduinoの割り込み機能で瞬時に捉えます。

  2. 方向の判別:
    2つの信号のズレ(位相差)を利用して、時計回りか反時計回りかを判断します。

  3. モーターの駆動:
    ダイヤルが1クリック動くごとに、モーターを50ステップ分動かします。

  4. リセット機能:
    ダイヤル自体がボタンになっており、押し込むと電源を入れた時の「0の位置」まで自動で戻ります。

プログラムコードのポイント

このコードを理解する上で、特に重要な「肝」となる部分が3つあります。

  • 割り込み(Interrupt)の活用:

    通常のプログラムは上から順に処理を行いますが、ダイヤルを回すのは人間のタイミングです。attachInterrupt を使うことで、他の処理をしていても「回った瞬間」だけは最優先で処理するため、取りこぼしがありません。

  • 位相差による方向判定:
    CLKピンとDTピンの2つの信号は、わざとタイミングがズレて出力されます。CLKが変化した瞬間のDTの状態を見れば、右か左かが100%分かります。

  • チャタリング対策(Debouncing):

    スイッチを押した際、物理的な接点が微細に震えることで「カチカチカチッ」と複数回押されたと誤認されることがあります。これを防ぐために、数ミリ秒の待機時間(delay(4))を設けています。

  • モーターの「熱」対策:
    ステッピングモーターは、止まっている時も電気を流し続けると非常に熱くなります。このコードでは、動かした直後に全てのピンを LOW(0V)にすることで、無駄な発熱を抑える工夫がされています。

各行のプログラムコードの意味

コードを機能ブロックごとに分けて解説します。

設定と準備(ライブラリと変数)

#include "Stepper.h" // モーター制御用のライブラリを読み込み
#define STEPS 32     // モーター内部の1回転ステップ数

volatile boolean TurnDetected;  // 回転を検知したかどうかのフラグ
volatile boolean rotationdirection; // 回転方向(時計・反時計)
  • volatile は「割り込みの中で書き換わる変数ですよ」とコンピュータに教える魔法の言葉です。

割り込み処理(isr関数)

void isr () {
  delay(4); // チャタリング防止
  if (digitalRead(PinCLK))
    rotationdirection = digitalRead(PinDT); // 方向を判定
  else
    rotationdirection = !digitalRead(PinDT);
  TurnDetected = true; // 回転したことを記録
}
  • ダイヤルが動いた瞬間に呼び出されます。ここで「どっちに回ったか」を判断し、「回ったよ!」という印(TurnDetected)を立てます。

メインループ(loop関数)

void loop () {
  small_stepper.setSpeed(700); // モーターの速度を設定

  // ボタンが押されたら0の位置に戻る
  if (!(digitalRead(PinSW))) {
    if (RotaryPosition != 0) {
        small_stepper.step(-(RotaryPosition * 50)); // 逆回転して戻る
        RotaryPosition = 0; // 位置をリセット
    }
  }

  // 回転が検知されたらモーターを動かす
  if (TurnDetected) {
    if (rotationdirection) {
      RotaryPosition--; // 位置を減らす
      small_stepper.step(-50); // 反時計回りに50ステップ
    } else {
      RotaryPosition++; // 位置を増やす
      small_stepper.step(50); // 時計回りに50ステップ
    }
    TurnDetected = false; // 処理が終わったのでフラグを戻す
  }

  // 待機中にモーターへの電流を止める(発熱防止)
  digitalWrite(8, LOW); digitalWrite(9, LOW);
  digitalWrite(10, LOW); digitalWrite(11, LOW);
}
  • 常に「ボタンは押されたか?」「ダイヤルは回ったか?」を確認しています。

  • 最後に各ピンを LOW にするのは、使っていない時にモーターが熱くなるのを防ぐための工夫です。

使用されている関数の意味

コード内で使われている主要な関数について解説します。

関数 役割 補足説明
attachInterrupt() 割り込みの予約 特定のピン(Pin 2)が変化した時だけ isr を呼び出します。
digitalRead() ピンの状態確認 電圧が 5V(HIGH) か 0V(LOW) かを調べます。
small_stepper.step() モーターを動かす 正の数で時計回り、負の数で反時計回りに指定数だけ進みます。
setSpeed(700) モーターの速さ設定 1分間あたりの回転数(RPM)を指定します。

実験結果:動かしてみた感想

想定通り、エンコーダーのカチカチという手応えに合わせて、モーターが小気味よく動いてくれました!


www.youtube.com

ただ、面白い挙動(課題)も見つかりました。

今のコードだと、100回カチカチと回した後にリセットボタンを押すと、モーターが 「ギュイーン!」 と一気に 100 ×times 50ステップ(5000ステップ)逆回転して戻ろうとします。

  • 速度の調整: 戻る速度が遅すぎると待ち時間が発生します。

  • 脱調に注意: 逆に速すぎると「ガガガッ」と異音がしてモーターがついてこれなくなる(脱調)ため、setSpeed の調整が重要です。

まとめ・応用

今回の仕組みを応用すれば、以下のようなものも作れそうです。

  • 自作スライダー: カメラの台を数ミリ単位で動かす。

  • 遠隔ドアロック: 手元のダイヤルで鍵を回す。

電子工作は、一度動くものができると一気に楽しくなりますね。「自分もやってみたい」という方の助けになれば幸いです!



にほんブログ村 その他趣味ブログ 電子工作へ
にほんブログ村