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

2018. 10. 12. 15:00

Arduino/Shield

2A Motor Shield for Arduino Twin with Bluetooth

DFRobot사의 2x2A DC Motor Shield for Arduino Twin 쉴드에 대한 네 번째 글입니다. 이번 글에서는 연재 마지막으로, 블루투스 통신을 이용하여 스마트폰 앱을 통해 모터 쉴드를 제어해 보겠습니다.

이를 위해, 보드는 DFRobot 사의 Bluno로 변경하고, 스마트폰을 통해 제어하며, 테스트를 위해 DVD 드라이브에서 꺼낸 DC모터를 이용하겠습니다.

관련글

DFRobot - Motor shield for Arduino #1 DC Motor

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

DFRobot - Motor shield for Arduino #2 Stepper Motor

윗 글에 이어, 동일한 모터 쉴드로 스텝 모터를 다루는 글입니다. 역시 DVD 드라이브에서 추출한 스텝 모터를 이용하였습니다.

DFRobot - Motor shield for Arduino #3 JoyStick

아날로그 조이스틱을 이용하여 모터 쉴드와 스텝 모터를 제어하는 방법을 설명하고 있습니다.

블루투스 아두이노 통합 보드, BLUNO

블루투스를 통하여 원격으로 제어하기 위해 이 글에서 사용한 조합입니다. 우선, 그 동안 테스트시에 사용했던 아두이노 우노 보드를 블루투스 4.0 통합 보드인 DFRobot 사의 BLUNO로 변경했습니다. 그리고, 연재에 사용하고 있는 모터 쉴드 외에 스마트폰과 블루노를 제어할 수 있는 블루투스 앱이 필요합니다.

Bluno는 DFRobot사에서 만든 아두이노 우노 호환 보드로, Bluetooth 4.0(BLE) 칩이 통합되어 블루투스 통신이 가능한 보드입니다. 블루투스 칩이 시리얼(Serial) 방식으로 연결되어 있어서 통신을 위한 별도의 세팅이나 라이브러리가 필요 없어 초보자도 손쉽게 사용할 수 있습니다. 이 보드에 대한 자세한 설명은 아래 관련 글을 참고하시기 바랍니다.

모터 쉴드와 블루노 보드를 결합한 모습입니다. 둘 다 검정색 보드라 잘 어울리는 듯 합니다.

아이폰용 BLUNO 원격제어 앱, GoBLE

원격 제어를 위해 사용할 앱입니다. DFRobot사에서 만들어 배포하는 것이고, 연결 및 사용법이 간단하고, 인터페이스도 아주 심플하며, 전용 라이브러리를 제공하기 때문에 프로그램 소스를 만들기도 어렵지 않습니다. 그런데, 아래와 같은 제약 사항이 있습니다.

  • 블루노 보드와만 연결됩니다
  • 아이폰 버전만 있습니다.

DFRobot사에서 자신들의 Bluno 보드를 위해 만든 앱이라서 타사 BLE 제품과는 호환되지 않습니다. 반대로, Bluno 보드와는 별도 설정없이 자동으로 연결되어 편합니다. 또, 현재 iOS(아이폰, 아이패드) 버전만 제공하고 있고, 안드로이드 버전은 아직까지 소식이 없는 것을 보니 만들지 않을 생각인 듯 합니다. 대신, playBLE라는 일반 유저가 만든 앱이 있어 나중에 잠깐 언급하겠습니다.

앱을 설치하고 실행한 모습입니다. 심플한 인터페이스를 보여 줍니다.

앱 화면 오른쪽 상단의 영문자 "i"를 누르면 위와 같은 설명 화면이 표시되고, 오른쪽 하단 "return"을 터치하면 원래 화면으로 돌아갑니다. 화면 왼쪽이 조이스틱이고, 오른쪽 버튼 4개와 가운데 버튼 2개가 있습니다. 다른 입력 키는 없으며, 가운데 상단에 연결 상태를 표시해주는 아이콘이 있습니다.

왼쪽 상단에는 모드 선택 버튼이 있습니다. "Status Mode"는 키 입력이 발생할 때마다 데이터를 전송하고, "Interval Mode"는 일정 시간마다 계속 전송합니다. Status Mode가 디폴트이며 변경 없이 사용하겠습니다.

X축, Y축은 화살표 방향대로입니다. 여기서는 DC모터 하나만 테스트하기 때문에 X축만 연결하여 테스트하겠습니다.

Bluno와 GoBLE의 간단한 연결 테스트
void setup() {
  Serial.begin(115200);
}
//
void loop() {
  if (Serial.available()) {
    Serial.print(Serial.read());
  }
}

아이폰과 블루노가 연결된 후 데이터를 받아  오는 간단한 테스트입니다. 보는 바와 같이 Serial 통신에 대한 설정 외에 다른 코드가 필요하지 않습니다. Serial 버퍼에 데이터가 도착하면 읽어서 그대로 시리얼 모니터에 출력하는 코드입니다.

캡처한 화면 상태가 좋지 않아 색상 구분이 좀 쉽지 않은데, 블루노의 전원이 들어온 상태에서 GoBLE 앱을 실행하면 자동으로 주변의 블루노를 찾아 링크시키고 아이콘의 색깔이 붉은색에서 초록색으로 변경됩니다. 이 아이콘을 다시 터치하면 연결이 끊기고 아이콘은 다시 붉은색으로 바뀝니다. 앱이 실행되는 중에는 이 과정을 계속 반복하기 때문에, 연결을 수동으로 끊더라도 조금  있으면 다시 자동으로 연결됩니다. 자동으로 연결되는데 걸리는 시간은 생각보다 꽤 길수도 있습니다. 몇초에서 십 몇초까지 걸리는 듯 하네요! 

GoBLE 앱이 연결을 성공하면 블루노 보드는 위와 같이 LINK LED가 켜집니다. 그리고, 데이터 송수신 여부를 RX, TX LED를 통해 보여 줍니다. GoBLE 앱은 데이터 송신만 하고, 수신은 않기 때문에 RX LED는 들어오지 않고 있습니다.

GoBLE 앱에서 조이스틱을 움직였을 때 블루노의 시리얼 모니터를 통해 출력된 결과입니다. 물론 이대로 사용하긴 힘들고, 단순히 아이폰 앱에서 블루노로 데이터가 전송되는지만 확인하면 됩니다. 이 데이터는 앱 화면의 조이스틱 데이터와 모든 버튼들의 데이터가 함께 들어 있습니다. 특정 버튼만 터치해도 모든 제어 데이터가 전송되는 것입니다.

또, Serial.print() 함수에 의해 위와 갈이 시리얼 모니터에 데이터가 출력되는데, 아두이노와 시리얼로 연결되어 있는 블루투스 칩에도 같은 데이터가 동시에 전송됩니다. GoBLE 어플은 어차피 블루노쪽으로 출력만하지 반대로 입력을 받진 않기 때문에 상관없지만, 만약 데이터를 주고 또 받아야 한다면, 테스트시에 시리얼 모니터 사용에 주의를 해야 합니다.

프로그램 소스 작성하기

먼저, DFRobot에서 제공하는 전용 라이브러리를 설치해야 합니다. 아래 링크로 이동하여 다운 받습니다.

링크 페이지로 이동하여 "GoBLE" 폴더를 다운 받아 오른쪽과 같이 아두이노 라이브러리 폴더에 만들어 줍니다.

#include <GoBLE.h>

우선, GoBLE 라이브러리를 포함시킵니다. GoBLE 라이브러리의 주요 기능은, GoBLE 앱으로부터 받은 데이터를 분석(파싱)하여 조이스틱과 각 버튼의 상태값을 구분하여 저장하는 것입니다. 위 쪽에서 테스트시 시리얼 모니터에 보이는 데이터가 파싱 이전의 원시 데이터입니다.

void setup() {
  Goble.begin();
  Serial.begin(115200);
}

setup() 함수입니다. Goble 인스턴스를 생성하여 저장 공간을 확보하고 멤버 함수들에 접근할 수 있게 합니다. 시리얼 통신 속도는 Bluetooth 칩이 연결된 기본 속도인 115,200보오(baud)로 설정합니다.

void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
  }
}

Goble.available() 함수는 시리얼을 통해 도착한 데이터가 있다면 "ture"값을 반환합니다. 데이터가 존재할 경우, Goble.readJoystickX() 함수를 이용해서 X축 값을 읽어 옵니다.

void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //
    Serial.print("Joystick Value: ");
    Serial.println(joystickX);
  }
}

Serial.print() 함수를 이용해 읽어온 데이터를 출력합니다.

결과 화면입니다. 아이폰 앱에서 조이스틱을 상하로 움직이면 위와 같이 X축 값이 출력됩니다. 이 때, 화살표가 가리키는 것처럼 속도를 115,200 baud로 설정해야 합니다.

#include <GoBLE.h>
#include <TM1637Display.h>
//
const int CLK = 2; // LED segments CLK
const int DIO = 3; // LED segments DIO
//
TM1637Display dsp(CLK, DIO);
//
void setup() {
  Goble.begin();
  Serial.begin(115200);
  dsp.setBrightness(7);
}
//
void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //
    dsp.showNumberDec(joystickX);
  }
}

이번에는 같은 결과를 시리얼 모니터가 아닌 LED 세그먼트를 통해 확인하는 소스입니다. LED 세그먼트 사용법은 이전 연재를 참고하시면 됩니다.

조이스틱을 움직이지 않는 중간 값은 128이고, 위로 129에서 255까지 증가하며, 아래로 127에서 1까지 감소합니다. 이 값의 변화를 이용하여 속도 조절에 응용할 수 있습니다.

GoBLE 앱으로 DC 모터 제어하기

이제 실제로 앱을 통해 모터를 제어해 보겠습니다. 테스트에 사용할 모터는 DVD 드라이브를 분해하여 얻은 디스크 트레이용 DC 모터입니다. 이전 연재에서 사용했던 것이므로 자세한 내용은 이전 글을 참고하시면 됩니다.

위와 같이 연결하였습니다. 블루노와 GoBLE이 연결된 상태에선 소스 업로드가 되지 않습니다. 꼭 연결을 해제하고 앱까지 닫은 상태에서 업로드 하시기 바랍니다.

#include <GoBLE.h>

먼저 GoBLE 라이브러리를 포함시킵니다.

#include <GoBLE.h>
//
// Set constants for Control Port
const int E1pin = 10; // Motor1 Speed Control - D10
const int M1pin = 12; // Motor1 Direction Control - D12
//

모터 쉴드를 위한 상수들을 선언합니다. E1pin은 디지털 10번 핀과 연결되고, 모터의 enable, disable, 그리고 속도조절을 담당합니다. M1pin은 디지털 12번 핀과 연결되고, 모터 구동 및 방향 조절에 사용되며, E1pin, M1pin은 쉴드의 모터 1번(M1)을 제어합니다.

void setup() {
  Goble.begin();
  //
  pinMode(E1pin, OUTPUT);
  pinMode(M1pin, OUTPUT);
}

setup() 함수입니다. Goble 인스턴스를 생성하고, E1pin(D10), M1pin(D12)을 출력 모드로 설정합니다.

void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //  
  }
}

이제 loop() 함수를 작성합니다. 우선, Goble.available() 함수를 이용하여 수신된 데이터가 있는지 체크하고, 데이터가 존재한다면 조이스틱의 X축 값을 가져옵니다.

X축의 움직임은 위와 같이 숫자값의 변화로 표현합니다. UP 방향은 숫자가 증가하고, DOWN 방향은 감소하므로 만약, 속도 조절 등에 이용하려면 그에 따른 코딩이 필요합니다.

void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //  
    if ( joystickX == 128 ) {
      // STOP
    } else if ( joystickX < 128 ) {
      // DOWN
    } else if ( joystickX > 128 ) {
      // UP
    }
  }
}

UP, DOWN, STOP 세 가지 상태를 가지므로 위와 같이 IF, ELSE IF 구조를 이용해 적용하겠습니다. 마지막 조건문은 생략해도 상관없습니다.

void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //  
    if ( joystickX == 128 ) {
      // STOP
      digitalWrite(E1pin, LOW);
    } else if ( joystickX < 128 ) {
      // DOWN
      digitalWrite(E1pin, HIGH);
      digitalWrite(M1pin, LOW);
    } else if ( joystickX > 128 ) {
      // UP
      digitalWrite(E1pin, HIGH);
      digitalWrite(M1pin, HIGH);
    }
  }
}

조이스틱 값이 128이면 모터는 움직이지 않아야 합니다. E1pin에 "LOW" 값을 주면 모터가 disable 상태가 되므로 이를 구현할 수 있습니다. 또는 E1pin에 아날로그 출력으로 숫자 "0"을 주면 속도가 0이 되므로 마찬가지로 정지 상태가 됩니다.

조이스틱 값이 128이 아니라면 모터는 어느 한 방향으로 움직여야 하므로, E1pin에 "HIGH" 값을 할당합니다. 그리고, M1pin에 "LOW" 또는 "HIGH" 값을 주어 각각 다른 방향으로 모터를 구동 시킵니다.

위와 같이 결과를 확인할 수 있습니다. 속도 조절은 없고 단순히 방향만 전환하며, 쉴드에선 초록색, 붉은색 LED가 각각 방향에 따라 점등됩니다.

속도 조절 적용하기
analogWrite(E1pin, 0);

속도 조절은 위와 같이 E1pin에 숫자 0에서 255까지 할당하면 가능합니다. 0은 정지, 255는 최고 속도입니다.

if ( joystickX == 128 ) {
      // STOP
      digitalWrite(E1pin, LOW);
    } else if ( joystickX < 128 ) {
      // DOWN
      analogWrite(E1pin, (256 - joystickX)); // 129 ~ 255
      digitalWrite(M1pin, LOW);
    } else if ( joystickX > 128 ) {
      // UP
      analogWrite(E1pin, joystickX); // 129 ~ 255
      digitalWrite(M1pin, HIGH);
    }

속도 조절을 위하여, 위와 같이 E1pin에 digitalWrite() 함수대신 analogWrite() 함수를 사용하면 되는데, DOWN 방향의 경우 값이 작을 수록 빠른 속도이므로 약간의 변환이 필요합니다.

#include <GoBLE.h>
//
// Set constants for Control Port
const int E1pin = 10; // Motor1 Speed Control - D10
const int M1pin = 12; // Motor1 Direction Control - D12
//
void setup() {
  Goble.begin();
  //
  pinMode(E1pin, OUTPUT);
  pinMode(M1pin, OUTPUT);
}
void loop() {
  if (Goble.available()) {
    int joystickX = Goble.readJoystickX();
    //  
    if ( joystickX == 128 ) {
      // STOP
      digitalWrite(E1pin, LOW);
    } else if ( joystickX < 128 ) {
      // DOWN
      analogWrite(E1pin, (256 - joystickX)); // 129 ~ 255
      digitalWrite(M1pin, LOW);
    } else if ( joystickX > 128 ) {
      // UP
      analogWrite(E1pin, joystickX); // 129 ~ 255
      digitalWrite(M1pin, HIGH);
    }
  }
}

여기까지의 전체 소스입니다. GIF 이미지로는 속도 변화를 표현하기가 어려워서, 결과 영상은 아래 동영상 마지막 부분에서 확인하시면 됩니다.

위에서도 언급했지만, GoBLE 앱은 아쉽게도 아이폰 버전만 있습니다. 대신, 안드로이드 기기에서는 일반 유저가 만든 playBLE 앱을 이용하면 되고, 아래 링크에서 확인할 수 있습니다.

모터 쉴드와 블루노 보드를 이용한 스마트폰 블루투스 제어에 대한 글은 여기 까지이며, 이것으로 DFRobot Motor Shield for Arduino Twin에 대한 연재를 마치겠습니다.



Comments