August 18, 2017

디바이스마트 미디어:

[35호]Arduino M0 & Arduino 9 Axes Motion Shield 리뷰

35 re (2)

 

Arduino M0 &

Arduino 9 Axes Motion Shield 리뷰

 

글 | 금강초롱 객원기자 blog.naver.com/crucian2k3

스마트폰에서 촉발된 IOT 기술의 빅뱅은 영향을 받지 않는 곳이 없을 정도로 무섭게 확산되고 있습니다.
마치 나비효과처럼 전 세계에서 자신의 손으로 뭔가를 만들고 싶어하는 DIY(Do It Yourself)족 및 컴퓨터를 잘 모르는 이들에게도 교육차원으로 많이 사용되어 선풍적인 인기를 끌고 있는 아두이노, 라즈베리파이 등에도 그 바람을 피하기 힘든 듯합니다.

35 re (1)

유난히 폭 넓은 사용자층을 형성하고 있는 아두이노 진영에서도 앙증맞은 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’ 모델이었다면 디버그 기능도 살펴 볼 수 있었을 텐데 하는 아쉬움도 있었습니다만 디버그 기능 외 차이점은 없다고 봅니다.

35 re (2)
그림1 : 아두이노-M0 박스 외관

뒷면에는 이탈리아에서 제조된 물품임을 확인하는 로고가 선명하게 인쇄되어 있습니다. 박스를 열면 앙증맞은(?) 보드가 한 장 덩그러니 들어가 있으며 ‘아두이노-우노’와 마찬가지로 Atmel사의 SAMD21G18A-AUT을 기반으로 한 보드가 보이며 전체적인 분위기는 ‘아두이노-레오나르도’와 유사하다고 생각됩니다.

35 re (3)
그림2 : 아두이노-M0 전면부
35 re (4)
그림3 : 아두이노-M0 후면부

‘9축 모션 센서 쉴드’ 보드는 그보다 약간 큰 박스로 구성되어져 있으며 얼핏 본다면 아두이노 본체로 오해라도 할 수 있을 만큼 비슷하게 생겼습니다.

쉴드 보드는 아두이노의 확장보드로 매우 다양한 쉴드보드가 존재합니다. 이번에 리뷰하는 쉴드 보드는 3축 14bit 가속도센서, 3축 16bit 자이로센서, 3축 지자기센서가 원칩에 들어있는 보쉬센서텍의 BNO055라는 칩을 기반으로 하고 있습니다.

35 re (5)
그림4 : 9축 모션센서 쉴드 박스 외관
35 re (6)
그림5 : 9축 모션센서 쉴드 후면부

 

2. 아두이노-M0 살펴보기

기 발매중인 모델 중 ‘아두이노-레오나르도’와 폼펙터 측면에서 유사성이 많음에 따라 두 모델을 상호 비교해 보도록 하겠습니다.

35sr  (2)

2.1 기본적인 스펙
우선 눈에 띄는 부분이 동작전압이 3.3V라는 점입니다.
5V를 기반으로 만들어진 쉴드를 연결할 때 주의가 필요해 보입니다.
다음으로 A/D변환기의 분해능이 12비트로 올라갔고 플래시메모리가 대폭 늘어났으며 무엇보다도 클럭 속도가 올라갔습니다.
한마디로 컴퓨팅 파워를 끌어 올렸다고 보면 틀림이 없을 것 같습니다.
이제 세부적인 변경 사항들을 하나하나 살펴보도록 하겠습니다.

2.2 전원공급핀
외부에서 전원을 공급받는 방법은 2가지가 있습니다.

35 re (7)

2.1mm 규격의 DC아답터를 사용하여 6~15V를 인가하는 방법과 마이크로USB 컨넥터를 통해 DC 5V를 인가하는 방법이 있습니다.
USB 2.0포트에 연결되는 경우 500mA가 한계치이므로 전력이 부족한 경우 DC아답터를 사용하여 공급할 수 있습니다.
DC아답터는 시중에서 9V, 12V를 흔히 구입할 수 있을 것 같으며 중심축이 +전원이고 외경은 GND가 되어야 합니다.

35sr  (3)

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입니다.

35sr  (4)

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’를 구입하면 다소 난감하리라 봅니다.

35 re (8)

3.1. ‘아두이노-M0’에 네이티브USB 연결하기
정확한 원인은 알 수 없었으나 USB드라이버가 제대로 인식되지 않아 애를 먹었습니다. 해결책을 찾아 arduino.org 포럼을 수소문한 끝에 방법을 알아내었고 다름 아닌 수동드라이버 인식 이었습니다. 아마도 이 글을 읽는 독자 중에는 동일한 증상을 겼을 가능성이 충분히 있다고 봅니다. ‘아두이노-레오나르도’인 경우에는 ‘아두이노 설치경로/driver’에서 손쉽게 드라이버 문제를 해결 할 수 있었습니다만 ‘Arduino-M0’는 이 방법이 소용이 없었습니다.
아래 그림과 같이 ‘기타장치 ▶ 알 수 없는 장치’ 현상이 있을 때 해결책입니다.

35 re (9)

장치관리자 ▶ 기타장치 ▶ 알 수 없는 장치 ▶ 드라이버 소프트웨어 업데이트
▶ 컴퓨터에서 드라이버 소프트웨어 업데이트
▶ 컴퓨터의 장치목록에서 직접 선택
▶ 포트 (COM & LPT)
▶ (제조업체)Arduino Sri(www.arduino.org)
▶ (모델)Arduino Zero Native Port 를 순서대로 선택합니다.

35 re (10)

이에 대한 설명을 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를 선택합니다.

35 re (11)

일단 아래와 같이 초 간단 코드를 넣어봅니다.

// 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가 하나 붙어 있으므로 이마저도 필요 없습니다.

35 re (12)

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

문제없이 잘 동작됨을 알 수 있기는 합니다만 전원을 끄거나 프로그램을 내려 보내면 다시 초기화 되어버리는 상황에서 얼마나 실효성이 있을지 의문이 들기도 합니다.

35 re (13)

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메모리카드소켓을 아래와 같이 직접 부착을 하였습니다.

35 re (14)
35 re (15)

회로도3 : SD Card Interface 부착

소리는 제 블로그(http://blog.naver.com/crucian2k3)를 방문하면 들을 수 있을 것입니다만 우선 오실로스코프에 나타난 파형은 아래와 같이 관찰할 수 있었습니다.

35 re (16)
35 re (17)
그림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 출력

음질은 FM 라디오수준 정도는 되는듯합니다만 사람에 따라 느낌은 다소 다르리라 봅니다. 코덱칩이 붙어있지 않은 상황에서도 ‘아두이노-M0’는 wav정도는 거뜬히 재생할 수 있음을 확인할 수 있었습니다.

· 인코딩작업 조건 : 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를 만들 수 있습니다.

35sr  (5)

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칩 스펙

35sr  (6)

6.2 시스템 아키텍처

35 re (1)

6.3. 9축 모션쉴드에 장착된 컨넥터
● 기판 상부에 위치한 커넥터는 다음과 같이 맵핑되어 있습니다.

35sr  (7)

● 기판 상부에 위치한 솔더링 점퍼

35sr  (1)
모션쉴드와 아두이노-M0는 TWI를 통해 서로 연결되게 됩니다.
INT핀은 기본적으로 오픈이 되어 있으나 인터럽트 서비스 등을 하기위해서는 D7 또는 D2에 연결되어야 합니다.

6.4. 센서 테스트
센서를 테스트 해보기 전에 Pitch, Roll, Yaw에 대해서 간단히 짚고 넘어갑니다.
말 그대로 모션을 처리하기 위해서는 3차원 좌표계에서 물체의 위치나 이동경로를 표현할 수 있어야 하는데, 이와 관련된 아주 기초적인 용어가 위에 언급한 피치, 롤, 요입니다. 이러한 용어는 항공기, 드론, 균형로봇 등에서 활발하게 사용됩니다.

35 re (19)

● Pitch(X축) : 피치는 비행기의 승강, 하강 개념입니다. 즉 조종사가 조종간을 앞으로 밀거나 뒤로 당기면 동체가 상승, 하강을 하게 되는데 여기에서 사용되는 용어에 해당합니다.
● Roll(Y축) : 항공기의 조종간을 좌우로 밀면 동체가 그에 따라 기울어질 때 나타나게 되는 현상입니다.
● Yaw(Z축) : 자동차의 핸들을 돌리면 좌, 우측으로 주행하는 방향을 칭하며 항공기에서는 왼발, 오른발 패달에 해당합니다.

가속도 센서는 현재의 기울어짐을 정확히 나타내는데 사용됩니다. 자이로센서는 센서가 회전이 되는 상황에서 시간에 따른 움직임을 추적할 수 있으며 적분방식으로 사용되고 이에 따라 시간에 따른 오차를 동반하게 됩니다.
따라서 정확한 피치와 롤 값을 얻기 위해 가속도센서와 자이로센서를 동시에 사용하게 됩니다. 여기서 가속도센서와 자이로센서만으로는 요 값을 정확히 산정해 낼 수 없는 문제에 봉착하며 이를 해결하기 위해 지자기센서가 사용됩니다. 이러한 내용을 좀 더 깊이 있게 접하고자 하는 독자는 아래 주소를 참고하시기 바랍니다.(http://www.hardcopyworld.com/ngine/aduino/index.php/archives/126)
이론은 이 정도로만 하고 9축 모션쉴드를 동작시켜 보고 과연 피치, 롤, 요가 어떻게 반응 하는지를 그래프로 살펴보도록 하겠습니다.

35 re (20)
그림9 : 9축 모션센서 출력

우선 Serial Oscilloscope 프로그램을 아래 주소에서 다운로드 받습니다. (http://www.x-io.co.uk/serial-oscilloscope/) 다음으로 아래의 프로그램을 ‘아두이노-M0’로 내려 보냅니다.

이 프로그램에는 쉴드에서 얻어진 가속도 데이터를 1줄에 3개씩 묶어 Native USB포트를 통해 PC로 전송을 하게 됩니다.
Serial Oscilloscope로 데이터가 들어오면 첫 번째 데이터는 적색, 두 번째 데이터는 녹색, 세 번째는 청색으로 그래프가 그려지게 됩니다.
아래 그래프를 보면 가속도 센서에서 피치(X축), 롤(Y축) 정보가 잘 얻어 짐을 알 수 있습니다.

35 re (21)
그림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 : 가속도센서 테스트

35 re (22)
9축모션쉴드를 장착한 모습

모션쉴드를 ‘아두이노-M0’에 결합하여 실제로 어떻게 동작 되는지 까지를 살펴봤습니다. 지면 관계상 위 예에서는 가속도센서만 그래프를 그렸습니다만 자이로센서나 지자기센서도 동일한 방식으로 접근하여 실제로 동작되는 모습들을 충분히 눈으로 볼 수 있을 것으로 봅니다.

35 re (23)
그림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

 

Cap 2016-05-20 11-01-08-470

Leave A Comment

*