Arduono 단독으로 스테핑 모터 제어 [모터 드라이버 필요 없음]

소개



스테퍼 모터를 마이크로 컴퓨터로 제어하려고 기사를 검색하면 거의 확실히 모터 드라이버가 세트로되어 있습니다. 글쎄, 올바른 선택입니다.
다만, Arduino에서 쵸로 스테핑 모터를 움직여 놀고 싶다고 생각했을 때에는 조금 문턱이 높지요.
그래서 이번에는 모터 드라이버를 사용하지 않고 Arduino만으로 스테핑 모터를 제어하고 싶습니다.

Arduino 단독으로 제어할 수 있는 스테퍼 모터



Arduino 단독으로 제어할 수 있는 스테핑 모터에는 2가지 정도 조건이 있습니다.

・여자 방식이 2상 유니폴라인 것
일반적인 스테핑 모터에는 크게 2상 유니폴라/2상 바이폴라가 존재합니다.
바이폴라는 코일에 흐르는 전류의 정역을 제어할 필요가 있습니다만,
Arduino 단독으로는 양의 전압만을 인가할 수 있습니다.

· 작은 것
Arduino 단독으로는 큰 모터를 움직일 수 없습니다.
소형 스테핑 모터는 2상 유니폴라인 경우가 많습니다.

이번은 아키즈키 전자 통상에서 구입할 수 있는 SPG27-1101 를 사용했습니다.


스테퍼 모터의 작동 방식



유니폴라 타입의 스테핑 모터의 대부분은 6개의 선이 나와 있습니다.
이 중 2개는 GND(센터)로, 나머지 4개가 제어용의 선이 됩니다.
이 제어용 선에 대해 순서대로 위상을 어긋난 펄스를 입력하여 회전을 제어할 수 있습니다.


소스 코드



실험용으로 만든 소스 코드는 여기입니다.

φ1, φ2, φ1, φ2를 각각 핀 10, 11, 12, 13에, φ1C, φ2C를 GND에 할당합니다.


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);
}

실제로 작동하려고했습니다 동영상
그다지 큰 토크는 기대할 수 없지만, 손가락으로 출력축을 잡아 올리면 모터가 회전하는 정도에는 토크가 나오고 있습니다.

측정



실제로 측정해 보면 이런 느낌이었습니다.

코일 단자간의 저항이 약 30[Ω]이었기 때문에, 70[mA]정도 흐르고 있는 느낌입니까.
정격에서는 핀당 40[mA]까지 라고 하는 일이므로, 너무 길게 놀지 않는 편이 좋을 것 같습니다.
일단 라이브러리에도 펄스 출력 지속 시간의 상한을 붙여 보았습니다 (default0.5 [sec])

요약



Arduino 단독으로 스테퍼 모터를 제어 할 수있었습니다.
본격적으로 움직이려면 역시 모터 드라이버로 드라이브하는 것이 좋을 것 같습니다만,
조금 시험에 움직여 보기에는 충분할까 생각합니다.

좋은 웹페이지 즐겨찾기