ChromeのPackaged AppでArduinoとシリアル通信

この記事はIoTアドベントカレンダー2014 1日目の記事です。

 

ChromeのPackaged AppでArduinoとシリアル通信をする方法を書きます。

Arduino/PC間でシリアル通信

ArduinoとPC間でシリアル通信をする方法として、
node.jsやRuby等使ってコンソールベースのプログラムを書いたり、
Flash、Processing等で作る方法がありますが、
去年辺りのChromeのバージョンアップに伴い、
ChromeのPackaged Appでシリアル通信ができるようになりました。

高速プロトタイピング

HTML/CSS、JSの知識でプログラムが組めるので、Webエンジニアにはとっかかりやすくなったのではないかと思います。
また、データ受信処理とGUIプログラムを同時に組めるのでプロトタイピングを作るのにわりかし最適じゃないかと思ってます。

先週末開かれたMFT2014に出展をしていたのですが、出店中に別の1つプロトタイプができてしまいました。

Chrome Packaged App

Chrome Packaged AppとはHTML/CSS/JSで書くWebアプリで、ネイティブアプリのようにふるまうことができます。
似たようなものにnode-webkitなんかがあります。

作り方はこのあたりを参照。

http://iti.hatenablog.jp/entry/2013/10/10/115550

サンプル

適当にサンプルを作ってみます。
今回は1秒毎にArduinoから適当な文字列が送られ、
Chrome側ではなにかしら受信したら画面上のカウンターをインクリメントする仕組みにしたいと思います。

環境はこちら

Google Chrome 39.0.2171.65 (Official Build)
Mac OS X 10.10.1

Arduino側Firmware

とりあえず適当な文字列をシリアルで送る処理をArduinoに書き込みます。

#define BAUDRATE 9600

void setup(){
    Serial.begin(BAUDRATE);
}

void loop() {
   Serial.println("ABCDE");
   delay(1000);
}

これだけ。
1秒間隔で文字列”ABCDE”を送ります。

Chrome Packaged Appでシリアル通信する

Packaged Appでシリアルのデータ受信を行います。
まずは通信をするためのポートを特定する必要があります。
今回はUSBでArduinoと接続している想定でいきます。
ArduinoIDEを開いて、ツールのシリアルポートを見て/dev/tty.usbなんちゃらと書いてあるのがポートです。

まずはchrome.serial.connectメソッドで接続をします。

chrome.serial.connect(port_name, {bitrate: bitrate}, function(info) {
    console.log(info);
});

port_nameは先ほど調べたUSBのポート、bitrateはfirmwareで指定した9600を指定しています。
接続が成功するとコンソールに接続情報が表示されるはずです。

次にシリアルで受信したデータを表示するコールバックの登録を行います。

chrome.serial.onReceive.addListener(function(res) {
    console.log(res.data);
});

この登録はchrome.serial.connectが実行される前に処理しておきましょう。
受信したデータres.dataはArrayBufferという型になっており、
文字列を受信した場合そのままでは扱いがむずいので、型の変換を行います。
以下のコードで、文字コードが整数値の配列型に変換されます。

var data = new Uint8Array(res.data);

こいつを一文字ずつ文字列に戻してやります。

var buffer = '';
for(i=0;i<data.length;i++) {
    buffer += String.fromCharCode(data[i]);
}

これで文字列に戻りました。

ただし、一回で受信するデータは、Arduino側から送信されたデータすべてではなく断片的に送られてきます。
そのためデータの終わり(改行)をこちらで検知して、一回のデータ送信を制御してやらんといけません。
それが以下のコード。

if(buffer.indexOf("\r\n") != -1) {
    tmp = buffer.split("\r\n");
    text_data = tmp[0];
    buffer = tmp[1];
    console.log(text_data);
}

受信の度にデータをBufferに保存、改行が入ってたら1回のデータとして検知し、その後の処理に続けていきます。
改行が入っていなければ再度受信を続けます。

全体のコードは以下の感じ。

(function() {
    var port_name = '/dev/tty.usbmodem1411',
        bitrate = 9600,
        buffer = '',
        $cnt = $('#cnt'), cnt = 0;

    $('#btnConnect').click(function() {
        // データ受信
        chrome.serial.onReceive.addListener(function(res) {
            var data = new Uint8Array(res.data), i,
                text_data, tmp;

            for(i=0;i<data.length;i++) {
                buffer += String.fromCharCode(data[i]);
            }

            if(buffer.indexOf("\r\n") != -1) {
                tmp = buffer.split("\r\n");
                text_data = tmp[0];
                buffer = tmp[1];
                console.log(text_data);
                $cnt.html(++cnt);
            }
        });

        // 接続
        chrome.serial.connect(port_name, {bitrate: bitrate}, function(info) {
            console.log(info);
        });
    });

})();

1秒ごとにコンソールに文字列が、
そして画面上のカウンターがインクリメントされるはず。

ポクポクカウンター

私事で恐縮ですが、先週末のMakerFaireTokyo2014で展示したポクポクカウンターという作品です。

https://github.com/okame/mokugyo_mft

その名の通り、木魚を叩くとPackagedApp内画面に表示されたカウンターがインクリメントされていく、だけです。

Arduinoでマイクの音量を計測し、打撃の計測を行い、シリアル通信でChromeへ送信しています。


Post Navigation