프로젝트 팀 Wired Factory의 SierraWhiskey 님의 제작기입니다. WiFi direct 를 이용한 무선 컨트롤 예제입니다. 미완의 프로젝트지만 관련 자료를 공개해 주셨습니다. http://mydiyrecipe.com/?p=101

“나의 첫 프로젝트 – 미완의 쿼드콥터 DIY”

title

2013년 여름 어느날, 자전거를 타고 우연히 들른 한강변 어느 이름모를 RC 항공기 활주로에서, 시원스럽게 하늘을 날아다니던 RC 항공기가 잊고 살았던 내 마음속 무언가를 건드렸다. ‘저걸 한번 만들어볼까? 뭐가 필요할까? 무엇부터 해야될까?’ 그리고 얼마 후 쿼드콥터라는 녀석을 알게되었다. 그냥 사다가 날려보는 건 내게 의미 없다. ‘명색이 엔지니어인데, 이 정도는 할 줄 알아야 되지 않을까?’ 나름의 호기도 부리며 신바람이 나서 재료를 사고 해외에서 배송되는 시간을 기다리며 즐거운 시간을 보냈던 것 같다. 처음 목표는 안드로이드 OS가 올라간 쿼드콥터. 이미 스마트폰에는 쿼드콥터에 필요한 센서(Gyro, Accelerometer, GPS)들과 모터 제어를 위한 네 개의 PWM포트 그리고 RF장치가 마련되어 있다. 스마트폰으로 조종하고 카메라 영상을 받아 FPV(First Person View)도 가능하게 하고 싶었다. 결과부터 말하자면 이런저런 이유에서 아직까지 이 녀석은 날지 못했다. 미완의 첫 프로젝트였지만 뜻깊은 첫 시도였기 때문에 여기에 남겨보고자 한다.

Backgrounds

– Quadcopter

쿼드콥터는 3개 이상의 모터와 프로펠러를 가진 멀티콥터 중에 4개의 모터와 프로펠러를가진 항공기를 말한다. 같은 쿼드라도 모터의 배치에 따라 쿼드콥터, X콥터, Y4콥터등으로 나뉜다. 모터의 수에 따라 트리, 헥사, 옥타콥터등 다양한 구성이 가능하다. 일반적으로 쿼드가 많이 쓰이는 이유는 모터가 적게 들어가면서도 안정성이 양호하고 직관적인 제어가 가능하기 때문이다. 상승하고 싶으면 모든 모터를 더 빨리 돌리고 하강하고 싶으면 속도를 늦추고, 어느 방향으로 가고 싶으면 반대쪽 추력을 상승시키고 어느 한쪽이 기울어지면 그 쪽 모터를 더 돌리고. 별다르게 찾아보지 않아도 이러한 접근이 가능할 정도로 직관적이다. 쿼드콥터에 대한 보다 자세한 정보는 아래를 참고하기로 하자.

http://en.wikipedia.org/wiki/Quadcopter

– BeagleBoneBlack

비글본 블랙은 TI사의 1GHz Sitara AM335x ARM cortex-A8 프로세서가 탑재된 저가의 고성능 개발 플랫폼이다.  오픈소스 소프트웨어 개발과 TI OMAP 단일칩 시스템 성능을 평가하기 위한 목적으로 지금까지 다양한 Beagle보드가 제공되었는데 그 중 가장 최근에 나왔고 가격이 저렴($55)하면서도 아쉽지 않은 성능을 가졌다. TI가 더이상 AP 프로세서를 개발하지 않으면서 다른 개발 플랫폼등과 비교해서 업데이트가 좋지 않다는 점은 흠이다. 최근에는 확인해보지 못했지만 기본기능(WIFI) 업데이트를 기다리며 꽤 오랜시간을 기다렸던 기억이 있다. 안드로이드, Linux등의 OS를 지원한다.

자세한 내용은 아래를 참고하기로 한다.

http://elinux.org/Beagleboard:BeagleBoneBlack

 What you need

1. X525 V3 fordling frame 2. XXD 2212 KV1000 brushless motor x 4 3. 9050 9x5 Propeller x 4 4. 20A ESC x 4 5. 11.1V 3000mAh 3S 35C Li-Po Battery 6. 3S Li-Po Battery Charger 7. Beaglebone Black 8. 10DOF 9-axis IMU( L3G4200D, ADXL345, HMC5883L, BMP085) 9. 10cmX10cm PCB 10. 23X2 pin header, 6 pin header socket 11. Jumper wires and soldering wire
1. X525 V3 fordling frame
2. XXD 2212 KV1000 brushless motor x 4
3. 9050 9×5 Propeller x 4
4. 20A ESC x 4
5. 11.1V 3000mAh 3S 35C Li-Po Battery
6. 3S Li-Po Battery Charger
7. Beaglebone Black
8. 10DOF 9-axis IMU( L3G4200D, ADXL345, HMC5883L, BMP085)
9. 10cmX10cm PCB
10. 23X2 pin header, 6 pin header socket
11. Jumper wires and soldering wire

Directions

1. 필요한 부품을 구매해 보자. Aliexpress.com이나 ebay.com과 같은 해외쇼핑몰을 이용하면 어렵지 않게 원하는 부품을 싼 값에 구할 수 있다. 왠만한건 무료배송이라는 건 장점이고 최대 한달 넘게 걸릴 수 있다는 건 함정이다. 싸고 배송이 오래걸린 다는 생각에 미리미리 주문해놓는다는 게 과소비를 야기할 수 있으니 주의가 필요하다. 구매했던 가격은 다음과 같다.

price

X525 패키지에는 쿼드콥터에 필요한 바디와 모터, 프로펠러, KK Multicopter 보드와 조립에 필요한 부품들이 포함되어 있다. KK Multicopter 보드는 RC비행에 필요한 MEMS 센서와 알고리듬의 다운로드가 가능한 MCU가 포함된 저가 보드이다. BBB(BeagleBone Black) 보드를 사용하기에  여기에서는 사용하지 않았지만 고정익 항공기 뿐만아니라 헬기, 다양한 멀티콥터에 사용가능한 firmware가 제공되고 있으며 Atmega168 MCU를 이용하여 직접 프로그래밍도 가능한점은 참고할만 하다.

2. 패키지에 포함된 메뉴얼을 따라 기체를 조립한다.

assemble

3. Beaglebone Black 보드를 구동해보자. 빌드서버를 만들고 코드를 다운받고 빌드하고 바이너리를 다운받는 내용은 경험의 정도에 따라서 쉬운일이기도 하고 어려운 일이 되기도 한다. 여기에서는 BBB보드를 어떻게 사용해야되는지에 대한 구체적인 내용은 생략하고자 한다. 하지만 걱정마시라. TI에서 제공하는 official 문서와 BBB를 사용하는 사람들의 포럼에 왠만한 정보는 다 공개되어 있다.

Developer Guide – http://processors.wiki.ti.com/index.php/TI-Android-JB-4.2.2-DevKit-4.1.1_DeveloperGuide

4. BLDC(Brushless DC) 모터를 사용하기 때문에 ESC(Electronic Speed Controller)를 이용하여 모터를 제어해야 한다. BLDC 모터의 경우 전기적, 기계적 잡음이 적고 수명이 길며 고속 제어가 용이하다. 반면 일반 DC모터에 비해 제어가 복잡하고 별도의 구동회로가 필요한 단점이 있다.  일반적인 RC ESC는 총 5개의 입력 라인과 3개의 출력 라인을 가지고 있다. 3개의 출력은 BLDC의 3상 입력을 위한 부분이며 2개의 입력은 배터리 전원(+/-)을 그리고 나머지 3개의 입력은 보드(수신기)에 연결(VCC, GND, CTRL)된다. 일반적인 보드 전압(≒5V)으로는 고속으로 모터를 드라이브 할 수 없기 때문에 보다 전압이 높고 방전율이 좋은 배터리 전압을 사용하게 된다. 결국 모터의 제어는 CTRL핀의 PWM(Pulse Width Modulation) 신호에 의해 결정된다. PWM은 펄스의 간격을 조절하여 변조하는 방식으로 Duty를 이용하여 모터의 강약을 조절할 수 있다.

pwm

절대적인 펄스의 폭보다는 주기에 따른 비율이 실제 속도를 제어한다. 예를 들면 20ms 주기의 펄스에서 High 레벨 구간이 1ms일 경우  모터는 Idle 상태가 되고 2ms일 경우 최대 속도가 된다. 결국 1 ~ 2ms 사이값으로  PWM 신호를 생성하여 모터 속도를 제어하는 것이 핵심이다.

BBB에서는 정확한 PWM을 제어하기 위한 eHRPWM(Enhanced High-Reolution Pulse-Width Modulator) 블럭을 제공한다. 자세한 내용은 아래를 참고하면 된다.

http://www.ti.com/lit/ug/sprufl3c/sprufl3c.pdf

여기에서는 4개의 모터를 위해 ‘ehrpwm.1’과 ‘ehrpwm.2’를 사용하였다. 각 블럭은 A, B 두개의 modulator를 가지고 있다.

/* Board-am335xevm.c */
#define BB_PWM_MOTOR12_DEVICE_ID   "ehrpwm.1"
#define BB_PWM_MOTOR34_DEVICE_ID   "ehrpwm.2"

static struct platform_pwm_motor_data quadcopter_pdata = {
    .pwm_12_id = BB_PWM_MOTOR12_DEVICE_ID,
    .pwm_34_id = BB_PWM_MOTOR34_DEVICE_ID,			
};
static struct pinmux_config motor1_pin_mux[] = {
    {"gpmc_a2.ehrpwm1A", OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT},
    {"gpmc_a3.ehrpwm1B", OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT},
    {NULL, 0},
};
static struct pinmux_config motor2_pin_mux[] = {
    {"gpmc_ad8.ehrpwm2A", OMAP_MUX_MODE4 | AM33XX_PIN_OUTPUT},
    {"gpmc_ad9.ehrpwm2B", OMAP_MUX_MODE4 | AM33XX_PIN_OUTPUT},
    {NULL, 0},
};

static struct platform_device am335x_evm_quadcopter = {
    .name  = "quadcopter",
    .id    = -1,
    .dev   = {
        .platform_data = &quadcopter_pdata,
    },
};

static struct pinmux_config quadcopter_gyro_irq[] = {
    {"mcasp0_fsr.gpio3_19", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
    {NULL, 0},
};

static struct pinmux_config quadcopter_accel_irq[] = {
    {"gpmc_ad11.gpio0_27", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
    {NULL, 0},
};

static void quadcopter_dev_init(int evm_id, int profile)
{
    int err;
    #define QUADCOPTER_MAX_FREQ 250

    setup_pin_mux(quadcopter_gyro_irq);
    setup_pin_mux(quadcopter_accel_irq);
    setup_pin_mux(motor1_pin_mux);
    pwm_pdata[1].chan_attrib[1].max_freq = QUADCOPTER_MAX_FREQ;
    am33xx_register_ehrpwm(1, &pwm_pdata[1]);
    setup_pin_mux(motor2_pin_mux);
    pwm_pdata[2].chan_attrib[1].max_freq =
    QUADCOPTER_MAX_FREQ;
    am33xx_register_ehrpwm(2, &pwm_pdata[2]);

    err = platform_device_register(&am335x_evm_quadcopter);
    if (err) {
        pr_err("failed to register quadcopter.\n");
    }
}

5. 여기에서 사용된 센서는 총 4개의 센서가 합쳐져 10DOF(Degree of freedom)를 표현하는 멋진 녀석이다. L3G4200D(Gyro), ADXL345(Accelerometer), HMC5883L(Compass), BMP085(Pressure) 센서가 함께 패키징되어 있다.  쿼드콥터에는 PID (Proportinal Integral Differential) 제어를 위해 자이로센서와 가속도센서가 꼭 필요하다. 자이로센서는 x/y/z 각 축을 회전축으로 발생하는 각속도를 측정하며 가속도센서는 중력가속도가 x/y/z 방향으로 미치는 영향을 절대적으로 보여준다. 처음에는 그냥 달려들었기 때문에 가속도 센서만으로 자세 제어가 가능할 걸로 믿었으나 모터의 심한 진동에서 오는 잡음에 가속도 센서는 취약하다. 하지만 절대값을 보여주기 때문에 누적오차는 상대적으로 적다. 자이로센서는 이와 반대로 실제 동작을 좀 더 정확하게 측정할 수 있는 반면 적분시 발생하는 누적 에러가 발생하게 된다. 일반적으로 두가지 센서의 장단점을 모아서 상보필터(Complementary Filter)를 구성하여 실제 쿼드콥터의 제어에 사용하게 된다. 이 칩의 컨트롤은 I2C를 통해 이루어진다. 모두 동일한 I2C 버스를 사용하며 각각 다른 Slave Address를 사용하여 커맨드를 구분한다. 지자기 센서와 고도 센서는 GPS와 합쳐져 자동비행/복귀에 사용될 수 있지만 기본 쿼드콥터 동작에는 사용되지 않는다. 여기에서 사용한 센서에 대한 driver는 이미 Linux 커널에 포함되어 있거나 웹에서 찾아볼 수 있다. 다음은 BBB보드에서 각 센서 device를 등록하는 부분이다.

/* Board-am335xevm.c */
static struct i2c_board_info am335x_i2c2_boardinfo[] = {
    {
	I2C_BOARD_INFO("l3g4200d", L3G4200D_I2C_ADDRESS>>1),
        .platform_data = &l3g4200d_info,			
        .irq = OMAP_GPIO_IRQ(L3G4200D_DRDY_GPIO),
    },
    {
        I2C_BOARD_INFO("bmp085", 0x77),
    },
    {
        I2C_BOARD_INFO("adxl34x", 0x53),
        .irq = OMAP_GPIO_IRQ(ADXl34X_DRDY_GPIO),
        .platform_data = (void *)&adxl34x_info,
    },
    {
        I2C_BOARD_INFO("hmc5843", 0x1e),
    },
};

6. 모터와 센서 동작에 성공하면 컨트롤에 필요한 최소한의 작업이 완료된 셈이다. 이제 BBB보드에 필요한 회로판을 구성해보자.  유지/보수의 편의성을 위해서 보드와 peripheral 사이의 연결은 헤더소켓과 핀헤더, 점퍼와이어를 적극 이용한다. UART TXD/RXD 라인은 디버그 용도 및 쿼드콥터에 커맨드를 보내기 위한 용도로 사용된다. Serial통신을 이용하여 BT/WIFI 연결이 가능하기 때문에 추후에 조종기 기능으로 확장될 수 있다. 여기에서는 별도로 조종기를 만들지 않고 USB-UART 케이블을 이용해 기체를 조정했다.

schematic2

1. BBB보드와 분리된 PCB 보드 - J8, J9, Header6와 결합된다. 2. BBB보드와 결합된 PCB 보드
1. BBB보드와 분리된 PCB 보드 : BBB 보드의 P8, P9 헤더소켓과 Header6 헤더핀에 결합된다.
2. BBB보드와 결합된 PCB 보드

7.  조립과 기본기능 확인

PCB 보드가 준비되면 기체에 견고하게 결합시킨다. PCB로 ESC와 센서의 PIN Layout에 맞춰 핀을 구성한 덕분에 어렵지 않게 조립을 완성할 수 있었다.

1. 모터 컨트롤을 위해서 네 개의 ESC에 연결된 모습 2. 조립이 완성된 모습 3. ESC와 모터의 연결 (Yellow와 Red가 교차될 경우 모터가 역방향으로 전환된다.) 4. BBB보드에 실장된 PCB 5. 조립이 완성된 모습 6. 센서모듈의 연결
1. 모터 컨트롤을 위해서 네 개의 ESC에 연결된 모습
2. 조립이 완성된 모습
3. ESC와 모터의 연결 (Yellow와 Red가 교차될 경우 모터가 역방향으로 전환된다.)
4. BBB보드에 실장된 PCB
5. 조립이 완성된 모습
6. 센서모듈의 연결

관심을 조금만 더 기울이면 인터넷상에 공개된 많은 정보들의 도움을 받았겠지만 이 때는 마음이 앞섰다. 네 개의 모터가 밸런스만 맞으면 뜨겠지하며 조립이 되자마자 모터를 각각 수동 조절하며 띄워보기를 시도했다. 이 과정에서 몇 가지 초보적인 실수를 했기 때문에 언급해보고자 한다.  일단 배터리는 전압만 생각하고 충방전율을 고려하지 않아 네개의 모터에 충분한 전류를 공급하지 못했다. 원가절감차원에서 가지고 있던 11.1V Li-Po 배터리를 사용했지만 800mAh, 20C 배터리로는 60cm 크기의 쿼드콥터를 띄우기에는 무리였다. 특정 모터만 갑자기 세게 돌거나 느려지며 기체가 뒤집어졌던 기억이 있다. 견고하게 결선하지 않은채 테스트를 진행하던도중 모터의 진동에 의해 배터리 전원에 쇼트가 발생했다. 일반 점퍼 와이어를 쓴 탓에 피복은 금방 불에 타버렸고 깜짝놀라 배터리를 분리하다가 손가락을 데이고 말았다. 쿼드콥터의 진동은 생각보다 훨씬 심하다. 불확실한 외부 요인에 의해 전선이 open 혹은 short되지 않도록 미리 신경써주어야 한다. 과전류에 의해서 전선이 쉽게 녹는걸 방지하기 위해서 전선 선택시 AWG값을 고려해야 한다. 물통 네 개로 쿼드콥터를 날지못하게 잡겠다는 생각은 아주 초보적인 생각이었다. 네 개의 KV1000급 모터가 만들어내는 양력은 저렇게 물통 네 개를 달아서 제어할만한 성격의 것이 아니었다.

1. 모터가 동작중인 쿼드콥터 2. 쇼트로 인해 녹아버린 점퍼 와이어 3. 30cm 이상 기체가 떠버리는 것을 방지하기 위한 아마추어 장비
1. 모터가 동작중인 쿼드콥터
2. 합선으로 인해 녹아버린 점퍼 와이어
3. 30cm 이상 기체가 떠버리는 것을 방지하기 위한 아마추어 장비

8. Software Implementation

Software 블록다이어그램은 다음과 같다.

block_diagram

Quadcopter 드라이버가 “/dev/quadcopter_dev” 이름으로 Misc. (miscellaneous) Device를 등록한다. File operation을 통해 Userspace에 있는 daemon과 통신한다.  daemon은 부팅시에 서비스로 등록된다. 최초 알고리즘을 kernel에 두었으나 PID  제어 과정에서 Floating 연산이 많아지면서 알고리즘을 이러한 연산이 보다 용이한 framework로 이동시켰다. 쿼드콥터 알고리즘 모듈을 NDK로 빌드하고 ADB로 push만 하면 되기 때문에 개발이 훨씬 용이해졌다. 쿼드콥터를 야외에서 날리고자 할 경우에는 당연히 RF 관련 HW/SW 모듈이 추가되어야 하겠지만 첫 번째 프로젝트의 목표는 쿼드콥터의 원활한 자세제어이다.  실내에서 안정적으로 가만히 떠있는 게 목적이기 때문에 USB-UART 케이블을 이용해도 충분하다. 따라서 UART를 통해 커맨드를 받아 조종정보를 daemon에 알려주는 application을 PC에서 콘솔을 통해 실행시켰다. 쉽게 말하면 PC의 화살표를 누르면 방향 조정을 그리고 ‘+/-‘를 누르면 스로틀 상승/하강 명령을 케이블을 통해 BBB에 전달한다. 사용자의 커맨드는 framework에서 돌고 있는 daemon에 전달되며 커널의 Quadcopter driver에서 읽어온 가속도/자이로 센서의 정보 그리고 이전 모터의 속도 정보를 Flight Algorithm 모듈로 전달한다. 가속도 센서와 자이로 센서의 정보는 인터럽트가 뜰 때마다 Quadcopter driver가 읽어서 daemon에  제공한다. Flight Algorithm은 PID 제어등을 통해 네 개의 모터의 새로운 컨트롤 정보를 daemon으로 다시 전달한다. daemon은 이 정보를 커널의 Quadcopter driver로 전달하여 ESC가 각 모터를 제어할 수 있도록 한다.

Conclusion

호기롭게 시작되었던 나의 첫 번째 프로젝트는 아직까지 미완으로 남아있다. 하드웨어 및 기본적인 하드웨어 제어는 완료된 반면 비행알고리즘이 완성되지 못했다. 바쁘기도 했고, 더 하고 싶은 일이 생긴 탓도 있지만 생각보다 위험하다는 점과 아무데서나 날릴 수 없다는 점도 한 이유가 되었다. 날씨가 따듯해지고 다시 열정이 생기면 언젠가 다시 미완의 프로젝트를 마무리 할 날이 올 거라 믿는다. 현재까지는 실패였지만 절반의 성공이었고, 잊고 살던 무언가를 깨우쳐준 소중한 경험이라 여기에 남긴다.