The jonki

呼ばれて飛び出てじょじょじょじょーんき

【Arduino】ステッピングモーターをArduinoで度数指定で動かす

最近ステッピングモーターというものを知りました。モーターなんですが、パルスを与えるたびにステップ(モーターによって違う)分だけ回転するというものです。そんなもんサーボにも出来るじゃないか、と思うかもしれませんが、基本的にサーボは180度ぐらいしか動きません。ステッピングモーターは角度を覚えていない変わりに、現時点からの回転量を細かく指示することができるものです。

作ったもの

ステッピングモーターについて

動作は非常に単純。コイルに電流を流してその電磁力で回転するというだけです。

Arduinoステッピングモーターを動かしてみる

下記を参考にさせて頂きました。こちらは可変抵抗の値に応じて回転速度を変更するものです。ただし、自分がやりたいのは指定した度数だけ回転するものなので、これをベースに改造します。

準備

ステップ角1度のSPG20-1000が良かったのですが、秋月で売り切れだったので他の安いやつでやってます。SPG20-1000でも回路は電源部分以外同じです。

部品名 数量 商品名
Arduino 1 Arduino UNO
ステッピングモーター 1 PF42T-96C4
ステッピングモーターIC 1 ステッピングモーターIC TA7774PG
抵抗 10kΩ(タクトスイッチのプルダウン用) 1 -
ジャンプワイヤ 適量 -
スイッチングACアダプター12V1A 1 超小型スイッチングACアダプター12V1A 100V〜240V GF12−US1210
DCジャック 1 ブレッドボード用DCジャックDIP化キット
トグルスイッチ(電源ON/OFF用 ) 1 -
タクトスイッチ 1 タクトスイッチ

回路

基本的にhiramine.comさんのサイトと同じです。モーターの配線はデータシートを参考にしてください。今回はバイポーラ駆動にするのでモーターの使う線は4本で、残りの2本は使いません。配線図の色と実際の色を合わせたのでそれも参考にしてみてください。ペアが10、11と14、15ピンですね。またタクトスイッチを押した時にだけ回転するようにしてみました。


プログラム

タクトスイッチを押した時に、可変抵抗の値に応じて指定角度分だけ回転させます。まずはTA7774PGのデータシートを見てみます。

端子の表を見て、AとBそれぞれの出力があることがわかります。バイポーラ駆動ですね。また外部からの信号の入力がIN AとIN Bにありますが、これも真理値表から分かる通り、入力の反転したものとセットで出るようになります。この反転はIC内で行われるので自分で反転したデータとかを入れる必要がないわけですね。


さて、次に回転のためのパルス生成ですが、下記のプログラムのようにします。4つのパルスを生成していますが、マイコン搭載ロボット製作入門 第7章 ステッピングモーターを動かしてみようの95ページの図の1、2、3、4に対応していることがわかるでしょうか。入力はAとBの2つだけですが、真理値表1からAとBの反転したものも出て、4つのOUTPUTがモータに繋がっています。
回転のためのパルスは参考の図にもあるように4段階で1ループ分になるので、1ステップの角度と指定の角度から何回パルスを生成すればよいのかを計算します。
また、今回利用したPF42T-96C4はデータシートから最大590pps、つまり1/590sec(=1.69msec)ぐらいのパルスで回せますが、トルクが出ないので今回は5msecにしてみました。データシートを見ると5msecで20mN・mぐらいのトルクが出てるようです。

#define INAPIN	         (7)
#define INBPIN	         (6)
#define TACTPIN          (8)
#define VOLUMEPIN	     (0)

#define BASESTEPANGLE    (3.75) // 1ステップの角度
#define PulseWidth       (5.0)  // 1パルスの長さ msec

bool rotLock = false;
void setup()
{
    pinMode(INAPIN, OUTPUT);
    pinMode(INBPIN, OUTPUT);
    pinMode(TACTPIN, OUTPUT);
    Serial.begin(9600);
}

void set_degree(float deg) 
{
    Serial.println(deg);
    int count = deg / BASESTEPANGLE / 4; // 1ループで4パルス分
    if(count > 0) {
        for(int i = 0; i < count; i++) {
            digitalWrite(INAPIN, HIGH);
            digitalWrite(INBPIN, HIGH);
            delay(PulseWidth);
            digitalWrite(INAPIN, LOW);
            digitalWrite(INBPIN, HIGH);
            delay(PulseWidth);
            digitalWrite(INAPIN, LOW);
            digitalWrite(INBPIN, LOW);
            delay(PulseWidth);
            digitalWrite(INAPIN, HIGH);
            digitalWrite(INBPIN, LOW);
            delay(PulseWidth);
        }
    } else {
        for(int i = count; i < 0; i++) {
            digitalWrite(INAPIN, LOW);
            digitalWrite(INBPIN, LOW);
            delay(PulseWidth);
            digitalWrite(INAPIN, LOW);
            digitalWrite(INBPIN, HIGH);
            delay(PulseWidth);
            digitalWrite(INAPIN, HIGH);
            digitalWrite(INBPIN, HIGH);
            delay(PulseWidth);
            digitalWrite(INAPIN, HIGH);
            digitalWrite(INBPIN, LOW);
            delay(PulseWidth);
        }
    }
}

void deg_test()
{
    int iValue = analogRead(VOLUMEPIN); // 0 - 1023
    // Serial.println(iValue);
    // 0-1023の区間を4分割して、その4つの領域に角度を割り当てる
    if(iValue < 1023 * 0.25) { // 256
        set_degree(180.0);
    } else if(iValue < 1023 * 0.5) { // 512
        set_degree(90.0);
    } else if(iValue < 1023 * 0.75) { // 768
        set_degree(-90.0);
    } else {
        set_degree(-180.0);
    }
}

void loop()
{
    if(digitalRead(8) == HIGH && rotLock == false) {
        rotLock = true;
        deg_test();
    } else if(digitalRead(8) == LOW && rotLock == true) {
       rotLock = false;
    }
}

終わり。ちょっと最初はとっつきにくいかもしれませんが、冷静に見るとすごい単純です。