2014年7月23日水曜日

Socket.IOとNode.js、Node-serialport、それにArduinoを加えてスマホから家電のスイッチを制御する(3)

こんにちは。前回までの記事ではNode.js、Socket.IO、Expressを使用してWebアプリケーションの開発方法を学んできました。ここからは、ブラウザを通して実世界とのインタラクションをデザインしていきます。具体的にはサーバPCにArduinoを接続することでさまざまなセンサやアクチュエータを動かしてブラウザでの操作を実世界に作用させていきます。Node.jsでSerial通信を行うためにNode-Serialportというパッケージを用います。今回の記事ではNode-SerialPortのインストールを行い、Arduinoとシリアル通信を行って、

  1. Arduinoからの情報をうけとる。
  2. Arduinoへ命令を出す。
という2つの動作を同時に実現したいと思います。

まずは、Node-SerialPortのインストールです。

これまでにやってきた方法と同じようにnpmを使用してインストールを行います。そのコマンドは、
npm install --save serialport
となっています。

続いては、Arduinoのプログラムを書きます。

ここで書くプログラムは非常に単純なシリアル通信のプログラムとなっています。内容としては、擬似乱数を生成しシリアル通信でindex.jsに送信、index.jsはクライアントとなるindex.htmlに受信した数値を送信し表示します。また、同時にindex.htmlに用意されたButton要素がクリックされたらindex.jsにイベントを送信し、index.jsからシリアル通信を利用してArduinoに命令を送信(今回は'1'を送信)し、命令を受信したArduinoでDigitalPinのHIGHとLOWを切り替えます。こうするとブラウザを経由してLチカ(LEDをチカチカさせること)ができるようになります。今回はLEDをソリッドステート・リレーに置き換えて、AC100V電源のON/OFFを切り替えます。

以下ソース
char incomingByte;
boolean sw = false;

void setup(){
    Serial.begin(57600);
    pinMode(4,OUTPUT);
}

void loop(){
        int rnd = random(1,100);
        delay(500);
        Serial.println(rnd);
        if(Serial.available() > 0){
            incomingByte = Serial.read();
            if(incomingByte == '1'){
                sw = !sw;
                if(sw == true){
                    digitalWrite(4,HIGH);
                }else{
                    digitalWrite(4,LOW);
                }
            }
        }
}
先ほど説明したように擬似乱数を生成してシリアル通信で送信し、命令があったらDigitalPinのHIGH/LOWを切り替えるというシンプルなプログラムになっています。DigitalPinが4番ピンを指定している理由は特にありません。何番でも大丈夫です。Arduinoの4番ピンにLEDのアノード(足が長い方)、GNDにカソードを刺します。電流制限抵抗とかはとりあえず気にしません。

続いてはChatアプリを基にシリアル通信を行うアプリを作製します。

でははじめにソースを示します。

index.js
ar app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var SerialPort = require('serialport').SerialPort;
var serial = new SerialPort('/dev/tty.usbmodemfd121',{
    baudrate:57600
});

app.get('/',function(req,res){
    res.sendfile('index.html');
});

serial.on('open',function(){
    console.log('open');
});

serial.on('data',function(data){
    io.emit('recvmsg',data.toString());
});

io.on('connection',function(socket){
    socket.on('message',function(msg){
        serial.write(msg,function(err,results){
        });
    });
});

http.listen(3000,function(){
    console.log('listen 3000 port');
});
新しく出てきたNode-SerialPortの部分は、
//ここと
var SerialPort = require('serialport').SerialPort;
var serial = new SerialPort('/dev/tty.usbmodemfd121',{
    baudrate:57600
});
//ここの部分です
serial.on('open',function(){
    console.log('open');
});

serial.on('data',function(data){
    io.emit('recvmsg',data.toString());
});

io.on('connection',function(socket){
    socket.on('sendmsg',function(msg){
        serial.write(msg,function(err,results){
        });
    });
});
上のほうではパッケージを使う宣言を行い、serialを作製しています。一番目の'/dev/tty.usbmodemfd121'という部分は、シリアルポートを特定する部分です。Macなのでこういった感じになっていますが、Windowsでは'COM3'などのようになるかもしれません。また、Raspberry Piに移植する際にもこの部分の変更が必要になります。
下の方では、Arduinoからのデータを受信し、index.htmlにrecvmsgというイベント名で文字列データとして送信する部分io.emit('recvmsg',data.toString());と、htmlからsendmsgイベントを受け取り、Arduinoに命令(msg)を送る部分serial.write(msg,function(err,results){});から成っています。とてもシンプルです。

index.html
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title>arduino control</title>
  <style>
   article, aside, dialog, figure, footer, header,
   hgroup, menu, nav, section { display: block; }
  </style>
 </head>
 <body>
            <h1>hello</h1>
            <button>SW1</button>
            <script src="/socket.io/socket.io.js"></script>
            <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
            <script>
                var socket = io();
                $('button').click(function(){
                    socket.emit('sendmsg','1');
                });
                socket.on('recvmsg',function(data){
                    $('h1').text(data);
                });
            </script>
 </body>
</html>
このHTMLは、h1要素とbutton要素の2つの要素のみで構成されています。先ほどのindex.jsでArduinoから受け取ったデータをrecvmsgイベントを通してh1要素に表示し、button要素がクリックされたら、sendmsgイベントを通してindex.jsに'1'を送信します。この'1'は最終的にindex.jsからArduinoに送信されます。

図に書くと
となります。これで、Arduinoから情報を受信しつつ、Arduinoに命令を送ることができる双方向のWebアプリケーションが完成しました。秋月電子のソリッドステート・リレーと組み合わせた例が以下になります。
この電球は家庭用AC100V電源につながっています。そのため扇風機など他の家電を動かすこともできます。もちろんソリッドステート・リレーだけでなく、サーボモータや赤外線LEDなどなどArduinoで動かせるものはなんでも使うことができますし、ブラウザに表示する情報も温度湿度や照度、果ては空気清浄度までArduinoにつけるセンサやアイデアによっては無限大です。カメラがiPhoneしかない関係上、ブラウザはMacBookのものを使っていますが、もちろんiPhoneから操作することも可能です。

さて、次回の記事ではこのシステムをRapsberry Piに移植し、自動起動化することでよりコンパクトで便利なシステムにまとめていきます。

2014年7月21日月曜日

Socket.IOとNode.js、Node-serialport、それにArduinoを加えてスマホから家電のスイッチを制御する(2.5)

こんにちは。前回の記事ではsocket.ioの公式チュートリアルであるchatアプリを作成しました。今回はnode-serialportを追加してブラウザからArduinoを操作するところまでを行いたいと思います。前回の記事でソースについて解説することを忘れていたので、軽く説明をしてから本題に入ります。

*意外と解説が長くなったのでArduinoを操作する部分は次回の記事で書くことにしました。

まず、index.jsの解説を行います。

ソースは、
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
 
app.get('/', function(req,res){
    res.sendfile('index.html');
});
io.on('connection',function(socket){
    socket.on('chat message', function(msg){
        io.emit('chat message',msg);
    });
});
http.listen(3000,function(){
    console.log('listenning on localhost:3000');
});
となっていました。上から順番に説明してきます。
まず、
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
の部分では使用するパッケージの読み込みをしています。おまじないと思っても使うことはできます。
次に、
app.get('/', function(req,res){
    res.sendfile('index.html');
});
の部分では同ディレクトリのindex.htmlを読み込みます。
また、
io.on('connection',function(socket){
    socket.on('chat message', function(msg){
        io.emit('chat message',msg);
    });
});
の部分ではwebサイト(localhost:3000)に接続したことを検知した際の処理を記述しています。ここでは接続状態であるときにindex.html側のスクリプトから'chat message'を受け取ったら、その内容(msg)をindex.htmlに対して返す。というような内容になっています。

続いてindex.htmlについて

index.htmlのhtmlの要素としては2つしかありません。まずひとつはチャットの表示部分であるList要素、それから発言BOXとしてのForm要素です。
index.htmlのソースを見てみましょう。
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
<script src="/socket.io/socket.io.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
    <input id="m" autocomplete="off"/><button id="btn">Send</button>
</form>
<script>
var socket = io();
$('form').submit(function(){
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
        });
socket.on('chat message',function(msg){
        $('#messages').append($('<li>').text(msg));
        });
</script>
</body>
</html>
まず重要なのが、
<script src="/socket.io/socket.io.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
の部分です。外部ファイルとしてsocketio.jsとjquery.min.jsを読み込んでいます。jqueryはhtmlの要素を楽に操作するために使用しています。
次に重要なのは
<script>
var socket = io();
$('form').submit(function(){
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
        });
socket.on('chat message',function(msg){
        $('#messages').append($('<li>').text(msg));
        });
</script>
の部分です。前半ではform要素の中でsumbitアクションが起きた時の動作を決めています。この書き方はjqueryのものなのですが、#が着くとidを指定、何もつかない場合はその要素を全て指定という解釈をしています。必要になったらググります。後半の部分では、index.jsからのchat messageを検知して、msgの内容をlist要素に追加するというようになっています。

理解するために図を書くと…
という感じになっています。
意外と長くなってしまったので今回の記事は2.5回として、Arduinoとの通信は次回の記事にしたいと思います。

※追記2014/07/2123:19
画像の紫の部分がindex.htmlとなっていますが正しくはindex.jsです。

Socket.IOとNode.js、Node-serialport、それにArduinoを加えてスマホから家電のスイッチを制御する(2)

こんにちわ。前回の記事ではNode.jsをインストールするところまでをおこないました。この記事ではnpm(node package manager)を利用してSocket.IOをインストールしてチュートリアルであるchatアプリを作製します。

Socket.IOのインストール

Socket.IOをインストールするためにはnpmを用います。Macbookの環境ではNode.jsを入れた際に同時にnpmもインストールされていました。ない場合は個別にインストールが必要です。コマンドは、
npm install --save socket.io
です。これでNode.jsのパッケージをインストールする方法がわかるようになりました。

chatアプリの作製

それではSocket.IOの公式チュートリアルに則ってchatアプリを作っていきます。これを通してSocket.IOの使い方を学びます。公式チュートリアルはhttp://socket.io/get-started/chat/でみることができます。それによると、まずpackage.jsonを作製する必要があります。新しくチャット用のディレクトリchatを作製して移動します。
mkdir chat && cd chat

package.jsonの作製
 これはプロジェクトについて記述するマニフェストファイルです。これをchatディレクトに入れておきます。中身には名前やバージョンを記述します。チュートリアルなので適当に記述しておきます。
{
  "name": "socket-chat-example",
  "version": "0.0.1",
  "description": "it is first socket.io sample",
  "dependencies": {}
}
のように書いておきましょう。dependenciesの部分には追加しているpackageの情報を記述しますが、まだなにも入れていないので空になっています。

expressとsocket.ioのインストール
 package.jsonを記述したら使用するパッケージをインストールしていきます。まずexpressをインストールします。expressはnodeのwebフレームワーク。だそうです。詳しいことはよくわかっていませんが、ものすごい機能があるイメージです。続けてSocket.IOもインストールします。
npm install --save express
npm install --save socket.io
saveオプションをつける意味としては、package.jsonのdependenciesに自動的にパッケージ名とバージョンを記述してくれるということがあります。chatディレクトリをみると、node_modulesというディレクトリができているのがわかると思います。これでexpressとsocket.ioのインストールが完了です。

chatアプリの記述
 ここまでで環境が整いましたのでchatアプリを記述していきます。作成するファイルはindex.jsとindex.htmlになります。まずソースを載せます。

index.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req,res){
    res.sendfile('index.html');
});
io.on('connection',function(socket){
    socket.on('chat message', function(msg){
        io.emit('chat message',msg);
    });
});
http.listen(3000,function(){
    console.log('listenning on localhost:3000');
});

index.html

<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
<script src="/socket.io/socket.io.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
    <input id="m" autocomplete="off"/><button id="btn">Send</button>
</form>
<script>
var socket = io();
$('form').submit(function(){
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
        });
socket.on('chat message',function(msg){
        $('#messages').append($('<li>').text(msg));
        });
</script>
</body>
</html>

これでチャットアプリが完成しました。これを実行するためには
node index.js
とやれば良いです。
動作の確認のためには複数のブラウザ(例えばノートパソコンとスマホ)からmacbookのipアドレス+3000ポートにアクセスします。例としては
http://192.168.1.2:3000/
のように入力すれば良いです。ipアドレスはifconfigを使用して調べます。
すると以下のようなチャットアプリが表示/動作します。
やったね!nodeのアプリを終了する際にはCtrl+cを押せば大丈夫です。

次回はchatアプリで学んだ方法を活かしてブラウザのボタンを押すとArduinoにシリアル通信を行い、Arduinoからの情報をシリアル通信で受信してブラウザに表示するアプリを作成します。

2014年7月20日日曜日

Socket.IOとNode.js、Node-serialport、それにArduinoを加えてスマホから家電のスイッチを制御する(1)

こんにちわ。このシリーズではNode.jsとExpress、Socket.IO、Node-serialportを使ってブラウザからArduinoからのシリアル通信を受け取ったり、ブラウザからArduinoへ制御コマンドをシリアル通信で送信してArduinoをコントールしたりします。最後にはRaspberry Piに移植して書いたプログラムをデーモン化することで、常にプログラムを動かし続け、ブラウザからAC電源のONOFFを制御するシステムを構築します。
 この記事では、nodebrewを利用したNode.jsのインストールについて記述します。

こんなのを作ることができます。

Node.jsのインストール
 Homebrewというパッケージ管理ソフトを使用してNodebrewをインストールします。なおapt-getやMacportsでもいいはずなので、そこは読み替えてください。Nodebrewはnodeのバージョン管理ソフトです。これをつかってNodeをインストールします。
 Homebrewでのインストールコマンドは、
(sudo) brew update
(sudo) brew install nodebrew
となっています。
パスの設定が必要になるので、.bashrcや.zshrcに
export "PATH=$HOME/.nodebrew/current/bin:$PATH"
と書き足しておきます。どこでも大丈夫だと思います。先頭でも、末尾でも。
インストールが無事終了していれば、
nodebrew help
と端末に入力するとnodebrewの使い方が表示されます。
nodebrew 0.7.4

Usage:
    nodebrew help                         Show this message
    nodebrew install             Download and install a  (compile from source)
    nodebrew install-binary      Download and install a  (binary file)
    nodebrew uninstall           Uninstall a version
    nodebrew use                 Use 
    nodebrew list                         List installed versions
    nodebrew ls                           Alias for `list`
    nodebrew ls-remote                    List remote versions
    nodebrew ls-all                       List remote and installed versions
    nodebrew alias          Set alias to version
    nodebrew unalias                 Remove alias
    nodebrew clean  | all        Remove source file
    nodebrew selfupdate                   Update nodebrew
    nodebrew migrate-package     Install global NPM packages contained in  to current version
    nodebrew exec  --   Execute  specified 

Example:
    nodebrew install v0.10.22     Install a specific version number
    nodebrew use v0.10.22         Use a specific version number
では、nodebrewをつかってnodeをインストールします。helpを参照するとインストールに使うコマンドは
nodebrew install 
or
nodebrew install-binary 
となっていることがわかります。僕は楽をしたかったのでinstall-binaryを選択しました。また、versionはなんとなくv0.10.26を選択。なので、インストールコマンドは
nodebrew install-binary v0.10.26
となります。次にどのバージョンを使用するかnodebrewに伝えます。
nodebrew use v0.10.26
そして、確認のために
nodebrew list
とすると使用しているNoad.jsのバージョンが表示されます。
nodebrew list
v0.10.26

current: v0.10.26
念のために、nodeコマンドを使用してnodeが使用できるようになったか確認します。
kiitani> node -v
v0.10.26
良さそうです。

これでNode.jsのインストールが完了です。
次の記事ではSocket.IOをインストールして公式チュートリアルであるchatアプリを作製することでSocket.IOの使い方を勉強します。


2014年7月6日日曜日

Raspberry Piを買って初期設定をする



すっごい久しぶりに書きます。
大学院生になってしまいました。

今日は近くの秋葉原でRaspberry Piを買ってきたので、セットアップを行いました。
忘備録を兼ねて簡単にまとめておきます。

  1. 購入すべきものと購入場所
  2. OSのインストール
  3. 初期設定
 ローカルホストとしてのPCはOSX 10.9.2 marvericksで端末にはiTerm2を使っています。VNCクライアントはFinderの機能を使います。Windowsの方はTeraTerm等でSSHを行うことができます。

1.購入すべきものと購入場所
 まずはRaspberry Piです。これがなくては始まりませんね?TypeBを買いましょう。秋葉原で現地調達するとなると、僕が確認したのはマルツと千石電商本館2Fです。マルツでは4700円+税、千石では4720円だったような気がします。今回は千石で買いました。それにしても千石電商本館2Fは色々センサやらモータも売っていてすごい楽しい。ちなみにRSオンラインから購入すれば3900円+送料です。今すぐ欲しい!休日にRaspiで遊びたいんだ!って人以外はネットで買ったほうが安いです。

 次に周辺機器です。
  • Raspberry Piの電源としてUSB(microB)充電器5V1Aのもの。
  • ストレージとしてClass10/8GB以上のSDカード。


  • ディスプレイ出力するためのHDMIケーブル。
  • 無線LANドングル もしくは LANケーブル。


  • あとは、持っていなければUSBキーボード。
これらは全てヨドバシカメラで購入。今からするとネットで買えばもっと予算が抑えられた気がします。注意点としては、Raspberry PiはSDカードとの相性があるので、http://elinux.org/RPi_SD_cardsを見て確認するといいかもしれません。

▲高専時代に買ったのと違って箱を開けたらボードでケースっぽいのはなかった。


2.OSのインストール
 Rapsberry PIのOSはさまざまなものがあり、NOOBSというシステムをつかってOS複数入れて切り替えて使うこともできますが今回は標準的なRASPBIANをインストールします。OSはhttp://www.raspberrypi.org/downloads/からダウンロードすることができます。僕はターミナルのddコマンドをつかってSDカードにOSのイメージを書き込みました。

 具体的な方法はhttp://www.myu.ac.jp/~xkozima/lab/raspTutorial1.htmlでとても詳しく記述されています。巨人の肩の上に乗っちゃいましょう。最近では、専用のソフトを使用するOSのインストール方法もあるようです。http://elinux.org/RPi_Easy_SD_Card_Setupで詳しく確認できます。また、それも不安だという人は、OS入りのSDカードを購入することもできます。割高ですが。

3.初期設定
 さまざまなサイトで初期設定について書かれているので、今回は自分がやったことをリストアップします。一度目に起動した時に出てくるあの青い設定画面はsudo raspi-configで再び出すことができます。

  • Expand File System
これを実行しないと、パーティションが小さいままでSDカードの容量がもったいないです。

  • Change User Password
セキュリティのためにデフォルトから変えましょう。ちなみにデフォルトはraspberryとなっています。

  • Internationalization Options
言語設定、地域に合わせた時刻設定、キーボードの種類の変更を行います。この時、言語設定でja_JP.UTF8を選択しておきましょう。この時、チェックを入れるためにはスペースキーを押します。またja_JP.UTF8を優先させることで、デスクトップを表示したとき日本語表示されます。時刻はAsiaからTokyoを選びます。

  • rootのパスワードの変更
デフォルトではrootにパスワードがかかっていません。コマンドは、

sudo passwd root

です。

  • 無線LANの設定
無線LANの設定はhttp://openrtm.org/openrtm/ja/content/raspberrypi_initial_settingを参考にすると良いです。


  • iptablesの設定
ファイアウォールを設定します。http://wordpress.zenmai.org/2013/09/29/raspberry-pi-9-2/の方の設定を参考に設定しています。このくらいを行っておけば最低限セキュリティを考えているといえるのでは無いでしょうか。Raspberry Piを踏み台にして、家のパソコンがいたずらされたらい屋ですからね…。



 えー。最後はオススメのサイトを紹介しまくるという投げやりな感じになってしまいましたが、次回はRaspberry Piに直接キーボードやモニターを刺さずに遠隔操作できるSSHやVCNについて書きたいと考えています。とりあえずググればできるよってことで!