[36호]카멜레온 DIY LED 이야기 2
카멜레온 DIY LED 이야기 2
WS2812B의 동작원리와 12색상환 만들기
글 | 신상석 ssshin@jcnet.co.kr
디바이스마트 매거진 독자 여러분, 안녕하세요. 앞으로 5회에 걸쳐 [카멜레온 DIY LED 이야기]를 진행할 신상석입니다. 이 이야기는 WS2812B라는 컬러 LED를 기반으로 제작된 [카멜레온 DIY LED] 시리즈를 이용하여 생활에 필요한 다양한 형상을 꾸며보고 이것을 다양한 컬러로 디스플레이 해보는 내용입니다. 앞으로 진행할 내용에 대하여 간단히 알아보면 다음과 같습니다. (약간 변경될 수도 있습니다.) 앞으로 즐겁고 유익한 강의가 될 수 있도록 많은 격려와 성원 부탁드립니다. |
디바이스마트 매거진 독자 여러분, 안녕하세요.
[카멜레온 DIY LED 이야기] 두번째 시간이 돌아왔습니다.뜸하게 만나므로 지난 시간에 어디까지 이야기했는지 기억이 잘 나지 않으실 것 같은데, 지난 시간에는 카멜레온 DIY LED에 대한 정의, 형태, 종류, 타 모듈과의 비교, 응용 예 등과 같이 전반적인 소개가 이루어졌습니다. 이번 호부터는 좀 더 세부적으로 카멜레온 DIY LED에 대하여 알아보는 시간을 갖도록 하겠습니다. 일단은, 카멜레온 DIY LED의 기본 LED인 WS2812B의 동작 원리에 대한 이야기로 시작해 보겠습니다. 어떤 분야든 개념과 원리가 중요하니까요.
WS2812B의 동작 원리
WS2812B의 특징은 간단하게 말해서, “내가 원하는 개수만큼 연속적으로 간단하게 연결하면서, 내가 원하는 시간에 내가 원하는 컬러(껐다 켰다 포함)로 자유롭게 표현할 수 있는 LED”라고 이야기한 바 있습니다.
WS2812B의 외관 모습은 지난번에 보았으므로 오늘은 신호선과 핀 배열을 살펴보겠습니다. 아래와 같이 생겼습니다.
4핀 중, VCC(+)와 GND(-)는 전원이고, DIN과 DOUT은 각각 데이터입력, 데이터출력 신호입니다. VCC와 GND는 3.5 V ~ 5.3 V 사이의 전원으로 여러 개의 WS2812B가 연결되는 경우에도 모두에게 공통으로 연결되어져야만 합니다. DIN은 WS2812B로 전달되는 데이터의 입력 신호선이고, DOUT은 DIN으로 들어온 데이터 중 자신이 사용하지 않는 데이터를 통과(bypass)시키는 출력 신호선인데, 여러 개의 WS2812B를 연결하는 경우에는 앞쪽 WS2812B의 DOUT이 뒤쪽 WS2812B의 DIN에 연결되는 형태로 직렬(시리얼) 연결합니다. 데이터를 공급해주는 제어기를 포함한 연결 관계를 그림으로 나타내 보면 아래와 같이 되겠습니다. 연결 방식은 상당히 간결한 편이지요.
데이터를 공급해주는 제어기를 포함한 연결 관계 |
이렇게 연결하고도 LED마다 따로따로 여러가지 색채와 동작을 표현할 수 있다는 것이 신기할 따름인데… 과연 어떻게 동작하는 것일까요? 살펴 보겠습니다.
세부적인 내부 회로도가 공개되어 있지 않아 정확하게 알 수는 없지만, 데이터시트에 나온 내용을 기준으로 WS2812B의 동작 방법을 설명하면 다음과 같습니다.
· 내부에 R(Red), G(Green), B(Blue)에 해당하는 컬러 LED와 이를 제어하는 로직이 함께 통합되어 있음
· DIN으로 입력된 데이터는 내부의 데이터 래치에 의하여 저장되고 신호증폭 로직을 거쳐 DOUT으로 출력됨
· 전원이 켜지거나, 데이터리셋이 되면, 내부 로직은 DIN 포트로부터 데이터를 받아들이는데, 처음 24비트는 자신의 내부 데이터 래치로 보내고 이후의 데이터는 DOUT 포트로 bypass하여 내보냄. 한편, LOW 전압이 50uS 이상 지속되면 데이터 리셋으로 간주하고 다시 처음부터 시작함
· 내부에 전송된 3바이트(24비트) 데이터는 1바이트(8비트)씩 녹색, 빨강, 파랑의 컬러 LED 값을 나타내며, 전송 순서도 녹빨파(GRB, Green, Red, Blue) 순임
· 전원은 3.5 V ~ 5.3 V까지 사용이 가능하며, 입력 데이터는 0.7 x VCC 이상의 전압이면 HIGH, 0.3 x VCC 이하의 전압이면 LOW로 처리됨 (5 V 전원의 경우 3.5 V 이상이면 HIGH, 1.5 V 이하이면 LOW)
· 데이터 전송 프로토콜은 펄스폭의 길이로 데이터값을 산정하는 방식을 사용하며, 아래와 같은 규격으로 판정함
즉, DIN 라인의 레벨이 400ns LOW + 850ns HIGH 를 유지하면 1비트의 데이터 HIGH로 인식하고, 800ns HIGH + 450ns LOW 를 유지하면 1비트의 LOW로 인식하는 방식
이와 같은 규격을 기준으로 처음 그림과 같은 연결에서 데이터가 전송되는 방법을 나타내면 아래 그림과 같습니다.
예를 들어 만약 첫번째 LED에는 빨강, 두번째 LED에는 파랑, 세번째 LED에는 녹색으로 LED를 1초 동안 켜고 싶다면, 제어기에서는 (0×00 ▶ 0xFF ▶ 0×00) ▶ (0×00 ▶ 0×00 ▶ 0xFF) ▶ (0xFF ▶ 0×00 ▶ 0×00) 을 보내면 LED가 원하는 색으로 켜지고 1초 후에 다시 (0×00 ▶ 0×00 ▶ 0×00) ▶ (0×00 ▶ 0×00 ▶ 0×00) ▶ (0×00 ▶ 0×00 ▶ 0×00) 을 보내면 LED가 모두 꺼지게 됩니다.
처음에 연속해서 9바이트의 데이터를 보내면, 첫번째 LED에서 3바이트를 사용하고, 이후 전달된 6바이트는 2번째 LED로 전달되며, 마찬가지로 두번째 LED는 전달된 6바이트 중 처음 3바이트를 사용하고 마지막 3바이트는 세번째 LED로 보내게 되는 방식을 사용하는 것입니다. 1초가 지난 후에 다시 9바이트의 데이터를 보내면 이것은 50us 보다 긴 시간 이후에 들어온 데이터이므로 이전 데이터의 연속으로 보지 않고, 새로운 데이터가 들어온 것으로 간주하여 다시 첫번째 LED에서 3바이트를 사용하는 방식으로 진행되겠습니다.
이런 원리를 잘만 이용하면, WS2812B LED를 내가 원하는 개수만큼 원하는 형태로 연결한 후, 이들의 색상이 시간에 따라 변화하도록 프로그램하는 것이 가능할 것 같네요. 오, 뭔가 있을 법한 느낌!!!
LED(JLED-BAR-1) 1개 불 켜기
그럼, 이제 문제는 0, 1 데이터, 나아가서 GRB 데이터, 더 나아가서 여러 개의 WS2812B 연결시의 데이터를 어떻게 프로그램으로 생성할 수 있는가 하는 것인데…
“천리길도 한 걸음부터”라고 했으니 일단 WS2812B 1개로 구성된 카멜레온 DIY LED인 JLED-BAR-1에 파랑색 불을 켜는 것으로부터 시작해 보겠습니다. 이 후 이것을 응용해서 1600만가지 이상의 컬러를 골라서 디스플레이 해보는 데까지 가보시지요. (와우!!!)
일단 JLED-BAR-1의 모습을 보실까요. 짜잔~~~!
앞면에는 WS2812B가 1개 배치되어 있고(컨덴서 1개 포함), 뒷면에는 2.54mm 1X3 핀헤더가 양쪽으로 배치되어 있습니다. 뒷면의 실크 표시는, V는 VCC(+5V), G는 GND, I는 DIN(데이터입력), O는 DOUT(데이터 출력)입니다.
JLED-BAR-1은 WS2812B를 기반으로 하여 이미 출시되어 있는 다른 상품과 확연히 차이가 나는 것이 3가지 있습니다.
첫째, 1X3 입력핀과 1X3 출력핀의 형태가 DIP 타입(2.54mm 핀헤더 타입)입니다. 입출력 신호가 SMD로 되어 있는 것은 납땜을 해야하는 번거로움이 있지만 이렇게 DIP 타입을 사용하면 케이블이나 점퍼 등을 사용하여 연결을 매우 쉽게 할 수 있는 장점이 있습니다.
둘째, 가로와 세로의 길이가 각각 1cm입니다. BAR 시리즈의 경우는 LED가 증가할 때마다 1cm씩 가로 길이가 증가하도록 설계되어 있습니다. 이렇게 하면 용도에 따라 매우 편리하게 적용이 가능합니다. 예를 들어 30cm X 20 cm 되는 액자의 테두리를 BAR 시리즈로 만든다면 가로는 JLED-BAR-10을 3개 연속 연결하면 딱 알맞게 적용이 되는 것이지요. 급할 때는 자 대용으로도 사용이 가능합니다. 그러면 아래 JLED-BAR-10 의 길이는 얼마일까요? (답이 없어도 알겠죠?)
셋째, 그림으로는 식별이 잘 안되지만 1X3 입출력 핀헤더는 가장자리에서 안쪽으로 1.27mm 거리에 위치합니다. 이렇게 되면 카멜레온 DIY LED 모듈 여러 개를 연속적으로 연결시 2X3 쇼트핀(JLED-CON-0, 2핀간의 거리 2.54mm)으로 바로 연결이 가능하므로 레고처럼 붙였다 떼었다 하는 동작이 매우 용이합니다. JLED-BAR-1과 JLED-TRI-3을 쇼트핀 3개로 결합한 형태를 보시지요.
쇼트핀 3개가 하나로 결합되어 있는 JLED-CON-0를 연결하면 아래와 같이 좀 더 깔끔하게 연결할 수 있습니다.
앞면도 보여드리지요.
자, 그럼 이제 JLED-BAR-1을 아두이노에 연결하여 파랑색 불을 켜는 것을 예로 들어 본격적으로 프로그램을 시작해 보겠습니다.
일단, 제어기 연결은 해놓고 시작합니다. 아두이노 UNO를 제어기로 사용하는 경우 아래와 같이 연결이 되겠습니다. 아두이노와 JLED-BAR-1의 신호쌍으로 +5V-V(VCC)(빨강선), GND-G(GND)(검정선), D2-I(DIN)(녹색선)을 각각 연결합니다.
파랑색 불이 들어오게 하려면 제어기(아두이노)에서 (0×00, 0×00, 0xFF)의 24비트 데이터를 JLED-BAR-1으로 보내주어야 합니다. 첫번째 데이터인 0×00을 보내려면 ‘0’ 을 나타내는 비트 신호를 8번 연속해서 보내주어야 하는데, 규격에 보면 ‘0’ 신호는 실제 WS2812B의 DIN 라인의 레벨을 ‘800ns HIGH + 450ns LOW’로 유지하여야 합니다. 우리는 제어기(아두이노)의 데이터 포트인 D2를 연결하였으므로 이 핀을 ‘800ns HIGH + 450ns LOW’로 8번 만들면 되겠네요.
엥? 그런데 어떻게 만들죠?
digitalWrite(D2) = HIGH;
delay_ns(400); // nano sec 딜레이함수
digitalWrite(D2) = LOW;
delay_ns(850); // nano sec 딜레이함수
이렇게 하면 될까요?
바로 문제에 봉착하게 됩니다. 첫번째 문제는 delay_ns() 라는 ns 단위 딜레이 함수가 아두이노에 존재하지 않는다는 것이고,(ms, us 딜레이 함수는 있는데…) 두번째 문제는 혹시 함수를 새로 만든다고 가정해도, ns 와 같이 아주 짧은 시간 동안의 딜레이를 적용할 수 있는 정확한 함수를 프로그램 하는 것이 가능하지 않을 것으로 판단된다는 것이고, 세번째 문제는 혹 이런 함수를 비슷하게 작성한다 하더라도 실제 이 함수를 실행하는데 소요되는 시간을 매우 정교하게 제어하는 것이 어렵다는 사실입니다.
그렇다면 … 어떻게 해야 하나요?
예. 정답! 이것을 해결하려면, 고급 언어인 C 언어 레벨에서의 프로그램을 포기하고 어셈블리(assembly) 언어를 이용하여 프로그램을 작성하여야 합니다.
어셈블리 언어는 기계어이므로, 실행 속도가 정해져 있습니다. 예를 들어 ‘nop’ 이라는 어셈블리 명령어는 거의 모든 프로세서에서 1 클록의 시간만을 사용합니다. 제어기(아두이노)가 만약 16Mhz 클록으로 동작하는 제어기(아두이노)라고 가정하면 ‘nop’을 실행하는데 걸리는 시간은 1/16000000 초 = 62.5ns가 됩니다. 이것을 잘 이용한다면 우리가 필요로 하는 형태의 데이터를 만들 수도 있을 것 같네요. 한 번 같이 해보실까요?
아두이노 UNO(16Mhz 클록)을 기준으로 ‘0’ 데이터를 한 번 만들어 보겠습니다.
‘0’ 데이터는 400ns HIGH + 850ns LOW 의 쌍으로 이루어집니다.
400ns의 HIGH를 유지하려면, 400/62.5 = 6.4 = 약 6 클록이 필요하고, 850ns의 LOW를 유지하려면, 850/62.5 = 13.6 = 약 14 클록이 필요하므로, 아래와 같이 프로그램하면 될 것 같습니다. (규격에 보면 +/- 2 클록 정도의 오차는 허용이 되므로 정수배를 취하여도 무방함)
// WS2812B ‘0’ 데이터 만들기
PORTD |= 0b00000100; // D2 디지털핀을 1로 만듬, 1-2 클록 소모(?)
asm volatile(“nop”); // 첫번째 nop, 어셈블리 명령어로 실행, 컴파일러 최적화 금지!
asm volatile(“nop”); // 두번째 nop, 어셈블리 명령어로 실행, 컴파일러 최적화 금지!
…
…
asm volatile(“nop”); // 다섯번째 “nop”, 여기까지 6-7 클록 소모(?)
PORTD |= 0b00000000; // D2 디지털핀을 0으로 만듬, 1-2 클록 소모(?)
asm volatile(“nop”); // 첫번째 nop, 어셈블리 명령어로 실행, 컴파일러 최적화 금지!
asm volatile(“nop”); // 두번째 nop, 어셈블리 명령어로 실행, 컴파일러 최적화 금지!
…
…
asm volatile(“nop”); // 열세번째 “nop” , 여기까지 14-15 클록 소모(?)
D2 핀의 상태를 바꾸려는 명령어는 최소한 1-2 클록은 소모될 것이라고 가정하고 ‘nop’ 명령어를 필요한 개수보다 1개 적은 개수만큼만 시행하면 가장 근접한 신호 파형을 만들 수 있을 것입니다. 물론, 좀 더 정확하게 측정하려면 어셈블리어로 컴파일된 .S 파일을 분석하던지 실제 이 부분의 실행 파형을 오실로스코프로 확실하게 확인하는 것이 좋겠습니다. 우리는 일단 그냥 사용해 보고 실제 프로그램을 실행해서 정말 되는지를 확인해 보는 것으로 하겠습니다. 그리고, 1비트 데이터를 보낼 때마다 위와 같은 프로그램을 직접 써 넣어 프로그램할 수는 없으니까, 이것을 마크로(MACRO)를 이용하여 선언을 해 놓은 것이 좋을 듯 합니다.
아래와 같이 마크로를 정의해 놓으면 조금 편리하게 사용할 수 있겠네요.
#define NOP asm volatile(“nop”)
#define NOP2 NOP; NOP
#define NOP3 NOP2; NOP
#define NOP5 NOP3; NOP2
#define NOP6 NOP3; NOP3
#define NOP12 NOP6; NOP6
#define NOP13 NOP6; NOP6; NOP
// WS2812B ‘0’ 데이터 만들기
PORTD |= 0b00000100; // D2 디지털핀을 1로 만듬
NOP5; // 5번의 “nop”
PORTD &= 0b11111011; // D2 디지털핀을 0으로 만듬
NOP13; // 13번의 “nop”
같은 방법으로 ‘1’ 데이터를 만들어 보겠습니다.
400ns의 HIGH를 유지하려면, 800/62.5 = 12.8 = 약 13클록이 필요하고, 450ns의 LOW를 유지하려면, 450/62.5 = 7.2 = 약 7클록이 필요하므로, 아래와 같이 프로그램하면 될 것 같습니다. (규격에 보면 150ns(+/- 2 클록 이상)의 오차가 허용이 되므로 정수배를 취하여도 무방합니다.)
// WS2812B ‘1’ 데이터 만들기
PORTD |= 0b00000100; // D2 디지털핀을 1로 만듬
NOP12; // 12번의 “nop”
PORTD |= 0b00000000; // D2 디지털핀을 0으로 만듬
NOP6; // 6번의 “nop”
0과 1을 만드는 것도 계속 사용할 것이니, 아예 이것도 ‘CODE0’, ‘CODE1’이라는 마크로로 선언해 놓는 것이 좋겠습니다. 덤으로 데이터리셋은 LOW 상태로 50us를 유지하는 것이므로 이것까지 ‘RES’라는 마크로로 함께 선언해 놓겠습니다.
#define CODE0 PORTD |= 0b00000100; NOP12; PORTD &= 0b11111011; NOP6
#define CODE1 PORTD |= 0b00000100; NOP5; PORTD &= 0b11111011; NOP13
#define RES PORTD &= 0b00000000; delay Microseconds(50)
자, 이제 기본 준비가 되었으니, 파랑색을 나타내는 (G, R, B) 값 (0×00, 0×00, 0xFF) 총 24비트의 값을 연속적으로 보내는 프로그램을 작성해 봅시다. 1비트 값을 보내는 코딩을 확장하여 순서대로 8비트씩 3번, 총 24비트를 전송하면 되겠습니다. G->R->B 순으로 보내야 하고, 바이트 내에서는 HIGH 비트 순으로 먼저 보내는 것이 규격이므로, 아래와 같이 되겠네요.
#define NOP asm volatile(“nop”)
#define NOP2 NOP; NOP
#define NOP3 NOP2; NOP
#define NOP5 NOP3; NOP2
#define NOP6 NOP3; NOP3
#define NOP12 NOP6; NOP6
#define NOP13 NOP6; NOP6; NOP
#define CODE0 PORTD |= 0b00000100; NOP5; PORTD &= 0b11111011; NOP13
#define CODE1 PORTD |= 0b00000100; NOP12; PORTD &= 0b11111011; NOP6
#define RES PORTD &= 0b00000000; delayMicroseconds(50)
void setup()
{
pinMode(2, OUTPUT);
}
void loop()
{
RES; // WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // G(Green)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // R(Red)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // B(Blue)
}
잘 되려나요? 한 번 해보겠습니다.
아두이노 스케치 돌리고, 컴파일 & 다운로드 얍!
파랑색 불이 잘 켜졌네요. 잘 된 것이겠죠?
그럼, 한 숨 돌리고, 잠시 쉬었다가, 조금 더 전진해 보도록 하겠습니다.
10분간 휴식~!
JLED-BAR-1으로 무지개색 불 켜기
파랑색 불 켜는 것에 성공하였으니, 빨강색과 녹색 불 켜는 것은 쉽게 할 수 있겠지요?. 빨강색은 (G, R, B) 값을 (0×00, 0xFF, 0×00)로, 녹색은 (G, R, B) 값을 (0xFF, 0×00, 0×00)로 보내면 되니까 바로 되겠습니다. 그런데, 노랑색을 디스플레이 하려면, 어떻게 해야 할까요?
그림에서와 같이 빛의 3원색은 빨강, 녹색, 파랑이고, 노랑색은 빨강과 녹색을 동일 비율로 합하면 될 것 같으므로, 노랑색은 (G, R, B) 값인 (0xFF, 0xFF, 0×00) = (0b111111111111111100000000)을 생성하여 보내면 될 것 같습니다.
void loop()
{
RES; // WS2812B 리셋, 0 상태로 50us delay
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // G(Green)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // R(Red)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
}
조심하여야 할 것은 일반적인 색상표는 코드를 (R, G, B) 순으로 표시하므로 이것을 WS2812B로 전송할 때는 이 순서를 그대로 사용하면 안되고 (G, R, B) 순으로 순서를 바꾸어 전송하여야 한다는 점입니다. 잊으시면 안됩니다!
예를 들어 주황색을 디스플레이하고 싶다면, 주황색의 (R, G, B) 값은 (FF, 66, 00)이므로 (G, R, B) 코드값은 (66, FF, 00)=0b011001101111111100000000 이 되므로 프로그램은 아래와 같이 됩니다.
void loop()
{
RES; // WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE1; CODE1; CODE0; CODE0; CODE1; CODE1; CODE0; // G(Green)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // R(Red)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
}
자, 그러면 이제 무지개색 표현에 도전해 보도록 합시다.
한가지 컬러가 디스플레이 되는 시간을 1초 정도로 하면 보기가 좋을 것 같습니다.
빨강색을 디스플레이하고 1초 기다렸다가, 다음에는 주황색을 디스플레이하고… 이렇게 7가지 컬러를 디스플레이하면 되겠네요. 1초 딜레이는 아두이노 라이브러리 delay()을 이용하면 쉽게 되겠지요? 모두 한 번 해 보겠습니다. 5분 기다려 봅니다.
(5, 4, 3, 2, 1, 0)
같이 해보시지요.
일단, 빨주노초파남보에 해당되는 (G, R, B) 코드를 위 색상표에서 눈대중으로 찾으면,
빨강 = (00, FF, 00), 주황 = (66, FF, 00), 노랑 = (FF, FF, 00), 초록 = (FF, 00, 00), 파랑 = (00, 00, FF),남색 = (00, 33, 99), 보라 = (00, 66, FF) 정도로 표시될 것 같습니다.
무식한 방법이긴 하지만 이 코드를 이용하여 위에서 사용했던 방법을 반복적으로 7번 사용하면서 디스플레이될 컬러만 순서대로 바꾸어주면 됩니다. 뭐 저라고 뾰족한 수는 없습니다.
#define NOP asm volatile(“nop”)
#define NOP2 NOP; NOP
#define NOP3 NOP2; NOP
#define NOP5 NOP3; NOP2
#define NOP6 NOP3; NOP3
#define NOP12 NOP6; NOP6
#define NOP13 NOP6; NOP6; NOP
#define CODE0 PORTD |= 0b00000100; NOP5; PORTD &= 0b11111011; NOP13
#define CODE1 PORTD |= 0b00000100; NOP12; PORTD &= 0b11111011; NOP6
#define RES PORTD &= 0b00000000; delayMicroseconds(50)
void setup()
{
pinMode(2, OUTPUT); // D2를 데이터비트로 사용
}
void loop()
{
RES; // 빨강, WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // G(Green)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // R(Red)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
delay (1000); // 1초 디스플레이
RES; // 주황, WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE1; CODE1; CODE0; CODE0; CODE1; CODE1; CODE0; // G(Green)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // R(Red)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
delay (1000); // 1초 디스플레이
RES; // 노랑, WS2812B 리셋, 0 상태로 50us delay
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // G(Green)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // R(Red)
CODE0; CODE0
; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
delay (1000); // 1초 디스플레이
RES; // 초록, WS2812B 리셋, 0 상태로 50us delay
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // G(Green)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // R(Red)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // B(Blue)
delay (1000); // 1초 디스플레이
RES; // 파랑, WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // G(Green)
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // R(Red)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // B(Blue)
delay (1000);// 1초 디스플레이
RES; // 남색, WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // G(Green)
CODE0; CODE0; CODE1; CODE1; CODE0; CODE0; CODE1; CODE1; // R(Red)
CODE1; CODE1; CODE1; CODE0; CODE1; CODE1; CODE1; CODE0; // B(Blue)
delay (1000); // 1초 디스플레이
RES; // 보라, WS2812B 리셋, 0 상태로 50us delay
CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; CODE0; // G(Green)
CODE0; CODE1; CODE1; CODE0; CODE0; CODE1; CODE1; CODE0; // R(Red)
CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; CODE1; // B(Blue)
delay (1000); // 1초 디스플레이
}
잘 되셨다면 자축의 물개박수~~~
내가 원하는 7가지 무지개 색깔을 디스플레이 하는데 성공하였다는 이야기는 R, G, B로 나타낼 수 있는 모든 경우의 컬러를 디스플레이할 수 있다는 이야기가 됩니다. 총 몇가지나 될까요? R, G, B 강도를 나타내는 비트가 각각 8비트씩이므로 만들어질 수 있는 총 가지수는 256X256X256 = 16,777,226(1600만 이상)이 됩니다.
와~ 내가 JLED-BAR-1 1개를 가지고 표현할 수 있는 컬러가 1600만가지라니… 뭔가 좀 뿌듯한 감정이 올라오는 것도 같죠?
JLED-RING-12 로 12색상환 만들기
이제 1개의 WS2812B LED의 색상은 자유롭게 표현 가능하므로 이번에는 여러 개의 WS2812B LED가 연속적으로 연결된 형태에서 다양한 색상을 만들어 보는 연습을 해보겠습니다. 목표는 WS2812B 12개를 연속적으로 연결하여 둥근 링 형태를 구성하고 여기에 12가지 컬러를 넣어 아래와 같은 12 색상환을 만들어보는 것입니다.
12색상환은 초등학교 미술시간에 한번쯤은 색칠해 보았을 것으로 생각되는데요. 마침 카멜레온 DIY LED에 이것과 비슷하게 생긴 JLED-RING-12 라는 제품이 있으니 여기에 색상을 입히면 안성맞춤이 될 것 같네요.
JLED-RING-12는 앞에서 WS2812B 동작 원리를 설명하면서 사용하였던 연결관계 그림과 동일한 방법으로 WS2812B 12개를 직렬(시리얼)로 연결한 둥근 반지(RING) 형태를 띄고 있습니다.
프로그램 방법은 JLED-BAR-1에서 사용한 것과 거의 동일합니다. 조금 다른 것은 JLED-BAR-1의 컬러를 준비할 때는 1개의 RGB 쌍을 준비하였다면, 이번에는 12개의 RGB 쌍을 준비하여야 한다는 것과, 이 데이터를 순서대로 딜레이없이(중요!, 딜레이가 50us를 넘으면 12개 LED가 켜지는 것이 아니고 1개 LED만 컬러가 12번 바뀌면서 켜짐) 연속해서 내보내야 한다는 것입니다.
그럼 준비를 해볼까요?
인터넷에서 12색상환에 사용될 12가지 색상에 대한 코드를 찾아보니 아래와 같이 나옵니다. (RGB 순)
조금 번거롭긴 하지만 아직 라이브러리를 사용하는 방법을 배우지 않았으니, 오늘은 그냥 머슴처럼 꾹 참고 한 개씩 순서대로 내보내는 코딩으로 계속 가겠습니다. (좀 더 깔끔하고 간단한 방법은 다음 시간에…)
숫자가 많이 나오므로 마크로 정의를 음성기호(phonetic alphabet)로 더 만들어 사용하면 편할 것 같으므로 아래와 같이 형태로 마크로를 추가합니다.
#define ONE CODE0; CODE0; CODE0; CODE1 // 1 = 0×1 = 0b0001
#define TWO CODE0; CODE0; CODE1; CODE0 // 2 = 0×2 = 0b0010
…
#define ALPHA CODE1; CODE0; CODE1; CODE0; // 10 = 0xa = 0b1010
…
#define FOXTROT CODE1; CODE1; CODE1; CODE1; // 15 = 0xf = 0b1111
#define NOP asm volatile(“nop”)
#define NOP2 NOP; NOP
#define NOP3 NOP2; NOP
#define NOP5 NOP3; NOP2
#define NOP6 NOP3; NOP3
#define NOP12 NOP6; NOP6
#define NOP13 NOP6; NOP6; NOP
#define CODE0 PORTD |= 0b00000100; NOP5; PORTD &= 0b11111011; NOP13
#define CODE1 PORTD |= 0b00000100; NOP12; PORTD &= 0b11111011; NOP6
#define RES PORTD &= 0b00000000; delayMicroseconds(50)
#define ZERO CODE0; CODE0; CODE0; CODE0 // 0 = 0×00 = 0b0000
#define ONE CODE0; CODE0; CODE0; CODE1 // 1 = 0×01 = 0b0001
#define TWO CODE0; CODE0; CODE1; CODE0 // 2 = 0×02 = 0b0010
#define THREE CODE0; CODE0; CODE1; CODE1 // 3 = 0×03 = 0b0011
#define FOUR CODE0; CODE0; CODE1; CODE1 // 4 = 0×04 = 0b0100
#define FIVE CODE0; CODE0; CODE1; CODE1 // 5 = 0×05 = 0b0101
#define SIX CODE0; CODE0; CODE1; CODE1 // 6 = 0×06 = 0b0110
#define SEVEN CODE0; CODE0; CODE1; CODE1 // 7 = 0×07 = 0b0111
#define EIGHT CODE0; CODE0; CODE1; CODE1 // 8 = 0×08 = 0b1000
#define NINE CODE0; CODE0; CODE1; CODE1 // 9 = 0×09 = 0b1001
#define ALPHA CODE0; CODE0; CODE1; CODE1 // 10 = 0x0a = 0b1010
#define BRAVO CODE0; CODE0; CODE1; CODE1 // 11 = 0x0b = 0b1011
#define CHARLIE CODE0; CODE0; CODE1; CODE1 // 12 = 0x0c = 0b1100
#define DELTA CODE0; CODE0; CODE1; CODE1 // 13 = 0x0d = 0b1101
#define ECHO CODE0; CODE0; CODE1; CODE1 // 14 = 0x0e = 0b1110
#define FOXTROT CODE1; CODE1; CODE1; CODE1; // 15 = 0x0f = 0b1111
void setup()
{
pinMode(2, OUTPUT); // D2를 데이터비트로 사용
}
void loop()
{
// WS2812B 리셋, 0 상태로 50us delay
RES;
// 빨강 : 0xff0000 ▶ 0x00ff00
ZERO; ZERO; FOXTROT; FOXTROT; ZERO; ZERO;
// 다홍 : 0xdc143c ▶ 0x14dc3c
ONE; FOUR; DELTA; CHARLIE; THREE; CHARLIE;
// 주황 : 0xff7f00 ▶ 0x7fff00
SEVEN; FOXTROT; FOXTROT; FOXTROT; ZERO; ZERO;
// 귤색 : 0xf89b00 ▶ 0x9bf800
NINE; BRAVO; FOXTROT; EIGHT; ZERO; ZERO;
// 노랑 : 0xffd400 ▶ 0xd4ff00
DELTA; FOUR; FOXTROT; FOXTROT; ZERO; ZERO;
// 연두 : 0x66cc00 ▶ 0xcc6600
CHARLIE; CHARLIE; SIX; SIX; ZERO; ZERO;
// 녹색 : 0x00ff00 ▶ 0xff0000
FOXTROT; FOXTROT; ZERO; ZERO; ZERO; ZERO;
// 청록 : 0×005666 ▶ 0×560066
FIVE; SIX; ZERO; ZERO; SIX; SIX;
// 파랑 : 0x0000ff ▶ 0000ff
ZERO; ZERO; ZERO; ZERO; FOXTROT; FOXTROT;
// 남색 : 0x080b54 ▶ 0x0b0854
ZERO; BRAVO; ZERO; EIGHT; FIVE; FOUR;
// 보라 : 0xee82ee ▶ 0x82eeee
EIGHT; TWO; ECHO; ECHO; ECHO; ECHO;
// 자주 : 0×800080 ▶ 0×008080
ZERO; ZERO; EIGHT; ZERO; EIGHT; ZERO;
RES;
}
컴파일 ▶ 업로드 하면, … 와우~~~ 멋진 색상환이 나왔습니다.
환상적이네요.
너무 밝아서 가까이에 가서 다시 크게 찍어 본 사진을 올려 봅니다. 또렷ㅍ하지는 않네요.
실제 색상은 훨씬 더 화려하고 또렷합니다.
여러분도 모두 성공하셨죠? 또 축하의 박수!
그리고, 또 하나의 중요한 사실은 이제 컬러 세팅하는 방법과 여러 개의 WS2812B를 제어하는 방법을 습득했으므로, 이제부터는 어떤 모양, 어떤 컬러, 어떤 동작도 조금씩만 응용하면 모두 다 만들 수 있는 능력을 갖추었다는 사실입니다. 엄청난 힘을 갖게 된 것이지요. 어벤저스(?) 같은 힘!
물론, 조금 찜찜하게 남아 있는 부분도 있습니다.
CODE0, CODE1을 생성하는 처리 방법이 확실하지 않다는 점과, 코드 작성이 MACRO로 하나씩 작성하도록 되어 있어 지루하다는 점입니다. 이것 때문일까요? JLED-RING-12의 불빛이 아주 살짝 흔들리는 것 같기도 하구요. 어쨌든, 여기에 대한 해결책은 다음 번 이야기 “카멜레온 DIY LED를 위한 아두이노 라이브러리”에서 깔끔하게 해결하는 것으로 하겠습니다.
즐거운 시간 되셨나요? 오늘밤에는 꿈 속에서 알록달록한 12가지 아름다운 꿈이 펼쳐지도록 여러분의 머리맡에 12색상환 프로그램을 수행하는 JLED-RING-12를 켜놓고 주무시는 경험을 해보는 것도 좋겠습니다. 그럼, 이번 호의 이야기는 여기서 마치고 다음 호에서는 좀 더 재미있는 이야기를 가지고 다시 만나겠습니다. 안녕히 계십시오.
[36호]업체탐방 – 최재규 매직에코 대표
업체탐방 인터뷰
최재규 매직에코 대표
최근 들어 IoT(사물인터넷)과 메이커(Maker)에 대한 대중의 관심이 높아지고 미국을 중심으로 불어오는 메이커 열풍이 우리나라까지 번져오고 있다. 기존에 복잡하고 전문적인 여러 과정을 거쳤던 제품의 제작이, 오픈소스 하드웨어를 활용해 아이디어가 있으면 누구든 만들어볼 수 있는 시대가 온 것이다. 사물인터넷이라는 우리의 주거 생활에 밀접한 주제부터, 산업에 활용되는 분야까지 광범위하게 모든 사람들로 하여금 아이디어를 실현할 수 있는 기회가 주어진 것이다.
각종 언론 매체에서 현재 세계에서 불어오는 이런 열풍을 소개하는 시사, 교양 프로그램들을 접하다 보면, 매직에코라는 업체가 꽤 자주 눈에 띄게 되었다. 사물 인터넷, 아두이노와 같은 대중적인 주제에 대해서 비단 ‘유통 또는 제조를 통한 제품 판매’라는 흔한 수익 구조가 아닌, ‘교육 컨텐츠 제작 및 메이커 대회 주관’과 같은 ‘서비스’로 이루어지는 활동이 주 활동이라는 것이 특이했다.
디바이스마트도 비단 제품 판매 뿐 아니라 교육에 대한 관심이 많았기 때문에, 이런 활동을 꾸준하고 폭넓게 진행하고 있는 매직에코에 연락을 하게 되었고, 서울 성수동 사무실에서 최재규 대표, 이준혁 매니저, 이정인 매니저 세 분을 만날 수 있었다. 인터뷰는 주로 최재규 대표님, 이준혁 매니저와 진행하였다.
취재 | 이용동 책임기자 bluelyd@ntrex.co.kr
매직에코 이준혁 매니저, 이정인 매니저, 최재규 대표(왼쪽부터) |
안녕하세요, 먼저 디바이스마트 매거진 독자들께 인사 말씀 부탁드립니다.
최재규 대표이사 (이하 최) : 안녕하세요, 저희 매직에코는 IoT와 메이커와 관련된 IoT 플랫폼 기업입니다. 매직에코의 뜻은 ‘마법의 생태계를 만들자’는 뜻입니다. 저는 현재 미래부와 같은 국가 기관에 속해 있는 한국사물인터넷 협회 포럼이나 ICT 포럼에서도 일을 하고 있습니다. 그러다 보니 자연스럽게 ‘메이커 생태계’를 조성하고 활성화 하는 데 관여를 하고 있습니다. 다른 사물 인터넷이나 메이커 관련 업체들과는 조금 다른 성향을 가지고 있습니다. 제품을 생산하거나 이런 일을 하는 것이 아니라, 주로 컨텐츠를 개발하고 메이커 관련 프로그램, 정책과 관련된 일에 치중하고 있어요. 저희 메인 비즈니스가 사물 인터넷 관련 플랫폼 개발이다 보니까 다른 업체들처럼 3D 프린터와 같은 장비를 직접 만들거나 하는 것이 아니라, 사물 인터넷 관련 신산업 조성, 인프라 구축에 대한 업무들을 진행하고 있습니다.
네, 안 그래도 K 방송사에서 최근 방영된 ‘4차 산업혁명’과 관련된 다큐에서 뵈었는데요.
최 : 프로그램 제작 관련 자문을 하다 보니 잠시 출연을 하게 되었습니다. 현재 해외에서는, 특히 미국은 메이커 붐이 현재 상당한 수준이고, 거기에서 새로운 회사와 새로운 직업도 많이 탄생을 하고 있죠. 이런 부분을 정부에서는 한국 내에도 어느 정도 적용되기를 원하고 또 가능하다고 보고, 저변 확산 차원에서 공교육에서도 이와 관련된 교육을 하고 있죠. 미국은 그런 메이커 열풍에 대해서 첨단 IT 기업들이 후원하고 있고, 대통령이 나서서 이런 ‘메이커 무브먼트’ 활성화를 위해 백악관에서도 매년 행사가 진행되고 있어요. 마찬가지로 한국에서도 미래부의 사물인터넷협회에서 나서서 ‘IoT’, ‘클라우드’, ‘빅데이터’, ‘메이커 무브먼트’ 총 4가지 키워드를 가지고 활성화 방안에 대해서 이런 저런 시도도 하고 노력하고 있습니다. 이런 내용들에 대해서 정책 자문을 하고 있는 것이 저의 역할이구요. 그러다 보니 국가에서 진행하는 정부나 서울시에서 진행하는 사물 인터넷 관련 정책이나 행사들에서 자문, 심사 위원 등 활동을 하고 있습니다.
그렇다면 컨텐츠나 정책, 행사 등 관련한 활동 외에 제품을 만들어서 판매하는 등의 활동은 없으신 건가요?
최 : 지금은 IoT 관련 플랫폼이라는 것을 만들고 있고, 거기서 파생된 7가지 제품군에 대한 개발을 약 3년 동안 쭉 해오고 있습니다. 그 중에서 한 제품이 곧 외부에 오픈될 예정입니다. 아직 이름을 정하지는 못했는데, 전동 데스크 제품이 가장 먼저 공개될 것 같습니다. 사물 인터넷이나 메이커 관련된 다른 일반적인 업체들과는 성격이 아무래도 다른 게, 저희는 주로 제품이 아닌 컨텐츠 및 플랫폼 개발이 주 영역이고 제품에 대한 것은 현재로서는 부수적인 부분이 되고 있는 거죠.
주 활동이 ‘무료 교육 컨텐츠 제작’이라고 하셨는데, 그렇다면 매직에코의 수익은 어떻게 창출되고 있나요?
최 : 만든 컨텐츠를 물론 무료로 공개를 하고는 있지만, 실질적으로 이 활동은 정부의 용역을 통한 사업이다 보니까 그 용역비가 저희의 활동을 가능하게 해 주는 것이죠. 그렇게 용역 받아 제작한 컨텐츠가 10make나 유튜브 등 다양하게 국가에서 마련된 정보 공유 사이트에 올라가고, 공유되고 있는 거죠.
매직에코에서 제작한 아두이노 키트등 교육용 컨텐츠와 관련 상품들 |
현재 국가에서 공교육으로서 아두이노, 라즈베리파이 등 기본적인 부분들을 많이 진행하고 있는데, 이런 교육들에 대해서는 어떻게 생각하시나요?
최 : 아시겠지만 이 시장이 ‘가능성’은 정말 많이 열리는데, 정작 그 가능성들이 실제로 열리고 있는 부분은 크게 없어요. 국가에서는 소프트웨어 교육이나 이런 부분에 대해서 의지도 있고 욕심도 있지만, 냉정하게 말하자면 정부에서 원하는 방향으로 공교육이 바뀌기는 쉽지만은 않을 거라고 생각합니다. 꽤 오래 걸리지 않을까 싶어요. 현재 교사가 43만 7천 명이 있는데, 그 중에서 소프트웨어를 전공으로 공부하셨던 분이 5만 명 정도밖에 안되고, 더 중요한 것은 올해 입학한 1학년 학생들이 30만 명 밖에 안되고, 그렇게 12년 동안 360만 명이다 보니, 43만 명의 교사로 이 교육을 해내야 하는데 아무래도 그것 자체도 쉽지 않을 것 같아요. 그렇게 되면 아무리 민간에서 메이커 붐이 일어나고 해도 공교육에서 받쳐주지 않는다면 그런 붐업 자체가 활성화되기가 어렵죠. 살짝 생기고 마는 상황? 그래서 민간에서 서로서로 ‘판을 키워보자’하고 협업이 잘 되는 것이 꽤 중요해진 상황입니다. 그렇지 않으면 이 열풍도 어렵지 않을까요?
지금 학교에서 이루어지고 있거나 이루어질 예정인 공교육의 측면 외에도, 국가적으로 다른 지원 사업이나 행사, 또는 공간들이 있는 것으로 알고 있는데, 이 부분들은 어떻게 진행되고 있고 앞으로는 어떨까요?
최 : 아무래도 내년이면 현 정부에서 다음 정부로, 정책적으로 조금은 변화될 가능성이 있기 때문에 전세계적인 추세라는 큰 틀에서 보자면 유지가 되겠지만, 실질적으로 디테일한 측면에서는 흐름 자체에 울컥거리는 변화가 생길 수밖에 없는 상황임은 맞는 것 같아요. 이러한 점이 사실 메이커 비즈니스의 맹점이라면 맹점이구요. 지금 ‘메이커 스페이스’라는 공간이 전국에 설치되어 있는데, 특히 현재 제가 심의 위원으로 있는 ‘무한상상실’이라는 메이커들을 위한 공간이 있어요. 그런데 이 공간들을 국가에서 메이커들을 지원해주기 위해서 설치했더니 민간에서 설치된 공간들이 다 죽더라구요. 무한상상실은 무료니까 민간의 유료 공간들이 메리트가 떨어지는거죠. 저희는 좀 특이한 케이스이긴 해요. 주로 공공기관 정책과 관련된 업무에 치중이 되어있으니까요.
최근에는 3D 프린터나 드론과 같은 핫이슈가 많이 등장하고 있는데요. 매직에코는 주로 어떤 비즈니스 모델을 대상으로 하고 계신가요?
최 : 기본적으로 저희는 Short-Term 비즈니스는 생각하지 않고 있어요. Long-Term 비즈니스만 보고 있구요. Short-term 비즈니스 중에서 가장 핫한 것이 바로 아까 말씀하신 드론이나 3D 프린터와 같은 제품이라고 저희는 생각하고 있구요. Long-term 비즈니스는 특정 어떤 상품이나 브랜드가 아니라, 컨텐츠 비즈니스라고 보고 있어요. 아시겠지만 키트 만드는 것이야 뭐 한국에서 만드는 것보다는 중국에서 가져다가 파는게 훨씬 싸고, 라즈베리파이도 좋다고 하지만 그것보다도 싸게 만들 수도 있는 거라고 생각하구요. 기능도 요즘같은 세상에 이제는 원-칩에 모든 기능이 다 탑재되는 시대이기 때문에, 그런 하드웨어들은 아무래도 시장도 빨리 변하고, 다채롭고 변수도 많은 것 같아요. 문제는 우리나라는 아직 시장이 받쳐주지 못하고 있어요. 해외는 물론 우리나라와는 상황이 다르긴 하죠. 그런 쪽에서 저희는 메이커 관련된 핫한 이슈들도 약간은 거리를 두게 되고, 그래서 하드웨어보다는 컨텐츠 개발, 민간 보다는 공공기관과 함께하는 쪽으로 신경을 많이 썼습니다.
매직에코의 부품 보관실 |
그렇다면 매직에코의 앞으로는, 어떻게 움직이실 예정인지, 이 시장은 어떻게 돌아갈 것으로 예상하시는지 궁금합니다.
최 : 올해부터는 판이 조금 달라질 것으로 생각해요. 그래서 사실 지금은 자세하게 말씀드릴 수는 없지만 저희가 준비하고 있는 부분도 있습니다. 아무래도 판을 좀 키울 수 있지 않을까 싶어요. 사실 저희는 직접 보드를 개발하면 되기 때문에 요즘 인기가 많은 ‘라즈베리파이’라는 제품이 썩 매력적이지는 않아요. 매직에코 전체 인력의 절반 이상이 대기업에서 10년 이상 개발 업무를 했던 경력자들로 구성이 되어있고, 이 인력들도 각각 소프트웨어, 클라우드, 모바일, 임베디드 모든 분야에 1명 이상 포진되어 있어서 자체 개발도 가능한 상황입니다.
물론 이 쪽 시장은 자체 개발이 크게 의미가 없는 것 같아요. 자체 개발이 중요한 게 아니라, 생태계가 중요하다고 생각하고 있어요. 그래서 이제 잘 아시겠지만, 전자XX, 아두이노XXX 등과 같은 카페나 커뮤니티 자체가 생태계거든요. 이런 생태계 자체를 인정하고 이 생태계에 맞게 움직여야 하거든요. 이 세계가 ‘한국형’이라는 것이 메리트가 따로 있는 곳이 아니라 사업 아이템도 부족하고 뻔하기 때문이죠.
그래서 이제는 제품만 판매하는 것이 아니라, 제품에 컨텐츠를 묶어서 팔아야 메리트가 있습니다. 그래야 단순히 ‘가격’이라는 것이 가장 중요한 기준이 되지 않게 되는거 거든요. 저희는 이게 핵심이라고 생각합니다. 저희가 유튜브에 올리고, 10Make라는 자체 사이트에 올린 동영상만 해도 최소 50시간은 넘는 컨텐츠를 제작했기 때문에, 지금은 큰 관심이 있는 분야는 아니겠지만 앞으로는 이런 쪽으로 더 중요한 시기가 온다고 보고, 이 쪽으로 준비가 많이 되어있기 때문에, 앞으로가 자신있습니다. 저희는 그래서 아직은 키트를 만들어서 판매하거나 하는 이런 쪽으로는, 당분간은 시장이 아주 커져서 필수적이 되지 않는 이상은 크게 메리트를 느끼지 않을 것 같습니다. 현재 한국의 이런 시장에서는 관심이 아직 별로 없구요, 컨텐츠 개발, 정부 과제 이런 쪽으로만 신경쓰고 있습니다. 여기 지금 같이 나와있는 이준혁 매니저, 이정인 매니저가 앞으로도 지속적으로 컨텐츠를 만들어 나가게 될 거라고 생각합니다.
상세한 답변 감사드립니다. 그럼 이번에는 직접 동영상을 녹화하시고, 현재 모든 매직에코 컨텐츠에 직접 출연하고 계시는 이준혁 매니저님과 이야기 한 번 나눠보겠습니다. 안녕하세요. 최근 매직에코 동영상에는 매니저님 얼굴이 모두 나오고, 영상들을 엄청 자주 찍으시는 것 같더라구요.
이준혁 매니저 (이하 혁) : 원래는 2014년도에 한 번 했구요, 작년 후반부터 해서 올 초까지 한 번 했어요. 한 기간에 여러 개를 한번에 30~80개 강의를 짧은 기간에 한 번에 찍는 형태로 진행하고 있어요. 해외 강의를 번역해서 진행하는 것도 있었고, 공공 기관의 용역에 따라서 조금씩 찍는 것도 있지만, 지금은 바쁘게 찍어서 올리고 있는 기간은 아니에요. 사실 저희도 뭔가를 찍으려고 하면 자료를 다 사야하고, 그걸 받아서 하는 데는 시간이 좀 걸리더라구요. 해외 제품은 특히 받는 데 시간이 좀 걸리고, 그 기간 안에 어느 정도 분량의 강의가 제작되어야 하니까, 그 기간 동안은 많이 바쁜 편이에요. 정부 과제의 경우에는 기간도 짧고 가격도 빠듯해서 제품 구하는 것 자체도 일이에요. 이렇게 디바이스마트와 자리가 마련되었다는 것 자체로 뭔가 반가운 것도 그런 이유가 조금 있죠. (웃음)
제가 인터넷으로 찾아보니까, 매니저님께서 대기업으로의 진로 기회를 박차고 매직에코에서 일하시고 있는 것으로 들었습니다. 매직에코의 어떤 점이 좋으셨나요?
혁 : 제가 작은 벤쳐에도 몇 군데 있어보고 했지만, 대기업으로 갈 수 있는 기회도 박차고 매직에코에 있었던 이유는 대표님께서 “너한테 돈은 많이 못 주지만, 너 스스로 자립할 수 있는 힘을 키우도록, 너 스스로를 키울 수 있는 기회를 많이 주겠다.”라고 말씀하셨던 게 좋았어요. 실제로도 몸은 힘들었지만 중요하고 어려운, 까다로운 일도 많이 주셨어요. 과제도 기회도 정말 많이 주셨거든요. 강의 기회도 주시고, 책을 쓸 기회도 주시고. 그래서 제가 이렇게 자신감도 얻을 수 있었고, 더 열심히 하게 되었고 그만큼 더 성장하고 있는 것 같아요. 대기업에서 주는 만큼의 연봉은 아니지만 그 연봉에 비할 수 없이 제가 더 많이 성장할 수 있었기 때문에 제가 몇 년 간, 후회 없이 일할 수 있었던 것 같아요. 그러는 기간 동안 힘들었을 제 와이프에게도 미안하고 또 그만큼 감사하고 있구요.
동영상을 만드는 사람들에게 ‘조회수’라는 것은 꽤 중요할 것 같아요. 지금의 컨텐츠에 따라오는 조회수나 기타 반응들, 만족하시나요?
혁 : 저는 일단 만족해요. 그 동영상들을 제 계정으로 다 연결을 해둬서 반응이 오면 알림이 오거든요. 메이커가 해외에서는 기술의 익숙하지 않은 사람들에게도 기술이 보급되고, 그러면서 누구나 메이커가 될 수 있는 조건이 갖춰져있어요. 그런데 우리나라는 아두이노를 어려운 것으로 알려주는 교수님들도 있었고 그런 분위기였어요. 그런데 최근에는 그래도 초등학생들도 많이 질문을 하고, 재미를 느끼는 일반인들이 정말 많아졌다는 것을 느낄 수 있어서 정말 기쁘고 뿌듯하고 만족해요. 솔직히 수익만 놓고보면 부족할 수 있지만, 그게 중요한 것은 아니거든요. 만족스러워요.
매직에코의 동영상 제작 스튜디오 |
그럼 옆에 계시는 이정인 매니저님, 어떤 계기로 매직에코에서 일하시게 되었나요?
이정인 매니저 (이하 인) : 아, 그 명함이 사실 좀 예전꺼라서 그렇고, 현재 대부분의 직원들이 “매니저”로 통일되어 있어요. 그리고 저희 회사가 IoT 쪽이라 메이커와 IoT 업무를 겸하시는 분이 많은데, 저는 메이커 쪽만 전담하고 있습니다. 제가 전공이 토목 공학과였고 대학원을 준비하다가 진로에 대해서 회의적인 부분이 불현듯 들면서 대기업이나 다른 기업에도 많은 지원을 했었어요. 사실 제 미래에 대한 진지한 고민 없이 흘러가는 대로 놔두었던 시간이었죠. 그러다가 창작에 대한 재미를 느끼게 되었고, 옆자리에 계신 이준혁 매니저님, 사실 그 당시에는 저는 대학생이었고 매니저님은 3D 프린터 교육에서 스승이었죠. 지금도 사부님이라고도 부르고 있어요. (웃음) 그 때 느낀 흥미로 ‘메이커’에 대한 진지한 꿈이 생겼고, 친구들끼리 메이커 팀도 만들고, E 방송사 다큐에도 운좋게 나오기도 하는 듯 열심히 활동했죠. 그 후에 매직에코에서 일할 수 있는 기회가 되었고, 메이커 팀은 아직도 활동하고 있어요.
뿌듯함과 보람이 많은 일인 것 같아서 좋아 보이네요. 긴 시간 동안 인터뷰 해주셔서 감사합니다.
혁 : 아닙니다. 이야기도 할 수 있었고 와주셔서 감사합니다. 정말로 이렇게 재밌고 즐겁게, 보람있게 일할 수 있어서 좋습니다. 농담 아니에요.(웃음)
인 : 준혁매니저님은 특히 알려주고 하는 것을 워낙 좋아하시고 해서 누구보다도 더 일을 즐기시는 것 같아요. 메이커페어나 전시회나 교육 가면 항상 미리 맥북을 챙겨가셔서 초등학생이나 어린이들에게 둘러싸여서 교육을 해주시고 있거든요. 멀리까지 이렇게 와주셔서 저희도 감사합니다.
마치며,,
인터뷰 내내 느낄 수 있었던 일에 대한 자신감과 전문성, 그리고 자부심을 가지고 있는 매직에코와 같은 기업이 있어 우리나라 메이커와 IoT 산업은 뒤쳐지지 않을 것 같았다. 앞으로도 더 많은 교류가 있기를 희망하며 매직에코 인터뷰를 마친다.
[36호]반딧불이, 센서 부착 맹인 지팡이
2015 ICT 융합 프로젝트 공모전 우수상
반딧불이, 센서 부착 맹인 지팡이
글 | 동양미래대학교 권영제, 김건희, 정원희, 정예진, 전병천, 피은영
심사평
펌테크 아이디어가 돋보이는 제품으로 실생활에서 맹인에게 실제 도움을 줄 수 있는 제품으로 충분한 상업적 가치가 있다고 생각합니다. 완제품으로 개발 경량화 및 신뢰성 확보 부분에 관한 연구가 좀 더 진행되어야 할것 으로 생각됩니다.
JK전자 기술적으로는 구현하는데 그리 어려운 점이 없지만, 시각 장애인들에게 꼭 필요한, 굉장히 유용한 도구를 아이디어로 구현했다. 진동 모터를 이용하여 지팡이를 사용하는 사람이 다른사람을 의식하지 않고 위험 요소를 전달받을 수 있게 한 점도 좋은 아이디어이다. 다양한 실전 테스트를 거쳐 저렴하게 보급이 된다면 아주 유익한 제품임에 틀림이 없다.
뉴티씨 장애인들과 같은 사회적 약자에 대한 관심과 적극적인 도움은 항상 필요하다. 이 작품은 장애인 중 맹인들에 대한 필수 제품이라고 할 수 있겠다. 맹인들의 보조눈이 될 수 있는 제품으로, 배터리가 오래가도록 하며, 가볍게 만드는 것이 관건이라고 하겠다. 다만, 기술적으로는 크게 어려움이 없는 제품이다. 기능 면에서는 관련된 기능들이 잘 동작할 경우, 기획된 점들은 구석구석 기능을 잘 계획하였으므로 동작면에서만 실제 맹인들이 사용하도록 하여, 잘 보완하면 좋은 제품이 될 것 같다. 항상 그렇지만, 동작하는 정도에 그치는 것과 실제 사용할 수 있는 제품을 만드는 것은 하늘과 땅 차이로, 매우 많은 자본과 시간이 투여되고 구현도 어려워진다. 하지만, 이러한 점들을 잘 극복하고 좋은 제품을 만드는 것이 엔지니어들의 몫인 것 같다. 창의성과 실용성 및 완성도 등에 높은 점수를 주었다.
칩센 맹인들을 위한 제품에 대해서는 창의적인 아이디어인것 같다. 실제로 맹인들이 사용하기에는 무겁고 복잡하지 않을 까라는 생각이 든다. 사람이 많은 곳이나 장애물이 많은 곳에서는 센서동작이 항시 작용될 것으로 보인다. 배터리를 충분히 사용할 수 있도록 보안이 필요해보인다. 진동으로 감지 하는 방법 외 다른 방법으로 알림설정이 추가로 있으면 좋겠으며, 맹인들이 주위에 있다는걸 알리는 방법도 맹인들이 길을 다니기에는 조금 도움이 되지 않을까 한다.
위드로봇 작품의 컨셉, 구현 완성도가 훌륭합니다. 색상 인식의 경우 실제에서는 오염에 의한 오인식이 발생할 것이고, 이것에 대한 대처가 필요해 보입니다. 또한 장애인을 대상으로 하는 작품일 경우 어렵겠지만 장애인과 한 번 접촉하여 어떤 점이 정말 필요한 것인지 문의해 볼 필요가 있습니다. 실제 맹인의 경우 일반인이 느끼는 진동모터의 진동을 수 십배 이상으로 느끼기 때문에 해당 지팡이를 조금만 사용해도 손의 감각이 쉬 피로해지는 현상을 호소할 수 있습니다. 실제로 많은 정부 과제에서 본 작품과 비슷한 장애인용 지팡이 개발이 진행되었고 또 그에 따른 연구 결과들이 많이 공개되어 있습니다. 이런 내용을 참고하여 기존 연구와 차별성을 설명했으면 더 좋았을 것 같습니다.
작품 개요
사실 이 작품을 만들게 된 계기는 간단했다. 밤늦게 집으로 가는 길에 옆으로 누군가 휙하니 지나가는데 맹인이었다. 어떤 작품을 만들지 고심하던 터였는데 혹시 구상이 떠오르지 않을까 싶어서 한참을 지켜보고 난 후 다가가 혹시 지팡이를 사용하는데 애로사항이 있는지와 다른 얘기들을 나누어 봤는데, 우리가 생각하는 것보다 불편하고 위험한 것들이 많이 있는 것을 알고 난 후, 마음이 좋지 못했다. 그래서 기존의 지팡이에 센서를 부착한다면 보다 사용하기 수월하지 않을까하는 생각에 제작에 임하였는데 의외로 이러한 것들이 외국에는 존재했지만 홍보가 부족했는지 사용자는 적었고, 국내에는 거의 전무하였다. 기존의 센서 지팡이가 있으므로 이를 모방했다는 오해를 받기 싫어 더욱 차별성을 두려고 센서의 위치와 각도에 신경을 쓰고 센서들을 추가시키는 등, 많은 신경을 써보았다.
시각 장애인은 안전하게 보행하기 위해 지팡이를 사용하거나 안내견과 동행한다. 하지만 기존의 방법에는 여러 가지 문제가 있다. 먼저 안내견은 장기간의 훈련이 필요하여 많은 시간과 비용이 소모된다. 또한 기존의 지팡이는 장애물의 거리와 위치를 정확히 인지시켜 주지 못하기 때문에 충돌위험이 있고 점자블록이 있다고 하더라도 사용자가 완벽히 인지하긴 무리가 있다. 이에 시각장애인은 위험에 노출되어 있는데, 이런 문제점으로 복잡한 도심 속에서 시각 장애인이 기존의 지팡이에만 의존하여 보행하기엔 많은 어려움이 있다는 생각을 했다. 그래서 더욱 안전하게 보행할 수 있도록 도움을 줄 수 있는 장치들을 고려해 본 결과, 초음파 센서와 적외선 센서로 위험수준을 거리로 측정하고 색상 인식센서로 점자블럭의 노란색을 인지한다. 조도센서를 이용하여 터널과 같은 어두운 곳을 지날 때 LED가 자동적으로 켜지도록 조치한다. 그리고 조도센서를 제외한 센서의 지정된 값을 인식했을 때 진동모터로 전달토록 했다. 이러한 작품 (반딧불이)을 사용함으로써 안내견을 훈련시키는 사회적 복지 비용을 절감할 수 있고, 시각 장애인들이 기존보다 더욱 안전하게 보행할 수 있도록 도움을 줄 것이다.
작품명은 밤하늘을 수놓는 마치 한 마리의 반딧불이와 같이 이러한 지팡이가 얼른 상용화되어 시각장애인들이 걷는 그 어두운 길을 따라 비추어주어 불편함 없이 행복하게 지내기를 고대하며 글을 마친다.
사용 부품 및 설명
주요 동작 및 특징
1. 초음파 센서(3m) : 기존의 지팡이는 전방의 장애물의 유무를 미리 알기 어려워 지팡이의 아래쪽에 초음파 센서를 추가함으로써 최대 전방 3m 안의 위험 요소 여부를 손잡이의 진동으로 알린다.
2. 초음파 센서(2m) : 또, 지팡이의 중반부에 추가한 초음파 센서로 낮은 천장 등 2m 내에 있는 상방의 장애물을 감지하여 진동으로 위험을 알린다.
3. 색상인식 센서는 지팡이의 하단부에 부착되어 횡단보도 앞 점자 블록, 계단의 안내선 등 맹인을 인도하는 노란 선을 인지하고 진동 모터가 부착된 손잡이에 진동을 울려 노란 선의 여부를 알려준다.
4. 적외선 센서는 내리막길이나 움푹 파인 도로 등 하방의 빈 공간을 인지하여 진동으로 알려준다.
5. 조도 센서는 어두운 밤길, 안개 낀 날에 주변의 어두움을 감지하여 LED를 점등시켜 시각 장애인의 존재를 타인에게 알린다.
6. 진동 모터는 손잡이에 부착하여 적외선 센서, 색상 인식 센서, 초음파 센서 등과 연동하여 진동으로 모든 위험을 알린다.
기존의 지팡이와 비교
회로와 소스 코드
색상인식센서
int s0=3,s1=4,s2=5,s3=6;
int out=2;ㅍ
int flag=0;
byte counter=0;
byte countR=0,countG=0,countB=0;
void setup()
{
Serial.begin(9600);
pinMode(s0,OUTPUT);
pinMode(s1,OUTPUT);
pinMode(s2,OUTPUT);
pinMode(s3,OUTPUT);
}
void TCS()
{
flag=0;
digitalWrite(s1,HIGH);
digitalWrite(s0,HIGH);
digitalWrite(s2,LOW);
digitalWrite(s3,LOW);
attachInterrupt(0, ISR_INTO,LOW);
timer0_init();
}
void ISR_INTO()
{
counter++;
}
void timer0_init(void)
{
TCCR2A=0×00;
TCCR2B=0×07; // the clock frequeny source 1024 points
TCNT2=100; //10 ms overflow again
TIMSK2 = 0×01; //allov interruput
}
int i=0;
ISR(TIMER2_OVF_vect)// the timer 2,10ms interrupt overflow again.Internal
// overflow interrupt excutive function
{
TCNT2=100;
flag++;
if(flag==1)
{
countR=counter;
Serial.print(“red=”);
Serial.print(countR,DEC);
digitalWrite(s2,HIGH);
digitalWrite(s3,HIGH);
}
else if(flag==2)
{
countG=counter;
Serial.print(” green=”);
Serial.print(countG,DEC);
digitalWrite(s2,LOW);
digitalWrite(s3,HIGH);
}
else if(flag==3)
{
countB=counter;
Serial.print(” blue=”);
Serial.println(countB,DEC);
digitalWrite(s2,LOW);
digitalWrite(s3,LOW);
}
else if(flag==4)
{
flag=0;
}
counter=0;
}
void loop()
{
TCS();
while(1);
}
적외선센서
const int sensorPin = A1;
const int M=8;
void setup()
{
Serial.begin(9600);
pinMode(M,OUTPUT);
pinMode(sensorPin,INPUT);
}
void loop()
{
long distance=0;
distance = 12343.85 * pow(analogRead(sensorPin),-1.15);
Serial.print(“distance : “);
Serial.print(distance);
Serial.println(“cm”);
if(0<distance<50)
{
digitalWrite(M,HIGH);
}
else{
digitalWrite(M,LOW);
}
}
조도센서
const int T = 1;// T = SENSOR
const int J = 0;// J = SERSOR VALUE
const int L=7;
void setup()
{
Serial.begin(9600);
pinMode(T,INPUT);
pinMode(L,OUTPUT);
}
void loop()
{
Serial.println(J);
J = analogRead(T);
if( J > 300 )
{
digitalWrite(L,LOW);
}else{
digitalWrite(L,HIGH);
}
}
초음파센서 소스 코드
int ultras=A4;
int ultras2=A3;
const int M = 9;
const int M2 = 8;
const int M3 = 7;
void setup()
{
Serial.begin(9600);
}
void Sultras()
{
long td=0;
float dist=0;
pinMode(ultras, OUTPUT);
digitalWrite(ultras,LOW);
delayMicroseconds(2);
digitalWrite(ultras,HIGH);
delayMicroseconds(5);
digitalWrite(ultras, LOW);
pinMode(ultras,INPUT);
td = pulseIn(ultras, HIGH);
dist= td/29./2.;
if(0<=dist<50)
{
digitalWrite(M,HIGH);
digitalWrite(M2,HIGH);
}
else if(150>=dist>50)
{
digitalWrite(M,LOW);
digitalWrite(M2,HIGH);
}
else if (dist>250)
{
digitalWrite(M,LOW);
digitalWrite(M2,LOW);
}
else
{
digitalWrite(M, HIGH);
digitalWrite(M2,LOW);
}
Serial.print(dist);
}
void Sultras2()
{
long tds=0;
float dist2=0;
pinMode(ultras2, OUTPUT);
digitalWrite(ultras2,LOW);
delayMicroseconds(2);
digitalWrite(ultras2,HIGH);
delayMicroseconds(5);
digitalWrite(ultras2, LOW);
pinMode(ultras2,INPUT);
tds = pulseIn(ultras2, HIGH);
dist2= tds/29./2.;
if(0<=dist2<200)
{
digitalWrite(M3,HIGH);
}else{
digitalWrite(M3,LOW);
}
Serial.print(” “);
Serial.println(dist2);
}
void loop()
{
Sultras();
Sultras2();
}
단계별 제작 과정
부품 구입
(1) 초음파, 적외선, 색상 인식, 조도 센서와 기존의 역할을 담당하는 맹인 지팡이를 구입, 또한 습도에 의한 부식,고장을 방지하기 위해 방수 스프레이를 구비해두었다.
회로 구성 및 코딩 작업
(1) 각 센서마다 소스코드를 입력하여 딜레이와 일정 조건을 코딩했다.
(2) 회로도
색상 인식 센서 |
초음파 센서 |
적외선 센서 |
조도 센서 |
3) 지팡이에 연결, 하드웨어 작업
(1) 초음파 센서 |
(2) 진동 모터 |
(3) 색상 인식 센서 |
(+)납땜 작업 |
(4) 연결 |
데이터 시트
1) 조도 센서
1.감도 빛의 파장에 따라 감도가 다름2.허용손실 비교적 큰 전류를 흘릴 수 있음 3.암 전류 4.명 전류 5.응답특성 |
|
조도센서의 구성부 |
2) 적외선 센서
적외선 센서의 블록다이어그램 |
적외선 센서의 핀 연결 |
3) 초음파 센서
초음파 센서의 핀 연결 |
초음파 센서 특성표 |
4) 색상인식 센서
색상인식 센서의 블록다이어그램 |
색상인식 센서의 핀 연결 |
5) 진동모터
진동모터 특성표 |
[36호]STM32F4의 DAC, DMA를 이용한 임의파형 발생기
ICT 융합 프로젝트 공모전 우수상
STM32F4의 DAC, DMA를 이용한 임의파형 발생기
글 | 단국대학교 김진우, 가천대학교 김준환
심사평
펌테크 상업적인 목적의 저가 보급형 제품으로 출시되어도 무방할 정도의 창의적인 아이디어 제품이라고 생각됩니다. 임의파형 편집 등의 기능을 가능하도록 구현한 점 등은 인상적인 부분이라고 생각합니다. 아쉬운 점은 출품작 제작 과정에 관련된 제출 서류가 미흡하여 상세한 내용을 확인할 수 없었고 이로 인해 평가에 다소 어려운 점이 있었다는 점 입니다.
뉴티씨 임베디드 개발자들은 경우에 따라 다양한 파형을 테스트해야 하는 경우가 생긴다. 이 어플리케이션은 그러한 개발자들의 수요를 충족시킬 수 있다는 점에서 높은 점수를 주고 싶다. 하지만 최근 각광받는 라즈베리파이 등 비 Windows 환경을 배려하지 않은 것은 아쉽다. 이 부분만 고쳐졌다면 리눅스 환경에서 개발하는 많은 임베디드 테스터에게 좋은 솔루션이 되었을 것 같다.
칩센 높은 수준의 기술구현에 흥미롭게 읽었습니다. 본 공모전이 ICT 융합프로젝트 공모전이라는 이름을 가지고 있지 않았다면 좀 더 높은 점수를 받았을 것 같습니다. 임의로 생성된 파형을 활용한 간단한 예시도 기재가 되었으면 좀 더 좋았을 것 같습니다. 예를 들자면 연구실용이나 개발용 임의파형 발생기보다 발생된 임의파형을 활용한 무선 전자악기 같은 ‘융합’이라는 주제나 컨셉이 필요해 보입니다. 블루투스 오디오를 활용하여 전송할 경우 레이턴시 때문에 악기로서 문제가 되는 부분을 짧은 데이터 전송으로 딜레이를 극복한다거나 하는 것도 좋지 않을까 합니다. 그 원리도 잘 설명하였으나 디바이스마트 잡지 기재가 필요한 이상, 다른학생들처럼 해당 작품을 재현하고 따라해볼 수 있도록 STM32F4(MCU)와 ESD110v2(BT)의 연결 구성 사진과 회로도, 코드 등도 필요해 보입니다.
위드로봇 실험 장비로 필요한 내용을 직접 임베디드로 구현하고, 사용자 편의성을 고려하여 PC 인터페이스 프로그램을 구현했을 뿐만 아니라 스마트폰을 이용하여 동일한 기능을 사용할 수 있도록 구성한 면에서 실용성이 무척 높은 작품이라 판단됩니다. 작품의 완성도도 무척 높으며 보고서 구성도 짧지만 핵심 내용이 모두 들어가 있었습니다. 아쉬운 점은 출력 파형이 얼마나 정밀하게 출력되는지에 대한 분석 자료가 없어 보고서 만으로는 “얼마나 잘 되었는지”를 정량적으로 판단할 근거가 없습니다. 이 부분이 추가된다면 무척 좋은 작품, 보고서라 생각합니다.
작품개요
· STM32F4 Micro Controller의 DMA와 DAC 기능을 이용하여 임의파형을 출력할 수 있는 임의파형 발생기를 제작한다.
· 사용자가 직접 파형을 생성하고 편집할 수 있는 윈도우 어플리케이션과 안드로이드 어플리케이션을 제작한다.
· 윈도우 어플리케이션 또는 안드로이드 어플리케이션을 통해서 사용자가 생성한 신호를 블루투스 통신을 이용하여 MCU로 전송하여 MCU의 디지털 핀을 통해서 신호를 출력한다.
작품 설명
주요 동작 및 특징
1) STM32F4의 DMA와 DAC 기능을 이용하여 신호 파형 출력
STM32F407의 DMA와 DAC 기능을 이용하여 사용자가 임의로 제작한 신호 파형을 I/O 핀을 통하여 출력할 수 있도록 한다. DAC(Digital-to-analog converter)를 이용하면 디지털 값을 0 ~ 3.3V 사이의 아날로그 신호로 출력할 수 있다. 그리고 DMA(Direct memory access)를 이용하면 Memory 영역과 Peripheral 영역과의 고속 데이터 전송을 구현할 수 있다. 즉, DMA를 통하여 CPU의 resource를 적게 소비하면서 고속으로 DAC에 필요한 데이터를 전송할 수 있다. 따라서 DMA와 DAC를 이용하여 고속의 아날로그 신호를 I/O핀을 통해 출력할 수 있다.
2) 윈도우 및 안드로이드 어플리케이션 제작
STM32F407의 DAC와 DMA기능을 통하여 사용자가 제작한 임의 파형을 아날로그 신호로 출력할 수 있다. 하지만 사용자가 파형을 쉽게 편집하기 위해서는 UI가 구성된 어플리케이션이 필요하다. 따라서 .Net Framework 기반의 윈도우 어플리케이션을 제작한다. 기본적으로 윈도우 어플리케이션에 필요한 기능은 사용자가 신호 파형을 생성할 수 있어야 한다. 마우스 클릭을 통해서 신호의 값을 정할 수 있으며, 한 주기에 대략 200개의 데이터가 필요하기 때문에 특정한 점만 클릭 시 자동으로 신호를 생성해주는 기능을 제공한다. 또한 c파일과 csv파일로 저장할 수 있는 기능을 제공한다. 안드로이드 어플리케이션도 추가적으로 제작하여 사용자가 굳이 윈도우 환경이 아니더라도 스마트 폰을 휴대하면 어디서든 신호를 생성하고 출력할 수 있도록 한다. 윈도우 또는 안드로이드 어플리케이션과 STM32F407간의 데이터 통신은 블루투스를 통하여 무선으로 제공하도록 제작한다.
3) 기존 함수 발생기 기능 구현
기존의 신호 발생기는 기본적으로 정현파, 톱니파, 구형파의 신호만을 제공한다. 하지만 본 과제에서 제작하는 신호 발생기는 기존의 신호 발생기에서 제공하는 정현파, 톱니파, 구형파를 포함하여 사용자가 임의로 제작한 신호 또한 출력할 수 있도록 한다. 따라서 이론상으로 모든 신호를 발생시킬 수 있다.
4) 임의파형 자동 파형 생성 기능 구현
사용자가 임의로 제작한 신호를 출력하기 위해서는 신호를 직접 그릴 수 있는 툴이 필요하다. 따라서 .Net Framework 기반의 윈도우 어플리케이션과 안드로이드 어플리케이션을 제작한다. 두 어플리케이션 모두 사용자가 직접 신호를 제작할 수 있도록 마우스 클릭과 터치를 통하여 신호를 발생할 수 있도록 한다. 하지만 사용자가 한 주기의 임의파형을 그리기 위해서 많은 수의 점을 직접 클릭하여 그려야 한다. 이는 많은 시간이 소요되므로 사용자가 원하는 파형의 주요 변곡점만 클릭하면 그 사이는 자동으로 연결해줄 수 있는 알고리즘을 적용한다.
따라서 좀 더 편하고 빠르게 파형을 생성할 수 있다. 이러한 점과 점 사이를 연결해주는 알고리즘으로 Monotone cubic interpolation과 Bezier Curve를 적용한다.
전체 시스템 구성
1) 시스템 구성도
PC 또는 안드로이드의 블루투스를 이용하여 MCU의 블루투스 모듈로 신호 데이터를 전송 후 전송된 데이터를 파싱, DMA와 DAC를 이용하여 2채널 아날로그 신호를 출력해서 사용자가 원하는 신호를 발생시킨다. 임의파형 발생기는 2채널을 지원한다
2) 윈도우 어플리케이션 개발
(1) 기본 UI 및 기능 설명
윈도우 어플리케이션을 실행시키면 기본적으로 위의 그림과 같이 실행된다. 최초 실행 시에는 그래프를 생성시킨 상태가 아니기 때문에 그래프가 표시되지 않는다. New 버튼을 통해서 그래프 생성을 위한 기본정보, 즉 데이터 개수와 최대 전압을 입력하면 그래프가 생성된다. 데이터 개수는 총 표현할 수 있는 점의 개수이면서 x축 인덱스의 개수가 된다. 최대 전압은 y축의 최대값이 된다.
New 버튼으로 데이터 개수와 최대 전압을 입력하면 입력한 정보를 기반으로 새로운 그래프가 생성된다. 그래프의 왼쪽에는 STM32F4 보드와 통신하기 위한 시리얼 통신 정보를 입력하고 시리얼 포트를 열 수 있는 메뉴들이 있다. 포트 이름, 보레이트, 데이터 비트, 스톱비트, 패리티비트 메뉴가 있다. 그 아래에는 채널 선택(기본적으로 2채널을 지원한다), 알고리즘(점과 점 사이를 이어주는 알고리즘) 선택, 그리고 주파수 입력을 위한 텍스트박스, 시리얼 통신 데이터 전송 버튼이 있다.
화면의 위쪽에는 여러 메뉴들이 있는데 다음과 같다.
New : 데이터 개수, 최대 전압을 입력하여, 새로운 그래프를 생성한다.
Open : 기존에 저장했던 그래프를 불러온다.
Close : 현재 작업중인 그래프를 닫는다.
Save : 현재 작업중인 그래프 데이터를 저장한다.
Save As : 현재 작업중인 그래프 데이터를 새로운 이름으로 저장한다.
Export to Excel : 그래프에서 생성한 파형 데이터를 엑셀파일(csv파일)로 저장한다.
Export to C Code : 그래프에서 생성한 파형 데이터를 C코드(c파일)로 저장한다.
Edit : Edit 모드, 그래프 화면 마우스 왼쪽 버튼 클릭 시 점 추가, 점을 마우스 왼쪽버튼 더블 클릭 시 해당 점 삭제, 마우스 휠로 확대/축소, 마우스 오른쪽 버튼으로 화면 이동을 한다.
Zoom In : 확대 모드로 마우스 왼쪽 버튼 클릭 시 해당 부분을 확대 한다.
Zoom Out : 축소 모드로 마우스 왼쪽 버튼 클릭 시 해당 부분을 축소 한다.
Pan : 화면 이동 모드로 마우스 왼쪽버튼으로 드래그 시 화면을 이동한다. (단, 그래프 생성시 입력한 데이터 개수와 최대 전압을 넘는 범위로는 이동이 불가능하다.)
Default View : 화면 배율을 기본 값으로 초기화한다.
Sine Wave : 사용자가 입력한 진폭을 갖는 사인 파형 신호를 생성한다.
Sawtooth Wave : 사용자가 입력한 진폭을 갖는 톱니 파형 신호를 생성한다.
Square Wave : 사용자가 입력한 진폭을 갖는 사각 파형 신호를 생성한다.
Waveform Generate : 사용자가 신호의 특정 변곡점만 클릭하고 Waveform Generate 버튼을 클릭시 해당 점과 점 사이를 자동으로 연결하여 그려준다. 이 때 사용하는 알고리즘은 그래프 왼쪽의 라디오 버튼을 통해 선택한다.
Clear : 화면을 클리어 한다.
Option : 줌 인 / 줌 아웃 배율 설정, 화면 이동시 감도 설정 등의 옵션을 설정한다.
(2) 화면 확대 / 축소 및 이동
기본적으로 그래프에서 Zoom In, Zoom Out, Pan 기능이 있지만 감도 설정, 키 설정 등이 불가능 하기 때문에 직접 위의 기능들을 구현하는 방식으로 개발하였다. 그래프의 프로퍼티중 Scale Max와 Min이 있는데, 이 값을 수정하면 그래프에서 보여지는 각 축의 최대값과 최소값을 바꿀 수 있다. 따라서 이 Scale Max와 Min 값을 가지고 Zoom In, Zoom Out, Pan 기능을 구현하였다. 위의 세 기능 모두 마우스 클릭 또는 마우스 드래그, 휠 등을 이용하여 작동할 수 있도록 하기 위해서 마우스 이벤트를 이용하였다.
기본적으로 마우스 클릭 이벤트 발생시에, 시스템으로부터 마우스 좌표를 얻어올 수 있다. 이 좌표는 전체 윈도우 폼을 기준으로 한 좌표이기 때문에 현재 그래프 상에서의 좌표로 환산한다. 위 그림의 붉은색 사각형처럼 마우스 좌표를 기준으로 가상의 사각형 박스의 각 꼭지점 좌표를 계산한다. (박스의 크기는 Zoom 배율의 설정 값에 따라 달라지게 된다.)
마우스 클릭 이벤트가 발생했을 때 사각형 박스의 각 꼭지점 좌표를 현재 그래프의 Scale Max와 Min으로 각각 설정한다. 그리고 그래프 컨트롤을 다시 그리게 하는 Refresh 메서드를 호출하면 새로 변경된 스케일의 그래프가 다시 그려지게 된다. 따라서 Zoom In이 된 상태로 보여지게 된다.
Zoom Out은 마우스 클릭 이벤트 발생시에, 현재 마우스 좌표를 기준으로 현재 그래프상에서 각 축의 Max 값과 Min 값까지의 거리 즉, 위의 그림에서 dx1, dx2, dy1, dy2를 구하고 이 길이에 Zoom 배율을 곱한 값을 새로운 그래프의 Scale Min, Max로 설정한다. Scale Max가 최대 범위를 넘거나 Scale Min이 0보다 작아질 경우에는 범위를 넘어가지 못하도록 처리를 해준다.
Pan 기능은 그래프를 확대했을 때 그래프의 다른 부분을 보기 위해서 마우스 드래그로 이동하는 것을 말한다.
마우스 다운 이벤트와 마우스 무브 이벤트를 이용하여 구현하였다. 마우스 클릭시 마우스 다운이벤트가 제일 먼저 발생하며, 이 때 현재 마우스 좌표를 저장해둔다. 그리고 클릭을 유지한 채 마우스를 움직이면 마우스 무브 이벤트가 발생한다. 이 때 아까 저장해 준 좌표와 현재 좌표 사이의 좌표값 차를 계산한다. 이는 위의 그림에서 dx, dy이다. 이 dx와 dy값에 일정 값(Pan 감도)을 곱하여 그래프의 Scale Max값과 Min 값에 더해주거나 빼줌으로써 그래프 화면의 이동을 구현할 수 있다.
(3) 기본 파형 생성
기존의 신호발생기에서 제공하는 사인파, 삼각파, 톱니파, 구형파를 사용자가 진폭만 설정하면 자동으로 생성해주도록 구현하였다.
위 그림과 같이 사인파, 삼각파, 톱니파, 구형파 등의 해당 메뉴를 클릭 시 파형의 최대 전압 값을 입력받을 수 있는 창이 뜬다. 값을 입력하고 확인을 누르면 파형이 자동으로 생성되게 된다.
사인파, 삼각파, 톱니파, 구형파에 해당하는 수식을 미리 저장해놓고 최대값을 입력 받으면 해당 값에 맞는 각 인덱스의 전압 값을 계산하여 그래프에 표시하도록 구현하였다.
(4) 자동 파형 생성
Waveform Generate 는 사용자가 파형을 생성할 때 모든 점을 다 찍어서 생성할 수 있지만 너무 시간이 많이 소요되므로 특정한 변곡점 몇 개만 찍고 나머지 부분은 자동으로 생성해주는 기능이다.
위 그림처럼 세 개의 점을 찍은 상태에서 Waveform Generate를 하게 되면 알고리즘 별로 아래와 같다.
Monotone cubic interpolation을 이용한 파형이다.
각 점을 직선으로 연결한 파형이다.
각각의 알고리즘은 문서의 다른 부분에서 설명한다. 점을 아예 찍지 않고 Waveform Generate 버튼을 누르게 되면 다음 그림과 같이 모든 점이 0값을 가지도록 그려진다.
기본적으로 파형생성을 할 때, x축 인덱스의 최소값과 최대값에서 y값이 그래프상에 그려져 있는지 아닌지 검사하고 안 그려져 있을 경우 y값이 0값을 가지도록 설정한다. 따라서 아무런 점을 찍지 않았을 때는 x=0, y=0 과 x= max_index, y=0 의 두 점이 기본적으로 자동으로 찍혀서 계산이 되기 때문에 그래프상의 모든 점에서 y값이 0으로 표시되어 생성되는 것이다.
위의 그림처럼 시작 인덱스와 끝 인덱스에서 y값을 설정해주지 않으면 0값이 기본적으로 들어 가므로 생성된 파형은 시작과 끝에서 0으로 수렴하는 모양으로 생성되게 된다.
(5) File 저장 및 불러오기
사용자가 작업하던 그래프를 저장하거나 불러올 수 있도록 현재 그래프의 상황을 저장하거나 불러올 수 있도록 하였다. 기본적으로 현재 그래프상에 표시되어 있는 점들의 좌표 정보를 저장하고 불러와야 한다. 따라서 그래프 상의 좌표 정보 데이터들을 하나의 객체로 감싸고 이를 직렬화하여 파일로 저장하고 불러 올 수 있도록 하였다.
기본적으로 C#에서 제공하는 BinaryFormatter 클래스를 사용하여 파일로 저장할 때에는 직렬화를, 파일에서 불러올 때에는 역직렬화를 하여 현재 그래프상의 데이터들을 저장하고 불러올 수 있게 하였다.
(6) Excel 또는 C코드로 내보내기
사용자가 직접 생성한 파형을 다양하게 이용할 수 있도록 엑셀 csv파일 또는 c코드 파일로 출력할 수 있도록 기능을 구현하였다.
기본적으로 csv파일은 쉼표로 각 셀의 데이터를 구분하는 방식으로 표현한다. 따라서 엑셀 csv파일로 저장할 때에는 StreamWriter 클래스를 이용하여 그래프 데이터 정보를 쉼표로 구분하여 파일로 저장하도록 하였다. c코드파일로 출력할 때에는 보통 기본적으로 MCU에서 DAC를 할 때 1차원 배열로 y값 데이터 정보를 주로 사용하기 때문에 1차원 배열로 텍스트를 생성하여 저장하도록 하였다. 역시 StreamWriter 클래스를 이용하여 저장하였다.
3) Andorid 어플리케이션 개발
(1) 기본 UI 및 기능 설명
위 그림은 처음 시작 UI이다. 1번을 클릭할 시 함수를 선택할 수 있는 리스트가 나타난다. 2는 블루투스를 켜거나 연결할 수 있고, 3, 4번은 구현한 그래프를 c, csv, txt 파일로 저장하거나 txt 파일을 불러올 수 있다. 5번은 임의 파형에서 직접 구현한 포인트를 가지고 Monotone cubic interpolation, Liner Curve, Bezier Curve 알고리즘을 이용하여 200개의 포인트를 자동으로 생성해 사용자가 쉽게 그래프를 그릴 수 있게 도와 준다. 6번은 블루투스와 연결된 임의 파형 발생기에게 200개의 임의 파형 데이터를 보내주어 임의 파형 발생기 보드에서 신호를 출력할 수 있게 해준다. 7번은 포인트를 제거 할 수 있다. 8번은 체크할 시 그래프를 수정할 수 있거나 삭제할 수 있게 해주고, 9번은 자신이 원하는 신호의 주파수를 입력 할 수 있다.
(2) 기본 파형 생성
기존 신호발생기와 같이 사인파, 톱니파, 삼각파, 구형파를 제공해준다. 함수 선택 버튼을 클릭하면 총 5가지의 리스트가 띄워진다.
사인파, 구형파, 톱니파, 삼각파 임의 파형 발생기를 선택할 수 있다.
이 함수를 가지고 Send 버튼을 클릭하면 블루투스에 연결되어 있는 임의파형 발생기보드에 데이터를 넘겨 원하는 파형을 출력할 수 있다.
(3) 자동 파형 생성
기본으로 제공된 파형뿐만 아니라 사용자가 원하는 파형을 만들어 줄 수 있게 해준다. 함수 리스트에서 Random을 선택하여 그릴 수 있다.
왼쪽 그림에 보면 빈 공간이 있다. 자신이 원하는 지점에 터치하여 오른쪽 그림처럼 원하는 그래프 모양을 그릴 수 있다. 이때, 사람이 그래프모양을 정확히 다 그리기에는 힘들거나, 번거로울 수 있다. 여기서 interpolation 알고리즘을 이용하여 자동으로 그래프를 그릴 수 있게 도와준다. Creation버튼을 클릭하면 interpolation 알고리즘이 3가지 나온다.
여기서 자신이 원하는 그래프를 그릴 수 있는 것을 클릭하여 Yes버튼을 클릭하면 자동으로 그래프를 그려준다.
왼쪽부터 사용자가 터치한 그림부터, Monotone Cubic, Liner Curve, Bezier Curve 알고리즘을 이용하여 그래프를 그릴 수 있다.
(4) File 저장 및 불러오기
사용자가 필요한 그래프를 그렸을 때 자신의 그래프를 계속 사용하고 싶을 때 저장버튼을 눌러 c코드 파일, txt파일, csv파일로 저장할 수 있다.
저장할 때 사용자가 원하는 파일로 지정을 하여 저장시킬 수 있다.
동시에 3가지 저장도 가능하다.
저장한 파일을 열어보면 함수의 그래프를 가지고 있다. csv파일을 열면 사용자가 바로 엑셀에서 그래프를 그릴 수 있게 하고, c파일은 배열에 데이터를 초기화 했다.
이렇게 불러오기 버튼을 클릭하여 저장한 파일을 불러오면 저장할 때 그렸던 그래프를 다시 그려준다.
4) STM32F의 DMA 및 DAC 기능을 이용한 신호 파형 출력
(1) 개발보드 및 블루투스 모듈 선정
개발보드로는 ST사의 STM32F407 MCU가 들어간 STM32F4DISCOVERY 보드를 사용하였다.
그리고 블루투스 모듈은 칩센사의 Parani-ESD110V2 모듈을 사용하였다. STM32F4는 32비트 MCU로 시스템 클럭은 최대 168MHz로 동작한다. 12비트 DAC, 32비트 타이머, DMA 등을 내장하고 있기 때문에 우리가 만들려는 임의파형 발생기의 메인보드로써 적합하기 때문에 선정하였다.
(2) 블루투스 통신 패킷
임의파형 발생기 개발보드와 윈도우 어플리케이션 또는 안드로이드 어플리케이션과 통신은 블루투스를 이용하여 데이터를 주고 받는다. 이 때 안드로이드 어플리케이션 또는 윈도우 어플리케이션에서 사용자가 생성한 임의 파형 데이터를 위의 그림과 같은 데이터 패킷으로 구성하여 전송하도록 구현하였다. 패킷의 각각의 항목에 대해서 설명하면 다음과 같다.
0xFF 0xFF : 데이터 패킷의 시작을 알리는 부분이다.
데이터 개수 상위 / 하위 바이트 : 시작을 알리는 0xFF, 0xFF 2바이트를 제외한 전체 데이터 패킷의 바이트 수를 나타낸다.
예를 들어서, 임의 파형 데이터의 포인트 개수가 200개라고 한다면, 기본적으로 파형 데이터는 12비트의 값(0~4095)을 가지므로 상위/하위 바이트로 나누어서 전송해야 한다. 따라서 200개의 파형 데이터는 400바이트가 되고, 채널, 주파수 상위/하위 바이트, 데이터 개수 상위 /하위 바이트의 바이트 수를 합치면 405바이트가 된다. 따라서 200개의 파형 데이터를 가지는 임의 파형을 전송하기 위해서는 총 407 바이트가 필요하고 그 중 0xFF, 0xFF 2바이트를 제외한 405라는 숫자를 데이터 개수 상위/하위 바이트로 나누어서 전송한다. 2바이트로 나누어서 전송하는 이유는 1바이트로는 0~255까지의 숫자만 표현 가능하므로 2바이트의 unsigned short int 데이터 형으로 구성하여 상위 바이트/하위 바이트로 1바이트씩 나누어서 전송한다.
주파수 상위/하위 바이트: 주파수도 1~20000(20kHz) 사이의 값이 될 수 있으므로 데이터 개수와 마찬가지로 2바이트의 unsigned short int 데이터 형으로 구성하여 상위 바이트/하위 바이트로 1바이트씩 나누어서 전송한다.
채널 : 기본적으로 임의파형 발생기는 2채널을 지원하므로 어떤 채널로 출력할 데이터인지 나타내는 채널 데이터가 필요하다. 1은 1채널, 2는 2채널을 의미한다. 따라서 1 또는 2의 값을 갖는다.
데이터 상위/하위 바이트 : 데이터 상위/하위 바이트는 임의파형 발생기 개발보드에서 12비트 DAC로 아날로그 신호로 출력할 데이터 값이다. 12비트 데이터이기 때문에 상위/하위 바이트로 나누어서 전송한다.
(3) 타이머를 이용한 DAC 트리거
DAC를 통해서 주기적인 신호를 표현하기 위해서는 DAC Conversion이 주기적으로 수행되어야 한다. 따라서 이를 위해서, 타이머의 트리거 기능을 이용한다. 우리는 STM32F4의 타이머 6/7을 이용하여 각각 채널1과 채널2의 DAC 트리거를 구현하였다.
타이머6을 DAC 채널1의 트리거로, 타이머7을 DAC 채널2의 트리거로 설정하였다. 타이머를 원하는 신호의 주파수로 동작하도록 프리스케일러와 카운터 레지스터를 설정하게 되면 Timer Trigger Output(TIMx_TRGO)이 원하는 주파수로 동작하고 DAC 인터페이스는 Timer Trigger Output의 Rising edge를 검출하여 DAC_DHRx 레지스터의 값을 DAC_DORx 레지스터로 전송한다. 따라서 원하는 주파수로 DAC Conversion이 수행되게 된다.기본적으로 타이머6/7의 메인 클럭은 시스템 클럭이 168MHz일 때 84MHz가 된다. 또한 타이머6/7의 프리스케일러와 카운터 레지스터는 16비트로 0~65535의 값을 갖게 된다.
원하는 주파수의 신호를 DAC로 트리거 하기 위해서는 아래의 공식을 통하여 원하는 주파수에 해당하는 타이머의 프리스케일러 값과 카운터 레지스터의 값을 구해야 한다.
Timer Period = Timer Frequency / Timer Prescaler / Frequency / Number of Data
Timer Period는 타이머의 카운터 레지스터의 값, Timer Frequency는 타이머의 동작 클럭으로 위의 그림에서 보듯이 타이머6/7은 시스템 클럭이 168MHz일 때 84MHz의 클럭으로 동작한다. 따라서 84000000의 고정값을 갖게 된다. Frequency는 원하는 신호의 주파수이며, Number of Data는 사용자가 편집한 파형의 데이터 개수이다.
(4) 오실로스코프에서 출력확인
위 그림에서 보듯이 오실로스코프에서 실제로 파형발생기와 같은 출력을 확인할 수 있다. 또한 임의그래프를 그려 실제로 출력해 보면 아래와 같이 나온다.
왼쪽 그림은 임의 그래프를 그린것이고 오른쪽 사진은 실제 출력했을 때 모습이다.
개발 환경
OS: Windows 7, Windows 8.1
Tool : Microsoft Visual Studio 2013, IAR Embedded Workbench, Eclipse
Language : C, C#, JAVA
단계별 제작 과정
기타
참고 문헌
1) STM32F407xx Datasheet
2) STM32F407xx Reference manual
3) http://developer.android.com/
[35호]Arduino M0 & Arduino 9 Axes Motion Shield 리뷰
Arduino M0 &
Arduino 9 Axes Motion Shield 리뷰
글 | 금강초롱 객원기자 blog.naver.com/crucian2k3
스마트폰에서 촉발된 IOT 기술의 빅뱅은 영향을 받지 않는 곳이 없을 정도로 무섭게 확산되고 있습니다.
마치 나비효과처럼 전 세계에서 자신의 손으로 뭔가를 만들고 싶어하는 DIY(Do It Yourself)족 및 컴퓨터를 잘 모르는 이들에게도 교육차원으로 많이 사용되어 선풍적인 인기를 끌고 있는 아두이노, 라즈베리파이 등에도 그 바람을 피하기 힘든 듯합니다.
유난히 폭 넓은 사용자층을 형성하고 있는 아두이노 진영에서도 앙증맞은 32비트급 아두이노 보드가 정식출시 되었으며, 이제는 프로토타이핑 보드도 고사양이 되는 길이 열린 듯합니다. 언제나 그래 왔듯이 세월이 지나면 더 쎈 녀석이 등장할 것입니다만…
여기서 프로토타이핑이란 용어가 낯설은 독자를 위해 첨언을 좀 하자면 실험실습 등을 위해 간이로 만들어보는 보드 혹은 도구 또는 그러한 일들을 의미합니다. 억지스럽게 표현해 본다면 시작품, 시제품, 연습용 제품 등으로 해석될 수 있을 듯합니다.
요 근래 이러한 아두이노 진영에 내분이 있었으며 2016. 3월 현재 arduino.cc 진영과 arduino.org로 나뉘어 아두이노에 대한 기술지원이 이뤄지고 있는 점은 제 개인적인 생각으로는 그리 바람직해 보이지 않습니다. 그도 그럴 것이 동일한 하드웨어를 다른 명칭으로 불러 혼란을 유발하거나 arduino IDE의 버전이 헛갈리게 발표되고 있는 점도 그러한 사실을 충분히 뒷받침 한다고 봅니다.
이러한 거시적(?) 상황을 살짝 감안 해보며 이번 차에는 막강한 성능을 가진 ‘아두이노-M0’를 다뤄보려 합니다. 본격적으로 ‘아두이노-M0’를 거론하기 전에 한두 해를 거슬러 올라가면, 지난 2014년 5월경 arduino.cc 진영에서 ‘ARDUINO-Zero’라는 Atmel 32비트 MCU를 사용하는 모델을 발표 합니다. 발표 후 1년여가 흐를 무렵 ‘arduino.cc’와 ‘arduino.org’로 조직이 분열되면서 ‘ARDUINO-Zero’가 ‘ARDUINO-M0-Pro’라는 명칭으로 arduino.org에서 발표가 됩니다. 그리고 얼마 후 arduino.org에서 ‘ARDUINO-M0-Pro’ 하드웨어에서 Atmel 의 디버거 기능인 EDBG를 제외한 새로운 모델인 ‘ARDUINO-M0’를 발매하게 됩니다.
위에서 열거한 ‘ARDUINO-Zero, ARDUINO-M0, ARDUINO-M0-Pro’는 사실상 같은 MCU를 사용하고 있으며 H/W 적으로는 EDBG만 있고 없을 뿐입니다. 이번에 다루게 될 ‘ARDUINO-M0’는 사실 이전에 발매된 ‘아두이노-레오나르도’와 닮은 점이 많습니다. 이에 대한 내용도 아래에서 잠깐 다뤄보고자 합니다.
이러한 ‘ARDUINO-M0’를 살펴보면서 제가 흥미를 가졌던 부분은
· D0, D1을 제외한 전 포트에 PWM 기능이 동작됨을 의미하는 ~ 문양이 있는데 이에 대한 특성은?
· Serial Port 어떻게 클래스 매핑이 되어 있는가?
· 8비트급 MCU를 쓰는 모델들에 비해 새로운 기능은 무엇이 있는가?
· 12비트 ADC는 충분히 쓸만 한가?
· 10비트 DAC를 어떻게 사용할 수 있는가?
· 실행속도는 8비트급에 비해 어느 정도 빠른가?
‘아두이노-M0’는 종래의 Atmega328을 사용하는 ‘아두이노-우노’ 시리즈 혹은 Atmega23u4를 사용하는 ‘아두이노-레오나르도’ 시리즈와 견주어 볼 때 노는 물이 다름은 이론의 여지가 없습니다. 저에게 M3를 사용하는 ‘아두이노-두에’가 있었다면 서로 비교해 볼 수 있었을 텐데 사정상 ‘아두이노-레오나르도’와 성능이나 기타 특이점에 대해만 논해 보려합니다.
이번 포스팅은 ㈜엔티렉스-디바이스마트의 지원을 받아 작성하게 되었습니다.
1. 제품 개봉기
‘아두이노-우노-R3’의 폼팩터를 그대로 계승하고 있기에 그다지 새로울 것은 없습니다. 다만 보드 자체가 매우 작고 정교하게 만들어 졌다는 느낌이 드는 것은 사실입니다.
기왕 하는 김에 ‘아두이노-M0-Pro’ 모델이었다면 디버그 기능도 살펴 볼 수 있었을 텐데 하는 아쉬움도 있었습니다만 디버그 기능 외 차이점은 없다고 봅니다.
그림1 : 아두이노-M0 박스 외관 |
뒷면에는 이탈리아에서 제조된 물품임을 확인하는 로고가 선명하게 인쇄되어 있습니다. 박스를 열면 앙증맞은(?) 보드가 한 장 덩그러니 들어가 있으며 ‘아두이노-우노’와 마찬가지로 Atmel사의 SAMD21G18A-AUT을 기반으로 한 보드가 보이며 전체적인 분위기는 ‘아두이노-레오나르도’와 유사하다고 생각됩니다.
그림2 : 아두이노-M0 전면부 |
그림3 : 아두이노-M0 후면부 |
‘9축 모션 센서 쉴드’ 보드는 그보다 약간 큰 박스로 구성되어져 있으며 얼핏 본다면 아두이노 본체로 오해라도 할 수 있을 만큼 비슷하게 생겼습니다.
쉴드 보드는 아두이노의 확장보드로 매우 다양한 쉴드보드가 존재합니다. 이번에 리뷰하는 쉴드 보드는 3축 14bit 가속도센서, 3축 16bit 자이로센서, 3축 지자기센서가 원칩에 들어있는 보쉬센서텍의 BNO055라는 칩을 기반으로 하고 있습니다.
그림4 : 9축 모션센서 쉴드 박스 외관 |
그림5 : 9축 모션센서 쉴드 후면부 |
2. 아두이노-M0 살펴보기
기 발매중인 모델 중 ‘아두이노-레오나르도’와 폼펙터 측면에서 유사성이 많음에 따라 두 모델을 상호 비교해 보도록 하겠습니다.
2.1 기본적인 스펙
우선 눈에 띄는 부분이 동작전압이 3.3V라는 점입니다.
5V를 기반으로 만들어진 쉴드를 연결할 때 주의가 필요해 보입니다.
다음으로 A/D변환기의 분해능이 12비트로 올라갔고 플래시메모리가 대폭 늘어났으며 무엇보다도 클럭 속도가 올라갔습니다.
한마디로 컴퓨팅 파워를 끌어 올렸다고 보면 틀림이 없을 것 같습니다.
이제 세부적인 변경 사항들을 하나하나 살펴보도록 하겠습니다.
2.2 전원공급핀
외부에서 전원을 공급받는 방법은 2가지가 있습니다.
2.1mm 규격의 DC아답터를 사용하여 6~15V를 인가하는 방법과 마이크로USB 컨넥터를 통해 DC 5V를 인가하는 방법이 있습니다.
USB 2.0포트에 연결되는 경우 500mA가 한계치이므로 전력이 부족한 경우 DC아답터를 사용하여 공급할 수 있습니다.
DC아답터는 시중에서 9V, 12V를 흔히 구입할 수 있을 것 같으며 중심축이 +전원이고 외경은 GND가 되어야 합니다.
2.3 메모리 관련사항
ATSAMD21G18 MCU는 256KB의 플레시메모리를 내장하고 있으며 이중 4KB는 부트로더 영역으로 사용됩니다. 이 부트로더 영역은 NVM 퓨즈에 의해 보호되도록 설정되어 있습니다. 램은 32KB가 내장되어 있으며 이중 16KB는 EEPROM 라이브러리에 의해 에뮬레이션 될 수 있습니다. 즉, EEPROM 라이브러리로 램 영역을 활용할 수는 있으나 전원이 차단되면 데이터는 유실 되게 됩니다.
2.4 입출력핀 관련사항
‘아두이노-M0’는 디지털 I/O핀으로 총 14개가 설정되어 있습니다. 이들은 pinMode(), digitalWrite(), digitalRead()함수를 사용하여 손쉽게 입·출력이 이뤄지게 됩니다.
위에서 언급한 바와 같이 ATSAMD21G18은 3.3V에서 동작되므로 신호 레벨은 3.3V가 됩니다. 풀업저항은 20∼60kΩ의 내부 풀업저항이 연결될 수 있으며 전원이 투입되면 기본적으로는 해제되어 있습니다. 최대 출력전류는 7mA입니다.
2.5 프로그래밍 관련사항
‘아두이노-M0’에 프로그래밍을 하기 위해서는 일단 플레시메모리가 삭제되어져야 합니다. 이 기능은 마이크로USB 커넥터로 구성된 네이티브USB포트를 통해 진행됩니다.
이 포트는 SAMD21에 직접 연결되어 있으며 업로드 진행시 일단 1200bps에서 플레시메모리 삭제가 진행된 후 다시 부트로더에 의해 57600bps등으로 연결되게 됩니다.
이러한 기능은 ‘아두이노 레오나르도’도 동일하며 프로그램을 업로드 시킨 후 네이티브 USB포트를 사용할 수 없는 지경으로 만들면 전용프로그래머를 사용하지 않고는 다시는 아두이노 IDE로 접근이 곤란해질 수 있는 위험이 있습니다.
2.6 USB 과전류 보호회로
아두이노-M0는 폴리퓨즈를 설치하여 과전류로부터 SAMD21을 보호하도록 되어 있습니다. 일반적으로 사용되는 USB2.0포트는 500mA이상의 전류가 흐르면 출력을 차단하는 기능을 갖고 있습니다. 과도한 전류를 흐르게 하는 경우에 다양한 요인에 의해 아두이노-M0가 동작되지 않거나 동작이 불안정해질 수 있음을 유의해야 합니다.
3. 아두이노-M0 연결하기
서두에서 밝힌 바와 같이 아두이노 진영에서 지난해 여름 무렵 상표분쟁이 있었다고 합니다. 2016. 3월 현재 www.arduino.cc와 www.arduino.org로 양분되어 아두이노 IDE와 각종 보드들을 공식적으로 지원하고 있는 형국입니다. 아두이노 IDE버전 1.6.x는 arduino.cc에서 공급하고 있고 1.7.x는 arduino.org에서 공급하고 있습니다. 또한 arduino studio란 IDE도 있는데 현재 알파버젼이 발표된 상태입니다.
금번에 리뷰가 진행되고 있는 ‘Arduino-M0’는 www.arduino.org에서만 공급되고 있으며 1.7.x버젼의 IDE에서 정상적으로 사용할 수 있습니다. 이런 이유로 보드에는 ‘NEW IDE www.arduino.org’라는 딱지가 가운데에 붙어 있습니다. 이러한 정보 없이 ’아두이노-M0’를 구입하면 다소 난감하리라 봅니다.
3.1. ‘아두이노-M0’에 네이티브USB 연결하기
정확한 원인은 알 수 없었으나 USB드라이버가 제대로 인식되지 않아 애를 먹었습니다. 해결책을 찾아 arduino.org 포럼을 수소문한 끝에 방법을 알아내었고 다름 아닌 수동드라이버 인식 이었습니다. 아마도 이 글을 읽는 독자 중에는 동일한 증상을 겼을 가능성이 충분히 있다고 봅니다. ‘아두이노-레오나르도’인 경우에는 ‘아두이노 설치경로/driver’에서 손쉽게 드라이버 문제를 해결 할 수 있었습니다만 ‘Arduino-M0’는 이 방법이 소용이 없었습니다.
아래 그림과 같이 ‘기타장치 ▶ 알 수 없는 장치’ 현상이 있을 때 해결책입니다.
장치관리자 ▶ 기타장치 ▶ 알 수 없는 장치 ▶ 드라이버 소프트웨어 업데이트
▶ 컴퓨터에서 드라이버 소프트웨어 업데이트
▶ 컴퓨터의 장치목록에서 직접 선택
▶ 포트 (COM & LPT)
▶ (제조업체)Arduino Sri(www.arduino.org)
▶ (모델)Arduino Zero Native Port 를 순서대로 선택합니다.
이에 대한 설명을 http://labs.arduino.org/Manual+installation+of+drivers+on+Windows에서도 확인할 수 있습니다.
3.2. (Demo1)Hello World에 도전하기
LCD가 없으니 LED로 도전해 보고자 합니다. 위에서 LED는 D13에 연결되어 있음을 알았습니다.
‘아두이노-우노’ 시리즈 등 8비트 계열과는 다른 MCU를 사용한 상황이므로 우선 www.arduino.org에서 특별히 제공하는 예제로 테스트를 해봅니다.
만일 시작하면서 로그를 꼭 보고자 한다면 setup()에 아래와 같은 코드를 넣어줍니다.
// If Serial moniter Used!
while (!SerialUSB);
● 소스의 위치 :
· http://labs.arduino.org ▶ DOCUMANTATION ▶ Boards
▶ Arduino M0
· http://labs.arduino.org/Arduino+M0
· http://labs.arduino.org/ArduinoM0+Blink+example
● 보드설정 : 아래와 같이
· 아두이노IDE1.7.8 ▶ 도구 ▶ 보드 ▶ Arduino M0를 선택합니다.
일단 아래와 같이 초 간단 코드를 넣어봅니다.
// setup() is the first function executed when you plug you board
// or when you reset it. This funcion runs once
void setup() {
// The pinMode sets digital pin 13 as an Output
pinMode(13, OUTPUT);
}
// After the setup() function, the loop runs over and over
// until you stop the board
void loop() {
digitalWrite(13, HIGH); // turn the LED on setting the pin 13 to HIGH
delay(1000);// wait for a second
digitalWrite(13, LOW); // turn the LED off setting the pin 13 to LOW
delay(1000);// wait for a second
}
Source Code1 : Blink
위 코드를 실행하기 위한 회로는 다음 장과 같습니다. 사실은 D13에 이미 LED가 하나 붙어 있으므로 이마저도 필요 없습니다.
1초 주기로 깜빡거리면 이제 ‘아두이노-M0’와 소통이 시작되었음을 의미합니다. 이제부터는 맛있게 요리하는 일만 남았습니다.
3.3. (Demo2) 인터럽트방식으로 알람시각을 알려주는 리얼타임시계
‘아두이노-M0’에는 RTC를 내장하고 있습니다. 정교한 32.768Khz 오실레이터까지 포함하고 있으므로 DS1302 등 RTC칩을 사용하지 않고도 시계 어플리케이션을 만들 수 있을 것 같습니다.
arduino.org 에 올라와 있는 예제를 한번 돌려 보기로 합니다.
***********************************************************************
* This sketch demonstrate how to use alarm in interrupt mode.
This mode is more conveniently because you use processor for other tasks and when alarm match occurs interrupt routine is executed.
In this way, alarm flag checking is indipendent from main program flow.
***********************************************************************
//*RTC Alarm in interrupt mode*/
#include <RTCInt.h> //include RTCint library
RTCInt rtc; //create an RTCInt type object
int buzzer=11; //connect the buzzer to digital pin 11
int red=12; //connect red led to digital pin 12
int green=13; //connect green led to digital pin 13
/*setup*/
void setup()
{
SerialUSB.begin(9600); //serial communication initializing
pinMode(green,OUTPUT); //define green as output
pinMode(red,OUTPUT); //define red as output
pinMode(buzzer,OUTPUT); //define buzzer as output
digitalWrite(green,LOW); //initialize the green to LOW level
digitalWrite(red,LOW); //initialize the green to LOW level
rtc.begin(TIME_H24); //RTC initializing with 24 hour representation mode
rtc.setTime(17,0,5,0); //setting time (hour minute and second)
rtc.setDate(13,8,15); //setting date
rtc.enableAlarm(SEC,ALARM_INTERRUPT,alarm_int); //enabling alarm in interrupt mode
rtc.local_time.hour=17; //setting hour alarm
rtc.local_time.minute=1; //setting minute alarm
rtc.local_time.second=10; //setting second to match
rtc.setAlarm(); //write second in alarm register
}
/*loop*/
void loop()
{ noTone(buzzer); // disable the buzzer
digitalWrite(green,HIGH); //turn on green led
delay(500); //wait 500 millisecond
}
*************** Interrupt routine for alarm ******************************
void alarm_int(void)
{
SerialUSB.println(“Alarm match!”);
for(int i=0; i < 30; i++)
{ digitalWrite(green,LOW); //turn off green led
tone(buzzer,200); //play buzzer
digitalWrite(red,HIGH); //turn on red green
for(int j=0; j < 1000000; j++)
asm(“NOP”); //in interrupt routine you cannot use delay function then an alternative is NOP instruction cicled many time as you need
digitalWrite(red,LOW); //turn off red green italWrite(13,LOW);
for(int j=0; j < 2000000; j++)
asm(“NOP”);
}
RTC->MODE2.INTFLAG.bit.ALARM0=1; //clearing alarm0 flag
}
- Source Code2 : RTC Alarm Clock
문제없이 잘 동작됨을 알 수 있기는 합니다만 전원을 끄거나 프로그램을 내려 보내면 다시 초기화 되어버리는 상황에서 얼마나 실효성이 있을지 의문이 들기도 합니다.
3.4. (Demo3) D/A컨버터 기능 맛보기
‘아두이노 M0’에는 10비트 D/A컨버터 기능이 있음을 살펴보았습니다. 이 D/A컨버터의 기능을 시험해보려고 arduino.org를 이곳저곳 기웃거려 봤으나 마땅 정보가 없었고 arduino.cc에서 아두이노-Zero 보드용으로 공개해 놓은 라이브러리를 입수 할 수 있었습니다.
소스를 쭉 살펴보니 44.1Khz로 sampling된 wav파일을 디코딩하는 라이브러리였고 과연 어느 정도의 음질인지 확인해 보고 싶었습니다. 그러나 아쉽게도 ‘아두이노-M0’에는 wave 파일을 담을 매체인 SD-CARD가 부착되어져 있지 않으므로 SD메모리카드소켓을 아래와 같이 직접 부착을 하였습니다.
회로도3 : SD Card Interface 부착 |
소리는 제 블로그(http://blog.naver.com/crucian2k3)를 방문하면 들을 수 있을 것입니다만 우선 오실로스코프에 나타난 파형은 아래와 같이 관찰할 수 있었습니다.
그림7 : DAC Analog Signal 출력 |
소스코드는 다음과 같습니다.
/*
Simple Audio Player for Arduino Zero
Demonstrates the use of the Audio library for the Arduino Zero
Hardware required :
* Arduino shield with a SD card on CS4
* A sound file named “test.wav” in the root directory of the SD card
* An audio amplifier to connect to the DAC0 and ground
* A speaker to connect to the audio amplifier
Arturo Guadalupi <a.guadalupi@arduino.cc>
Angelo Scialabba <a.scialabba@arduino.cc>
Claudio Indellicati <c.indellicati@arduino.cc>
This example code is in the public domain
http://arduino.cc/en/Tutorial/SimpleAudioPlayerZero
*/
/*
Modify 2016.2.29 By D.H.Kim SD Memory Card Interface
[SD CARD]—-[ARDUINO]
9: NC —–
1: CS —–D4
2: DI <—-MOSI(84)
3: VSS1—–GND(86)
4: VDD —–3.3V
5: CLK <—-CLK(83)
6: VSS2—–GND(86)
7: DO —->MISO(81)
8: NC —–
*/
#include <SD.h>
#include <SPI.h>
#include <AudioZero.h>
void setup()
{
// debug output at 115200 baud
SerialUSB.begin(115200);
//Wait until USB CDC port connects
while(!SerialUSB);
// setup SD-card
SerialUSB.print(“Initializing SD card…”);
if (!SD.begin(4)) {
SerialUSB.println(“ failed!”);
while(true);
}
SerialUSB.println(“ done.”);
// 44100kHz stereo => 88200 sample rate
AudioZero.begin(44100);
}
void loop()
{
int count = 0;
// open wave file from sdcard
File myFile = SD.open(“test.wav”);
if (!myFile) {
// if the file didn’t open, print an error and stop
SerialUSB.println(“error opening test.wav”);
while (true);
}
SerialUSB.print(“Playing”);
// until the file is not finished
AudioZero.play(myFile);
SerialUSB.println(“End of file. Thank you for listening!”);
//while (true) ;
}
- Source Code3 : WAV File 출력
· 인코딩작업 조건 : 44.1Khz, 8bit mono sampling
· 라이브러리 출처 : https://www.arduino.cc/en/Tutorial/SimpleAudioPlayerZero
4. 시리얼 포트와 관련된 유의 사항
아래와 같이 시리얼 클래스는 Serial5를 써서 Pin0, Pin1을 통해 통신(TTL Level)하는 방법과 SerialUSB(CDC)를 사용하는 방법이 있습니다.
즉 Serial5는 H/W타입의 시리얼포트라고 볼 수 있겠습니다.
이 시리얼5와 SerialUSB는 동시에 사용될 수 있으며 매우 간단하게 USB To Serial Bridge를 만들 수 있습니다.
4.1. (Demo4) USB To Serial 브릿지 구현 예
아래에 실제로 구현된 Bridge Source입니다.
D0, D1을 통해 TTL신호가 들어오거나 나가게 되며 USB CDC를 통해 PC측과 연결되게 됩니다. 이러한 기능은 유사한 H/W 구조를 가진 ‘아두이노 레오나르도’에서도 구현이 가능합니다.
이때는 시리얼클래스명이 다르므로 주의해야 합니다.
/*
leo_usb2serial
아두이노 M0를 활용한 USB to Serial Bridge
자료참고 : https://petervanhoyweghen.wordpress.com/2012/11/08/
using-the-leonardo-as-usb-to-serial-converter/
*/
static long baud = 57600;
static long newBaud = baud;
// this pin will output the DTR signal (as set by the pc)
#define DTR_PIN 13
#define LINESTATE_DTR 1
void lineCodingEvent(long baud, byte databits, byte parity, byte charFormat)
{
newBaud = baud;
}
void lineStateEvent(unsigned char linestate)
{
if(linestate & LINESTATE_DTR)
digitalWrite(DTR_PIN, HIGH);
else
digitalWrite(DTR_PIN, LOW);
}
void setup() {
pinMode(DTR_PIN, OUTPUT);
digitalWrite(DTR_PIN, LOW);
Serial5.begin(baud);
SerialUSB.begin(baud);
//Wait until USB CDC port connects
while(!SerialUSB){};
}
void loop() {
// Set the new baud rate
if(newBaud != baud) {
baud = newBaud;
SerialUSB.end();
SerialUSB.begin(baud);
}
//Copy byte incoming via TTL serial
if (Serial5.available()) {
char c = (char)Serial5.read();
SerialUSB.write(c);
}
//Copy byte incoming via CDC serial
if (SerialUSB.available()) {
char c = (char)SerialUSB.read();
Serial5.write(c);
}
}
- Source Code4 : USB 2 SERIAL
5. (Demo 5) A/D 컨버터관련 사항
● 함수명 : analogReference(ref)
· AR_DEFAULT : VDDana(3.3V) 핀의 전압을 사용
· AR_INTERNAL : 1V
· AR_EXTERNAL : 가변적이다.
● 함수명 : analogReadResolution(res)
· 8: 0 to 255
· 10: 0 to 1023
· 12: 0 to 4096 (최고 해상도)
//Define the Temperature Sensor Pin
#define ADCVREF 3.3f
#define ADCMAXCOUNT 4096.0f
#define ADCVDIV 1.0f
#define ADCACCUR (ADCVREF / ADCMAXCOUNT) // 0.00080566
#define ADCRESOLUTION 12
int sensorPin = A0;
int inTmp;
/********************************************************************
* Function Name: int lowPassFilter2(int adVal)
* Return Value:
* Parameters:
* Description: 제1차 저주파 필터로 여러 함수에서 공통적으로 사용될 수 있으므로 구조체를
* 통해 접근이 이뤄지도록 한다.
*
* NOTE: http://wlsgk123123.blog.me/
********************************************************************/
#define LPFALPHA 0.95f
int lowPassFilter2(int adVal)
{
static float xLFP;
static float prevX;
static unsigned short firstRun;
if (firstRun == 0){
// 필터가 호출되면 처음 실행되는 부분으로 함수 내부의 변수들을 초기화 한다.
prevX = 0;
firstRun = 1;
}
// 이전 값에다 현재 값의 LPFALPHA 만큼을 더한 값이 최종 현재 값이 된다. 즉, 이전 값과 현재 값의 일정 퍼센트 만을 더해 현재 값을 생성해 내는 방식으로 필터링 한다.
xLFP = (LPFALPHA * prevX) + (1 – LPFALPHA) * (float)adVal;
prevX = xLFP;
return (unsigned int)prevX; // 정수값 만을 반환 시킨다.
}
/*
-AR_DEFAULT: the default analog reference are 5V or 3.3V;
-AR_INTERNAL: an built-in reference, equal to 1 volts
-AR_EXTERNAL: use as reference the voltage applied to AREF pin in the range 0-5V only.
*/
void setup() {
//Start Serial connection to read results in Serial Monitor
SerialUSB.begin(9600);
analogReadResolution(ADCRESOLUTION);
analogReference(AR_DEFAULT);
}
void loop() {
int lpfVar;
int adVal;
float rawADVoltage;
signed int adcMiliVolts;
signed int miliRealTemp;
//Get the sensor raw reading
//then convert it from a
// 10bit: 0 to 1023 digital range(1step = 0.00322)
// 12bit: 0 to 4095 digital range(1step = 0.0008056)
// 만일 12bit모드면 [21.9℃] 는 888이 읽힌다
// 888 = 0.719v / 0.0008056
adVal = analogRead(sensorPin);
// A/D채널을 읽어
lpfVar = lowPassFilter2(adVal); // 저역통과필터
// A/D변환 결과를 Voltage로 변환 시킨다.
// 이때 절사가 일어나 0.1도의 편차가 발생한다.
rawADVoltage = (float)lpfVar * ADCACCUR * ADCVDIV;
// Voltage를 MCP9700의 온도값 형태인 mV로 변환 시켜준다.
// 719.00 = (0.719 * 10000) / 10
adcMiliVolts = rawADVoltage * 1000.0f;
// MCP9700스타일의 온도를 섭씨 형태로 변환 시켜준다.
// 이때 온도는 219 = 719 – 500
miliRealTemp = adcMiliVolts – 500;
//Convert the raw value to Celsius
//temperature = (temperature – .5) * 100;
SerialUSB.print(adVal); SerialUSB.print(“, “);
SerialUSB.print(lpfVar); SerialUSB.print(“, “);
//SerialUSB.print(rawADVoltage); SerialUSB.print(“, “);
//SerialUSB.print(adcMiliVolts); SerialUSB.print(“, “);
SerialUSB.println(miliRealTemp);
//Print the temperature value to Serial Monitor
//SerialUSB.println(voltage);
//Read the temperature each second
delay(10);
}
- Source Code5 : 12Bit ADC
10bit 상태에서는 ADC 값이 1 증가 혹은 감소할 때마다 0.00322v (3.3v/1024)를 차지하게 됩니다. 이로 인해 MCP9700 등 고정밀 아날로그 센서를 사용하면 수숫점 이하의 온도는 약 0.3V 단위로 증가 혹은 감소하게 됩니다(19.8℃ ▶ 20.1℃).
그러나 12bit에서는 1스텝 당 0.0008056(3.3/4096)이 되므로 좀 더 정확한 소숫점 이하 자릿수 표현이 가능합니다(0.1도씩 증가 : 21.5℃ ▶21.6℃).
6. 9축 모션센서 쉴드
BNO055 9축 모션센서 칩은 종래의 칩에 비하면 대단히 고 집적화된 기능을 포함하고 있습니다. 우선 3축 14비트 가속도계, 3축 16비트 자이로스코프, 3축 지자기센서로 구성되어 있으며 BSX3.0 FusionLib를 통해 손쉬운 접근이 가능하도록 만들어졌습니다.
이 라이브러리는 내장된 32비트 머신에서 실행되며 초당 ±2,000℃ 범위를 출력할 수 있습니다. 이를 통해 3차원 가속기능, 3가지 방향의 지자기 강도데이터를 얻을 수 있고 오일러각도, 회전벡터, 선형가속, 중력벡터와 같은 센서 융합정보를 산출해 낼 수 있습니다.
이 보드는 5V가 인가되지만 내부적으로는 3.3V로 레벨쉬프트 되어 구동됩니다. 또한 이 칩은 네비게이션, 로봇, 운동, 증강현실, 상황인식, 태블릿, 울트라북 등의 하이테크한 전자제품에 두루 사용될 수 있다고 합니다. 그럼 BOSCH의 데이터쉬트에 기재된 내용을 바탕으로 각 파트를 좀 더 상세히 살펴보도록 하겠습니다.
6.1. Bosch Sensortec GmbH의 BNO055칩 스펙
6.2 시스템 아키텍처
6.3. 9축 모션쉴드에 장착된 컨넥터
● 기판 상부에 위치한 커넥터는 다음과 같이 맵핑되어 있습니다.
● 기판 상부에 위치한 솔더링 점퍼
모션쉴드와 아두이노-M0는 TWI를 통해 서로 연결되게 됩니다.
INT핀은 기본적으로 오픈이 되어 있으나 인터럽트 서비스 등을 하기위해서는 D7 또는 D2에 연결되어야 합니다.
6.4. 센서 테스트
센서를 테스트 해보기 전에 Pitch, Roll, Yaw에 대해서 간단히 짚고 넘어갑니다.
말 그대로 모션을 처리하기 위해서는 3차원 좌표계에서 물체의 위치나 이동경로를 표현할 수 있어야 하는데, 이와 관련된 아주 기초적인 용어가 위에 언급한 피치, 롤, 요입니다. 이러한 용어는 항공기, 드론, 균형로봇 등에서 활발하게 사용됩니다.
● Pitch(X축) : 피치는 비행기의 승강, 하강 개념입니다. 즉 조종사가 조종간을 앞으로 밀거나 뒤로 당기면 동체가 상승, 하강을 하게 되는데 여기에서 사용되는 용어에 해당합니다.
● Roll(Y축) : 항공기의 조종간을 좌우로 밀면 동체가 그에 따라 기울어질 때 나타나게 되는 현상입니다.
● Yaw(Z축) : 자동차의 핸들을 돌리면 좌, 우측으로 주행하는 방향을 칭하며 항공기에서는 왼발, 오른발 패달에 해당합니다.
가속도 센서는 현재의 기울어짐을 정확히 나타내는데 사용됩니다. 자이로센서는 센서가 회전이 되는 상황에서 시간에 따른 움직임을 추적할 수 있으며 적분방식으로 사용되고 이에 따라 시간에 따른 오차를 동반하게 됩니다.
따라서 정확한 피치와 롤 값을 얻기 위해 가속도센서와 자이로센서를 동시에 사용하게 됩니다. 여기서 가속도센서와 자이로센서만으로는 요 값을 정확히 산정해 낼 수 없는 문제에 봉착하며 이를 해결하기 위해 지자기센서가 사용됩니다. 이러한 내용을 좀 더 깊이 있게 접하고자 하는 독자는 아래 주소를 참고하시기 바랍니다.(http://www.hardcopyworld.com/ngine/aduino/index.php/archives/126)
이론은 이 정도로만 하고 9축 모션쉴드를 동작시켜 보고 과연 피치, 롤, 요가 어떻게 반응 하는지를 그래프로 살펴보도록 하겠습니다.
그림9 : 9축 모션센서 출력 |
우선 Serial Oscilloscope 프로그램을 아래 주소에서 다운로드 받습니다. (http://www.x-io.co.uk/serial-oscilloscope/) 다음으로 아래의 프로그램을 ‘아두이노-M0’로 내려 보냅니다.
이 프로그램에는 쉴드에서 얻어진 가속도 데이터를 1줄에 3개씩 묶어 Native USB포트를 통해 PC로 전송을 하게 됩니다.
Serial Oscilloscope로 데이터가 들어오면 첫 번째 데이터는 적색, 두 번째 데이터는 녹색, 세 번째는 청색으로 그래프가 그려지게 됩니다.
아래 그래프를 보면 가속도 센서에서 피치(X축), 롤(Y축) 정보가 잘 얻어 짐을 알 수 있습니다.
그림10 : 가속도센서 출력화면 |
arduino.org에서 공개해 놓은 예제를 Serial Oscilloscope로 볼 수 있도록 조금만 변경해 봅니다.
/********************************************************************
* Copyright (C) 2011 – 2014 Bosch Sensortec GmbH
*
* Usage: Example code to stream Accelerometer data
*
* License:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*/
/*
9축모션쉴드를 테스트해보기 위해 만들어진 프로그램
*동작시키는 방법*
1. Serial Osciloscope 프로그램을 아래 주소에서 다운로드 받는다.
( http://www.x-io.co.uk/serial-oscilloscope/ )
2. 아래 3개 파트로 나뉘어진 주석을 한 영역씩만 풀어가며 아두이노-m0로 내려 보낸다.
3. Serial Osciloscope로 데이터가 들어오면 첫번째 데이터는 적색,
두번째 데이터는 녹색, 세번째는 청색으로 그래프가 그려진다.
4. 결과 : 가가속도 센서에서는 피치(X축), 롤(Y축) 정보가 잘 얻어 짐을 알 수 있다.
*/
//Contains the bridge code between the API and the Arduino Environment
#include “NAxisMotion.h”
#include <Wire.h>
//Object that for the sensor
NAxisMotion mySensor;
//To store the last streamed time stamp
unsigned long lastStreamTime = 0;
//To stream at 25Hz without using additional timers
//(time period(ms) =1000/frequency(Hz))
const int streamPeriod = 40;
//Flag to update the sensor data
//Default is true to perform the first read before the first stream
bool updateSensorData = true;
//This code is executed once
void setup() {
//Peripheral Initialization
//Initialize the Serial Port
//to view information on the Serial Monitor
SerialUSB.begin(115200);
while(!SerialUSB);
//Initialize I2C communication to the let the
//library communicate with the sensor.
I2C.begin();
//Sensor Initialization
//The I2C Address can be changed here
//inside this function in the library
mySensor.initSensor();
//Can be configured to other operation modes as desired
mySensor.setOperationMode(OPERATION_MODE_NDOF);
//The default is AUTO
//Changing to manual requires calling the relevant
//update functions prior to calling the read functions
mySensor.setUpdateMode(MANUAL);
//Setting to MANUAL requires lesser reads to the sensor
mySensor.updateAccelConfig();
updateSensorData = true;
SerialUSB.println();
SerialUSB.println(“Default accelerometer configuration settings…”);
SerialUSB.print(“Range: “);
SerialUSB.println(mySensor.readAccelRange());
SerialUSB.print(“Bandwidth: “);
SerialUSB.println(mySensor.readAccelBandwidth());
SerialUSB.print(“Power Mode: “);
SerialUSB.println(mySensor.readAccelPowerMode());
//Countdown
SerialUSB.println(“Streaming in …”);
SerialUSB.print(“3…”);
delay(1000); //Wait for a second
SerialUSB.print(“2…”);
delay(1000); //Wait for a second
SerialUSB.println(“1…”);
delay(1000); //Wait for a second
}
void loop() { //This code is looped forever
//Keep the updating of data as a separate task
if (updateSensorData) {
//Update the Accelerometer data
mySensor.updateAccel();
//Update the Linear Acceleration data
mySensor.updateLinearAccel();
//Update the Gravity Acceleration data
mySensor.updateGravAccel();
//Update the Calibration Status
mySensor.updateCalibStatus();
updateSensorData = false;
}
if ((millis() – lastStreamTime) >= streamPeriod) {
lastStreamTime = millis();
//Accelerometer X-Axis data : 적색그래프
SerialUSB.print(“ aX: “);
SerialUSB.print(mySensor.readAccelX());
SerialUSB.print(“m/s2, “);
//Accelerometer Y-Axis data : 녹색그래프
SerialUSB.print(“ aY: “);
SerialUSB.print(mySensor.readAccelY());
SerialUSB.print(“m/s2, “);
//Accelerometer Z-Axis data : 청색그래프
SerialUSB.print(“ aZ: “);
SerialUSB.print(mySensor.readAccelZ());
SerialUSB.print(“m/s2, “);
SerialUSB.println();
updateSensorData = true;
}
}
- Source Code5 : 가속도센서 테스트
9축모션쉴드를 장착한 모습 |
모션쉴드를 ‘아두이노-M0’에 결합하여 실제로 어떻게 동작 되는지 까지를 살펴봤습니다. 지면 관계상 위 예에서는 가속도센서만 그래프를 그렸습니다만 자이로센서나 지자기센서도 동일한 방식으로 접근하여 실제로 동작되는 모습들을 충분히 눈으로 볼 수 있을 것으로 봅니다.
그림11 : 모션센서 방향각, X축 방향은 보드의 가로방향이며 Y축은 세로방향, Z축은 중심점이다 |
7. 마무리
아두이노 진영이 이처럼 각광 받을 수 있었던 것은 폼펙터 표준화와 쉴드 호환성이 가장 큰 요인이 아니었나 봅니다.
심지어 아두이노와 아주 이질적으로 보이는 제조사 측에서도 아두이노의 폼펙터를 따라하고 심지어 명령어까지도 동일하게 만드는 것을 보면 대세는 아두이노가 맞는 듯합니다. 이러한 상황에서 최근에 출시된 ‘아두이노-M0, 아두이노-M0-Pro, 아두이노-Zero’ 등은 동일한 MCU를 사용하기에 성능은 대동소이하며 컴퓨팅 파워에 목말라 하던 하이엔드 지향형 사용자층에게 강하게 어필 할 수 있을 것으로 봅니다.
특히 ‘아두이노-M0’의 기능 중 DAC는 간단한 효과음, 음악, 목소리 등을 발생시킬 수 있음에 따라 다양한 용도가 있을 듯합니다.
9축 모션센서 쉴드 또한 막강한 성능을 자랑하긴 합니다만, 이 쉴드보드는 임베디드컴퓨터 쪽을 전문을 다루는 사람이 아니라면 상당한 진입장벽을 느낄 수도 있을 것 같습니다. ‘아두이노-M0’와 모션쉴드를 결합하면 게임컨트롤러, 균형로봇, 드론 등등에 매우 유용하게 사용될 수 있을 것으로 기대됩니다.
시간이 허락되는 대로 모션쉴드를 응용한 재미나는 프로젝트로 진행해보고자 하며 제 블로그(blog.naver.com/crucian2k3)에서 결과물을 보실 수 있을 것입니다.
감사합니다.
8. 참고자료
1. Arduino-M0 공식제품 소개서 : www.arduino.org
2. Arduino-M0 ‘How to your board.’ Document : labs.arduino.org
3. 9축 모션쉴드 : www.arduino.org
4. 자세제어와 관련된 아티클 : www.hardcopyworld.com
5. DAC 라이브러리 및 예제 : www.arduino.cc
6. 시리얼 오실로스코프 : www.x-io.co.uk