Raspberry PiとNode.jsで作る独立稼働モバイルサーバ

Raspberry Piを購入したきっかけ
筆者がRaspberry Piを購入したのは、3,500円程度でLinuxが動くという理由からでした。よく使用するArduino Uno※1が3,000円くらいでマイコンレベルなのに比べると、性能的にはるかに安かったのです。しかし、買った時点では特に何に使おうかは考えていませんでした。とりあえず起動して、安いのにXウィンドウ動いてスゴイな、という印象でした。ところがふとしたことから、次に取り上げるNode.jsが動くらしいという情報を得て、本格的にいじり始めました。
まずはNode.jsをRaspberry Piにインストールして、チャットアプリを作成するところまでを説明していこうと思います。後半ではRaspberry PiでNode.jsを使ったプロトタイピングの例を紹介します。
- ※1 Arduino Uno: プロトタイピングデバイスとも呼ばれる。初心者でも使える小型マイコンボード
Node.jsとは
Node.jsはサーバーサイドJavaScriptとも呼ばれ、サーバ側もクライアント側もJavaScriptで記述できるのが大きな特徴です。またNode.jsは大体の場合、WebSocketの実装であるSocket.IOモジュールと組み合わせて使われ、リアルタイムWebを実現するためのサーバとして利用されるパターンが多いようです。Node.jsのインストールからSocket.IOを使ったチャットアプリの作成までの過程を、順を追って説明していきます。
準備
まずはRaspberry Piに公式のカーネル一式がインストールされて起動していて、リモートログインしている、という前提から始めます。早速Node.jsをインストールするのですが、Node.jsは開発のスピードが速くバージョンがすぐに上がってしまいます。そのため、Node.jsのバージョンを管理するためのマネージャをまずインストールし、実際に使用するバージョンのNode.jsをインストールするようにします。今回はnodebrewというバージョンマネージャを使用します。
1 | pi@raspberry ~ $ sudo apt-get update |
2 | pi@raspberry ~ $ sudo apt-get install vim # エディタとしてvimをインストールしておく(他でもよい) |
3 | pi@raspberry ~ $ curl -L git.io/nodebrew | perl - setup |
.bashrcにパス(export PATH=HOME/.nodebrew/current/bin:PATH)を追加して読み込み直します。
1 | pi@raspberry ~ $ vim .bashrc # エディタで"export PATH=$HOME/.nodebrew/current/bin:$PATH" を追加 |
2 | pi@raspberry ~ $ source .bashrc |
Node.jsのインストール
Node.jsの最新バージョンはv0.11.15(8/12現在)ですが、今回はv0.10.12を使用します。Raspberry Piは、以前はソースを落としてきてセルフビルドに2時間近く掛かっていたのですが、現在は下記のようにバイナリをインストールできるようになっています。
1 | pi@raspberry ~ $ nodebrew install-binary v0.10.12 |
このバージョンを使えるように下記コマンドを使用します。
1 | pi@raspberry ~ $ nodebrew use v0.10.12 |
2 | v0.10.12 |
3 |
4 | current: v0.10.12 |
複数のバージョンをインストールしたい場合は、同じように他のバージョンもインストールできます。使用するバージョンを切り替える場合は、上記コマンドで使用するバージョンを指定して切り替えられます。インストールされているNode.jsのバージョンを調べるには、下記コマンドを使用します。
1 | pi@raspberry ~ $ nodebrew list |
これでNode.jsのインストールは完了です。
expressのインストール
次にNode.jsでよく使われるWebフレームワークのexpressをインストールします。ここでnpmというコマンドを使いますが、これはnodebrewのインストール時に同時にインストールされています。npm : Node Package Manager で、Node.jsに関するインストールその他を管理するモジュールです。通常npmコマンドを使用してインストールすると、カレントディレクトリに展開されます。今回のexpressはカレントディレクトリではなく、-gオプションを付けてグローバルインストールしておきます。
1 | pi@raspberry ~ $ npm install -g express |
expressを使ったサンプルアプリを動かす
では、expressを使ってNode.jsサーバを作って動かしてみましょう。expressを使う時にテンプレートエンジンとして-eオプションでEJSを指定します。
01 | pi@raspberry ~ $ mkdir work # workディレクトリ作成 |
02 | pi@raspberry ~ $ cd work |
03 | pi@raspberry ~/work $ express -e sample |
04 |
05 | create : sample |
06 | create : sample/package.json |
07 | create : sample/app.js |
08 | create : sample/public |
09 | create : sample/public/javascripts |
10 | create : sample/public/images |
11 | create : sample/public/stylesheets |
12 | create : sample/public/stylesheets/style.css |
13 | create : sample/routes |
14 | create : sample/routes/index.js |
15 | create : sample/routes/user.js |
16 | create : sample/views |
17 | create : sample/views/index.ejs |
18 |
19 | install dependencies: |
20 | $ cd sample && npm install |
21 |
22 | run the app: |
23 | $ node app |
出力された指示通りにします
1 | pi@raspberry ~/work $ cd samaple && npm install |
さて、あとは実行するだけです。ifconfigで予めRaspberry PIのIPアドレスを調べておいてください。
1 | pi@raspberry ~/work/sample $ node app.js |
2 | Express server listening on port 3000 |
PCなどのブラウザから"Raspberry PIのIP"である3000ポートにアクセスして、下記の画面が表示されればOKです。これでNode.jsを使ったWebサーバが動作しました。
図1: Express起動画面
Socket.IOのインストール
先ほどのNode.jsのWebサーバを拡張してSocket.IOを使ったリアルタイムなチャットアプリを作成します。Socket.IOは双方向通信用のプロトコルであるWebSocketを、ブラウザに依存せず、違いを吸収するため使うモジュールとここでは覚えておいてください。まずは作ったアプリにSocket.IOのモジュールを追加します。
1 | pi@raspberry ~/work/sample $ npm install socket.io |
現時点ではv0.9.16がインストールされました。
チャットアプリの作成
チャットアプリ作成のため、下記ファイルを作成・修正します(下記コードはここからダウンロードできます)
- app.js
- views/index.ejs
- public/javascripts/chat.js
動作確認
先ほどと同じように実行して、2つ以上のブラウザからアクセスしてみてください。
1 | pi@raspberry ~/work/sample $ node app.js |
これで、テキストを入力してメッセージを送りあうことができます。しかもリアルタイムにやりとりできます。
図2: 2つのブラウザでチャットしているところ
まとめ
最近流行りのNode.jsをRaspberry Pi上で動かしてみました。実際、動いているのは普通のDebian Linuxですから特に難しいことはありません。ちょっと違うのは、このサーバが手元にある小型な機械で動いているところでしょうか。
続いてこのNode.jsをベースとした、Raspberry Piならではのプロトタイピングとして「独立稼働サーバ」を作った例を解説します。また、さらにそれを応用したカーナビゲーションのプロトタイプを紹介したいと思います。
ここまで説明したNode.jsとRaspberry Piの小型持ち運び可能というメリットを活かして、独立稼働型のモバイルサーバを作ってみました。その概要を説明し、Raspberry Piの可能性を考えてみます。
モバイルサーバ化のための準備
まず、モバイルサーバ化して何をするか?を考えます。単にRaspberry Piをモバイルサーバにしてもただのサーバです、今回はここにハードウェアの連携機能を付け加えてみます。Raspberry Piは外部シリアル通信が利用できるので、それを使ってハードウェアと接続できます。今回、外部にセンサーを接続することを考えました。また、独立稼働させるには有線LANではなく無線系のネットワークも必要になりますし、電源もバッテリ駆動とします。今回作るものを整理すると以下のようになります。
- Raspberry Piとハードを連携させる(シリアル通信)
- ネットワークには無線系が必要
- 独立稼働にするためにバッテリ稼働させる
では順に説明していきます。
Raspberry PiでNode.jsを使ったシリアル通信
今回シリアル通信する対象としてArduinoを使いました。PCでもなんでもいいのですが、せっかくなのでLEDを点灯させようと思います。ArduinoはPCと接続するUSBケーブルがUSBシリアルになっていますので、これをそのまま使うことができます。
Node.jsでのシリアル通信には、node-serialportを使うことでRaspberry PiとArduinoをNode.jsサーバを介して通信できるようになります。JavaScriptの知識だけでハードウェア制御できてしまうのでかなり便利です。写真1はArduino上のLEDを、ブラウザで制御できるようにしたものです。ここでは、Node.jsサーバにSocket.IOを組み込むことで、ブラウザの操作でArduino上のLEDをリアルタイムで変化させることができるようになります。
写真1: Raspberry PiからArduinoボード上のLEDを制御
無線系のネットワークを用意する
無線LANでもいいのですが、モバイルサーバなので3Gネットワークを使ってみましょう。今回はUSB通信モジュールを使ってネットワーク接続します。参考にしたのは「Akagawa Multimedia Laboratory」のサイトです。このサイトにもありますが、USB通信モジュールはRaspberry PiのUSB電源供給では足らないようなので、セルフパワーが必要になります。筆者が試してみてもバスパワーではUSB通信モジュールは動きませんでした。
バッテリを用意する
前述の理由もあり、Raspberry Piの電源としてもバッテリが必要なため、セルフパワー対応のUSBハブを購入し、2口のUSB電源供給を持つモバイルバッテリを用意しました。モバイルバッテリが本体より大きくなるというモバイルらしくない仕様になってしまいましたが……
サーバとして稼働させる
さて準備が整ったので、サーバとして構築します。しかしここで問題があります。今までの流れでわかるかもしれませんが、Raspberry Piはサーバとして稼働しているため、サーバ用のURLアドレスがわからないとブラウザなどのクライアントからアクセスできません。通常のXi契約ではグローバルIPアドレスが割り当てられますが、固定アドレスではなく接続の度に変更される可能性があり、サーバ用のURLアドレスとしては使用できません。
そこで今回は、筆者の所属先であるフリービットの仮想IPv6技術Emotion Linkを使用します。この技術は簡単に言えば、IPv6 over IPv4トンネリングを使うことで、機器にIPv6アドレスを割り当ててアクセス可能にする仕組みです。このためにRaspberry Piには弊社のELスタックというソフトウェアを組み込みます。ELスタックはIPv6経由で来たパケットをNode.jsが動作する3000ポートにポートフォワードします。これで3Gネットワークであっても固定のIPv6アドレス経由でアクセスできるようになりました。
ところがまだ課題があります。アクセスする側のクライアントもIPv6でないとIPv6のサーバにアクセスできません。そのため、図3のようにVPS上にリバースプロキシを用意し、IPv6とIPv4の相互変換を行うことで解決します(リバースプロキシにはWebSocketに対応したnginx1.3.13を使用)。
図3: クライアントとサーバのアクセス経路
これでAndroidやiPhoneなどのIPv4しか動作しない機器からも、Raspberry Piにアクセス可能になりました。ついに独立稼働モバイルサーバの完成です。あなたがRaspberry Piをどこへ持って行こうとも、VPSに割り当てたURL経由でモバイルサーバへアクセスすることが可能です。
ハードウェアを接続して稼働させた状態が写真2になります。このシステムは一つの可能性を示しています。通常はクライアントがセンサー情報などをサーバへ送信するのですが、このシステムではサーバであるRaspberry Piにセンサーを接続することで、接続してきたクライアントへセンサー情報をpush配信する仕組みが実現できるというわけです。
写真2: Raspberry Piをバッテリ駆動にしてモバイルサーバに
応用編:サーバpush型のカーナビのプロトタイプを作ってみた
これまでの経緯を踏まえ、プロトタイプを作成してみました。せっかくのモバイルサーバですから、走るサーバ「push型配信のカーナビゲーションシステム」をプロトタイピングしてみました。構成は以下のようになります。
図4: カーナビプロトタイプの全体システム構成概要
前述で説明したシリアル通信の部分に、USBタイプのGPSモジュールを接続するようにします。これで、GPS情報をRaspberry Piに取り込んで位置情報を取得できるようになります。サーバとしては取得した位置情報をGoogle Maps上に表示するだけで、アクセスしてきたブラウザ等では自車の位置が表示されるようになります。サーバアプリはGPSからの位置情報を受信すると、そのままクライアントに対してJSON形式の位置データをpush送信するようにしています。500msくらいの間隔で1回の更新が行われます。クライアント側では、位置情報が更新される際に前の位置からラインを引くようにしておき、軌跡が表示されるようにします。
せっかくなのでAndroidアプリも作ってみた
基本的にはAndroidやiPhoneでもChromeなどのブラウザからサーバのURLにアクセスすることで位置が表示されますが、せっかくなのでAndroidアプリを作成してみました。著者が作成したWebSocket用クライアントを利用して改良しました。サーバからJSON形式の位置情報がpushで送信されて来るので、端末のGPSを使うことなくMaps上に位置を表示するだけの非常に簡単なアプリになります。電池の消費量も抑えられますね。完成したプロトタイプを車に乗せるとこんな感じになりました(写真3)。GPSはUSBを延長してダッシュボードの上に貼り付けています。Android端末のケーブルはシガーソケットからの電源供給用です。
写真3: 車載サーバとしての走行試験環境
実走行試験をしてみた結果
さて、準備が整ったので実走行試験してみました。AndroidアプリとPCブラウザでのスクリーンショットと、実走行試験を動画撮影もしてみました。
図5: Androidアプリでの軌跡表示
図6: PCブラウザでの軌跡表示
実際に運転していても比較的安定して更新されますが、さすがに少しの遅延はあります。LTE(Xi)ではあまり接続できず3G通信(FOMA)となっていたようです。走行試験中は2回ほどネットワークが切断されたのか、サーバの反応が無くなってしまいました(リカバリは入れていません)。また、走行試験中にTwitterなどでURLを公開し、第3者にサーバにアクセスしてもらい、どこからでもリアルタイムに位置がバレる(笑)ことも確認できました。
このシステムのメリットは、以下のようなものが考えられます。
- あくまでサーバが位置情報をpushするので、クライアントアプリとしてのマッシュアップの要素が大きい
- 位置をキックに周辺情報やルート探索なども実装できる。
- Android端末の場合はGPSを使用しないので電池消費量を抑えられる
- 車のように何人かで移動する時でも情報やコンテンツのシェアが可能
このシステムを利用すると、車1台1台にURLが付くという面白いシステムができます。車載サーバとして発展させれば、様々な車両データを記録保存したり、配信したりできるようになります。
まとめ
記事の集大成として、Raspberry Piを使ったモバイルサーバを構築してみました。またそれを使った製品プロトタイプの作成を行いました。
いわゆる通常のPCレベルの性能が小型化することで、汎用技術を使った応用が比較的簡単に行えます。また今回の要素技術にNode.jsがありますが、これはHTML5の広義規格であるWebScoketを用いたpushサーバの実装になります。HTML5というとブラウザ依存がなくなり、Webの世界が広がるイメージがありますが、WebSocketのようなプロトコルを取り出して考えると、組込み機器などへの応用も幅広く考えることができます。特に今回のシステムは、クライアントではなく、サーバにGPSを接続し、サーバ自体が移動体センサーサーバになることで、情報をpush配信する。というところが面白いところです。その他にも3G通信網でのIPv6によるネットワーク・リーチャビリティを確保することで、M2Mとしての応用も考えられます。
クラウドが当たり前になりサーバがデータセンターにある時代から、手元に乗るクラウドサーバが実現できるようになりました。HTML5時代のシステムアーキテクチャを描き直すことで、Webだけではなくデバイスなどの機器も含めた広がりを考えてみることもできます。Raspberry Piはその可能性を十分に示してくれる魅力的なデバイスと言っていいでしょう。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- expressで開発したWebアプリをeXcaleで動かす
- Socket.IOを使ってNode.jsでリアルタイムWebアプリを開発する
- リアルタイム通信で活用!注目の技術「Node.js」とは【初心者向け】
- 簡単なリアルタイムチャットアプリを作成する
- 2017年に見ておきたい12のJavaScriptライブラリ
- クロスドキュメントメッセージングやWebSocketを使ってみる
- Arduino vs. Raspberry Pi:あなたにぴったりのDIYプラットフォームはどっち?
- 「GitHub」にブランチ保護、Dependabot、Secret Scanningを設定してみよう
- 123d CircuitsとArduino実機で電子工作(1)
- ミニ四駆の遠隔操作を実現しよう!- Arduino Pro Mini組み立て編