23 2月

Node.js with Arduino


  • Draft
  • 作成日:2013年2月23日
  • 作成者:AONO Masayuki<msyaono(at)rockos.co.jp>

本書はArduinoを使ってnode.jsと連携するまでの記録です。

1 導入編

ハードウェア構成

ここでは、Arduinoをネットワークに繋いで照度センサの値をnode.jsアプリに送るために必要な最小構成のハードウェアを準備する。

名称 メーカ(購入先) 数量 単価 備考
ARDUINO Uno R3 Amazon 1 2,520
イーサネットシールド for Arduino (micro SD, Wiznet W5100) Amazon 1 1,700 MacAddr 90-A2-DA-0D-D1-A3
ブレッドボード Amazon 1
Cdsセル、抵抗、ジャンパ線 Amazon 一式
USBケーブル(A-B) Amazon 1

setup&config

  1. Arduino IDEのMac版をダウンロード

  2. ArduinoとMacをUSBケーブルで接続

  3. IDEを立ち上げてツール->シリアルポートから/dev/tty.usbmodemfd121を選択する。

動作確認

LEDブリンクサンプル

  1. ファイル->スケッチの例->01.Basics->Blinkを選択する。
  2. サンプルソースコードがIDE上に表示されるので、コマンドキー⌘+Rでコンパイルする。
  3. ⌘+UでArduinoに書き込む。
  4. バイナリが正常に転送されるとプログラムが走り、LEDが1秒周期でON/OFFする。

Webserverサンプル

  1. ファイル->スケッチの例->Ethernet->WebServerを選択する。
  2. MACアドレスとIPアドレスを書き換える。

    byte mac[] = { 
    0x90, 0xA2, 0xDA, 0x0D, 0xD1, 0xA3 };
    IPAddress ip(192,168,50, 177);
    
    
  3. ⌘+Rでコンパイル、⌘+UでArduinoに書き込む。
  4. 同じセグメントからhttp://192,168.50.177にアクセスすると、アナログ値が表示される。

sample source

/*
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0D, 0xD1, 0xA3 };
IPAddress ip(192,168,50, 177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
                    // add a meta refresh tag, so the browser pulls again every 5 seconds:
          client.println("<meta http-equiv=\"refresh\" content=\"5\">");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");       
          }
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Websocketのサンプル

ArduinoにCdsセルを接続し、測定値を生でNode.jsアプリケーションに送信するサンプル。

  1. Githubで公開されているWebsocketclientライブラリ をZipでダウンロードする。
  2. 以下のフォルダーにコピーする。
     # mv ~/Downloads/ArduinoWebsocketClient-master /Applications/Arduino.app/Contents/Resources/Java/libraries/
    
    
  3. ディレクトリ名に’-‘がつくとArduinoIDEにおこられるので、名前を変更する。
    # mv ArduinoWebsocketClient-master Websocket    
    
  4. ArduinoIDEを起動し、スケッチ->ライブラリを使用->Websocketを選択する。

  5. Arduino側はsocketクライアントとしてプログラムを作成する。

    #include "Arduino.h"
    
    #include <WebSocketClient.h>
    #include <SPI.h>
    #include <Ethernet.h>
    
    // Enter a MAC address and IP address for your controller below.
    // The IP address will be dependent on your local network:
    byte mac[] = { 
    0x90, 0xA2, 0xDA, 0x0D, 0xD1, 0xA3 };
    IPAddress ip(192,168,50, 177);
    
    /* socket.io server */
    char SERVER[] = "192.168.0.150";
    byte PORT = 3011;
    WebSocketClient client;
    
    
    // Initialize the Ethernet server library
    // with the IP address and port you want to use 
    
    void setup() {
    
    
      // Open serial communications and wait for port to open:
      Serial.begin(9600);
       while (!Serial) {
        ; // wait for serial port to connect. Needed for Leonardo only
      }
      // start the Ethernet connection and the server:
      Ethernet.begin(mac, ip);
    
      Serial.print("Debug: Setup");
      delay(1000);
    
      if(client.connect(SERVER, "/socket.io/1/websocket/", 3011)){
        client.setDataArrivedDelegate(dataArrived);
        delay(1000);
      } else { 
        while(1){}
      }
    
    }
    
    void dataArrived(WebSocketClient client, String data) {
      Serial.println("Data Arrived: "+data);
    }
    
    /*
     * main loop
     */
    void loop() {
    
      client.monitor();
      /* Read value of Cds cell*/
      int sensorReading = analogRead(0);
    
      /* send a message */
      String message = "{";
      message += "\"CDS_A0\":";
      message += sensorReading;
      message += "}";
    
      client.send(message);
      delay(1000);
    }
    
    
  6. Node.jsで動くSocketサーバのプログラムを以下に示す。
    var HOST = '127.0.0.1';
    var PORT = 3011;
    
    function log(objs) {
        var d = new Date,
            fmtDate = '',
            month;
        var msg = {};
        month = d.getMonth() + 1;
    
        fmtDate = d.getFullYear() + '/' + month + '/' +     d.getDate() +
            ' ' + d.getHours() + ':' + d.getMinutes() + ':' +
            d.getSeconds() + ':' + d.getMilliseconds();
    
        console.log(fmtDate + ' ' + objs.title+':'+objs.info);
    }
    /**
     *
     */
    var ws = require('websocket.io').listen(PORT);
    
    ws.on('connection', function(socket){
        log({'title':'socket','info':'bound on '+PORT});
        socket.on('message', function(data){
            log({'title':'socket','info':data});
        });
    });
    
  7. arduinoを起動した時のServer側のログ
    $ node unosrv
    $ node websocksrv.js 
    2013/2/26 11:37:5:890 socket:bound on 3011
    2013/2/26 11:37:7:7 socket:{"CDS_A0":626}
    2013/2/26 11:37:8:9 socket:{"CDS_A0":626}
    2013/2/26 11:37:9:16 socket:{"CDS_A0":625}
    2013/2/26 11:37:10:17 socket:{"CDS_A0":626}
    2013/2/26 11:37:11:22 socket:{"CDS_A0":625}
    
%d人のブロガーが「いいね」をつけました。