본문 바로가기

2014
마이크로소프트웨어

글: 안진섭 | jinniahn@magice.co / 2014년 5월 12일

 

 

Node.js로 만들어가는 IoT 세상(2)

 

 

아두이노를 활용한 IoT 프로젝트

지난 시간에는 사물인터넷(Internet of Things, 이하 IoT)의 전반적인 의미와 IoT 시대에 Node.js가 의미하는 바는 무엇인지 살펴봤다. 이번 시간에는 오픈소스 하드웨어의 대표격인 아두이노와 Node.js를 어떤 방식으로 연결하는지 살펴볼 것이다. 더불어 Node.js에서 아두이노를 제어하는 대표적인 라이브러리 ‘duino’를 이용해 간단한 센서와 액츄에이터를 동작시키는 샘플도 살펴본다.

 

 

1회| IoT 분야에서 주목받고 있는 Node.js
2회 | 아두이노와 Node.js를 이용한 IoT 프로젝트
3회 | Node.js 기반의 웹, 모바일, Things를 하나로 연결하기

 

 

 

IoT 제품들은 인터넷을 통해 서로 인지하고 연결됐을 때 더 큰 시너지를 낼 수 있다. 이런 의미에서 Node.js는 IoT의 한 축이 될 수 있다. Node.js는 인터넷 서비스를 효율적으로 만들기 위한 API와 모듈들을 제공한다. 또 안정적이면서 낮은 성능의 기기에서도 높은 성능을 제공해 IoT의 요구사항을 충족시키는 것이 바로 Node.js다.

 

이번 시간에는 코드를 통해 Node.js와 IoT가 어떻게 접목될 수 있는지 살펴볼 것이다. 그 한 가지 방법으로 Node.js와 아두이노를 연동하는 방법을 살펴본다. Node.js에서 아두이노의 핀들을 제어해 여러 센서와 액츄에이터(모터나 LED처럼 외부에 정보를 표시하는 장치들)를 제어할 수 있게 된다면 Node.js의 장점인 네트워크 기능을 통해서 아두이노의 기능을 외부로 오픈해 서비스하는 것도 어렵지 않다. 이런 서비스를 만들기 위한 사전 단계로 아두이노를 Node.js API를 사용해 제어해 볼 것이다.

 

사전 준비물

 

먼저 아두이노와 센서를 연결하는 방법을 살펴볼 것이다. 그러기 위해서는 아두이노를 비롯한 부품이 몇 가지 필요하다. 아두이노와 부품들은 국내의 부품 판매 업체를 통해 쉽게 구입할 수 있다. 혹시나 아두이노가 없다면 이번 기회에 하나 구입을 해보는 것도 좋겠다. 가격도 저렴하고 무엇보다 재미있으며 활용도가 높다. 지금까지는 프로그램의 실행 결과를 모니터로만 확인했다면 이번 기회에 외부의 세계로 영역을 더 확장해 볼 수도 있을 것이다. 예를 들어 페이스북과 연동해 메시지가 오면 LED를 켜는 서비스를 만들 수도 있다. 이 밖에도 아두이노를 이용한 사례는 다양하므로 이번 기회에 그 재미를 느껴보길 바란다. 조립 장난감을 다루듯 여러 가지 부품을 조립해 간단한 기능을 구현할 수 있다. 준비물은 다음과 같다.

 

- 아두이노 우노 : 프로그램을 입력해 센서나 액츄에이터를 제어할 보드
- LED : 전원을 인가하면 작은 불빛을 표시함
- 서보 모터 : 원하는 각도로 움직이는 모터
- 버튼 : 사용자의 입력을 받을 버튼
- 저항 10K 옴 : 풀다운 저항으로 사용될 저항

 

다음의 사이트를 통해 대략 5만 원에 모두 구입할 수 있다.

 

- mpucafe(cafe.naver.com/mpucafe)
- 동신 전자(www.ds-parts.co.kr)
- 아트로봇(www.artrobot.co.kr)
- 그린전자 마트(gemart.co.kr)

 

필요한 부품들
<그림 1> 필요한 부품들

 

전자 부품을 다루는 것에 부담을 느끼는 독자가 있다면 걱정하지 않아도 된다. 아두이노는 전자와 컴퓨터 지식이 거의 없는 예술가들과 아이들도 재미있게 뭔가를 만들어볼 수 있도록 쉽게 만들어졌다. 마시모 반지의 TED 영상을 참고하면 필자가 말하는 의미를 알 수 있을 것이다.

 

아두이노는 어떤 보드인가?

 

본론으로 들어가기 전에 아두이노에 대해 언급하는 것이 좋을 것 같다. 아두이노는 이탈리아어로 ‘강력한 친구’라는 뜻을 가지고 있다. 이름의 의미처럼 모터나 LED, 센서 등 전자 부품을 다룰 때 아두이노는 강력한 친구가 돼 줄 것이다. 왜냐하면, 보통 이런 종류의 일을 하기 위해서는 AVR(아트멜사의 RISC 단일칩 마이크로컨트롤러)이나 8051 등 프로그램이 가능한 칩이나 조그마한 부품과 씨름을 해야 하는데 아두이노는 이런 문제점들을 개선해 USB에 보드를 연결하는 것만으로 개발 준비가 끝나도록 설계됐다.

 

2005년에 마시모 반지는 그의 동료들과 함께 하드웨어나 소프트웨어를 잘 모르는 디자이너나 예술가들이 사용할 수 있을 만큼 단순하고 어떤 용도로든 사용이 가능하도록 기능을 자유롭게 확장할 수 있는 저렴한 가격의 보드를 만들고자 했다. 이런 의도로 만들어진 것이 아두이노다. 아두이노는 MPU(Micro Processor Unit)로 아트멜의 칩을 사용했고, USB를 통해 프로그래밍이 가능하며 여러 센서와 액츄에이터들을 연동할 수 있는 싱글 마이크로컨트롤러 보드다.

 

아두이노 우노 Rev 3
<그림 2> 아두이노 우노 Rev 3

 

아두이노를 다루기 위해 특별한 장비가 필요한 것은 아니다. USB를 통해 전원을 공급하고 프로그래밍할 수 있다. 프로세싱이라는 IDE를 차용해 C/C++를 프로그램할 수 있도록 수정했다. 비록 C/C++를 사용하고 있지만 쓰는 방식이 기존의 프로세싱과 유사해 사용이 쉽다. 또 C/C++를 지원하기 때문에 기존의 AVR 소스도 그대로 가져와 쓸 수 있고, 필요한 부품들을 아두이노의 핀과 연결한 뒤 프로그램을 작성하면 그대로 동작하는 특징을 가지고 있다.

 

아두이노의 스펙

 

아두이노에는 아두이노 우노를 비롯해 듀, 마이크로, 메카 등 많은 제품들이 있다. 최근에는 ‘YUN’이라는 제품이 공개됐는데, YUN은 하나의 보드에 리눅스 시스템과 아두이노 시스템을 올릴 수 있도록 듀얼 시스템을 지원하는 아두이노의 최신 버전이다. 이 글에서는 가장 기본이 되는 아두이노 우노에 대해 알아본다.

 

아두이노 우노의 스펙
<그림 3> 아두이노 우노의 스펙

 

아두이노 우노는 ATmega328 칩을 사용하고 있다. 사용 가능한 핀의 개수나 내부 운영 전압 등은 이 MPU 칩과 관련이 있다. 우노는 <그림 3>과 같이 디지털 핀과 아날로그 핀을 합쳐서 20개의 핀을 지원한다. 이 핀들은 센서와 같이 외부의 부품과 연결할 때 사용되는데, 20개의 핀이 많은 것 같지만 LCD나 FND와 같은 부품들이 한 번에 6개 혹은 8개의 핀을 필요로 한다는 점을 생각하면 많다고 할 수도 없다.

 

아두이노 우노는 프로그램 저장 용량이 32KB다. 그나마 0.5KB는 부트로더가 사용하고 있다. 또 프로그램 실행 시에 사용되는 SRAM은 고작 2KB가 전부다. MPU 클럭은 16MHz로 인텔 286 컴퓨터의 클럭수와 대동소이하다. 성능이 뛰어난 지금의 컴퓨터 스펙과 비교하면 보잘 것 없는 수준이다. 그러나 아두이노는 성능에 비해 다양한 분야에 활용된다. 인터넷을 통해 검색해보면 저성능이지만 할 수 있는 것이 생각보다 많다는 사실에 놀랄 것이다. 또 확장 보드가 많아 필요한 기능의 보드를 추가해 기능을 확장할 수도 있다.

 

아두이노의 특징

 

아두이노 프로젝트가 시작된 것이 2005년이니 올해로 10년이 됐다. 그동안 아두이노는 많은 사람들의 관심을 받으면서 발전을 거듭했다. 자신의 프로젝트에 아두이노를 사용하고 결과물을 공유하는 문화가 형성되기도 했는데, 이런 결과는 아두이노의 특징에서 비롯된 것이다.

 

아두이노의 첫 번째 특징은 저렴한 가격이다. 정품의 경우 아두이노 스토어에서 세금을 제외하고 20유로에 구입할 수 있다. 국내에서 구입한다고 해도 3만5,000원 내외로 구입이 가능하다. 또 정품이 아니더라도 호환 보드들이 많아 저렴한 가격에 구입할 수 있다. 저렴한 가격은 많은 사람들이 아두이노를 쉽게 접할 수 있는 여지를 제공했다. 아무리 좋은 기능을 갖췄더라도 10만원이 넘는 보드라면 부담스러울 수밖에 없다. 그런 면에서 아두이노는 가격을 낮춤으로써 대중화의 첫 번째 과제를 해결한 셈이다.

 

둘째는 오픈소스 하드웨어라는 점이다. 아두이노는 자사의 보드를 만들어 판매할 뿐 아니라 보드의 회로도를 Creative Common 라이선스로 공개한다. 덕분에 개인 혹은 업체들이 호환 보드를 만들거나 확장 보드를 만들 수 있게 됐다. 이는 과거에 IBM이 다른 제조사들이 PC를 제작할 수 있도록 PC의 아키텍처를 공개해 시장을 확대했던 것과 같은 효과를 만들어 냈다. 시장에 존재하는 수많은 아두이노 호환 보드들이 오픈소스 하드웨어의 결과물이라고 할 수 있다. 결과적으로 아두이노가 보편화돼 관련 자료들도 쉽게 구할 수 있게 됐다.

 

마지막으로 간단한 개발환경을 꼽을 수 있다. 아두이노는 AVR을 기반으로 한 보드다. 일반적으로 AVR 프로그래밍을 할 때 WinAVR로 컴파일하고 ISP 장비를 통해 업로드해야 하는 불편함이 있었는데, 아두이노는 USB를 이용해 프로그램하는 방식을 사용한다. 또 프로세싱 기반의 IDE를 적용해 프로세싱만큼이나 간단하게 개발을 진행할 수 있다. 혹자는 아두이노가 개발환경을 단순화하는 데만 집중한 것 아니냐고 비판하기도 하지만, 초보자들에게 있어서 쉬운 개발환경은 큰 장점이 아닐 수 없다.

 

아두이노의 단점

 

아두이노에 장점만 있는 것은 아니다. 먼저 성능과 기능의 한계를 아두이노의 단점으로 꼽을 수 있다. 앞에서 살펴본 것처럼 아두이노는 MPU을 사용하고 있는데, 아두이노 우노는 고작 16MHz의 속도로 동작한다. 무엇보다 스토리지가 작아 조금만 복잡한 코드를 작성해도 업로드조차 되지 않는 경우가 발생한다. PC나 서버에서 작업을 하던 개발자라면 아두이노의 환경이 답답할 수밖에 없다.

 

또 하나의 단점은 테스트의 어려움이다. IDE를 이용해 쉽게 작성이 됐다고 해도 컴파일이나 업로드, 테스트 과정이 쉽지는 않다. 애플리케이션을 작성할 때 요구되는 테스트 코드 역시 존재하지 않는다. 하드웨어의 성능만 봐도 무거운 프로그램을 작성할 수 없다는 걸 예상할 수 있지만 테스트 코드를 작성하고 실행하는 것이 어렵다는 점도 아두이노의 단점이다. 많은 장점을 가진 아두이노지만 이처럼 태생적 한계를 극복하는 것은 쉽지 않다. 그렇기 때문에 이러한 단점들을 Node.js를 통해 보완하려는 것이 이 글의 목적이라고 하겠다.

 

아두이노의 인터페이스와 API

 

아두이노에서 많이 쓰이는 물리적인 외부 인터페이스와 API들을 살펴보도록 하자. Node.js를 이용해 아두이노를 제어하려면 아두이노에서 사용 가능한 인터페이스와 API를 Node.js에서 사용할 수 있어야 한다. 그럼 아두이노에 사용되는 인터페이스는 무엇이 있는지 살펴보자. <그림 4>는 아두이노 우노의 레이아웃이다.

 

아두이노 우노의 핀 레이아웃
<그림 4> 아두이노 우노의 핀 레이아웃

 

1. 디지털 I/O

아두이노의 핀 레이아웃 중 가장 많은 핀이 배정돼 있으며 외부의 디지털 신호들, 소위 0, 1로 대변되는 신호를 감지하거나 반대로 신호를 외부로 보낼 때 사용된다. 대표적으로 버튼, LED, LCD 등과 같이 디지털 신호를 주고 받을 때 사용된다. 이 핀에 사용되는 아두이노 API들은 다음과 같은 것들이 있다.

 

- pinMode() : 디지털 핀의 입력 혹은 출력을 설정함.
- digitaIRead() : 외부의 신호를 읽음. 5V이면 HIGH(1), 0V이면 LOW(0)을 반환함.
- digitalWrite() : 외부에 신호를 보냄.

 

디지털 핀은 입력과 출력이 같은 핀에서 이뤄지기 때문에 사용 전에 pinMode로 입출력 여부를 지정해야 한다.

 

2. 아날로드 I/O

아두이노에는 외부의 아날로그 값들을 읽기 위해 아날로그 핀들이 별도로 마련돼 있다. 이 핀은 외부의 아날로그 신호를 감지해 0~1023 사이의 값으로 변환한다. 아두이노는 아날로그 출력을 하지 못한다(최소한 우노에서는 그렇다). 디지털 보드는 0을 나타내기 위해 0V를, 1을 표현하기 위해 5V를 사용하고 있다. 이 때문에 아날로그를 표현하기 위해 2.5V를 만들 수는 없다. 하지만 디지털로 아날로그 신호를 비슷하게 만들 수는 있다. PWM(펄스 폭 변조 방식)을 사용하는 방법인데, 10ms라는 시간 동안 5ms는 5V로, 다음 5ms는 0V를 주는 것이다. 그러면 전체적으로 2.5V의 효과를 얻을 수 있다. 이 기능을 이용하기 위해서는 디지털 핀 가운데 3, 5, 6, 9, 10, 11 핀을 사용해야 한다. 내부 PWM을 위한 타이머가 이 핀들과 연결돼 있기 때문이다.

 

- analogRead() : 외부의 아날로그 신호(전압)를 받아 디지털 값으로 읽음
- analogWrite() : PWM을 이용해 아날로그 신호를 외부로 보냄. 입력 값으로 0~255 사이의 값을 파라미터로 받음

 

3. SPI(Serail Peripheral Interface)

SPI는 주로 2개 이상의 마이크로컨트롤러를 연결해 데이터를 빠르게 교환하고자 할 때 사용하는 방식이다. 이를 위해서 4개의 선이 필요하며, ICSP(In Circuit Serial Programming)로 지원된 핀을 사용하거나 디지털 핀 가운데 10, 11, 12, 13 핀을 사용한다. SPI를 사용하기 위해 아두이노는 SPI library를 제공하고 있다.

 

- SPI library : SPI 통신을 위한 라이브러리

 

4. I2C(Inter-Integrated Circuit)
SPI와 마찬가지로 2개 이상의 아두이노 보드를 연결할 때 사용되며, 칩 간의 데이터를 전송하기 위해 사용되기도 한다. 2개의 선만으로 간단히 구성할 수 있어 많이 사용된다. SPI 방식에 비해 속도가 느려 빠른 데이터 교환이 필요치 않은 경우에 사용된다. I2C 역시 SPI와 마찬가지로 별로의 라이브러리가 제공된다.

 

- Wire library : I2C를 위한 통신용 라이브러리

 

5. 시리얼 통신
USB와 같은 직렬 통신 방법 중 하나로 아두이노 보드와 PC 간의 데이터 통신에 사용된다. 개발보드에서 디버깅용으로 많이 사용되는 기본 인터페이스로, PC와 연결할 때 이 방법을 이용한 예제를 다룰 것이다. 이 방식은 표준 자체가 오래돼 보편적이면서 TX, RX와 같이 2개의 선만 있으면 되기 때문에 구성도 간단하다. 아두이노는 디지털 핀 0과 1을 시리얼 포트에 사용하고 있다. 따라서 시리얼 통신을 하게 된다면 디지털 핀 0과 1은 사용할 수 없다.

 

- Serial library : 시리얼 통신용 라이브러리

 

시리얼 통신을 이용해 아두이노와 Node.js 연결하기

아두이노 보드와 PC의 연결
<그림 5> 아두이노 보드와 PC의 연결

Node.js는 리눅스나 윈도우와 같은 운영체제를 필요로 한다. 하지만 아두이노는 운영체제를 설치할 수 있을 만큼의 스펙을 가지고 있지 않다. 따라서 2개의 별도 시스템을 구성해야 한다. 하나는 Node.js가 실행될 마스터이고 또 하나는 마스터의 명령을 수행할 슬레이브다. 이 두 시스템은 시리얼 케이블로 연결돼 시리얼 통신을 하게 된다.

 

필자는 PC가 마스터 노드가 되도록 아두이노를 USB로 연결했다. 이때 두 노드 간의 명령은 시리얼 통신으로 주고 받게 된다. 이때 사용되는 Node.js의 라이브러리는 다음의 두 가지가 있다. 대부분의 아두이노를 다루는 프로젝트들은 이 두 가지 라이브러리 중 하나를 선택해 사용한다.

 

- duino(github.com/ecto/duino)
- firmata(firmata.org/wiki/Main_Page)

 

firmata는 MIDI 프로토콜을 기초로 만들어진 프로토콜로, 이 방식을 지원하는 언어에서 다양한 라이브러리로 제공된다. duino는 firmata에 비하면 프로토콜 구조가 간단하고 쉽다는 장점이 있지만 프로토콜의 지원 범위가 한정돼 있어서 기능을 확장하기 위해 코드를 수정해야 한다.

 

두 가지 라이브러리가 하는 역할은 동일하다. 모두 Node.js와 아두이노 간의 명령이나 데이터를 교환하는 프로토콜을 구현하는데, firmata는 프로토콜을 표준화하고 있어 Node.js 외에 다양한 언어로 구현된 라이브러리들이 존재하는 반면 duino는 자체 프로토콜을 사용하고 있어서 Node.js 외에 언어를 사용하려면 라이브러리를 작성해야 한다. 지원하는 API에도 차이가 있다. firmata는 디지털 I/O, 아날로그 I/O뿐 아니라 I2C와 SPI통신 API도 지원한다. 반면에 duino는 디지털 I/O와 아날로그 I/O, 서보모터 등 기본적인 API만 지원한다. 따라서 필요에 따라 직접 프로토콜을 수정해 기능을 추가해야 하는 경우도 있다.

 

앞에서 살펴본 바와 같이 두 라이브러리는 아두이노의 기본 API들을 대체하는 수준의 API를 제공하고 있음을 알 수 있다. 그 때문에 이를 이용해 부품별로 고수준의 API를 만들기도 한다. 예를 들어 john-five(github.com/rwaldron/johnny-five)라는 라이브러리는 firmata API를 다수의 부품별 API로 세분화해 제공한다.

 

아두이노에 duino 코드 업로드하기

duino를 사용하기 위해서는 아두이노에 duino 프로토콜을 해석할 수 있는 프로그램을 설치해야 한다. 아두이노 프로그램(github.com/ecto/duino/blob/master/src/du.ino)을 다운로드해 아두이노 IDE로 업로드한다. 일단 du.ino가 아두이노 보드에 올라가면 아두이노 IDE가 필요 없게 된다. 이제 Node.js를 이용해 프로그래밍하는 일만 남았다.

 

du.ino를 아두이노 보드에 업로드
<그림 6> du.ino를 아두이노 보드에 업로드

 

du.ino를 업로드할 때 보드와 시리얼포트를 <그림 6>과 같이 설정한다. <그림 6>은 윈도우에서 스케치 프로그램으로 업로드하는 것을 보여주고 있다. 다른 운영체제를 사용하고 있다면 각 환경에 맞도록 수정해야 한다. 업로드가 완료되면 Node.js로 아두이노를 제어할 준비가 모두 끝난 것이다.

 

샘플 소스와 의존 라이브러리

여기서 사용할 샘플 코드를 github에 올려두었다. 링크(github.com/jinniahn/duino_sample)를 이용해 소스를 다운로드하고 npm install 명령으로 의존모듈들을 설치해야 한다. duino 모듈은 github에 있는 최신 소스를 사용하고 있다. 또 의존 라이브러리로 ‘SerialPort’ 모듈이 있는데, 이 모듈을 컴파일해야 하므로 윈도우의 경우에는 설치가 쉽지 않다. 여기서는 리눅스를 이용하도록 하겠다. 꼭 윈도우에서 사용하고자 하는 경우에는 SerialPort 모듈의 설치 문서(github.com/voodootikigod/node-serialport#to-install)를 참고하기 바란다.

리눅스나 맥에서 작업하고 있다면 간단히 다음과 같이 NPM(Node Packaged Module)을 이용해 설치할 수 있다.

 

<리스트 1> NPM을 이용한 SerialPort 모듈 설치

$> cd $duino_sample_path
$> npm install

 

위의 $duino_sample_path는 github에서 받은 소스의 경로로 변경해야 한다.

 

[예제 1] 버튼을 눌러 LED에 불 켜기

이제 예제를 다뤄볼 것이다. 첫 번째는 LED와 버튼을 이용하는 예제다. 간단하지만 디지털 I/O를 다뤄 볼 수 있는 대표적인 예제다. 아두이노는 대부분 외부의 입력을 센서를 통해 입력받아 어떤 결과를 LCD나 부저와 같은 방식으로 출력한다. 예제에서는 단색 LED로 외부에 정보를 표시하는 방법을 살펴볼 것이다. 우선 회로도부터 살펴보자(<그림 7> 참조).

 

버튼과 LED의 연결 회로도
<그림 7> 버튼과 LED의 연결 회로도

 

회로도를 보면, 아두이노의 2개의 핀을 사용한 것을 확인할 수 있다. 버튼과 연결되는 디지털 핀 2(D2)와 LED에 연결될 디지털 핀 8이 사용된다. 회로도를 간단히 하기 위해서 5V와 GND는 아두이노와 연결하지 않았다. 하지만 실제 부품을 연결할 때는 모두 아두이노 보드의 전원핀을 이용해야 한다. 

 

회로도는 흔히 사용되는 회로도의 기호들을 사용했다. 간략하게 설명을 하면 <그림 8>과 같다.

 

회로 기호 설명
<그림 8> 회로 기호 설명

 

<그림 8>은 앞으로의 예제에서 사용할 부품들을 회로 기호로 표시한 것이다. 아두이노 보드는 사각형으로 보드를 표현하고 있다. 보드에 연결되는 핀 중 사용할 핀을 기호로 표시한다. 보드에는 많은 핀들이 존재하지만 회로도에서 모두 표시할 필요는 없다. 사용할 핀만 표시하면 된다. 저항은 지그재그 선으로 이뤄진 기호를 사용하고 있다. 저항값은 저항 기호 옆에 적는다. 빛 감지 센서와 LED는 빛이 들어가고 나가는 방향에 따라 화살표가 다른 것이 특징이다. 스위치는 버튼을 누르면 연결되고 떼면 연결이 끊어진다. 마지막으로 전원이다. 본 예제의 회로도에서는 전원을 아두이노 보드와 연결하지 않았지만 실제로 회로를 구성할때는 반드시 보드의 전원을 사용해야 한다.

 

이 예제를 실행하기 위해서는 1개의 버튼과 1개의 LED, 그리고 10K 옴의 저항이 필요하다. 부품들을 회로도에 따라서 잘 연결하자. LED의 경우 극성이 정해져 있다. 다리가 긴 쪽이 +극이고 짧은 쪽이 -극이다.

 

<리스트 2> 버튼이 누르면 LED에 불이 들어옴(button_led.js)

var arduino = require('duino')

var board = new arduino.Board({ // <=== 1
debug: true,
// if mac, use below
// device: ‘usb’

// linux serial dev : /dev/ttyACM0
device: 'ttyACM0' // <=== 2
});

var led = new arduino.Led({ //<=== 3
board: board,
pin: 13
});

var button = new arduino.Button({ //<=== 4
board: board,
pin: 2
});

button.on('up', function(){ //<=== 5
led.off();
});

button.on('down', function(){ //<=== 6
led.on();
});

 

<리스트 2>의 코드를 보자. 이 코드의 목적은 버튼을 누르고 있으면 LED에 불이 들어오고 아니면 꺼지도록 하는 것이다. 이를 위해서 버튼과 LED를 제어할 필요가 있다. duino에는 각각의 클래스를 제공하고 있다. 소스 코드에서 1번은 아두이노와의 연결과 데이터 교환을 담당하는 board다. 여기에 시리얼포트의 이름이 들어간다. 리눅스를 사용하고 있다면 ttyACM0을 사용하고 맥이라면 usb를 입력한다. board 객체는 버튼이나 LED를 다루기 위해 반드시 필요한 값으로 객체 생성 시에 사용된다. 3, 4번에 led와 button 객체를 생성하면서 board를 사용한 것을 기억하자. 그리고 추가적으로 핀 번호도 지정해 각 부품이 어떤 핀에 연결될 것인지 지정한다. 회로도에서 지정한 것처럼 디지털 핀 2와 버튼을 연결하고 디지털 핀 13에 LED를 연결했다. 소스 코드에도 이 정보를 반영했다.

 

버튼을 누르면 button 객체에 ‘down’ 이벤트가 발생한다. on 메소드를 사용해 해당 이벤트에 핸들러를 등록해 둔다(<리스트 2>의 6). 핸들러에서는 led.on() 명령으로 LED에 전원이 공급된다. 아두이노의 코드들 대부분은 이처럼 이벤트에 의해 동작한다. Node.js는 event emitter가 있어 센서의 이벤트에 따른 동작을 쉽게 구현할 수 있다.

 

[예제 2] 주변의 밝기 알아보기

또 다른 예제를 보도록 하자. 앞에서 버튼을 사용해서 디지털 신호를 받았다면 이번에는 아날로그 값을 읽어보도록 할 것이다. 우리 주변의 정보들은 대부분 아날로그 값이다. 온도, 습도, 기압, 조도과 같은 정보들은 디지털 값들처럼 0, 1의 값으로 정확히 표현되지 않는다.

 

조도 센서를 연결한 회로도
<그림 9> 조도 센서를 연결한 회로도

 

아날로그 값들은 특정 시점에 샘플링을 통해서만 디지털 값으로 변환한다. 이는 ADC(Analog-to-Digital Converter)에 의해 샘플링된다. 아두이노의 아날로그 입력 핀들에는 이 ADC가 연결돼 있다. 이번에는 외부의 밝기를 알아보는 예제를 통해 아날로그 값을 어떤 식으로 읽어 오는지 확인해 본다. 이 예제를 응용하면 아날로그 값으로 입력 받는 온도 센서, 습도 센서를 이용할 수 있다.

 

이번 예제는 조도 센서를 A0 핀에 연결하게 된다. 이때 조도 센서와 GND 사이에 10K 옴을 사용하고 있다. 이는 버튼을 이용할 때처럼 조도 센서의 저항값이 너무 작을 경우 회로에 많은 전류가 흐르는 것을 방지하기 위해서 사용된다. 이러한 역할을 하는 저항을 ‘풀다운 저항’이라고 한다. 아날로그 센서를 사용할 때 많이 사용되는 구성이다. 그리고 디지털 핀 13에 LED를 연결하도록 한다. 이 예제의 목적은 조도 값에 따라 LED가 켜지거나 꺼지도록 하는 것이다.

 

<리스트 3> 예제를 위한 소스 코드

var arduino = require('duino')
var board = new arduino.Board({ // <=== 1
debug: true,
// if mac, use below
// device: 'usb'

// linux serial dev : /dev/ttyACM0
device: 'ttyACM0' // <=== 2
});

// setup light sensor
// get data every 1sec
// PIN : A0
var light_sensor = new arduino.Sensor({ //<=== 3
board: board,
pin: 'A0',
throttle: 1000
});

var led = new Arduino.Led({ // <===4
board: board,
pin: 13
});

light_sensor.on('read', function(err,data){ // <===5
console.log('val = ' + data);
if( data > 200 ) { //<===6
led.off();
} else {
led.on();
}
});

 

<리스트 3>은 앞에서 살펴봤던 버튼 예제와 크게 다르지 않다. 먼저 아두이노 보드와의 연결을 담당하는 board 객체를 생성한다. 아날로그 핀에 연결된 조도 센서는 sensor 객체를 이용하게 되는데, 이때 pin 값은 ‘A0’으로 한다. 보드의 아날로그 핀인 A0 핀을 의미한다. throttle은 sensor 값을 읽는 주기를 나타낸 것으로, 1000ms로 한다. 1초마다 센서 값을 읽는다는 뜻이다. 기본값은 10ms이다. sensor 객체의 값이 주기적으로 읽혀지면 “read” 이벤트가 발생한다. 5번은 센서가 읽혔을 때 호출되는 이벤트 핸들러다. 핸들러에 들어오는 값으로 로직을 처리한다. 여기서는 조도 입력 값이 200이 넘으면 LED를 끄고 그 이하이면 LED 켜도록 돼 있다. 즉, 주변이 밝으면 조명을 끄고 어두우면 조명을 켠다. 아두이노의 아날로그 핀 값은 0~1023의 값으로 변환돼 입력된다. 조도의 경우 이 값이 높을수록 주변이 밝음을 의미한다. LED 대신 형광등을 연결할 수 있다면 방이 어두워지면 자동으로 불이 켜지는 장치를 만들 수도 있겟다.

 

duino의 다른 클래스들

예제를 통해 duino 라이브러리의 Board, Sensor, Led, Button을 살펴봤다. 이것들 외에도 다양한 클래스가 라이브러리로 제공된다. 모터를 제어할 수 있는 Servo 클래스나 초음파로 거리를 구하는 Ping 클래스, 동작감지 센서를 통해 주변 사람의 움직임을 감지하는 Pir 클래스 등이 그것들이다.

 

duino 라이브러리의 다른 클래스들
<그림 10> duino 라이브러리의 다른 클래스들

 

이들 각각의 클래스들은 그에 해당하는 센서 혹은 액츄에이터들을 제어할 수 있다. 간단한 예제들은 여기에 있는 API를 사용해 개발이 가능하다. 하지만 아두이노 보드가 다른 보드와 통신해야 한다면 시리얼통신이나 SPI 혹은 I2C 방식으로 연결하게 되는데, duino는 아직 이런 통신 부분에 대한 것을 제공하고 있지 않다. 만약 이런 부분이 필요하다면 duino를 수정해야 한다. 하지만 프로토콜 자체가 단순하므로 원하는 기능을 구현하는 것이 그리 어렵지는 않다. 다만 수정할 때는 duino의 Node.js 코드와 아두이노 코드를 모두 수정해야 함을 기억하자.

 

시리얼 연결 방식의 문제와 해결 방법

duino는 시리얼을 통해 핀 모드 설정, 디지털 핀 제어, 아날로그 입출력 등 아두이노가 다룰 수 있는 저수준의 API를 Node.js에서 그대로 사용할 수 있도록 제공한다. 이 API를 사용하는 Node.js는 아두이노를 세밀하게 다룰 수 있다. LED나 Servo 모터 하나하나를 모두 다룰 수 있는 것이다. 하지만 정밀도가 요구되는 상황에서는 적용하기 어렵다. 이는 Node.js 때문이라기보다 OS의 특성에 기인한다. Node.js가 실행되는 리눅스와 같은 OS는 실시간 OS가 아니기 때문에 어떤 명령을 수행하는 데 얼마 동안의 시간이 소요되는지 확신할 수 없다. 이 때문에 Node.js로는 정확한 제어가 어렵다. 이 문제를 해결하는 방법은 두 가지다.

 

첫째는 아두이노가 실행할 명령을 한 번에 주고 실행시키는 방식이다. Node.js가 세부적인 API까지 사용할 수 있다는 것은 분명 장점이다. 아두이노의 코드가 커지는 것을 방지할 수 있을 뿐 아니라 아두이노의 코드를 업데이트하는 것보다는 Node.js의 코드를 변경하는 것이 더 쉽기 때문이다. 그렇다면 Node.js로 저수준 API를 사용하면서 실시간성을 보장할 방법은 없을까? 현재 방식의 문제는 명령마다 매번 통신해서 명령을 전달하고 실행하는 것이다. 이때 통신 회선의 속도와 Node.js가 실행되는 OS로 인해 명령의 실행 시점이 정확하지 않다. 그렇다면 실행해야 하는 명령을 하나의 단위로 묶어 전달한 뒤 실행시키는 방법을 생각해 볼 수 있다. 이 방식을 사용하면 기존처럼 저수준 API를 그대로 사용할 수 있고 수정해야 하는 코드 역시 많지 않게 된다. 단지 트랜잭션 명령을 시작하고 종료하는 코드만 있으면 된다.

 

둘째는 실시간성이 필요한 코드를 미리 아두이노에 개발해 놓는 방식이다. 단순하게 생각하면 명령이 너무 세부적이라는 것이 문제가 된다. 예를 들어 LED를 제어하기 위해 핀 번호를 설정하면 불이 켜지는 명령을 따로 하는 것이다. 이를 하나의 명령으로 만들면 문제가 해결된다. 대신 아두이노에서 처리해야 하는 코드가 만들어지고 Node.js는 아두이노에 이 핸들러를 실행시키는 명령을 보낸다. 명령이 많아져 아두이노의 코드가 커지는 것만 아니라면 이 방법 역시 훌륭한 해결법이다.

 

이 두 가지 방법의 차이는 결국 메인 로직을 어디에 둘 것인가이다. Node.js의 장점을 충분히 살리고자 한다면 첫 번째 방법이 더 적합하지 않을까 생각한다.

 

정리하며
Node.js의 장점은 기능의 확정성에 있다. NPM을 통해 수만 개의 모듈에 제공되고 있다. 또 Node.js 자체는 기본 기능에 매우 충실하다. 기본적인 file I/O 기능, 바이너리 데이터를 위한 Buffer 클래스 등 최소한의 기능을 제공하면서 시스템의 안정성에 더 무게를 뒀다. 이 외에도 고급 기능들은 모두 NPM으로 관리되는 모듈이 제공된다. 앞서 살펴봤던 duino도 이 모듈 중의 하나이다.

 

이번 시간에는 아두이노를 Node.js에서 어떻게 다루는지, 또 어떤 방식으로 제어하는지 살펴봤다. Node.js의 진정한 가치는 인터넷 연결에서 발휘된다. 다음 시간에는 아두이노의 기능을 웹서비스로서 외부에 제공하는 기능을 구현해 볼 것이다.

 

 

[참고자료]
1. duino (github.com/ecto/duino)
2. firmata (firmata.org/wiki/Main_Page)
3. Node.js (nodejs.org)
4. 샘플 소스 (github.com/jinniahn/duino_sample)

 

 

 

/필/자/소/개/

 

 

MS_writer_anjinsub.jpg안진섭 jinniahn@magice.co | 중학교 때부터 컴퓨터 프로그래밍을 배우기 시작해 이제는 프로그래밍을 취미로 하는 평범한 개발자다. 주로 모바일과 서버 프로그램을 다루며, Emacs와 맥을 좋아한다. 프로그래밍 언어로는 루비, 파이썬, 자바스크립트를 선호하며 모바일과 컴퓨터에도 관심이 많다. 최근에는 사물인터넷에 관심을 가지기 시작해 초소형 컴퓨터로 주변의 평범한 사물들을 스마트하게 만드는 재미에 빠져 있다. 집과 사무실의 기기들을 인터넷에 연결해서 손가락 하나로 모든 것을 제어할 수 있는 집을 만드는 것이 꿈이다.

 

 

 

※ 본 내용은 (주)마소인터렉티브(http://www.imaso.co.kr/)의 저작권 동의에 의해 공유되고 있습니다.
    Copyright ⓒ Maso Interactive Corp. 무단전재 및 재배포 금지

    [원문출처 : http://news.imaso.co.kr/64041]

 

 

 

맨 위로
맨 위로