CoffeeScript
Node.js
RaspberryPi
Node.jsDay 12

Node.jsでRaspberryPiのGPIOを良しなにする方法

More than 1 year has passed since last update.

Node.jsのAdvent Calendar 12日目です。

巷でIoTとか流行ってるので大学でちょっと電子工作(Arduino)をした時についでにRaspberryPiを買ってから早2ヶ月

Raspbianを入れてから放置したままだったので

これを機会にRasPiでGPIOやっていきたいと思います!


Q. 何故 Node.jsでやるのか?

A. JavaScriptが好きだからです!!

けど、構文そのものはすきではな開発効率のためCoffeeScriptを普段から使っているのでCoffeeScriptで書いていきます。


使うもの (環境)


  • 秋葉原で衝動買いしたRaspberryPi B+ - Raspbian GNU/Linux 7 (wheezy)

  • Amazonで買ったB+用のケーブルとブレッドボード

  • Arduinoと一緒に買ったLEDなどなど

  • Ethernetケーブルとアダプター(大学やカフェとかでも使えるように)


Node.jsのインストール

バージョン管理にはnodebrewを使います。


nodebrewのインストール

$ curl -L git.io/nodebrew | perl - setup


nodebrewからnodeのインストール

インストール方法は二通りあり


  • ソースコードをダウンロードしてコンパイル

  • バイナリをダウンロードして設置

一番手っ取り早いの後者のバイナリをダウンロードするタイプなんですが

新しいバージョンのだとRaspberryPi用のバイナリがなかったりします。


バイナリがない場合

$ nodebrew install-binary v0.11.14

v0.11.14 is not found

Can not fetched: http://nodejs.org/dist/v0.11.14/node-v0.11.14-linux-arm-pi.tar.gz


今回、自分がbinary installで動くのを確認したのはv0.10.28なので

バイナリインストールする場合は以下のコマンドでインストールします。

$ nodebrew install-binary v0.10.28


RaspberryPiのGPIOを操作する方法

プログラムからRaspberryPiのGPIOの操作方法は二通り

メモリに直接書き込む/sys/class/gpioをシェルから操作することでGPIOをON/OFFできます。

とりあえずシェルを使ってNode.js抜きで操作してみたいと思います。

回路は発光ダイオードを直接繋いだだけのシンプルなものでやってみます。

IMG_20141212_033412.jpg

(写真ですみません。回路図の画像を作れるWebサービスないかな...)

// GPIO24 を使うためのコマンド

$ echo 24 > /sys/class/gpio/export

// IN/OUTの設定 出力する場合はout
$ echo out > /sys/class/gpio/gpio24/direction

// 信号のON/OFFの切り替え ONは1 OFFは0
$ echo 1 > /sys/class/gpio/gpio24/value

// OFFにする
$ echo 0 > /sys/class/gpio/gpio24/value

// unexport
$ echo 24 > /sys/class/gpio/unexport

出力するだけならシンプルですね。

ちなみにメモリを直接操作する方法は Node.jsでどうやればいいのかよくわからないので今回は保留 (/dev/mem をあれやこれやするようですがまだよくわからないのでまた今度)


Node.jsからGPIOを操作する

/sys/class/gpio をNode.jsから操作する方法で行こうとお思います。

さっきの操作をNode.jsでやるにはFileSystemを使えばOKです。


fs = require 'fs'
path = require 'path'

dir = '/sys/class/gpio/'
pin = 24

# export
fs.writeFileSync path.join(dir, 'export'), pin

gpio24 = path.join dir, 'gpio' + pin

# directionの設定
fs.writeFileSync path.join(gpio24, 'direction'), 'out'

# 値の書き込み
fs.writeFileSync path.join(gpio24, 'value'), 1

# 3秒後に終了
setTimeout ->
fs.writeFileSync path.join(gpio24, 'value'), 0
fs.writeFileSync path.join(dir, 'unexport'), pin
, 3000

わかりやすくするため同期メソッドを使いましたが

JavaScript的には非同期がいいと思うのでasyncやPromiseなんかを使うといいと思います。


Lチカ

プログラミングの最初の一歩がHello Worldなら

電子工作の最初の一歩はLチカです。

Lチカとは「LEDチカチカ」の略です。

既に冒頭でやってしまってますがライブラリを使った もう少しちゃんとしたLチカをやりたいと思います。

ライブラリは覚えたての知識であるPromiseを活用したいのでPromise使ったライブラリないかなぁと思って探したんですが

なかったので作ったnode-pi-gpioを使いたいと思います。

回路は上の写真と同じです。


l_chika.coffee


GPIO = require 'node-pi-gpio'

pin = 24

time = 500

_loop = (gpio, val)->
gpio.value val
setTimeout _loop, time, gpio, (unless val then 1 else 0)

GPIO.open pin, 'out'
.then (gpio)->
process.on 'SIGINT', ->
gpio.value 0
gpio.close()
.then ->
process.exit()
_loop(gpio, 1)
return
.catch (err)->
console.log 'err', err.stack


実行するとLEDが0.5秒ごとにON/OFFが切り替わると思います。

終了するには Ctrl+c を入力して終了させます。


ボタンの入力を受け付ける

今度はボタンを使って入力を受けてみたいと思います。

ちなみにfs.watchでは変更をキャッチできないようです。orz

IMG_20141212_022913_2.jpg

回路は先程のLチカのやつに追加してます。

ボタンを橋渡しのようにつけてGRAND側に抵抗(10k)、ボタンと抵抗の間に線を繋ぎます。

繋ぐ先はGPIO25になってます。


button.coffee

GPIO = require 'node-pi-gpio'
Promise = require('es6-promise').Promise

led_pin = 24
button_pin = 25

Promise.all [GPIO.open(led_pin, 'out'), GPIO.open(button_pin, 'in')]
.then (res)->
console.log 'open'
[led, button] = res

process.on 'SIGINT', ->
led.value 0
Promise.all [led.close(), button.close()]
.then ->
process.exit()

button.on 'change', (val)->
console.log 'change', val
led.value val
.catch (err)->
console.log 'err', err.stack


ボタンを押すとLEDが光るサンプルです。

Lチカとボタンのソースコードはgithubのexampleに入っています。

npmのスクリプトも設定しているので

npm installした後に

$ npm run example:l_chika

$ npm run example:button

で、すぐに実行できます。


まとめ

ネタかぶりを防ぐためにRaspberryPiを使おうとしたけど、参考文献少ないしライブラリも少ないしfs.watchは使えないし

自分でライブラリ書いてるしで想像より大変でした。

赤外線とかもうちょっとセンサー使ったあれこれも紹介したかったんですが長くなりそう(*1)なのでここではHelloWorld的なところまでにしておきます。

*1 文量ではなく作業量 orz

追記:

どうもrpio

Node.js Advent Calendar 2014 明日は@Wmrfreewさんが担当です!