아두이노 드론 만들기 #1


지난 포스팅에서 잠시 언급했지만 정말 BLDC 모터 돌리는데만 꼬박 1주일이 걸렸다. 중간에 잠깐 되는 듯하다가
변속기(이하 ESC) 2개만 태워먹고 결국은 실패했다. 괜한 도전을 시작했나 싶었으나 그래도 인생 짬밥이 있는데
하다보면 수가 나겠거니 하고 계속 시도하다가 결국은 모터를 구동하는데 성공했다.


오늘 포스팅은 간단하게 BLDC 모터를 구동하는 과정을 정리해보도록 하겠다. 
사실상의 주된 내용은 아두이노의 Servo 라이브러리에 대한 설명이니 이 부분이 필요없는 분들은 그냥
맨 마지막 동영상이나 보시고 넘어가시라~


간단한 기초 지식 설명


이미 아는 사람은 다 알지만 나는 문돌이의 입장에서 글을 쓰는만큼 간단하게 기초 지식부터 짚고 넘어가겠다.
하지만 나보다 더 잘 설명하는 글들이 많으니 그냥 링크로 대신한다(결코 귀차니즘의 발로가 아니라고는 말 못하겠다…). 
개인적으로 가장 설명이 잘 되어있다고 생각되는 블로그들을 위주로 링크한다.


BLDC 모터 : http://bit.ly/2uCa078
ESC : http://bit.ly/2sABx7F (혹은 위의 BLDC 설명 블로그에서도 확인 가능)
LiPO 배터리 : http://bit.ly/2tAxSrJ
프로펠러 : http://bit.ly/2uW2eV5


일단 가장 기본적으로 필요한 지식들은 위의 4가지라고 보면 될 것 같다. 문제는 이미 조립이 되어있는 완제품이나
아니면 모든 구성품들이 다 갖추어진 조립 Kit를 사는 경우가 아니라면 이 4가지 부품의 궁합을 잘 맞춰서 구매를
해야 하는데 이 과정이 꽤나 성가시고 어렵다. 


특히나 각각의 부품을 검색하다보면 설명한 글마다 부품 제조업체에서 제공하는 data sheet를 보면 사용법을 알 수 
있다고 하는데 웬만한 제품이 중국산이다보니 제대로된 data sheet 찾기가 결코 만만치 않다.


내가 지금 사놓은 부품 중 일부도 모터와 프로펠러는 짝이 맞는데 ESC와 배터리가 맞지 않아 추가로 구매해야 하는
상황이다. 무려 4세트나 되는데…ㅠ.ㅠ


아무튼 직접 제작을 목표로 하시는 분들은 위 내용들을 잘 숙지하셔서 불필요한 낭비를 줄이도록 하시길 빈다.


아두이노 RF 통신하기


사실 조종기도 따로 사고 싶었으나 조종기와 수신기 가격이 결코 만만치가 않았다. 게다가 그런 것을 사다 집에 들여
놓으면 분명 집사람의 반발이 있을 것 같아 도무지 살 엄두가 나질 않았다.


그래서 대안으로 선택한 것이 아두이노의 조이스틱 모듈과 nRF24L01 트랜시버의 무선 통신을 이용하여 
조종기를 만들기로 했다. 이 부분도 불필요하게 글의 길이가 길어지는 것을 막기 위해 링크로 대신한다.


아두이노 조이스틱 모듈 사용 : http://bit.ly/2uVzwn2
nRF24L01을 이용한 무선 통신 : http://bit.ly/2sRbmhh


이 과정에서는 주의할 점이 조이스틱 모듈이 원점이 제대로 안잡힌다는 문제다. 낱개로 파는 조이스틱 모듈과 두 개가
하나의 기판에 붙은 것 2종류의 조이스틱 모듈을 사용해보았는데 두 종류 모두 센터값 512에서 멈춰있지 않고 계속
1~2 정도의 오차가 생기면서 값이 지속적으로 변하였다. 내가 불량품을 산 것인지 대체로 이정도는 허용 범위인 것인지
모르겠다.


관련 스케치 코드는 다음 포스팅에서 공개하도록 하겠다.


ESC 캘리브레이션하기


바로 이 작업에서 1주일의 시간과 2개의 ESC가 날아갔다…ㅠ.ㅠ
ESC에 대해 설명한 글들에서도 자세한 정보들은 data sheet를 참조하라는데 data sheet 찾는 것도 만만치 않고
또 찾아도 내용 파악이 쉽지 않다…-.-


ESC 캘리브레이션이란 간단히 말하면 조종기의 최솟값/최댓값과 ESC의 최솟값/최댓값을 mapping 시켜주는
과정이다. 다음 블로그에서 조금 자세히 알아볼 수 있을 것이다.


ESC 캘리브레이션이란? : http://ivivaldi.blog.me/220917752795


하지만 처음 실패의 이유는 곰곰히 생각해보면 개발자로서 참 부끄러운 일이기도 하다.
흔히 뭔가 준비가 안되어있는 사람들에게 하는 말이 ‘군인이 전쟁터에 총도 안들고 나간다’는 것이다.
군인에게 가장 필요한 도구가 ‘총’인 것과 같이 개발자에게 가장 필요한 도구는 API다.
군인이 전쟁터에서 훌륭히 싸우기 위해 평소에도 총에 기름칠을 하고 정비를 하듯이 개발자도 자유자재로 원하는 
기능을 만들어내기 위해서는 적재적소에 올바른 API를 적용할 줄 알아야 한다. 비록 평소에 달달 외우지는 못할지언정
어떤 API를 쓸 상황이 되면 그 API에 어떤 속성들이나 함수들이 있으며 그 사용법은 어떻게 되는지를 한 번쯤은
살펴보고 사용을 해야 할 것이다.


나의 실패는 바로 이 과정이 없었기 때문이다.
아래 코드는 최초로 찾은 아두이노를 통해 ESC를 캘리브레이션 하는 코드이다.

#include <Servo.h>

Servo esc_b; 
Servo esc_r; 

int black = 180; //모터로 들어가는 초기값은 180. 즉 최대값.
int red = 180;

void setup() {

  Serial.begin(9600);
  esc_b.attach(6, 1000, 2000); //내가 실수한 부분!!!
  esc_r.attach(7, 1000, 2000); 

  Serial.setTimeout(50); 
  esc_b.write(180);
  esc_r.write(180);
}

void loop() {

  esc_b.write(black); 
  esc_r.write(red);

  Serial.print(black);
  Serial.print('\t');

  Serial.print(red);
  Serial.println('\t');
}

void serialEvent()
{
  while (Serial.available()) {
    black = Serial.parseInt();
    red = Serial.parseInt();
  }
}



물론 이 코드를 그대로 쓰지는 않았다. 우선 다행스러워보이는 것은 BLDC 모터를 제어하는데도 Servo 라이브러리를
사용한다는 것이다. Servo라이브러리라면 작년에 4족보행 로봇 만들 때 지겹게 써오던 라이브러리가 아닌가?


하지만…난 Servo 라이브러리를 반쪽만 알고 있었다…


Servo 라이브러리 살펴보기


Servo 라이브러리는 PWM을 통해 모터를 제어하기 위한 라이브러리이다.



이 Servo 라이브러리의 출력함수에는 2가지가 있다. 바로 write()와 writeMicroseconds()이다.
두 함수 모두 int 값을 파라미터로 받지만 그 범위가 틀리다. 다음은 각 함수의 특징이다.


  1. write(int value) : value의 범위는 0 ~180이다. value는 각도를 의미한다. 90을 중심으로 90보다 작은 값과 90보다 큰 값은 서로 반대 방향으로 움직인다. 내부적으로 writeMicroseconds함수를 호출한다.
  2. writeMicroseconds(int value) : value의 일반적인 범위는 1000 ~ 2000이나 모터 제조사에 따라 700 ~ 2300까지도 설정 가능하다. 모터가 움직이지 않을 때까지 최댓값을 늘릴 수 있으나 모터가 움직이지 않음에도 지나치게 값을 올릴 경우 높은 전류가 흘러 위험하다.


볼드 처리한 문구에 주목을 해야 한다. 우선 write함수는 내부적으로 writeMicroseconds를 호출하게 되어있다.
하지만 두 함수는 각각의 범위가 있고 그 범위가 서로 다르다. 때문에 write함수에서 writeMicroseconds함수를
호출할 때는 map함수를 통해 write에서 사용하는 범위인 0 ~ 180의 값을 writeMicroseconds에서 사용하는
범위의 값으로 변환하여 호출을 한다. 그런데 이 때 단순히 0 ~ 180을 1000 ~ 2000으로 변환하지 않는다.
즉, map(value, 0, 180, 1000, 2000)으로 호출하지 않는다는 말이다. 바로 다음과 같이 호출한다.

value = map(value, 0, 180, SERVO_MIN(),  SERVO_MAX());


이것이 어떤 의미일까? 차근 차근 알아보자.
우선 Servo 라이브러리에는 MIN_PULSE_WIDTH와 MAX_PULSE_WIDTH라는 2개의 상수가 정의되어있다.
MIN_PULSE_WIDTH는 544라는 값을 가지고 있고 MAX_PULSE_WIDTH는 2400이라는 값을 가지고 있다.


또한 Servo 라이브러리에는 SERVO_MIN()와 SERVO_MAX()라는 매크로 함수가 정의되어 있는데 각각 다음과 
같다.

#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4)  // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4)  // maximum value in uS for this servo


마지막으로 우리가 Servo 라이브러리를 사용하기 위해서는 attach() 함수를 통해 모터가 연결된 PIN을 이용하게 
되는데 이 attach 함수는 2개의 함수가 오버로딩 되어있다. 다음과 같다.

uint8_t Servo::attach(int pin)
uint8_t Servo::attach(int pin, int min, int max)



그런데 이 처음의 파라미터 하나짜리 attach 함수도 내부적으로는 파라미터 3개짜리 attach 함수를 호출하도록 되어있다.
즉, uint8_t Servo::attach(int pin)함수의 전체 모습은 다음과 같다.

uint8_t Servo::attach(int pin)
{
  return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}


그리고 파라미터 3개짜리 attach 함수에서는 두 번째와 세 번째 파라미터를 다음과 같이 this->min과 this->max에
할당한다.

this->min  = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max  = (MAX_PULSE_WIDTH - max)/4;


위 내용을 참고할 수 있도록 Servo 라이브러리 소스 코드와 아두이노 공식 사이트의 레퍼런스 페이지를 링크한다.



Servo 라이브러리 소스코드 : http://bit.ly/2tZ4kGh
아두이노 레퍼런스 페이지 : http://bit.ly/1NjpZI0


나의 실수


앞서도 말했듯이 나는 검색을 통해 아두이노로 ESC 캘리브레이션을 하는 소스를 찾았고 그 것을 그대로 쓰지 않고
수정을 했다. 수정한 코드는 다음과 같다. 몰론 이 코드는 잘못된 코드다…-.-

#include <Servo.h>

Servo esc; 

int max = 180; //모터로 들어가는 초기값은 180. 즉 최대값.

void setup() {

  Serial.begin(9600);
  esc_b.attach(9); //내가 실수한 부분!!! attach 함수의 두 번째와 세 번째 파라미터의 의미를 몰랐다.

  Serial.setTimeout(50); 
  esc.write(180);
}

void loop() {

  esc.write(max); 

  Serial.print(max);
  Serial.print('\t');
}

void serialEvent()
{
  // 이 시점에서 시리얼 모니터를 통해 0을 입력한다.
  while (Serial.available()) {
    max = Serial.parseInt();
  }
}


만약 이 코드대로라면 한 번 계산을 해보자. attach(int pin) 함수를 사용한 경우 write함수에서 writeMicroseconds를 호출할 때 값이 어떻게 매핑될까? 순서대로 살펴보자.


  1. attach(9) 호출
  2. attach(9, 544, 2400) 호출
  3. this->min과 this->max에는 모두 0이 할당됨
  4. esc.write(180) 호출
  5. 내부적으로 val = map(180, 0, 180, 544, 2400)을 통해 값을 매핑한 후 writeMicroseconds(val) 호출


이렇게 되면 결국 최댓값은 2400이 설정되고 만일 모터가 최댓값 2000까지 설정된 모터라면 앞서 본 것과 같이
높은 전류가 흐르게 되어 위험한 상황이 될 수도 있는 것이다. 이후로도 유사한 맥락의 실수를 몇처례 더 한 후 결국
ESC 2개를 태워먹고 말았다.


드디어 모터를 돌리다!


결국 진행 단계에서는 확실하게 원인을 찾지 못하였고 2300kv급의 레이싱 드론용 모터로 테스트 하던 것을 1000kv
모터로 시도하여 성공하게 되었다. 아마도 1000kv 모터는 2400 이상의 신호에도 견디도록 제작된 것 같다.
하지만 역시 안전한 구동을 위해서는 파라미터 3개짜리 attach 함수를 이용하여 최솟값과 최댓값을 명시적으로 지정해
주는 것이 바람지할 것으로 생각된다.


아래 동영상은 모터 구동 성공 동영상이다. 




모터가 어찌나 세게 도는지 혼자서 날아가는 줄 알았다…-.-
프로펠러 붙이면 어찌될지 자못 기대가 된다.


정리


결정적으로는 모터의 허용 값을 몰랐던 것이 원인이겠으나 역시나 Servo 라이브러리의 함수들을 좀 더 제대로
알고 썼더라면 조금 더 일찍 성공에 다다르지 않았을까 하는 생각이 든다.

시작이 반이라고…이제 모터 돌렸으니 프로펠러만 달면 붕붕 날아다닐까?
다음 포스팅에서는 진짜 그런지 한 번 확인해보도록 하겠다^^






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^


아두이노 드론 만들기 : Prologue


뭔가 촉이 왔다!
그래서 혹시나 하고 지난 블로그를 되돌아 봤더니…역시나…
아두이노 4족보행 로봇 만들기를 처음 포스팅 한 것이 2016년 6월 20일이었다.
이건 뭐…지킬박사와 하이드씨도 아니고, 늑대인간도 아니고…여름만 되면 공돌이로 변신하고자 하는 욕구가 넘치는
돌연변이 문돌이라고나 할까…-.-


그 때 첫 문장이 이러했다.


이제 막 걸음마를 뗐는데…
벌써 수퍼맨이 되어 날아가려고 한다고나 할까… 

[아두이노] 아두이노 4족보행 로봇 만들기 ~ 1


그랬다. 그 때는 정말 아무 것도 모른 채로 하룻강이지 범 무서운 줄 모르고 무작정 덤볐던 것 같다^^
그러면 지금은? 일단 걷는 것은 해봤으니 진짜로 날아볼 수 있을까?


솔직히 말하면 그리 자신은 없다. 아두이노라는 공통점이 있을 뿐 사용하는 모터도 다르고 모터가 다르니 구동하는
방식도 다르고, 게다가…내가 만들려는 것이 보통 볼 수 있는 프로펠러가 4개나 6개 달린 그런 드론이 아니라 단지
프로펠러 1개로 날아가는 흔히 싱글콥터라고 불리는 형태의 것이라 더더욱 쉽지 않을 것 같다.


상상은 자유~


사실 처음에는 기왕 해보는 거 남이 하지 않은 걸 해보자 하고 프로펠러 하나짜리 드론을 생각했는데 역시나 내가
생각한 것은 이미 지구인의 절반은 생각한 것이라…벌써 그런 시도들을 잔뜩 하고 있었다. 하지만 그게 끝이 아니므로
그냥 도전하기로 했다.


이미 사람들이 만든 싱글콥터들

http://www.techholic.co.kr/news/articleView.html?idxno=6677

https://youtu.be/pF0uLnMoQZA?list=PLbfJADDuNxBd8rud9H4eLfhcK113_XTJB


굳이 싱글콥터를 만들기로 한 이유는? 모터 하나 살 돈밖에 없어서…는 아니고…^^;

최초의 발상은 영화 ‘프로메테우스’로부터 왔다. 프로메테우스에 보면 외계 행성에 도착한 지구인들이 엔지니어의
기지를 탐사할 때 한 과학자가 2대의 공모양 드론을 날린다. 그 드론들은 레이저를 쏘면서 동굴(기지) 내부를 스캔하고
스캔한 데이터는 모선에 입체 영상으로 재구성된다. 바로 그 드론을 만들어보고 싶었다.




하지만 현시창이라던가…
내가 뭔수로 그런걸 만드나…ㅠ.ㅠ
그래도 흉내나 내보려고 했으나 처음부터 막힌 것이 3D 프린터가 없는 상태에서 공 모양의 껍데기를 만들 재간이
없는 것이다. 결국 애초의 목표는 포기를 하고 대신에 프로펠러 1개로 움직이는 녀석으로 바람의 영향을 받지 않는
좁은 공간을 탐색할 수 있는 드론을 한 번 만들어보자고 생각했다.


되든 말든 상상은 할 수 있는거니까.


벋뜨 그러나...내 머리 속에는 왼쪽의 아이언맨이 있으나 내가 손에 쥘 아이언맨은 오른쪽이 아닐까 싶은 불안감이…-.-



준비 작업


까~이꺼! 드론 뭐 별거 있나? 모터 좀 사다가 배터리 연결하고 아두이노 연결해서 프로펠러 막 돌리면 붕붕 거리면서
날아다니…기는 개뿔…모터 돌리는데만 일주일이 걸렸다…ㅠ.ㅠ 일단 모터를 돌리는 과정은 다음 포스팅에서 자세히
다루기로 하고 오늘은 무엇무엇을 준비했나 보자.


이제부터 나오는 용어들은 드론으로 검색하면 모두 자세히 알 수 있는 내용이므로 별다른 설명 없이 지나가겠다.


우선은 무조건 소형화를 목표로 하여 가장 작은 재료들을 모았다. 아무래도 드론 하면 핵심 부품이 모터이므로
모터를 검색했다. 그리고는 주로 미니 드론에 쓰이는 코어리스(coreless) 모터를 발견하고는 아무생각없이 모터와
짝이 맞는 프로펠러와 함께 덜컥 구입을 했다.


하지만 이 모터는 한개로 드론을 만들 수 있는 추력(쉽게 말해 들어올릴 수 있는 힘)이 나오질 않았다.
기본적으로 모터 외에도 배터리와 플라잉 컨트롤러(비행을 제어하는 보드. 나는 아두이노를 사용하기로 한 것이다) 등이
더 붙어야 하는데 거기까지는 어떻게 될까 했더니 아두이노를 구동하기 위해 따로 배터리를 달거나 혹은 전원을 분배
할 수 있는 장치가 더 필요했던 것이다. 결국 이 모터는 아래와 같은 요상한 물건을 하나 만들어놓고는 일단 고이 
보관하기로 했다.



그리고 곧 브러쉬리스(Brushless) 모터 + ESC + 프로펠러 세트인 제품을 하나 샀는데 이놈은 프로펠러 길이가
10인치(약 26Cm)인 놈이라서 다시 레이싱 드론용으로 모터와 프로펠러 5인치(약 12Cm)짜리를 따로 구입했다. 
이번에는 혹시 잘 안되면 일반적인 드론을 만들어보고자 4세트를 샀다. 


더이상의 자세한 내용은 생략하고 기본적으로 필요한 구성품을 보면 다음과 같다.


  1. 아두이노 나노2개 : 하나는 조종기용, 하나는 드론용
  2. nRF24L01 트랜시버 2개 : 역시 하나는 조종기용, 하나는 드론용
  3. 브러쉬리스 모터 1개
  4. 전자 변속기(ESC) 1개
  5. 프로펠러 2개 (정방향 1개, 역방향 1개) : 모터와 변속기 프로펠러는 세트 상품
  6. 조종기용 조이스틱 한 개 (조이스틱 2개가 붙어있는 모델)
  7. 리튬 폴리머 배터리 11.1v 550mAh 30C 2개 (한 개는 2호기 만들면 쓸 것)
  8. 리튬 폴리머 충전기 1 개


일단 여기까지가 기본적으로 모터를 구동시키는데 필요한 부품들이다. 최종 완성을 위해서는 방향타에 쓰일
서보모터와 몇가지 센서들이 더 필요하게 될 것이다. 물론 외장도 만들어야 하고…


정리


사실 아직 만들던 4족보행 로봇도 완성시키지 못한 상태다.
언제나 느끼는 바이지만 나는 프로토타입형 인간이다. 실제 회사 업무를 할 때도 초기 작업은 빠르고 정확하게
잘 하는 편인데 프로젝트가 궤도에 오른 후에는 엄청 게을러진다…-.-


아마도 이 드론 프로젝트도 일단 날고나면 뒷방으로 밀려날지도…^^;


하지만 나의 큰 그림상에서는 이 드론 만들기도 로봇 만들기에 연장선 상에 있으니 조만간 통합 작업이 이루어질
것이다. 그 과정에서 꼭 필요한 것이 3D 프린터인데…언제나 살 수 있을까…ㅠ.ㅠ 서울 시내에 무료로 사용할 수
있는 곳도 있다니 우선은 그쪽을 이용해보는 것도 방법이긴 하겠다.


암튼 이번 포스팅은 이만 줄이고 다음 포스팅에서는 브러쉬리스 모터 구동과 ESC 설정에 대해 알아보도록 하겠다.






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^