2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Arduono単体でステッピングモーターを制御する [モータードライバー不要]

Last updated at Posted at 2021-01-17

はじめに

ステッピングモーターをマイコンで制御しようと記事を検索すると、ほぼ間違いなくモータードライバーがセットになっています。まあ正しい選択ですよね。
ただ、Arduinoでチョロっとステッピングモーターを動かして遊んでみたい、と思った時にはちょっと敷居が高いですよね。
そこで今回は、モータードライバーを使用せず、Arduinoだけでステッピングモーターを制御してみたいと思います。

Arduino単体で制御できるステッピングモーター

Arduino単体で制御できるステッピングモーターには2つほど条件があります。

・励磁方式が2相ユニポーラであること
 一般的なステッピングモーターには大きく 2相ユニポーラ/2相バイポーラ が存在します。
 バイポーラはコイルに流す電流の正逆を制御する必要がありますが、
 Arduino単体では正の電圧しか印加することができません。

・小さいこと
 Arduino単体では大きなモーターを動かすことができません。
 小型のステッピングモーターは2相ユニポーラであることが多いようです。

今回は秋月電子通商で購入できるSPG27-1101を使用しました。
SPG-1101

ステッピングモーターのしくみ

ユニポーラタイプのステッピングモーターの多くは6本の線が出ています。
このうち2本はGND(センター)で、残りの4本が制御用の線になります。
この制御用の線に対して順番に位相をずらしたパルスを入力することで回転を制御できます。
dotstudio, inc.

ソースコード

実験用に作成したソースコードはこちらになります。

φ1,φ2,φ1,φ2 をそれぞれピン10,11,12,13に、φ1C,φ2CをGNDに割り当てています
スクリーンショット 2021-01-18 20.53.55.png

steppermotortest.cpp
# include <Arduino.h>
//#include "tmDeltaTime.h"
//#include "tmStepperMotor.h"

class TmDeltaTime{
    public:
    TmDeltaTime(){
        Setup();
    };
    void Setup(){
        currentMillis = millis();
        deltaMillis = 0;
    }
    uint32_t Update(){
        uint32_t nowMillis = millis();
        deltaMillis = nowMillis - currentMillis;
        currentMillis = nowMillis;
        return deltaMillis;
    };
    uint32_t GetDeltaMillis(){
        return deltaMillis;
    };
    private:
    uint32_t currentMillis;
    uint32_t deltaMillis;
};

class TmStepperMotor{
    public:
    TmStepperMotor(uint8_t _phA=9, uint8_t _phB=10, uint8_t _phAi=11, uint8_t _phBi=12, uint32_t _delay = 50, bool _dir = false, uint32_t _pulseWidth=500){        
        mPh[0] = _phA; mPh[1] = _phB; mPh[2] = _phAi; mPh[3] = _phBi;
        mIsNegative = _dir;
        mDelay = _delay;
        mPhase = 0;
        mSumMillis = 0;
        mPulseWidth = mPulseTimer = _pulseWidth;
    };
    void Setup(){
        for(int i=0; i< 4; ++i){
            pinMode(mPh[i],OUTPUT);
            digitalWrite(mPh[i],LOW);
        }
    }

    uint32_t Update(uint32_t _deltaMillis){
        if((mPulseTimer>0)&&(mDelay > (mPulseWidth+10))){
            mPulseTimer -= _deltaMillis;
            if(mPulseTimer<=0){
                phaseOff();
            }
        }
        mSumMillis += _deltaMillis;
        if(mSumMillis >= mDelay){
            mSumMillis -= mDelay;
            mPhase = updatePhase(mPhase,mIsNegative);
            mPulseTimer = mPulseWidth;
        }
        return mSumMillis;
    }
    void SetDelay(uint32_t _delay){
        mDelay = _delay;
        //mSumMillis = 0;
    }
    uint32_t GetDelay(void){
        return mDelay;
    }
    void SetDirection(bool _isNegative){
        mIsNegative = _isNegative;
        //mSumMillis = 0;
    }
    bool GetDirection(void){
        return mIsNegative;
    }
    void SetPulseWidth(uint32_t _width=100){
        mPulseWidth = mPulseTimer = _width;
    }
    uint32_t GetPulseWidth(void){
        return mPulseWidth;
    }

    private:
    uint8_t mPh[4];
    uint8_t mPhase;
    bool mIsNegative;
    uint32_t mDelay;    
    uint32_t mSumMillis;
    uint32_t mPulseWidth;
    uint32_t mPulseTimer;

    uint8_t updatePhase(uint8_t _phase, bool _isNegativeRotation = false){
        static uint8_t phaseArr[] = {HIGH,LOW,LOW,HIGH};
        for(int i=0; i< 4; ++i){
            digitalWrite(mPh[i],phaseArr[(_phase+i) & 3]);
        }
        return _isNegativeRotation ? ((_phase+3) & 3):(_phase+1) & 3;
    }
    void phaseOff(){
        for(int i=0; i< 4; ++i){
            digitalWrite(mPh[i],LOW);
        }
    }
};

TmDeltaTime* pDeltaTime = new TmDeltaTime();
TmStepperMotor* pStepMotor = new TmStepperMotor(10,11,12,13,30,false);
uint32_t invTimer=0;
uint32_t spdTimer=0;

void setup() {
  pDeltaTime->Setup();
  pStepMotor->Setup();
  pStepMotor->SetPulseWidth(20);
}

void loop() {
    uint32_t delta = pDeltaTime->Update();

    invTimer+= delta;
    if(invTimer >= 10000){
      invTimer-= 10000;
      pStepMotor->SetDirection(!pStepMotor->GetDirection());
    }
    spdTimer+= delta;
    if(spdTimer >= 3000){
      spdTimer-= 3000;
      pStepMotor->SetDelay(pStepMotor->GetDelay()==30 ? 300 : 30);
    }

    pStepMotor->Update(delta);
    delay(1);
}

実際に動作させてみた動画
それほど大きなトルクは期待できませんが、指で出力軸をつまみ上げるとモーターが回転する程度にはトルクが出ています。

測定

実際に測定してみるとこんな感じでした。
IMG_9646.jpg
コイル端子間の抵抗が約30[Ω]でしたので、70[mA]程度流れている感じでしょうか。
定格では1ピンあたり40[mA]までという事なので、あまり長く遊ばない方が良さそうです。
一応ライブラリにもパルス出力持続時間の上限をつけてみました(default0.5[sec])

まとめ

Arduino単体でステッピングモーターを制御することができました。
本格的に動かすにはやはりモータードライバーでドライブした方が良さそうですが、
ちょっと試しに動かしてみるには十分かと思います。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?