[37호]Genuino 101 Review
IOT 세계의 다크호스
Genuino 101 Review
글 | 금강초롱 blog.naver.com/crucian2k3
Genuino101(이하 제누이노101) 보드는 그간의 ATMEL사 MCU를 기반으로 하는 여러 보드들과는 다르게 인텔사의 Curie칩을 사용하여 보드가 설계되었습니다. 그 뿐만이 아니라 그간 쉴드 형태로 연결해 사용하던 블루투스 모듈과 6축 모션센서가 온보드에 장착이 되었습니다.
그것도 그냥 있는 것이 아니라 본체 내 MCU 안에 완전히 녹아 들어가 있어 한 몸을 이루고 있기에 내장 라이브러리를 통해 손쉽게 접근이 가능한 측면이 있기는 합니다만 세상 모든 일이 그렇듯 눈여겨볼 대목도 있는 듯합니다. 즉, 온 보드에 실장 된 블루투스 모듈과 모션센서를 기반으로 만들어진 코드는 너무도 독자적이라 이식성에 문제를 야기할 수밖에 없게 됩니다. 이는 아두이노 우노 기반에서 만들어진 코드는 큰 어려움 없이 이 보드로 포팅이 될 것으로 봅니다만, 그 반대는 거의 불가능한 측면이 있게 됩니다. 한마디로 비가역적입니다.
그러함에도 이러한 보드가 출시된 것은 신선한 충격이며 이 보드를 기반으로 하는 원대한 생태계를 꿈꾸는 이들이 있음을 느끼기에 부족함이 없습니다. 블루투스 4.0 LE 기술이 내장되어 있다는 의미는 외부와 소통함을 목적으로 한다는 말과 일맥상통하며 스마트폰과 연계되어 다양한 실험을 해 볼 수 있는 환경을 만들어 준다는 의미가 되기도 합니다. 아두이노와 인텔에서 제공하는 다양한 예제 프로그램을 직접 실행 시켜 보며 어떤 특성이 있는지 살펴보고, 보드 활용을 위한 기본적인 사항들을 차근차근 더듬어 보도록 하겠습니다. 본 리뷰의 마지막 실험으로 제누이노101 보드를 비콘(BT Beacon)으로 만들고 스마트폰에 비콘을 인식할 수 있는 앱을 설치하여 제누이노101 근처에 다가가면 본 리뷰 후원사 홈페이지가 열리는 것을 시연해 보고자 합니다. 물론 얼마나 근처로 다가가면 동작되게 할 것인지? 어느 웹사이트가 열리게 할 것인지? 등등은 독자님들 마음대로 설정할 수가 있습니다. 이 글을 접하는 독자님들이 이 실험 하나만으로도 제누이노101 보드가 갖고 있는 뛰어난 하드웨어의 특성을 충분히 맛 보고도 남지 않을까 예상해 봅니다. 제누이노101 보드는 출시된 지 얼마 되지 않았을뿐더러 국내에 소개도 거의 되지 않아 해외 자료들을 다수 참고삼았습니다. 본 리뷰보고서는 (주)엔티렉스-디바이스마트의 지원을 받아 작성하게 되었습니다.
1. 개요
제누이노101 보드는 인텔®큐리™칩을 기반으로 하는 보드입니다.
흔히 사용되는 ATmega328을 사용하는 아두이노 우노 계열의 보드나 ATmega 32U4를 사용하는 레오나르도 계열의 보드와는 완전히 다른 칩셋입니다. 최근에 선보인 32비트MCU가 탑재된 아두이노M0에는 SAM32D계열로서 이 역시 Atmel사 칩입니다. 인텔®큐리™칩은 기본적으로 블루투스 4.0 LE와 6축 모션센싱 기능을 원칩에 내장하고 있는 다소 독특한 칩이라고 봅니다. 이 칩에는 x86(쿼크)코어와 ARC코어를 단일화한 것으로 32Mhz의 클럭이 공급되며 연산능력은 타의 추종을 불허하는 수준으로 생각됩니다. 여기서 x86이 시사하는 바가 있습니다. 즉, 제누이노101 보드는 백그라운드에 x86을 기반으로 하는 모디파이드 된 리눅스운영체제 (RTOS)를 깔고 있으며 그 위에 아두이노 폼펙터에 충실한 하드웨어를 갖추고 있는 형상입니다. 사용자는 이 부분을 그저 블랙박스로 취급하고 아두이노향 각종 명령어들로 제누이노와 친하게 지내면 그만인 것입니다. 독자님들이 원한다면 우분투 환경에서 제누이노 펌웨어를 수정한 후 다시 업로드를 할 수도 있도록 인텔사에서는 준비를 해놓았습니다. (http://blog.naver.com/jjy0501/220235133315) 아두이노라는 브랜드는 미국에서만 사용이 가능하며 미국 이외의 국가서는 제누이노라는 상표명으로 통용이 됩니다. 두 제품명간 특성에 차이는 없습니다.
1.1. 제누이노101 vs 아두이노M0 스펙 비교
구분 | 기술적 사양 | |
제누이노101(32bit MCU) | 아두이노M0(32bit MCU) | |
마이크로컨트롤러 | 인텔큐리( Intel® Curie™) 칩 | AT-SAMD21G18, 48pins LQFP |
작동전압 | 3.3V (5V 톨러런트 I/O) | 좌동 |
입력전압(권장) | 7 – 12V | 6 – 15 V |
입력전압(제한) | 7 – 20V | 4.5 – 20 V |
디지털 I/O핀 | 20개, Digital IO 4개의 PWM 출력 and UART | 20개, Digital IO 12개의 PWM and UART |
아날로그 입력 핀 | 6개 | 좌동 |
I/O 핀 당 DC 전류 | 20mA | 7mA |
플래시 메모리 | 196KB | 256KB(Bootloader 4KB) |
SRAM | 24KB | 32KB |
CLOCK SPEED | 32MHz | 48MHz |
특별기능 | 블루투스 4.0 LE, 6축 가속도센서/자이로센서 | 10bit DAC 1개 |
길이 | 68.6 mm | 좌동 |
폭 | 53.4 mm | 좌동 |
1.2. 프로그램 작성
제누이노101은 아두이노 IDE 1.6.7 이상에서 다른 보드들과 마찬가지로 프로그래밍이 가능합니다. 아마도 대부분의 IDE에서는 제누이노101이 기본적으로 설정되어 있지 않을 것입니다. 아래와 같이 간단하게 신규보드를 등록할 수 있습니다. ■ Arduino IDE ▶ 도구 ▶ 보드 ▶ 보드관리자로 진입해 들어갑니다.
조금 아래로 내려보면 Intel Curie Boards by Intel 버전 1.0.6이 보이며 선택을 한 후에 설치를 누르면 간단히 인텔 큐리칩이 장착된 제누이노101을 사용할 수 있게 됩니다. 다른 보드도 사용하고자 한다면 이와 같은 방법으로 간단히 등록이 가능합니다.
보드와 PC간의 연결은 아두이노 우노에서와 마찬가지로 USB-B타입의 케이블로 연결되며 제누이노101은 내부에 우분투 기반의 RTOS가 돌고 있다는 점이 차이점이라면 차이점이며 그 이외는 아두이노 우노와 대동소이하다고 보면 틀림이 없습니다. 한 가지 유의할 사항이 있다면 이 보드는 3.3V 기반이므로 5V 신호를 인가하는 경우 보드에 데미지가 가해질 수 있으므로 주의를 해야 합니다.
1.3. 전원공급
제누이노101보드 역시 다른 시리즈의 아두이노와 마찬가지로 외부전원과 USB 커넥터를 통한 전원을 모두 받을 수 있으며 자동으로 선택이 됩니다. 외부전원용 커넥터는 2.1mm DC어댑터용 플러그로 구성되어 있으며 중심축이 +전원입니다. 필자의 경험상 아두이노 계열의 보드를 사용하면서 정말로 주의해야하는 사항이 있습니다. 바로 보드에 나와 있는 Vin, 5V, 3.3V 핀과 관련된 사항으로 이 단자는 반드시 출력용으로만 사용이 되어져야 합니다. USB 커넥터를 꽂거나 혹은 외부전원을 DC 플러그를 통해 연결하면 위 3개의 단자에는 5V와 3.3V가 나오게 됩니다. 이 전원은 다른 보드를 동작시키기 위해 보드 내부의 레귤레이터에서 생산한 전기이며, 만일 외부에서 이 전압을 만들어 역으로 인가하게 되면 보드내부의 소자에 심각한 데미지를 입히게 됩니다.
전기와 관련된 사항을 부주의하게 여기면 당장 보드손상이라는 낙심은 물론이고 화재 등과도 연결될 수 있는 중요한 사안이라고 생각합니다. 내장된 3.3V 레귤레이터는 최대 1.5A까지를 흘릴 수 있으며 IOREF 핀을 통해 보드의 I/O가 몇 볼트의 전압에서 동작되고 있는지를 감지하여 적절한 목적으로 운영될 수 있도록 정보를 제공해 줍니다. 이 핀에서는 당연히 3.3V가 나옵니다.
1.4. 메모리
내장된 메모리는 2개의 마이크로컨트롤러에서 공유하여 사용되며 플래시메모리는 총 384KB이나, 스케치에서 196KB만 사용이 가능합니다. 없어진 188KB는 백그라운드에서 리눅스기반의 RTOS가 점유하고 있습니다. 다음으로 SRAM은 총 80KB가 내장되어 있으나 스케치를 위해서는 4KB가 사용이 가능합니다. 나머지 역시 내장 OS에서 점유되어 사용되고 있습니다. 제누이노101은 인텔사에서 아주 작정을 하고 많은 투자가 있었음을 알 수 있는 대목입니다. 이 보드를 위해 운영체제까지 새롭게 디자인 한 것으로 보입니다.
1.5. 시그널 입·출력
제누이노101은 아두이노 우노 기반의 폼팩터를 그대로 계승하여 총 20개의 GPIO(General Purpose I/O)핀을 제공하고 있습니다. 다른 보드들과 마찬가지로 pinMode(), digitalWrite(), digitalRead() 함수를 통해 기본적인 신호 입출력이 이뤄집니다. 또한 핀 3, 5, 6, 9 등 4개는 analogWrite()함수를 통해 PWM출력을 내보낼 수 있으며 모든 핀들은 3.3V에 최대 20mA를 입출력(source or sink)할 수 있습니다.
■ 각 핀들의 기능 정리
포트 | 세부사항 |
Serial 포트 | ■ 아두이노 우노의 폼팩터를 그대로 계승하여 D0이 RX, D1이 TX이며 TTL 시리얼데이터를 송수신 할 수 있음 ■ Serial1 클래스를 사용하면 pin0(Rx), pin1(Tx)를 사용할 수 있음 ■ 기본적으로 USB CDC채널을 통한 가상 시리얼 통신은 물론 UART 타입의 Serial도 동시에 사용할 수 있음. 이는 제누이노101, 아두이노 M0 등에서는 공통으로 제공되는 기능으로 보드의 유용함을 배가시켜 줌 |
External Interrupt | ■ 모든 핀에서 외부 인터럽트 소스를 처리할 수 있습니다만 CHANGE인터럽트를 쓰고자 한다면 핀 2, 5, 7, 8, 10, 11, 12, 13을 사용해야 함 ■ 인터럽트는 attachInterrupt() 함수를 통해 사용할 수 있음 |
SPI | ■ 보드 하부에 위치한 2.54mm 헤더핀에 SPI 관련 신호가 나와 있으며 SS, MOSI, MISO, SCK 핀 등으로 구성되어 있음 ■ 고속으로 I/O가 필요한 SD메모리카드, Color TFT LCD제어 등에 유용하게 사용될 수 있음 |
LED | ■ 녹색LED가 D13에 연결되어 있으며 High에서 ON, Low에서 OFF됨 ■ 보드의 동작 상태를 모니터링 하거나 간단한 실험에 사용됨 |
Analog | ■ 아나로그 입력핀은 A0~A5까지 총 6개가 구비되어 있으며 10비트 해상도를 갖고 있음. 따라서 0~1023까지 총 1024스탭으로 아날로그 시그널을 분해할 수 있음 ■ 레퍼런스 전압은 기본적으로 3.3V |
TWI | ■ I2C라고도 부르는 TWI는 SDA 핀과 SCL 핀을 사용하며 Wire 라이브러리를 통해 손쉽게 이용이 가능함 |
2. 아두이노 / Genuino 101 시작하기
이제 제누이노101보드를 사용하여 실제로 동작을 시켜보면서 어떤 특성이 있는지 하나하나 살펴보도록 하겠습니다. 인텔 큐리칩의 최대 장점은 저소비전력과 블루투스 4.0 LE, 6축 모션센서가 단일칩에 내장된 것이라고 할 수 있겠습니다. 얼핏 생각해봐도 스마트폰과 연계하여 재미난 것들을 많이 해볼 수 있을 것 같습니다. 아두이노 본사 홈페이지, 인텔사 홈페이지와 포럼에 올라와 있는 여러 가지 예제와 사례들을 참조하여 이렇게 갖고 놀 수 있겠구나 하는 것을 본격적으로 보여 드리고자 합니다. 이 제품이 갖는 한 가지 유의사항은 스케치가 로딩되고 난 후에 곧장 실행되는 것이 아니라 약간의 뜸 들이는 시간이 걸린다는 것입니다. (약 10초) 지금부터 다룰 내용들은 처음 아두이노를 접하는 분들은 좀 난이도가 있을 수도 있을 듯합니다. 아두이노 세계를 완전히 처음 접하는 독자님들은 아두이노 우노 시리즈부터 시작하시길 권장합니다.
2.1. 제누이노101과 우노의 간략 차이점 비교
구분 | 아두이노 우노 | 제누이노 101 |
마이크로컨트롤러 | ATmega328 | Intel® Curie™ |
동작전압 | 5V | 3.3V |
USB 가상시리얼포트 | Serial class | Serial class (USB To Serial 회로 불필요) |
H/W 시리얼포트 | Serial1 class | |
SoftWare 시리얼 장치 | 최고속도 38,400bps | 최고속도 57,600bps |
온보드 주변장치 | - | 블루투스 4.0 LE 6축 모션센서 (자이로스코프 3축, 가속도센서 3축) |
특별 라이브러리 | - | CurieBLE (Bluetooth Low Energy module 제어) CurieIMU(6-axis 가속도센서, 자이로센서 제어) Curie Timer One (Timer 함수) |
2.2. 업로드 절차
스케치가 보드에 업로드 후 실행을 시작하기 전에, 몇 초 정도의 지연이 있습니다. 전원이 새롭게 인가되거나 ResetM 버튼을 누를 때도 똑같습니다. 이때는 시리얼 모니터를 열어도 열리지 않게 됩니다. 이 시간은 넉넉잡아 10초 가량 됩니다. 제누이노101 내부적으로 RTOS가 돌고 있음에 따라 발생되는 현상으로 생각됩니다. 이는 제조사에서 이러한 특성을 보인다고 공개한 사항이므로 특별히 문제가 있는 것은 아니라고 봅니다. 프로그램이 시리얼창이 열린 후 구동되게 하고자 할 때는 setup()에 다음 코드를 추가 한다.
while (!Serial) ;
3. 제누이노101을 활용한 실험환경 구성하기
제조사에서 예제로 제시해 준 프로그램을 중심으로 특수한 주변기기인 모션센서, 블루투스 4.0 LE 모듈 등을 테스트 해보기로 하겠습니다. 이 예제를 따라해 보시면 이렇게 할 수 있겠구나 하는 생각이 드실 것으로 봅니다.
3.1. CurieIMU 라이브러리 기반 모션센서 움직임 표출하기
모션센서하면 MPU6050을 떠올릴 수 있습니다만 이 센서를 능가하는 모션센서가 우리의 제누이노101 보드상 큐리칩에는 내장을 하고 있습니다. 이 데모는 제누이노101보드의 큐리칩에 기본적으로 내장되어 있는 6축 가속도, 자이로센서의 값을 읽어 표출하는 것입니다. 여기서 가속도계는 보드의 움직이는 방향정보를 제공하고, 자이로센서는 각속도를 제공해 줍니다. 이 가속도계와 자이로센서를 융합하여 IMU(Intertial Monitoring Unit : 관성측정장치)를 형성하게 됩니다. 예제에 사용된 Madgwick 필터 알고리즘은 6축의 값에서 쿼터니언(4원수) 계산에 사용되게 됩니다. 쿼터니언은 Pitch, Roll, Yaw 등 각도 계산에 사용되며 결국은 X, Y, Z축 주위의 물체 회전이 일어난 정도를 알 수 있게 해 줍니다.
[MPU-6050 가속도 자이로센서 모듈 |
3.2. 실험절차
제누이노101보드를 준비한 다음 라이브러리 관리자에서 Madgwick 라이브러리를 설치합니다. (아두이노IDE > 스케치 > 라이브러리추가 > 라이브러리관리) 다음으로 PC에서 눈으로 볼 수 있도록 프로세싱 프로그램을 설치해야 합니다.
프로세싱 프로그램은 https://processing.org/download/에서 다운받으면 됩니다. 제누이노101 라이브러리는 https://github.com/01org/corelibs-arduino101에서 다운받아 라이브러리에 등록하면 됩니다.
4. (예제1) 모션센서 시각화
4.1. 제누이노101용 소스코드
Madgwick 필터를 사용하여 프로세싱 상에서 동작 상태를 모니터링 하는 예제입니다.
ㅇ 파일명 : IMU_OrientationVisualiser.ino
===============================================
Example sketch for CurieIMU library for Intel(R) Curie(TM) devices.
Copyright (c) 2015 Intel Corporation. All rights reserved.
Based on I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050
class by Jeff Rowberg: https://github.com/jrowberg/i2cdevlib
===============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
Genuino 101 CurieIMU Orientation Visualiser
Hardware Required:
* Arduino/Genuino 101
Modified Nov 2015
by Helena Bisby <support@arduino.cc>
This example code is in the public domain
http://arduino.cc/en/Tutorial/Genuino101CurieIMUOrientationVisualiser
*/
#include <CurieIMU.h>
#include <MadgwickAHRS.h>
Madgwick filter; // Madgwick 객체를 생성해 냅니다.
int ax, ay, az;
int gx, gy, gz;
float yaw;
float pitch;
float roll;
int factor = 800; // 감도 조절을 위해 자이로스코프의 원래 값을 나눠준다.
// 시리얼 보레이트를 올리면 이 값도 변경시킨다.
int calibrateOffsets = 1; // 캘리브레이션을 할지 말지 설정
void setup() {
Serial.begin(9600); // 시리얼 통신 초기화
CurieIMU.begin(); // 장치 초기화
if (calibrateOffsets == 1) {
//자이로와 가속도센서의 오프셋을 설정하는 기능
Serial.println(“Internal sensor offsets BEFORE calibration…”);
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Z_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getGyroOffset(X_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getGyroOffset(Y_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getGyroOffset(Z_AXIS)); Serial.print(“\t”);
Serial.println(“”);
// To manually configure offset compensation values, use the following methods instead of the autoCalibrate…() methods below
// CurieIMU.setGyroOffset(X_AXIS, 220);
// CurieIMU.setGyroOffset(Y_AXIS, 76);
// CurieIMU.setGyroOffset(Z_AXIS, -85);
// CurieIMU.setAccelerometerOffset(X_AXIS, -76);
// CurieIMU.setAccelerometerOffset(Y_AXIS, -235);
// CurieIMU.setAccelerometerOffset(Z_AXIS, 168);
// 올바로 오프셋이 설정되기 위해서는 제누이노보드가 수평으로 유지되어 있어야 한다.
Serial.print(“Starting Gyroscope calibration…”);
CurieIMU.autoCalibrateGyroOffset();
Serial.println(“ Done”);
Serial.print(“Starting Acceleration calibration…”);
CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
Serial.println(“ Done”);
Serial.println(“Internal sensor offsets AFTER calibration…”);
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Z_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS)); Serial.print(“\t”);
Serial.print(CurieIMU.getAccelerometerOffset(Z_AXIS)); Serial.print(“\t”);
Serial.println(“”);
}
}
void loop() {
// 가속도와 자이로센서로부터 원시데이터를 읽어 온다.
CurieIMU.readMotionSensor(ax, ay, az, gx, gy, gz);
// MagdwickAHRS.h 함수를 통해 쿼터니언을 계산하여 가져온다.
filter.updateIMU(gx / factor, gy / factor, gz / factor, ax, ay, az);
// 쿼터니언으로부터 yaw, roll, pitch를 계산해낸다.
yaw = filter.getYaw();
roll = filter.getRoll();
pitch = filter.getPitch();
// print gyro and accel values for debugging only, comment out when running Processing
/*
Serial.print(ax); Serial.print(“\t”);
Serial.print(ay); Serial.print(“\t”);
Serial.print(az); Serial.print(“\t”);
Serial.print(gx); Serial.print(“\t”);
Serial.print(gy); Serial.print(“\t”);
Serial.print(gz); Serial.print(“\t”);
Serial.println(“”);
*/
if (Serial.available() > 0) {
int val = Serial.read();
if (val == ‘s’) { // 시리얼 포트로 “s”라는 문자가 오는지 체크. 즉 프로세싱코드에서 보내야함
Serial.print(yaw);
Serial.print(“,”); // 콤마가 구분자로 사용된다.
Serial.print(pitch);
Serial.print(“,”); // 콤마가 구분자로 사용된다.
Serial.println(roll);
}
}
}
4.2. 프로세싱용 소스코드
아래 파일은 PC상에서 프로세싱을 실행시킨 후 불러들이면 3D애니메이션으로 된 제누이노101 보드가 보입니다.
ㅇ 파일명 : IMU_OrientationVisualiser_Processing.pde
import processing.serial.*;
Serial myPort;
int newLine = 13; // new line character in ASCII
float yaw;
float pitch;
float roll;
String message;
String [] ypr = new String [3];
void setup()
{
size(600, 500, P3D);
/*자신의 제누이노보드의 통신속도와 PC의 포트번호를 참조하여 설정한다.*/
//myPort = new Serial(this, Serial.list()[0], 9600); // if you have only ONE COM port active
myPort = new Serial(this, “COM51″, 9600); // if you know the 101 COM port
textSize(16); // set text size
textMode(SHAPE); // set text mode to shape
}
void draw()
{
serialEvent(); // read and parse incoming serial message
background(255); // set background to white
translate(width/2, height/2); // set position to centre
pushMatrix(); // begin object
rotateX(pitch); // RotateX pitch value
rotateY(-yaw); // yaw
rotateZ(-roll); // roll
drawArduino(); // function to draw rough Arduino shape
popMatrix(); // end of object
// Print values to console
print(pitch);
print(“\t”);
print(roll);
print(“\t”);
print(-yaw);
println(“\t”);
myPort.write(“s”); // “s”를 제누이노 보드로 보내 다음 문자를 받아 들인다.
}
void serialEvent()
{
message = myPort.readStringUntil(newLine); // read from port until new line (ASCII code 13)
if (message != null) {
ypr = split(message, “,”); // split message by commas and store in String array
yaw = float(ypr[0]); // convert to float yaw
pitch = float(ypr[1]); // convert to float pitch
roll = float(ypr[2]); // convert to float roll
}
}
void drawArduino() {
/* function contains shape(s) that are rotated with the IMU */
stroke(0, 90, 90); // set outline colour to darker teal
fill(0, 130, 130); // set fill colour to lighter teal
box(300, 10, 200); // draw Arduino board base shape
stroke(0); // set outline colour to black
fill(80); // set fill colour to dark grey
translate(60, -10, 90); // set position to edge of Arduino box
box(170, 20, 10); // draw pin header as box
translate(-20, 0, -180); // set position to other edge of Arduino box
box(210, 20, 10); // draw other pin header as box
}
출처 : https://www.arduino.cc/en/Tutorial/Genuino101CurieIMUOrientationVisualiser
4.3. 동작화면
프로세싱 동작화면 |
그래픽 구현장면 |
4.4. 작동 원리
Madgwick 필터 알고리즘은 오픈 소스이며, Madgwick의 논문에 잘 서술이 되어있다고 합니다. Madgwick 필터 알고리즘은 세바스찬 Madgwick에 의해 2010년에 개발되었습니다. 이 알고리즘은 낮은 샘플링 속도에서도 효율적으로 동작되도록 설계되어 있습니다.
프로세싱 쪽에서 ‘s’ 문자를 송신하면 제누이노101에서는 yaw, pitch, roll값을 차례로 보내도록 프로토콜이 만들어져 있습니다. 이러한 체계는 예제를 위해 간이로 만들어진 것이며 제대로 사용되기 위해서는 에러 처리 작업 등이 필요합니다. 실제 동작되는 동영상은 제 블로그를 통해서도 보실 수 있을 것입니다.
(Madgwick 필터 알고리즘 오픈 소스는 http://www.x-io.co.uk/res/doc/madgwick_internal_report.pdf에서 볼 수 있습니다.)
5. (예제2) Curie IMU IMU 정보 그래프로 표출
자이로센서와 가속도센서의 값 6개를 시리얼 포트로 출력한 후에 시리얼 오실로스코프로 관찰을 해보도록 합니다.
5.1. 시리얼오실로스코프 설치하기 시리얼 오실로스코프 프로그램은 오픈소스기반의 프로그램으로서 최대 9채널의 값을 그래프로 표현해 낼 수 있습니다. 시리얼 오실로스코프프로그램을 아래에서 다운로드 받습니다.
ㅇ https://github.com/xioTechnologies/Serial-Oscilloscope
5.2. 시리얼오실스코프 간단한 사용법
ㅇ 시리얼로 보낼 때 기본원칙 : “11,22,33\r”
위와 같은 데이터를 시리얼 오실로스코프로 보내면 CH1에는 11, CH2에는 22, CH3에는 33이 들어가게 됩니다. 즉 데이터 구분자가 콤마가 되게 됩니다.
ㅇ 기본설정 순서
Baud rate 설정 ⇒ Serial Port 설정 ⇒ Osciloscope를 선택하여 데이터 3개 이하가 콤마로 구분되어 전송되어 온다면 “Channels 1, 2, and 3″을 선택하면 됩니다. 선택 시 보이는 UI는 다음과 같이 조절합니다.
5.3. 소스코드
===============================================
Example sketch for CurieIMU library for Intel(R) Curie(TM) devices.
Copyright (c) 2015 Intel Corporation. All rights reserved.
Based on I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050
class by Jeff Rowberg: https://github.com/jrowberg/i2cdevlib
===============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
===============================================
#include “CurieIMU.h”
int ax, ay, az; // accelerometer values
int gx, gy, gz; // gyrometer values
const int ledPin = 13; // activity LED pin
boolean blinkState = false; // state of the LED
int calibrateOffsets = 1; // int to determine whether calibration takes place or not
void setup() {
Serial.begin(9600); // initialize Serial communication
while (!Serial); // wait for the serial port to open
// initialize device
Serial.println(“Initializing IMU device…”);
CurieIMU.begin();
// verify connection
Serial.println(“Testing device connections…”);
if (CurieIMU.begin()) {
Serial.println(“CurieIMU connection successful”);
} else {
Serial.println(“CurieIMU connection failed”);
}
// use the code below to calibrate accel/gyro offset values
if (calibrateOffsets == 1) {
Serial.println(“Internal sensor offsets BEFORE calibration…”);
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS));
Serial.print(“\t”); // -76
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS));
Serial.print(“\t”); // -235
Serial.print(CurieIMU.getAccelerometerOffset(Z_AXIS));
Serial.print(“\t”); // 168
Serial.print(CurieIMU.getGyroOffset(X_AXIS));
Serial.print(“\t”); // 0
Serial.print(CurieIMU.getGyroOffset(Y_AXIS));
Serial.print(“\t”); // 0
Serial.println(CurieIMU.getGyroOffset(Z_AXIS));
// To manually configure offset compensation values,
// use the following methods instead of the autoCalibrate…() methods below
//CurieIMU.setAccelerometerOffset(X_AXIS,495.3);
//CurieIMU.setAccelerometerOffset(Y_AXIS,-15.6);
//CurieIMU.setAccelerometerOffset(Z_AXIS,491.4);
//CurieIMU.setGyroOffset(X_AXIS,7.869);
//CurieIMU.setGyroOffset(Y_AXIS,-0.061);
//CurieIMU.setGyroOffset(Z_AXIS,15.494);
Serial.println(“About to calibrate. Make sure your board is stable and upright”);
delay(5000);
// The board must be resting in a horizontal position for
// the following calibration procedure to work correctly!
Serial.print(“Starting Gyroscope calibration and enabling offset compensation…”);
CurieIMU.autoCalibrateGyroOffset();
Serial.println(” Done”);
Serial.print(“Starting Acceleration calibration and enabling offset compensation…”);
CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
Serial.println(” Done”);
Serial.println(“Internal sensor offsets AFTER calibration…”);
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS));
Serial.print(“\t”); // -76
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS));
Serial.print(“\t”); // -2359
Serial.print(CurieIMU.getAccelerometerOffset(Z_AXIS));
Serial.print(“\t”); // 1688
Serial.print(CurieIMU.getGyroOffset(X_AXIS));
Serial.print(“\t”); // 0
Serial.print(CurieIMU.getGyroOffset(Y_AXIS));
Serial.print(“\t”); // 0
Serial.println(CurieIMU.getGyroOffset(Z_AXIS));
}
// configure Arduino LED for activity indicator
pinMode(ledPin, OUTPUT);
}
void loop() {
// read raw accel/gyro measurements from device
CurieIMU.readMotionSensor(ax, ay, az, gx, gy, gz);
// these methods (and a few others) are also available
//CurieIMU.readAcceleration(ax, ay, az);
//CurieIMU.readRotation(gx, gy, gz);
//ax = CurieIMU.readAccelerometer(X_AXIS);
//ay = CurieIMU.readAccelerometer(Y_AXIS);
//az = CurieIMU.readAccelerometer(Z_AXIS);
//gx = CurieIMU.readGyro(X_AXIS);
//gy = CurieIMU.readGyro(Y_AXIS);
//gz = CurieIMU.readGyro(Z_AXIS);
// display tab-separated accel/gyro x/y/z values
// Serial.print(“a/g:\t”);
Serial.print(ax);
Serial.print(“\t”);
Serial.print(ay);
Serial.print(“\t”);
Serial.print(az);
Serial.print(“\t”);
Serial.print(gx);
Serial.print(“\t”);
Serial.print(gy);
Serial.print(“\t”);
Serial.println(gz);
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(ledPin, blinkState);
}
6.1. 동작화면
① 제누이노101 개발중 스케치화면 ② 시리얼모니터화면 ③ 시리얼오실로스코프 메인화면 |
④ CH1∼3 - Red : ax – Green : ay – Blue : az ⑤ CH4∼6 - Red : gx – Green : gy – Blue : gz |
기본적인 동작은 MPU6050을 사용하는 것과 견주어 봐도 별 차이가 없습니다. 다만 차이가 있다는 점은 MPU6050을 사용할 때는 TWI통신을 하여야 하는데 제누이노101에서는 인스턴스만 생성해 주는 것으로 간단히 마무리할 수 있습니다.
6.2. (예제3) CurieBLE 라이브러리 기반 스마트폰으로 LED 제어하기
제누이노101 보드에 내장된 블루투스 통신기능을 활용하여 스마트폰의 명령에 따라 보드의 LED를 점멸하는 테스트를 해보고자 합니다. HC-05 등 아두이노의 블루투스 실험에서 많이 등장하는 모듈이 있기는 합니다만 온보드로 되어 있는 블루투스 모듈은 상당한 접근 편리성을 제공해 준다고 볼 수 있습니다. 큐리칩에 내장되어 있으므로 시리얼, TWI, SPI 등의 통신과정 없이 직접 접근이 이뤄지게 됩니다. 이 점이 좀 생소할 수는 있겠습니다만 제누이노101과 친해 지려면 열심히 적응해야지 별 수 없습니다.
6.3. 실험을 위한 사전준비
우선 스마트폰(안드로이드 or 아이폰)과 제누이노101 보드를 준비합니다. 스크래치쪽 프로그램에서는 아래와 같은 함수와 라이브러리들이 동원됩니다. 다음으로 스마트폰에도 약간의 준비가 필요합니다.
구분 | 파일 & 함수명 | 비고 |
라이브 | CurieBLE.h | 블루투스에 접근하기위한 라이브러리 |
blePeripheral- ConnectHandler() | 블루투스로 연결을 처리하는 함수 연결시 LED를 점등 시킨다.
시리얼 모니터로도 메시지를 내보낸다. |
|
함수 | blePeripheral- DisconnectHandler() | 연결을 중지시킨다. 시리얼 모니터로도 상태 메시지를 출력한다. |
switchCharacte-risticWritten () | 스마트폰의 NRF 마스터 컨트롤러의 명령에 따라 LED를 켜거나 끕니다. |
제누이노101 보드의 LED를 스마트폰으로 제어하기 위해서는 스마트폰에 ‘nRF Master Control Panel(BLE)’라고 하는 앱을 설치하여야 합니다.
플레이스토어에서 다운받아 설치를 합니다. 설치를 완료한 후 아래 [그림1] 처럼 SCAN을 실행시키고 LEDCB가 발견되면 connect 버튼을 누릅니다. 연결이 되고나면 아래 [그림2]와 같은 모습을 볼 수 있을 것입니다. 여기서 “Unknown service UUID 19B10000-E8F2-537E-4F6C-D104768A1214“를 선택 합니다.
이것은 스케치의 아래 구문으로 인해 이렇게 보이는 것입니다.
그림 1 | 그림 2 |
BLEService ledService(“19B10000-E8F2-537E-4F6C-D104768A1214″); Unknown service UUID를 탭하면 [그림3]과 같은 모습을 볼 수 있으며⇅를 누르면 [그림4]와 같은 모습을 볼 수 있습니다. 여기서 값으로 1또는 0을 쓰면 제누이노101 보드의 LED를 켜거나 끌 수가 있겠습니다.UNIT는 unit8을 선택해야 합니다.
그림 3 | 그림 4 |
보드상에는 D13에 1608사이즈보다 좀 더 작아 보이는 작은 LED가 붙어 있어 이를 제어합니다만 너무 작아 외부에 고휘도 LED를 D13에 연결해 보았습니다. 그림4에서와 같이 1을 전송하면 D13이 High가되어 LED가 켜지고 0을 전송하면 LED가 꺼짐을 알 수 있습니다. 우리의 제누이노101 보드로 블루투스를 통한 원격제어가 어떻게 이뤄지는가를 적나라(?)하게 체험을 해봤습니다.
그림 5 |
그림 6 |
6.4. 적용코드
/*
* Copyright (c) 2016 Intel Corporation. All rights reserved.
* See the bottom of this file for the license terms.
*/
#include <CurieBLE.h>
const int ledPin = 13; // 보드상에 있는 LED를 사용하기위해 설정
BLEPeripheral blePeripheral; // 블루투스 패리퍼럴 인스턴스를 생성한다.
BLEService ledService(“19B10000-E8F2-537E-4F6C-D104768A1214″); // 서비스를 생성한다.
// switch characteristic 를 원격장치에서 읽고 쓸 수 있도록 생성한다.
BLECharCharacteristic switchChar(“19B10001-E8F2-537E-4F6C-D104768A1214″, BLERead | BLEWrite);
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT); // LED포트(pin 13)를 출력으로 설정
// 주변장치에게 광고할 제누이노101보드의 블루투스 이름
// 즉, 이 이름이 스마트폰 등에서 확인이 된다.
blePeripheral.setLocalName(“LEDCB”);
// UUID를 설정한다.
blePeripheral.setAdvertisedServiceUuid(ledService.uuid());
// 서비스와 특성 정보를 추가시킨다.
blePeripheral.addAttribute(ledService);
blePeripheral.addAttribute(switchChar);
// 주변장치를 연결하거나 끊기 위한 이벤트 핸들러를 할당 한다.
blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler);
blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
// 특성제어를 위한 이벤트 핸들러를 할당한다.
switchChar.setEventHandler(BLEWritten, switchCharacteristicWritten);
// 특성정보를 초기화 한다.
switchChar.setValue(0);
// 서비스를 광고한다. 즉, 다른 기기에서 이제부터 이 서비스를 탐지(탐색) 할 수 있다.
blePeripheral.begin();
Serial.println((“Bluetooth device active, waiting for connections…”));
}
void loop() {
// 주변장치로부터 반응을 지속적으로 폴링한다.
blePeripheral.poll();
}
// 접속이벤트 처리용 핸들러
void blePeripheralConnectHandler(BLECentral& central) {
// central connected event handler
Serial.print(“Connected event, central: “);
Serial.println(central.address());
}
// 접속끊김 이벤트 처리용 핸들러
void blePeripheralDisconnectHandler(BLECentral& central) {
// central disconnected event handler
Serial.print(“Disconnected event, central: “);
Serial.println(central.address());
}
// 실제로 LED를 제어하는 부분으로 switchChar.value()값을 읽어 LED 점멸을 제어한다.
void switchCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic) {
// central wrote new value to characteristic, update LED
Serial.print(“Characteristic event, written: “);
if (switchChar.value()) {
Serial.println(“LED on”);
digitalWrite(ledPin, HIGH);
} else {
Serial.println(“LED off”);
digitalWrite(ledPin, LOW);
}
}
/*
Copyright (c) 2016 Intel Corporation. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
출처 : https://www.arduino.cc/en/Tutorial/Genuino101CurieBLECallbackLED
블루투스를 통해 스마트폰과 통신이 정확히 되기 위해서는 인텔사에서 미리 만들어 놓은 BLEPeripheral 클래스에 대해서 많은 학습이 필요하리라 봅니다. 단순히 값을 넘겨주고 넘겨받는 차원이 아니라 블루투스 장치에 접근하기 위한 인스턴스 생성까지를 해주어야 하므로 좀 더 고차원적인 일을 할 수는 있을 것으로 봅니다만 학습을 필요로 하는 것이 그만큼 많아질 공산이 큽니다.
7. (예제4)심장박동 모니터 시뮬레이션
블루투스로 스마트폰과 연결된 상태에서 심장 박동을 모니터링 해보도록 하겠습니다. 정말로 심장박동을 모니터링하기 위해서는 손가락의 혈류흐름을 감지하는 센서가 필요합니다만 편의상 A0에 포텐셔메터를 연결하여 심장박동센서에서 심박 수가 얻어 짐을 포텐셔메터의 각도 값에 따른 저항 값으로 대체 합니다. 이 예제를 돌려보기 위해서는 스마트폰에 ‘nRF Toolbox for BLE’가 설치되어야 합니다.
7.1. 제누이노101측 HW구성
우선 테스트를 위해 포텐셔메터와 LED 1개를 아래와 같이 연결합니다.
핀 | 부품연결 | 비고 |
A0 | 포텐셔메터 2번핀 | 심장박동 신호값 |
+3V | 포텐셔메터 3번핀 | |
GND | 포텐셔메터 1번핀 | |
D13 | LED Anode | 상태표시 |
GND | LED Cathode |
7.2. 스마트폰측 환경설정
ㅇ nRF Toolbox for BLE를 플레이스토어에서 찾아 설치합니다.
ㅇ 제누이노101용 심장박동 시뮬레이션 소스코드
/* Copyright (c) 2015 Intel Corporation. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
This sketch example partially implements the standard Bluetooth Low-Energy Heart Rate service.
For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
*/
#include <CurieBLE.h>
BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you’re programming)
BLEService heartRateService(“180D”); // BLE Heart Rate Service
// BLE Heart Rate Measurement Characteristic”
BLECharacteristic heartRateChar(“2A37″, // standard 16-bit characteristic UUID
BLERead | BLENotify, 2); // remote clients will be able to get notifications if this characteristic changes
// the characteristic is 2 bytes long as the first field needs to be “Flags” as per BLE specifications
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?
// u=org.bluetooth.characteristic.heart_rate_measurement.xml
int oldHeartRate = 0; // last heart rate reading from analog input
long previousMillis = 0; // last time the heart rate was checked, in ms
void setup() {
Serial.begin(9600); // initialize serial communication
pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected
/* Set a local name for the BLE device
This name will appear in advertising packets
and can be used by remote devices to identify this BLE device
The name can be changed but maybe be truncated based on space left in advertisement packet */
blePeripheral.setLocalName(“HeartRateSketch”);
blePeripheral.setAdvertisedServiceUuid(heartRateService.uuid()); // add the service UUID
blePeripheral.addAttribute(heartRateService); // Add the BLE Heart Rate service
blePeripheral.addAttribute(heartRateChar); // add the Heart Rate Measurement characteristic
/* Now activate the BLE device. It will start continuously transmitting BLE
advertising packets and will be visible to remote BLE central devices
until it receives a new connection */
blePeripheral.begin();
Serial.println(“Bluetooth device active, waiting for connections…”);
}
void loop() {
// listen for BLE peripherals to connect:
BLECentral central = blePeripheral.central();
// if a central is connected to peripheral:
if (central) {
Serial.print(“Connected to central: “);
// print the central’s MAC address:
Serial.println(central.address());
// turn on the LED to indicate the connection:
digitalWrite(13, HIGH);
// check the heart rate measurement every 200ms
// as long as the central is still connected:
while (central.connected()) {
long currentMillis = millis();
// if 200ms have passed, check the heart rate measurement:
if (currentMillis – previousMillis >= 200) {
previousMillis = currentMillis;
updateHeartRate();
}
}
// when the central disconnects, turn off the LED:
digitalWrite(13, LOW);
Serial.print(“Disconnected from central: “);
Serial.println(central.address());
}
}
void updateHeartRate() {
/* Read the current voltage level on the A0 analog input pin.
This is used here to simulate the heart rate’s measurement.
*/
int heartRateMeasurement = analogRead(A0);
int heartRate = map(heartRateMeasurement, 0, 1023, 0, 100);
if (heartRate != oldHeartRate) { // if the heart rate has changed
Serial.print(“Heart Rate is now: “); // print it
Serial.println(heartRate);
//const unsigned char heartRateCharArray[2] = { 0, (char)heartRate };
const unsigned char heartRateCharArray[2] = { 0, (unsigned char)heartRate };
heartRateChar.setValue(heartRateCharArray, 2); // and update the heart rate measurement characteristic
oldHeartRate = heartRate; // save the level for next comparison
}
}
7.3. 스마트폰에서 동작이 되고 있는 화면
HRM 선택 | CONNECT |
HartRateSkech | HartRate 그래프 |
스마트폰에서 ‘nRF Toolbox for BLE‘ 아이콘을 터치하면 [HRM]을 선택할 수 있는 초기 화면이 보입니다. HRM이 선택되면 [CONNECT] 단계로 넘어갑니다. [HartRateSkech]를 선택하면 비로소 심장박동 모니터를 볼 수 있습니다. 본 프로그램은 일종으로 시뮬레이터로 제누이노101의 포텐셔메터를 돌리면 심장박동 값을 스마트폰 측으로 전송할 수 있게 됩니다.
8. (예제5) 제누이노101을 비콘으로 만들기
IOT라는 용어와 함께 빠지지 않고 등장하는 것이 비콘입니다. 비콘은 등대라는 의미로 전자기파를 주기적으로 발사시켜 자신의 존재를 알리는 장치를 통칭합니다. 블루투스뿐만 아니라 Wi-Fi를 사용해서도 비콘을 만들 수 있으며 디지털시대를 맞이하여 단순히 존재뿐만 아니라 위치, 거리, 메시지 등의 정보를 함께 실어서 보낼 수가 있습니다. 블루투스 4.0 LE는 매우 낮은 전력을 사용하는 통신규격으로, 블루투스 헤드셋, 마우스, 키보드 등에 널리 사용되며 코인배터리를 사용하는 디바이스에 매우 적합한 특성을 갖고 있다고 봅니다. 우리의 제누이노101 보드에는 블루투스 4.0 LE가 들어가 있고 이를 제어할 수 있는 큐리칩이 있으므로 비콘을 만들 수 있을 것이란 생각에 열심히 구글링한 결과 쓸만한 Sample Code를 얻을 수 있었습니다.
8.1. 스마트폰 환경설정
우선적으로 비콘 신호를 잡아낼 앱을 스마트폰에 설치하여야 합니다. 구글 플레이스토어 > eddystone > iBeacon & Eddystone를 설치합니다. iBeacon은 애플사가 미는 비콘 생태계이고 Eddystone은 구글이 미는 생태계입니다. 제누이노101로 실험하는 환경은 Eddystone입니다. 열정적인 누군가가 iBeacon 스케치를 발표할 수도 있을 듯 합니다만 아직은 발견할 수가 없습니다.
8.2. 아두이노 환경구성
우선 비콘을 돌릴 수 있도록 환경을 재구성 하여야 합니다. 블루투스와 관련된 라이브러리를 설치하여야 하며 아래 URL로 접속하여 다운받은 후 압축을 풀어 제누이노101 라이브러가 설치된 곳에 붙여 넣으면 됩니다.
필자의 경우 경로는 다음과 같습니다. C:\Users\home\AppData\Local\Arduino15\packages\Intel\hardware\arc32\1.0.6\libraries
ㅇ 라이브러리 주소 : https://github.com/bneedhamia/corelibs-arduino101/tree/support-eddystone-url
ㅇ 아두이노 스케치 다운로드 https://github.com/bneedhamia/CurieEddystoneURL
소스코드가 너무 길어 도입 부분만 언급하면 아래와 같습니다.
/*
* Eddystone URL for Arduino/Genuino 101.
*
* This is an Intel Curie Eddystone-compatible Sketch
* (https://github.com/google/eddystone).
*
* The Eddystone BLE protocol is used by the Physical Web(tm) project
* (https://github.com/google/physical-web).
* The Physical Web project is about BLE beacons that broadcast URLs
* so your users don’t have to download an app just to interact with
* your device.
*
* Note: this version doesn’t support Eddystone Config mode.
* To change the URL, you need to modify MY_URL and reload the Arduino.
*
* Parts required:
* Arduino/Genuino 101. This Sketch runs only on Curie-based devices.
* No other hardware is required.
*
* To Use:
* – Setup your CurieBLE libraries to support Eddystone.
* Doing this may be a little complicated until the Eddystone support
* is added to the CurieBLE library. Until then…
* There are two ways to do that:
* 1) Pull code from https://github.com/bneedhamia/corelibs-arduino101/tree/support-eddystone-url
* or
* 2) Replace CurieBLE/BLEPeripheral.* and CurieBLE/keywords.txt
* with a modified version that supports Eddystone Advertising packets.
* See https://github.com/bneedhamia/CurieBLEServiceData
* once that’s done…
* – Set MY_URL to the url for the beacon you wish to broadcast.
* – Download this Sketch to an Arduino/Genuino 101.
* – Download a Physical Web app to your phone.
* For example, Google’s Physical Web Android app is at
* https://play.google.com/store/apps/details?id=physical_web.org.physicalweb
*
* Copyright (c) 2016 Bradford Needham, North Plains, Oregon, USA
* @bneedhamia, https://www.needhamia.com
* Licensed under the Apache 2.0 License, a copy of which
* should have been included with this software.
*/
/*
* Note: as of this writing, the documentation of the CurieBLE library
* is the library source, at (on Linux)
* ~/.arduino15/packages/Intel/hardware/arc32/1.0.4/libraries/CurieBle/src
*
* Version 1.0.4 of CurieBle doesn’t support Eddystone-format
* BLE Advertising packets, for 2 reasons:
* – It uses the BLE code for Incomplete Service UUID list
* instead of Complete Service UUID list code required by Eddystone.
* – It doesn’t support Service Data, which is required by Eddystone.
*
* Note: the name of the Curie BLE library changed between 1.0.4 and
* the latest (as of March 10, 2016) version:
* In 1.0.4, the name is CurieBle.h; in later versions, it’s CurieBLE.h
*/
#include <CurieBLE.h> // BHN-Modified Curie-specific BLE Library
/*
* Pinout:
* PIN_BLINK = digital Output. The normal Arduino 101 LED.
* If everything is working, the LED blinks.
* If instead there is a startup error, the LED is solid.
*/
const int PIN_BLINK = 13; // Pin 13 is the on-board LED
/*
* The (unencoded) URL to put into the
* Eddystone-URL beacon frame.
*
* NOTE: the encoded length must be under 18 bytes long.
* See initEddystoneUrlFrame().
*
* NOTE: This Sketch supports only lower-case URLs.
* See initEddystoneUrlFrame().
*/
const char* MY_URL = “http://www.devicemart.co.kr/”;
/*
* The reported Tx Power value to put into the Eddystone-URL beacon frame.
*
* From the Eddystone-URL Protocol specification
* (https://github.com/google/eddystone/blob/master/eddystone-url/README.md#tx-power-level)
* “the best way to determine the precise value
* to put into this field is to measure the actual output
* of your beacon from 1 meter away and then add 41dBm to that.
* 41dBm is the signal loss that occurs over 1 meter.”
*
* I used the Nordic nRF Master Control Panel Android app
* (https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en)
* to measure the beacon power at 1 meter.
*/
const int8_t TX_POWER_DBM = (-70 + 41);
/*
* Maximum number of bytes in an Eddystone-URL frame.
* The Eddystone-URL frame contains
* the frame type, Tx Power, Url Prefix, and up to 17 bytes of Url.
* (The spec isn’t completely clear. That might be 18 rather than 17.)
*/
const uint8_t MAX_URL_FRAME_LENGTH = 1 + 1 + 1 + 17;
/*
* Eddystone-URL frame type
*/
const uint8_t FRAME_TYPE_EDDYSTONE_URL = 0×10;
/*
* Eddystone-URL url prefix types
* representing the starting characters of the URL.
* 0×00 = http://www.
* 0×01 = https://www.
* 0×02 = http://
* 0×03 = https://
*/
const uint8_t URL_PREFIX_HTTP_WWW_DOT = 0×00;
const uint8_t URL_PREFIX_HTTPS_WWW_DOT = 0×01;
const uint8_t URL_PREFIX_HTTP_COLON_SLASH_SLASH = 0×02;
const uint8_t URL_PREFIX_HTTPS_COLON_SLASH_SLASH = 0×03;
/*
* eddyService = Our BLE Eddystone Service.
* See https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
* and https://github.com/google/eddystone/blob/master/protocol-specification.md
* NOTE: as of this writing, Eddystone doesn’t seem to be part of the Standard BLE Services list.
*
*/
BLEService eddyService(“FEAA”);
BLEPeripheral ble; // Root of our BLE Peripheral (server) capability
<중략>
8.4 최종화면
모든 작업이 순조롭게 진행 되었다면 아래와 같은 스마트폰 화면을 보실 수 있습니다. 이 정보는 비콘과 스마트폰을 연계하여 어떠한 형태로 동작을 시킬 수 있는지를 보여주는 단순한 사례에 해당됩니다. 좀 더 그럴싸한 앱을 개발하여 적용한다면 실용성을 갖춘 제품도 가능하리라 예상해 봅니다. 이 앱을 통해 전파 수신세력, 서비스 형식, 비콘과 스마트폰간의 거리, 비콘을 발견했을때 접속할 URL 등의 정보를 얻을 수가 있습니다.
9. 정리
이상으로 제누이노101 보드가 가진 특징 위주로 쭉~ 살펴봤습니다. 아두이노 우노에 비해 파워풀한 성능과 다양한 기능으로 무장한 제누이노101은 매우 강력하다는 느낌이 우선적으로 듭니다. 아무리 아두이노가 학습용으로 많이 사용되는 물품이라 하지만 간단한 테스트 하는 용도를 넘어서기에 부족함이 없을 것 같다는 생각이 또한 들었습니다. 이 보드의 가장 강력한 점을 들라고 한다면 블루투스 4.0 LE의 탑재라고 생각됩니다. 단순히 SPP(Serial Port Profile)로 UART 통신 정도나 하는 그런 블루투스 디바이스와는 완전히 차원이 다른 기능으로 무장하고 있다는 점입니다. 이 모듈을 이용하여 Beacon으로 활용하거나 6모션센서로 센싱된 결과 값으로 로봇 등을 제어하되 블루투스 기능으로 원격제어하는 용도에 아주 잘 맞는 제품으로 생각됩니다. 이런 점에서 볼 때 아두이노를 처음 접하는 새내기 아누이노어들에게는 조금 벅찬 제품일 수 있겠다는 생각도 한편으로 듭니다. 일전에도 잠시 다뤄본 바 있는 에디슨보드는 프로토타이핑용 혹은 IOT용으로 사용하기에는 너무도 강력함에 기인된 구조상 불편한 점(70핀 히로세 커넥터 등)이 다소 있었다면 제누이노101 보드는 이런 불편 점을 일소시킨 보드라는 생각이 듭니다. 이 보드는 인텔에서 적극적으로 밀고 있는 보드인 만큼 시장에서 상당한 반향을 몰고 올 소지도 충분히 있다고 봅니다. 제누이노101 보드를 한마디로 표현해 본다면 아두이노 외투를 걸친 초미니 PC 정도에 해당될 수 있을 것 같습니다. 이상으로 제누이노101 보드에 대한 리뷰를 마칩니다. 감사합니다.
자료참고
1. 제누이노 공식 웹사이트 : www.arduino.cc/en/Main/ArduinoBoard101
2. 인텔사 큐리칩 공식 소개 페이지 : www.intel.com/content/www/us/en/wearables/intel-curie-fact-sheet.html
3. 인텔 큐리칩 개인 포스팅 자료
http://blog.naver.com/jjy0501/220235133315
http://www.bodnara.co.kr/bbs/article.html?num=117199
4. 쿼터니언 관련 기초지식 : ko.wikipedia.org/wiki/%EC%82%AC%EC%9B%90%EC%88%98
5. 프로세싱 프로그램 다운로드 : processing.org/download/
6. 제누이노101 라이브러리 : github.com/01org/corelibs-arduino101
7. 제누이노101 실험용 소스코드
www.arduino.cc/en/Tutorial/Genuino101CurieIMUOrientationVisualiser
www.arduino.cc/en/Tutorial/Genuino101CurieIMURawImuDataSerial
www.arduino.cc/en/Tutorial/Genuino101CurieBLECallbackLED
www.arduino.cc/en/Tutorial/Genuino101CurieBLEHeartRateMonitor
8. madgwick 라이브러리 논문 : www.x-io.co.uk/res/doc/madgwick_internal_report.pdf
9. PC기반 시리얼 오실로스코프 프로그램 : github.com/xioTechnologies/Serial-Oscilloscope
10. 비콘 관련 언론 보도자료 : news.naver.com/main/read.nhn?mode=LSD&mid=sec&sid1=101&oid=469&aid=0000059091
11. 에디스톤 제누이노101 라이브러리 : github.com/bneedhamia/corelibs-arduino101/tree/support-eddystone-url
12. 제누이노101용 에디스톤 스캐치 : github.com/bneedhamia/CurieEddystoneURL