Raspberry Piに接続したフルカラーLEDをNode.jsから制御する

Raspberry PiのGPIOの制御方法がわかったので、Node.jsからGPIOをコントロールできるようにします。

Node.jsからGPIOを叩く

前回のGPIO制御のコマンドをそのまま使うような書き方をします。

var exec = require('child_process').exec;

exec('gpio -g mode 23 out');

こんな感じで設定をして

exec('gpio -g write 23 1');

とすれば、23がHiになります。

Node.jsからフルカラーLEDを制御する

これだけでは面白く無いので、ブレッドボードにフルカラーLEDを接続してPWM使って色を変えるようにしてみます。PWMはアナログ出力で、Raspberry Piは18番のみがPWMが使えるようになっているので、RGBのBを18に接続して、RとGを普通のGPIOに接続しました。

GPIO Peripheral
Full Color LED
R - GPIO4 : 23
G - GPIO3 : 24
B - GPIO1 : 18 : PWM

ブラウザクライアントはexpress + Node.js + Socket.IOで作成しました。(以前のエントリを参照)LEDコントロールUIにはjQuery Knobを使っています。ブラウザでノブの値を変化させたら、その値を元にLEDの色を変化させるようになっています。

f:id:tomo_watanabe:20130121213903p:plain

以下サーバ側(app.js)コード抜粋

// メッセージを受けた時の処理
socket.on('message', function(data) {
    // 接続しているクライアントに全てに送信
    socket.broadcast.emit('message', { value: data.value });
    // B
    exec('gpio -g pwm 18 ' + data.value % 1024);
    // R
    if ((1024 <= data.value && data.value < 2047) 
        || (3072 <= data.value && data.value < 4095) ) {
        exec('gpio -g write 23 1');
    } else {
        exec('gpio -g write 23 0');
    }
    // G
    if ((2048 <= data.value && data.value < 3071) 
        || (3072 <= data.value && data.value < 4095) ) {
        exec('gpio -g write 24 1');
    } else {
        exec('gpio -g write 24 0');
    }
});

回路例は以下(LEDはカソードコモン:GND共通を使用)

f:id:tomo_watanabe:20130121215824p:plain

これでノブをぐりんぐりんすれば、フルカラーLEDの色が変化します(^^)/

しかし・・・予想してたとはいえ追従性能がかなり悪い...orz

f:id:tomo_watanabe:20130120233345j:plain

まとめ

リアルタイムWebとリアルデバイスを接続してみるという実験でしたが、Socket.IOのログレベルを下げてるのですが、実際の動作としては変化の追従がかなり遅いです。クリックだとパッパッと変化するのですが、アナログ的に変化させるとキツイです。今回の変化量は 0 〜 4096の間で変化量を都度送信しているのですが、Node.jsの処理が追いついていないのか、GPIOを叩くコードの部分がネックなのか切り分けできていません。いずれにしてもこの程度の処理でログが目で追えるような速度ではハードリアルタイムは無理です。やはりリアルタイムWebといえども、ハードリアルタイムを期待するのはかなり厳しいようです...(^^; 改善方法をご存知の方はぜひ教えて下さい

WebSocket系を使ったリアルタイムWebと、リアルデバイスとの接続させた場合のネックは見えました。ネックを解消し、あくまでハードリアルタイムを求める、あるいはWebSocketの性能レベルとハードリアルタイムを別々に考えシステムを設計する。という2通りの方法があります。普通に考えれば後者で、よくある電源のON/OFFくらいのレベルであれば十分対応可能ですが、もっと違うことを考えて行かないと面白くないですよね...

今回のコードはgithubに置いてあります。