DFRobot - Motor Shield for Arduino #2 Stepper Motor

2018. 10. 1. 11:06

Arduino/Shield

2A Motor Shield for Arduino Twin with Stepper

이전 글에서 소개했던 DFRobot사의 2x2A DC Motor Shield for Arduino Twin 쉴드를 이용하여 이번 글에서는 스테핑(또는 스텝) 모터를 구동해 보겠습니다.

이전 글에서 사용한 DC모터와 마찬가지로 DVD 드라이브를 분해하여 얻은 스테핑 모터를 이용하여 예제를 작성하였습니다.

관련글

DFRobot - Motor shield for Arduino #1 DC Motor

여기서 사용하는 모터 쉴드에 대한 소개와 기본적인 사용 방법을 설명하고 있습니다.

DFRobot - Motor shield for Arduino #3 JoyStick

이 글에 이어서, 아날로그 조이스틱을 이용하여 스텝 모터를 다루는 글입니다.

DFRobot - Motor shield for Arduino #4 Bluetooth 원격 제어

이전에 사용한 DC모터를, 블루투스를 통하여 스마트폰으로 제어하는 간단한 예제를 소개합니다.

스테핑 모터(스텝 모터)

스테핑 모터(Stepper, Stepping, Step 모터)는 그 이름처럼 모터의 회전이 스텝 단위로 행해집니다. 한 스텝, 두 스텝, 정해진 각도만큼 회전하고 일정한 스텝 수가 모이면 한 바퀴의 회전이 완성됩니다. 예를 들어, 어떤 모터의 한 스텝당 회전 각도가 1.8도라면 한 바퀴를 돌기 위해선 200번의 스텝(360/1.8)을 채워야 합니다.

DC 모터의 경우 엔코더 등 회전수 체크를 위한 별도의 구성이 필요하지만, 스텝 모터는 매 스텝마다 정해진 각도만큼 이동하기 때문에, 별다른 도움 없이 회전수 계산이 가능하고, 이 점 때문에 원하는 만큼 정확한 이동이 가능 합니다. 그래서, 3D 프린터 등에서 주로 사용되고 있습니다.

여기서 사용할 DVD 드라이브의 스텝 모터는 바이폴라(Bipolar) 방식으로 가장 흔하게 볼 수 있는 종류입니다. 4개의 입력선을 통하여 디지털 펄스를 받고 이를 모터의 회전으로 변형하는데, 여기서는 작동 원리는 생략하고, 구동하기 위해서 어떻게 신호를 구성해야 하는지만 설명하겠습니다.

바이폴라 스텝 모터는 이름처럼 내부에 두 개의 코일(Coil)이 감겨 있습니다(Winding). 이 두 개의 코일에 번갈아 신호를 주면 회전을 하게 되는데, 코일마다 두 개의 입력선을 가지고 있고, 따라서 총 4개의 입력을 구성해야 합니다.

이 코일을 하나의 DC모터라고 보시면 이해하기 더 쉽습니다. 즉, 쉬운 이해를 위해 간단히 얘기하면, 스텝 모터안에 두 개의 DC모터 A, B가 있고, 각각 A1, A2, B1, B2라는 두 개의 입력선을 가지고 있습니다. A1에 +(positive) 전원을 연결하고 A2에 -(negative, ground) 전원을 연결하면 정해진 방향으로 회전을 하고 편의상 이를 정방향forward) 회전이라 한다면, A1, A2에 극성을 반대로 연결하면 역방향 회전을 합니다. B 코일도 마찬가지이므로, A 정방향, A 역방향, B 정방향, B 역방향 이렇게 총 네 가지의 스텝이 존재하고, 이를 순서대로 조합하면 스텝핑 모터가 일정한 방향으로 회전하게 됩니다.

모터가 회전하기 위해선, 이 4개의 스텝이 순서대로 발생해야 합니다. 우선 A코일 다음에 B코일, 또 B코일 다음에 A코일 이렇게 번갈아 구동해야 하고, 4번의 스텝당, 각 코일의 정방향, 역방향 회전이 한 번씩만 실행되어야 합니다.

그림에서, 모터를 회전하기 위해, 위 순서대로 +(positive) 전원을 연결한다면 모두 같은 방향으로 회전합니다. A코일 먼저 시작할 때, A 정방향 다음엔 B 정방향이 오고, A 역방향 다음엔 마찬가지로 B 역방향이 와야 회전이 이루어 집니다. 반대로, B코일 먼저 회전을 시작한다면, 이와는 반대로, B 정방향 다음에 A 역방향이 오고, B 역방향 다음에 A 정방향이 와야 합니다.

반대로, 위와 같이 순서를 구성하면 전체적인 회전 방향이 역방향이 됩니다. 설명이 복잡할 뿐이지, 배선 연결이 제대로 되었고, A다음에 B, B 다음에 A가 오고, 네 가지 스텝이 한 번씩만 오도록 구성하면 어느 한 방향으로 회전이 발생하게 됩니다.

DVD 드라이브의 스텝 모터

 DVD 드라이브를 분해하여 얻은 스텝 모터입니다. 바이폴라 방식이며, 분해 과정은 이 글 끝에 있는 영상에서 확인할 수 있습니다.

모터의 입력 포트입니다. 두 개의 코일을 위한 총 4개의 포트가 있습니다.

설명서나 표시가 따로 없기 때문에 어떤 포트가 동일 코일에 연결된 한 쌍인지 확인해야 합니다. 가장 쉬운 건 멀티미터(테스터)를 통한 통전(도통) 테스트입니다. 두 지점이 연결되었다면 "삐~"하고 벨이 울리는 기능인데, 동일 코일에 연결되었다면 벨이 울리겠죠! 아니면 위 그림처럼 두 포트간 저항값을 측정해봐도 됩니다. 연결되었다면 약간의 저항값이 측정되지만, 다른 코일간에는 단선된 것이므로 저항값이 무한대로 찍힙니다.

측정 결과, 위와 같이 동일 코일을 찾고 전선까지 납땜하였습니다. 좌측 2개, 우측 2개가 각각 하나의 코일을 구성하고, 만약, 빨간선을 A1이라 한다면 노란선이 B1, 검정선이 A2, 흰색 전선이 B2가 됩니다. 어느 쪽이 A인지 B인지는 상관없습니다. 서로 번갈아 구동되고, 각 포트에 한번씩 +전원을 할당하면, 어느 방향으로든지 회전하니까요!

스텝 모터를 위와 같이 핀헤더를 이용하여 쉴드에 연결하였습니다. 쉴드 상의 핀 번호 1, 2, 3, 4는 차례대로 M1-, M1+, M2-, M2+ 이고, M1쪽에 한 코일, M2쪽에 다른 코일이 연결된 것입니다. 즉, 빨간선은 M1-, 검정은 M1+, 노랑은 M2-, 흰색은 M2+에 연결되었는데, 편의상 순서대로 연결했을 뿐이고, 빨강, 검정을 M2에 연결해도 되고, 빨강, 노랑이 각각 M1+, M2+에 연결되어도 상관없습니다. 코딩할 때 회전 방향만 주의하면 됩니다.

단, 빨강이 "-"인데 노랑이 "+"가 할당되면, 즉 빨강과 노랑 또는 검정과 흰색이 다른 극성으로 연결되면 코딩이 엄청 복잡해지므로 되도록 모터의 포트 순서대로 연결하는 쪽을 권장합니다.

예제 소스 작성하기

모터 스텝 순서는 위와 같이 구성하였습니다. 물론 M2쪽부터 시작해도 되는데, 대신 회전 방향만 반대가 됩니다.

// constants
const int E1pin = 10;
const int E2pin = 11;
const int M1pin = 12;
const int M2pin = 13;

이전 글의 DC모터용 예제와 마찬가지로, 우선 네 개의 상수를 선언하였습니다. 속도 제어를 위한 E1, E2, 방향 제어를 위한 M1, M2를 각각 핀 10~13번에 연결하기 위해 미리 선언한 것으로, E1, E2는 속도 제어뿐만아니라, 디지털 값(HiGH, LOW) 할당을 통해 enable, disable 제어가 가능합니다. 이 쉴드는 단지 4개의 제어 포트만을 이용하여 두 개의 DC모터를 구동할 수 있기 때문에, 구성이나 코딩이 간단해지는 장점이 있지만, 각 포트를 개별적으로 제어하는 건 불가능 하기 때문에 활용성은 좀 떨어집니다.

// control signal out to shield
void setup() {
  pinMode(E1pin, OUTPUT);
  pinMode(E2pin, OUTPUT);
  pinMode(M1pin, OUTPUT);
  pinMode(M2pin, OUTPUT);

setup() 함수를 작성합니다. 제어 신호를 모터에 보내야 하기 때문에, 위에서 선언한 상수를 이용하여 핀 모드를 "출력(OUTPUT)"으로 설정하였습니다.

void loop() {
  for (int i = 0; i < 20; i++) {
  //rotation : M1+, M2+, M1-, M2-
  }
  for (int i = 0; i < 20; i++) {
  //rotation : M1+, M2-, M1-, M2+
  }
}

Loop() 함수입니다. 두 개의 For문이 각각 반대 방향으로 회전하며, 각 방향으로 20번의 스텝씩 이동합니다. loop() 함수는 반복해서 실행하므로, 결과적으로 일정 간격 만큼 좌우로 계속해서 왔다갔다 하게 됩니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    //rotation : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); //to stop rotation previously

임의로 정한 순서에 따라 "M1"쪽 부터 구동을 시작할 것인데, 그 전에 먼저 이전에 진행중이던 회전을 멈춰야 합니다. 4번 행에서 E2pin에 "LOW" 값을 주어 M2모터를 disable했습니다. E1, E2 핀에 "LOW"값을 할당하면 disable, "HIGH"를 할당하면 enable상태가 됩니다.

한 번에 한 코일만 동작해야 하고, 멈추기 전까진 계속 동작하기 때문에, 위와 같이 다른 스텝을 진행하기 전에 이전 스텝을 멈추는 코드가 필요합니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable

반대로, For문에 의해 반복되면서 M1쪽도 이전 스텝(M2)에서 disable된 상태이기 때문에, 5번 행에서 보듯이 enable시켜야 합니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time

6번행에서 M1+ 포트에 "+"를 할당하여 회전을 시작합니다. 그 다음 7번 행처럼 약간의 딜레이를 주어야 합니다. 각 펄스당 최소한의 간격이 있어야 구분이 가능하기 때문입니다. M1, M2 핀은 "LOW"값을 줄 때, "+(positive)"가 할당됩니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time
    //
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, LOW); // positive at M2+
    delay(10);

"M1+"에 이어서 "M2+"를 구동하는 코드를 추가했습니다. 마찬가지로, M1 disable, M2 enable, M2+에 positive(+) 할당을 차례대로 코딩하였습니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time
    //
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, LOW); // positive at M2+
    delay(10);
    //
    digitalWrite(E2pin, LOW); // M2 stop
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, HIGH); // positive at M1-
    delay(10);
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, HIGH); // positive at M2-
    delay(10);
  }

4 번의 스텝에 대한 모든 코드이고, 한쪽 방향으로 20번의 스텝을 진행하게 됩니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2-, M1-, M2+
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, HIGH); // positive at M2-
    delay(10);
	//
    digitalWrite(E2pin, LOW); // M2 stop
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, HIGH); // positive at M1-
    delay(10);
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, LOW); // positive at M2+
    delay(10);
  }

반대 방향에 대한 코드입니다. 표시된 부분만 서로 바뀌었고 나머진 동일합니다.

void loop() {
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2+, M1-, M2-
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time
    //
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, LOW); // positive at M2+
    delay(10);
    //
    digitalWrite(E2pin, LOW); // M2 stop
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, HIGH); // positive at M1-
    delay(10);
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, HIGH); // positive at M2-
    delay(10);
  }
  for (int i = 0; i < 20; i++) {
    // rotation order : M1+, M2-, M1-, M2+
    digitalWrite(E2pin, LOW); // to stop rotation previously
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, LOW); // positive at M1+
    delay(10); // Do not missing, needs a time
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, HIGH); // positive at M2-
    delay(10);
	//
    digitalWrite(E2pin, LOW); // M2 stop
    digitalWrite(E1pin, HIGH); // M1 enable
    digitalWrite(M1pin, HIGH); // positive at M1-
    delay(10);
	//
    digitalWrite(E1pin, LOW); // M1 stop
    digitalWrite(E2pin, HIGH); // M2 enable
    digitalWrite(M2pin, LOW); // positive at M2+
    delay(10);
  }
}

완성한 전체 코드입니다. 작동 테스트는 아래 영상 마지막 부분에 있습니다. 이번 글은 여기에서 마치고, 다음 글에선 이어서 이 쉴드를 조이스틱을 이용하여 제어하는 예제를 작성해 보겠습니다. 이상입니다.

Comments