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

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

회로도

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

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

var arduino = require('duino')
var board = new arduino.Board({ // 
debug: true,
// if mac, use below
// device: 'usb'
// linux serial dev : /dev/ttyACM0
device: 'ttyACM0' // 
});

// setup light sensor
// get data every 1sec
// PIN : A0

var light_sensor = new arduino.Sensor({ //
board: board,
pin: 'A0',
throttle: 1000
});

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


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

은 앞에서 살펴봤던 버튼 예제와 크게 다르지 않다. 먼저 아두이노 보드와의 연결을 담당하는 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 클래스 등이 그것들이다.

이들 각각의 클래스들은 그에 해당하는 센서 혹은 액츄에이터들을 제어할 수 있다. 간단한 예제들은 여기에 있는 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도 이 모듈 중의 하나이다.

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

[출처] https://www.imaso.co.kr/news/article_view.php?article_idx=20140701142507