Node.js(5) three.js

前回作ったNode.jsベースのWebアプリで、Raspberry PiをWebサーバにしてデバイスの情報をブラウザに表示する目的はほぼ実現できた。
JavaScriptにはブラウザで各種データをビジュアルに表示するライブラリが豊富にあり、手軽に使えることもわかったので仕上げとしてそのあたりを試してみる。

使用したのは3Dライブラリのthree.js。WebGLをJavaScriptで手軽に使うことができる。

とりあえずテクスチャを貼った立方体を表示させて、Raspberry Piから送られてくる加速度センサの値でそれを動かすようにしてみた。
スクリーンショット 2015-05-30 14.23.50
ブラウザ側でマウスによってカメラを動かせるようにしたので、複数のクライアントから接続した場合、立方体の動きは全く同一になるが、表示される角度や大きさはクライアント側で個別のものとなる。

ソースコード一式はこちら

gitでソースをクローンしたら、以下のようにnpmでモジュールをインストールして動かすことができる。

$ git clone https://github.com/tokoya/node_three.git  
$ cd node_three  
$ npm install  
$ npm start  

ブラウザからは前回と同じように「Raspberry PiのIPアドレス:3000/users」へアクセス。

three.jsは実行時にサイトからダウンロードする事も可能なようだが、ローカルなネットワーク環境下でも動かせるように/public/javascripts/にthree.min.jsとTrackballControls.jsを予め置いてある。

データの3D処理は完全にブラウザ側で行われるので、Raspberry Piの処理能力とは無関係にリッチな表現ができるのは面白い。かなり高度な表現ができるライブラリも各種存在しているので、Raspberry Piとの組み合わせは表現の幅が広がるのではないかと思う。

広告

Node.js(4) I2C

Webサーバとクライアント(ブラウザ)間でコネクションを維持したまま通信を行うsocket.ioライブラリを、Node.jsで使用してWebアプリを作成するのは思ったよりも簡単に出来た。socket.ioを使用するとブラウザ側からリクエストを送出する事無く、サーバ側から自動的に配信を行うPUSH型のアプリを作成できるので、今回はそれを試してみる。

Raspberry PiのGPIOポートにスイッチを付けてその状態を配信するだけでも良いのだが、シンプル過ぎて面白く無いので以前Pythonで使ってみた加速度センサモジュールを今回も使用した。加速度センサモジュールについてはここを参照。

前回と同じようにexpressフレームワークが生成したコードのpackage.jsonに、必要なライブラリの定義を追加。Raspberry Pi用のI2Cパッケージはいくつか存在するようだが、今回はこれを使用した。

{
  "name": "i2c_acc",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.0",
    "cookie-parser": "~1.3.4",
    "debug": "~2.1.1",
    "ejs": "~2.3.1",
    "express": "~4.12.2",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "socket.io": "^1.3.5",
    "i2c": "~0.2.1"
  }
}

加速度センサからのデータ読み出しと、socket.ioによる通信はアプリケーションのエントリポイント”/bin/www”で、サーバオブジェクト生成後に呼び出されるapp_i2c.jsに記述。

var express = require('express');
var router = express.Router();
var i2c = require('i2c');
var addr = 0x1d;
var wire = new i2c(addr, {device: '/dev/i2c-1'});

function signed(n) {
  return (n < 128) ? n : n - 256; 
}

function app_i2c(server) {
  var io = require('socket.io')(server);
  wire.writeBytes(0x16, [0x05], function(err, res){});
  wire.writeBytes(0x10, [0,0,0,0,0,0], function(err, res){});
  setInterval(function() {
    wire.readBytes(0x06, 3, function(err, res){
      io.sockets.emit('event', {
        x: signed(res[0]),
        y: signed(res[1]),
        z: signed(res[2]),
      });
    });
  }, 100);
}

module.exports = app_i2c;

加速度センサを初期化した後、100msec周期でx,y,z値を読み出し、接続されているすべてのクライアントに対してその値を送信している。
続きを読む »

Node.js(3) socket.io

前回作ったNode.jsのWebアプリは、クライアント(ブラウザ)からのリクエストを受けて結果を返す昔ながらの静的なWebスタイルなので、Raspberry Piをサーバとしてリアルタイムにセンサの値を表示させたいといった用途にはあまり向いていない。
JavaScriptを使ってブラウザから定期的にhttpリクエストを送信する事で、リアルタイム性のあるWebアプリを実現する方法は既に広く使われているが、最近ではWebサーバとブラウザ間で直接コネクションして通信を行うWebSocketの規格が登場し、Node.jsでも簡単に使えるようなので試してみた。

Webアプリの機能としては前回と同じくブラウザからの操作でRaspberry PiのLEDをOn/Offするだけだが、リクエストはsocket.ioで送信してレスポンスもsocket.ioのイベントとして受け取る。これによって複数のブラウザから同時にRaspberry Piに接続した場合、どれかがLEDの状態を変えた時に全てのクライアントがその変化をリアルタイムに知ることができる。

プロジェクトの全コードは前回と同じくGitHubに置いた

順番に見ていこう。まずexpressフレームワークで自動生成したプロジェクトのpackage.jsonに、GPIO操作とscoket.ioのパッケージ定義を追加した。

{
  "name": "led_io",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.0",
    "cookie-parser": "~1.3.4",
    "debug": "~2.1.1",
    "ejs": "~2.3.1",
    "express": "~4.12.2",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "onoff": "~1.0.2",
    "socket.io": "^1.3.5"
  }
}

アプリケーションのエントリポイント”/bin/www”で、サーバオブジェクト生成後にsocket.io用のオブジェクト作成と呼び出しを追加。ここは分けずにwwwに直接コードを追加しても良かったのだが、見通しを良くするためにこうした。

var server = http.createServer(app);
var sock = require('../sock'); // 追加
sock(server); // 追加

socket.io用オブジェクトの処理は、クライアントから接続されてイベントを受信した時、パラメータに従ってLEDをOn/Offしてから、その状態を全てのクライアントに対して送信する。

var io = require('socket.io');  
var gpio = require('onoff').Gpio;
var led = new gpio(17, 'out');

function sock(server) {
  var sock = io.listen(server);
  sock.sockets.on('connection', function(socket) {
    socket.on('event', function(data) {   // クライアントからのイベント受信
      console.log('socket id: [' + socket.id + '] data: ' + data.onoff);
      if (data.onoff == 'on') {
        led.writeSync(1);
        sock.sockets.emit('event', { onoff: 'on' });  // 全てのクライアントへ送信
        // 送信元にだけ送信する場合は
        // socket.emit を使う
        // 送信元以外の全てに送信する場合は
        // socket.broadcast.emit を使う
      }
      if (data.onoff == 'off') {
        led.writeSync(0);
        sock.sockets.emit('event', { onoff: 'off' }); // 全てのクライアントへ送信
      }
    });
    socket.on('disconnect', function() {  // 切断
      console.log('disconnect id: [' + socket.id + ']');
    });
  });
}

module.exports = sock;

コメントにもあるように、サーバからクライアントへの送信は、全てのクライアント、イベントを送信したクライアント、イベントを送信したクライアントを除く全て。に対して行うことができる。
今回は使用しなかったが、クライアントをルームに分けて、同じルームに入っているクライアントにだけ送信する事もできる。
サーバ側のコードとしてはこれで終わり。次はクライアント側を見ていこう。
続きを読む »

Node.js(2) GPIO

Raspberry PiにNode.jsをインストールして、ExpressフレームワークでWebアプリを簡単に作成して動かすことができたが、何もデバイスを制御しない状態ではRaspberry Piを使う意味が無いので、まずはGPIOを制御するモジュールを追加して簡単な制御を行ってみる。

Node.jsのRaspberry Pi用GPIOパッケージは何種類も存在していて、ざっと調べてみた限りでは以下の三種類が良く使われているようだ。

  1. pi-gpio
  2. rpi-gpio
  3. onoff

今回はその三種類の中からonoffを試してみたが、最初に目についたというだけで特に理由はない。他のパッケージでも恐らく同様に使えるはず。

インストールはExpressでプロジェクトのひな型(プロジェクト名はledとする)を作ってからそのディレクトリに移動して

$ express -e led
$ cd led
$ npm install
$ npm install onoff

を実行するか、あるいは生成されたpackage.jsonにパッケージ名”onoff”を追加してから npm install を行えば良い。

{
  "name": "led",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.0",
    "cookie-parser": "~1.3.4",
    "debug": "~2.1.1",
    "ejs": "~2.3.1",
    "express": "~4.12.2",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "onoff": "~1.0.2"
  }
}

このパッケージを使用してGPIO操作を行う場合、ユーザがgpioグループに属していればルート権限が不要なのでデフォルトの「pi」ユーザならそのままで使えるが、新たに作成したユーザでログインしている場合はsudoを付けてNode.jsを起動するか、あるいはそのユーザをgpioグループに属させる必要がある。

$ sudo gpasswd -a ユーザID gpio

GPIO操作のサンプルとして、まずは定番のLED点滅を行ってみる。
GPIOの適当なポートにLEDと電流制限抵抗をつなぎ、ポートに”1″を出力すると点灯、”0″を出力すると消灯する状態になっている場合、ブラウザからの操作でLEDをON/OFFするには/routes/users.jsファイルに以下のようなコードを書く。LEDはGPIO17(ピン番号11)に接続した。

var express = require('express');
var router = express.Router();

var GPIO = require('onoff').Gpio;
var led = new GPIO(17, 'out');

/* GET users listing. */
router.get('/', function(req, res, next) {
  console.log(req.query);
  var onoff = req.query.onoff;
  var msg = '';
  if (onoff == 'on') {
    led.writeSync(1);
    msg = 'LED ON';
  }
  if (onoff == 'off') {
    led.writeSync(0);
    msg = 'LED OFF';
  }
  res.send(msg);
});

module.exports = router;

ブラウザからHTTPのGETでパラメータが送られてきた時、”onoff”の値が”on”ならばLEDを点灯、”off”ならば消灯という動きをするので、本来ならばブラウザで表示するHTMLファイルを作成しなければならないが、動作を試すだけならばGETのパラメータを直接URLに書いて確認できる。

プロジェクトのディレクトリに移動して

$ npm start

でWebアプリを起動した後、サーバが起動して待受け状態になるまで少し待ってから、PCのブラウザで以下のようにアクセスする。

Raspberry PiのIPアドレス:3000/users?onoff=on

スクリーンショット 2015-05-12 10.38.35
全て正しければこれでRaspberry PiのGPIOに接続したLEDが点灯するはず。URLの最後を”onoff=off”に変えれば消灯する。
続きを読む »

Node.js

例年のことだが12月から3月にかけては非常に忙しく(年度末のせい)、Raspberry Piに電源を入れている暇もなかったのだが、GW前にはどうにか落ち着いてきたのでblogを再開。

今まではほとんどPythonを使ってRaspberry Piに接続したセンサからデータを取得したりしていたが、最近は制御系のシステムでもブラウザをUIに使えないか?という話が仕事の案件として割と多く、その関係でJavaScriptをRaspberry Piで試したりしている。

サーバーサイドはPHPでクライアントがJavaScriptというパターンが一般的には多いようだが、異なる言語でシステムを組むのはどうも抵抗があったので、サーバーサイドもJavaScriptで作成できる「Node.js」をRaspberry Piに導入して動かしてみたところ、非常に簡単にWebアプリを構築する事ができた。

Node.jsはapt-getでインストールすると古いバージョンが入ってしまうので、raspbianでは以下のようにDebパッケージからインストールする。

$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb 
$ sudo dpkg -i node_latest_armhf.deb

インストール後にバージョンを確認するとv0.12.1だった

$ node -v
v0.12.1

この状態でもサーバーサイドJavaScriptを動作させる事は可能だが、Webアプリのひな形を自動生成してくれるフレームワーク「express」が非常に便利なので、これもインストールしておく。インストールにはNode.jsに含まれるパッケージ管理ツール「npm」を使用。

$ sudo npm install -g express-generator

npmでパッケージをインストールする時に「-g」オプションを付けると、すべてのプロジェクトで共通のモジュールとしてインストールされる。付けないとプロジェクト毎のフォルダにインストールされるので、同じモジュールでもプロジェクト毎にバージョンが異なるものを使うといった事ができるようだ。

expressでWebアプリのひな形を作成し、起動するには以下のように行う

$ express -e MyWebApp
$ cd MyWebApp
$ npm install
$ npm start

「express -e MyWebApp」でMyWebAppプロジェクトのフォルダが作成され、その中にひな形となるファイル一式が自動生成される。オプションの「-e」はHTMLテンプレートエンジンにEJSを使用するという指定で、何も付けないデフォルトではJADEを使用したひな型になるのだが、JADEは簡潔に書ける代わりに表記法を覚える必要があるので、最初はEJSで始める事をお勧めする。

「npm install」を実行すると生成されたpackage.jsonに記載されたパッケージがインストールされる。
「npm start」はpackage.jsonの「scripts:start」に記載された内容を実行するので、実際には「node ./bin/www」が実行される事になる。
「./bin/www」はサーバオブジェクトを生成して待ち受け状態に入り、ブラウザからアクセスされると「app.js」の内容に従って其々の処理を行うという動きをする。Node.jsのサーバはデフォルトではポート3000を使用するので、ブラウザでRaspberry Piのポート3000にアクセスすれば良い。IPが「192.168.1.12」だとしたら「192.168.1.12:3000」にアクセスする。

Raspberry Piのコンソールに

> node ./bin/www

GET / 200 574.327 ms - 207
GET /stylesheets/style.css 200 222.119 ms - 110
GET /favicon.ico 404 203.292 ms - 1998

のように表示されて、ブラウザに
express
と応答が表示されていればOK。Raspberry Piではサーバの起動に少し時間がかかるので、すぐにアクセスするとエラーになる場合がある。

expressはルートの下に「/users」というページを自動生成しているので、アプリが起動した状態で「192.168.1.12:3000/users」へアクセスすると

respond with a resource

と一行だけ表示されるはず。これは「./routes/users.js」ファイルの

router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

によって表示されているもので、app.jsファイルの

var users = require('./routes/users');
app.use('/users', users);

という二行の定義から呼び出されている。つまり同じようにクラスを作ってapp.jsファイルに追加すれば、Webアプリのページを増やすことができる。

Raspberry PiでWebアプリを動かす場合は、何かデバイスを制御したりセンサの値を取得したりといったコードをこのひな型に追加していく事になるのだが、長くなるのでそれは次回。