[아두이노] Stepper Motor 원하는 각도 회전(2)

IOT/아두이노|2019. 5. 3. 09:00

[아두이노] Stepper Motor 원하는 각도 회전(2)



지난 시간에 Stepper Motor를 원하는 각도로 회전 시켰는데 오늘은 Bluetooth로 스마트폰에서 아두이노 연결 된 Stepper Motor를 회전 시키는 실험을 하도록 하겠습니다.


1. Stepper Motor + Bluetooth 통신 준비


스마트폰과 아두이노는 Bluetooth를 통해 통신합니다.


스마트폰 Bluetooth 어플은 아무거나 사용해도 됩니다. 실험에서는 Controller mode와 Terminal mode를 사용하여 실험 했네요. Controller mode은 버턴을 지정하고 버턴을 클릭하면 해당 버턴값을 아두이노로 보내는 형식이고요, Terminal mode은 채팅하는 식으로 아두이노 IDE 시리얼모니터에서 값을 입력하는 것과 유사합니다. 직접 전송할 값을 타이핑해서 보내는 방식입니다. 버턴을 눌러서 그 값을 전송하는 방식과 직접 타이핑해서 전송하는 방식이 들어 있는 어플이면 아무거나 상관 없습니다. 직접 앱인벤터로 만드셔도 되고요.


그냥 시리얼 통신으로 값을 전달할 수 있는 Bluetooth 어플이면 아무거나 상관 없습니다. 안드로이드면 구글스토어에서 Arduino Bluetooth만 치셔도 많은 어플들이 검색되니깐 실험하고 싶은 어플을 아무거나 선택하시면 됩니다.

2. Stepper Motor + Bluetooth 회로도



  • 준비물 : 5V 스템모터, ULN2003 모터드라이버, Bluetooth(HC-06) 1개, 아두이노우노
  • 내용 : 8,9,10,11핀을 순서대로 IN1, IN2, IN3, IN4에 연결하고 스템모터와 UNL2003 모터쉴드에 연결하고 Bluetooth를 2, 3번에 연결한다.

  • Rx - 데이터 읽기 (BlueRX =>arduino Pin3)
  • Tx - 데이터 보내기(BlueTX =>arduino Pin2)


지난 시간의 Stepper Motor 회로도에서 Bluetooth만 하나 더 연결한 회로도 입니다.

2. 코딩 - I



Stepper

#include <Stepper.h>
  • Stepper stepper(STEPS, IN1, IN2, IN3, IN4) : 사용하는 Stepper Motor 스템수, 각 4핀을 세팅.
  • stepper.setSpeed(값) : Stepper Motor의 속도 설정.
  • stepper.step(스텝수) : 스템수로 회전 각을 표현 한다.

시리얼 통신

  • Serial.begin(9600) : 시리얼 통신 시작(9600 통신속도)
  • Serial.println(값) : 시리얼모니터 출력
  • Serial.available() : 시리얼통신으로 데이터가 들어놨는지 상태 확인
  • Serial.parseInt() : Int형으로 데이터를 읽음

SoftwareSerial 통신

#include <SoftwareSerial.h>

SoftwareSerial mySerial (rx, tx) : 소프트시리얼 객체선언(rx(수신), tx(전송))
mySerial.begin(9600) : 시리얼 통신 시작(예로 9600 통식속도를 사용해 봤네요.)
mySerial.write(값) : 데이터 전송
mySerial.available() : 데이터 들어왔는 확인
mySerial.read() : 전송된 데이터 1byte 읽기


[지난 시간 소스]

#include <Stepper.h>

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup()
{
  stepper.setSpeed(12);
  Serial.begin(9600);
}

void loop()
{
   if(Serial.available()) {
    int val=Serial.parseInt(); //회전각 int형으로 읽기
    
    val=map(val,0,360,0,2048); //회전각 스템 수
    stepper.step(val);
    Serial.println(val);
    delay(10);
  }
}

위 소스를 가지고 수정을 합시다. Bluetooth 통신을 하기 위해서 SoftwareSerial 라이브러리를 이용하여 통신을 하게 됩니다 그래서, 다음과 같은 Bluetooth 통신 명령 과정이 필요합니다.

#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

이렇게 초기 선언을 합니다. 2번핀은 Bluetooth의 TX핀이고 3번핀은 Bluetooth의 RX핀입니다. 혼동하시면 안됩니다. 나머지 코딩은 Serial 단어를 mySerial로만 변경하시면 코딩 수정이 끝납니다. 변경되는 부분은 아래와 같습니다.

void setup()
{  
  mySerial.begin(9600);
}
void loop()
{
   if(mySerial.available()) {
    int val=mySerial.parseInt(); //회전각 int형으로 읽기
    mySerial.println(val);
    delay(10);
  }
}

합쳐진 코딩은,

#include <SoftwareSerial.h>
#include <Stepper.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup()
{
  stepper.setSpeed(12);  
  mySerial.begin(9600);  
}

void loop()
{
 
  if(mySerial.available()) {
    int val=mySerial.parseInt();
    val=map(val,0,360,0,2048);
    stepper.step(val);
        mySerial.println(val);
    delay(10);   
  }
}

[결과]
Terminal Mode로 값을 직접 타이핑 한 값으로 회전시키면 다음과 같은 결과가 나오네요. 360도를 보내면 아두이노가 Bluetooth로 받은 후 Stepper Motor를 회전시킨후 회전 시킵니다. 그리고 나서 스템수를 다시 스마트폰으로 보내고 스마트폰는 받은 스템수를 아래 이미지 처럼 "HC-06: 2048"이라고 출력 됩니다.


간단히 실험 영상을 보시기 바랍니다.


3. 코딩 - II


코딩-I은 스마트폰으로 각도를 채팅방식으로 입력을 해서 Stepper Motor를 회전 시켰다면 이제는 방향버턴키로 회전시키는 코딩으로 수정하도록 하겠습니다. 참고로 방향키버턴으로 눌러서 회전 시키면 위 코딩-I 소스대로 하면 문제가 좀 발생합니다. 그 이유는 mySerial.parseInt() 함수 때문에 그렇습니다. 만약에 각도 데이터를 전송하고 읽을때 읽는 데이터가 밀리면 통신 버퍼에 쌓이게 되고 그러면 합쳐진 상태로 각도를 읽는 문제가 발생합니다. 가령, 10도 회전을 연달아 이어서 10, 10 이렇게 전송이 되었을 때 받는 아두이노에서 데이터가 쌓여 1010이렇게 되면 parseInt()함수는 한번에 1010각도로 읽어버리게 됩니다. 즉, 10, 10 이렇게 회전 시켜서 20도를 회전 시켜야 하는데 1010 이것을 한번에 읽어서 1010각도로 회전 시켜버리는 문제가 생기게 됩니다. 그래서 방향키를 방향 알파벳 한글자로 해서 mySerial.read()로 1byte씩 읽고 그 값에 따라 회전시키는 방법으로 쉽게 제어할 수 있도록 코딩을 변경 하겠습니다.

코딩-1 소스에서,

  if(mySerial.available()) {
    int val=mySerial.parseInt();
    val=map(val,0,360,0,2048);
    stepper.step(val);
        Serial.println(val);
    delay(10);   
  }

이 부분만 변경하면 됩니다.

int angle = 0; //외부변수 현재 각도값
if(mySerial.available()) {
      int val=0;
      char ch=mySerial.read();

      if(ch=='a')val=10;      //시계방향
      else if(ch=='d')val=-10; //반시계방향
      else val=0;
      
      angle+=val;
      val=map(val,0,360,0,2048);  
      stepper.step(val);
      //Serial.println(angle);      
      delay(10);
}

if문으로 1byte 읽은 알파벳이 ch변수에 저장되고 이 저장된 변수가 'a'면 정방향 10도 회전, 'd'면 역방향 10도 회전시키고 그외 키 값은 무시 0도 회전으로 if문에서 체크하여 val 변수에 회전시킬 각도값을 저장하게 했습니다.

여기서 외부 변수로 angle에 대한 동작 명령은 코딩하지 않았습니다. 이것은 여러분들이 나중에 활용하라는 의미로 남겨 둔 변수입니다. 이 변수는 현재 코딩에서는 없어도 되는 변수이지만 구지 표현한 이유는 나중에 어려분들이 Stepper Motor를 회전을 제어할 때 꼭 필요한 변수이기 때문입니다. 예를 들면, 우리가 Stepper Motor 회전을 시키면 700도 정방향으로 회전 시켰다가 역방향 200도 회전 시키고 또 다시 정방향, 역방향 이렇게 계속 회전을 시킬 경우 Stepper Motor라 마지막 회전된 위치를 단순히 회전만 시키면 알 수 없습니다. 이때 angle이라는 변수를 하나 선언해 놓고 처음 회전이 시작한 위치를 0도에 지정해놓고 계속 회전 값들을 angle변수에 더하게 되면 Stepper Motor의 시작 위치 0도에서 어느 방향으로 회전을 하더라도 현재 회전한 위치를 알 수 있게 됩니다.

여기서, 한가지 예로 외부 입력값 E(End)라고 생각하고 위 if문에 연장 선상으로 if문으로 아래와 같이 코딩하면

else if(ch=='e') val = -angle;

이렇게만 표현하면 e키가 입력된 순간 angle의 변수 안에는 지금 까지 회전되어 진 현재의 위치각도를 가지고 있기 때문에 그 값에 -(마이너스)를 붙이면 원상태 0도로 되돌아 가게 됩니다. 즉, 90도가 현재의 위치면 -angle로 -90도 만큼 회전 하면 0이 되겠죠. 다시 -90도가 현재의 위치면 -(-90)이니깐 +90도 만큼 회전 하면 0이 됩니다. 결론은 e키가 입력되면 이 한줄로 처음 자신의 위치로 되돌아 가는 명령을 코딩할 수 있습니다.

angle의 변수를 남겨 둔 이유는 여러분들이 나중에 회전을 제어할 때 언제든지 자신의 위치로 되돌아 갈 수 있고 현재의 회전 된 위치 값을 가질 수 있으면 그 기준으로 특별한 회전을 제어할 수 있게 되기 때문에 이런 angle 변수가 중요하기 때문에 선언만 해놓았습니다. 나머지는 여러분들이 이 변수를 가지고 어떻게 활용할지는 여러분의 몫입니다.

종합해보면,

#include <Stepper.h>
#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

int angle = 0;

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  stepper.setSpeed(12); 
}

void loop()
{
  if(mySerial.available()) {
      int val=0;
    char ch=mySerial.read();
      if(ch=='a')val=10;      
      else if(ch=='d')val=-10;
      else val=0;
      
      angle+=val;
      val=map(val,0,360,0,2048);  
      stepper.step(val);
      Serial.println(angle);      
      delay(10);
    }
}

[결과]



Controller Mode를 누르면 위 그림처럼 버턴 이미지로 구성된 창이 뜹니다. 그리고 톱니모양 설정을 누르면 버턴 키 값을 지정할 수 있습니다. 게임 방향키값인 a,s,w,s키로 우선 설정했는데 실제 실험에서는 a,d키만 사용합니다. 이 키값을 통해서 Setpper Motor를 회전 시키게 됩니다.

간단히 스마트 폰으로 방향키를 누렀을 때 Stepper Motor가 회전되는 실험 영상입니다.

마무리


이렇게 해서 스마트폰으로 간단히 회전을 시키는 법을 배웠습니다. Bluetooth를 한번 소개한 뒤에 계속 중복된 실험이 이뤄지고 있는데 이런 실험 과정을 여러분들도 실험하면서 계속 반복 학습을 해주세요. 그래야 나중에 다른 부품을 사용하더라고 이 부품을 이전에 배웠던 부품들과 쉽게 연결할 수 있습니다. 어떻게 두 부품을 결합하고 두 부품의 소스 코딩을 어떻게 합쳐지고 코딩이 되는지 그 감각을 익히셨으면 합니다. 그리고 하나의 표현으로 끝내지 말고 다른 표현을 계속 머리속에서 상상하셔야 합니다. 처음에는 이게 힘들지만 나중에는 재밌는 놀이처럼 여러가지의 상상을 하게 됩니다.

그런데 처음 배우시는 분들은 Bluetooth로 통신하는 실험만 하고 끝나고 Stepper Motor 회전 실험만 하고 넘어 갑니다. 나주엥 어떤 주제로 작품을 만들려고 할 때 그 때부터 문제가 발생합니다. 두 개 이상의 부품을 합치는 실험을 할 때 회로도 표현은 그럭저럭 되는데 코딩부분은 둘을 합치는 방법 자체를 이해를 못하는 경우가 많기 때문에 여러분들은 처음 부품을 배울 때 그 부품을 다른 부품과 계속 연결해서 실험하셔야 나중에 어떤 부품이든지 쉽게 표현을 할 수 있게 됩니다.

오늘 실험은 Stepper Motor를 하나를 조정했지만 두개 이상 연결하면 RC카 또는 로봇팔 등의 구현이 가능하고 Stepper Motor은 다양한 관절 제어에 사용하니깐 한번 SF영화나 애니메이션에서 봤던 장면들을 떠올리시고 거기서 Stepper Motor가 적용된다면 어떤 느낌으로 회로도를 구성하고 코딩 하면 좋을 지 상상의 나래를 펼쳐 보세요.


댓글()