Adobe AIR for AndroidからWebSocket経由でlitteBitsのサーボモジュールと傾き情報を連動させるメモ

Socket通信できるとリアルタイムに情報がやりとりでき面白いです。Adobe AIR for Androidから傾きセンサーをWebSocket経由でlitteBitsのサーボモジュールと連動させるメモです。

今回は、Adobe AIR for AndroidでもWebSocket通信ができるので、それを利用してAndroid実機の傾き情報をWebSocket経由でlitteBitsのサーボモジュールを連動させることをやってみます。WebSocketで連動できると、スマートフォン含めていろいろなデバイスが情報として簡単に「のり付け」できるようになりますし、Adobe AIR for Androidで専用のアプリを作ればスマートフォン上のセンサー情報をとれるので、インタラクティブに幅が広がると思おいます。

今回やりたいこと

早速始めていきましょう。このように傾きセンサーの情報送るAIR for Androidのアプリをつくり、HerokuでWebSocketサーバーで中継して、Raspberry PiでWebSocketを見るサーバーを立ててlittleBitsを連携させます。

image_20151220_120421_7

  • AS3WebSocketを利用してAIR for Androidを連携した記事をベースにAIR for Androidのアプリをつくる
  • HerokuでWebSocketサーバーを作りアプリと連携できるようにする
  • Raspberry PiでWebSocketを見るサーバーを立ててlittleBitsを連携させる
  • 実際に動かしてみる

AS3WebSocketをベースにAIR for Androidのアプリをつくる

このようなアプリです。スマホの傾きをX Y Z軸全部とっていますが、今回はY軸の傾きと連動させます。

image_20151220_112742_2

ほぼ、こちらの記事をベースにしています。

このように100ミリ秒で傾き情報を計測しつつ

        // 加速度センサーの判定
        if(Accelerometer.isSupported){
            mcView.addEventListener(Event.ENTER_FRAME,handlerEnterFrame);
            accelerometer = new Accelerometer();

            // 取得時間隔を変更
            accelerometer.setRequestedUpdateInterval(100);
            // 加速度センサーのイベント設定
            accelerometer.addEventListener(AccelerometerEvent.UPDATE,handlerAccelerometerUpdate);
        } else {
            mcView.txtResult.text = "Accelerometer.isSupported : false";
        }

加速度をテキストフィールドに出力しながら、 Heroku上のWebSocketに送ります。

    private function handlerAccelerometerUpdate(event:AccelerometerEvent):void {
        // 加速度をテキストフィールドに出力
        var x:Number = Math.floor(event.accelerationX * 100) / 100;
        var y:Number = Math.floor(event.accelerationY * 100) / 100;
        var z:Number = Math.floor(event.accelerationZ * 100) / 100;
        // 文言を表示
        var str:String = "";
        str += "x:" + x + "\n";
        str += "y:" + y + "\n";
        str += "z:" + z + "\n";
        mcView.txtResult.text = str;
        // Heroku WebSocketに送る
        var sendStr:String = JSON.stringify({x:x,y:y,z:z});
        _ws.sendUTF( sendStr + "\n" );
    }

HerokuでWebSocketサーバーを作りアプリと連携できるようにする

Heroku本家の以下の記事を参考にWebSocketサーバーを立てます。

WebSocketがAdobe AIR for Androidから傾き情報を受け取ると接続しているもの全部に傾き情報を伝えます。

    // 傾き情報などメッセージ送信時
    ws.on('message', function (message) {
        message = message.split("\n").join("");
        messageData = {
            type:"accelerometer",
            message:JSON.parse(message)
        }
        console.log(messageData);
        
        // 接続しているもの全部に傾き情報を伝える
        wss.clients.forEach(function each(client) {
            try { client.send( JSON.stringify(messageData) , function(){}); }
            catch (e) { console.log('error');console.log(e); }
        });
        
    });

ソースは以下のとおりです。

var WebSocketServer = require("ws").Server;
var express = require('express');
var app = express();
var http = require('http');
var server = http.Server(app);
var wss = new WebSocketServer({server: server})

var messageData = {};

console.log("websocket server created");

var ws;

wss.on("connection", function(_ws) {

    ws = _ws;

    console.log("websocket connection open");

    messageData = {
        type:"message",
        messge:"websocket connection open"
    }

    ws.send(JSON.stringify(messageData),function(){});

    // 傾き情報などメッセージ送信時
    ws.on('message', function (message) {
        message = message.split("\n").join("");
        messageData = {
            type:"accelerometer",
            message:JSON.parse(message)
        }
        console.log(messageData);
        
        // 接続しているもの全部に傾き情報を伝える
        wss.clients.forEach(function each(client) {
            try { client.send( JSON.stringify(messageData) , function(){}); }
            catch (e) { console.log('error');console.log(e); }
        });
        
    });

    ws.on("close", function() {
        console.log("websocket connection close");
    })
})

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/', function(request, response) {
    response.send('Hello World!!');
});

server.listen(app.get('port'), function(){
  console.log('listening on *:' + app.get('port'));
});

状況がわかるコンソールページを作りまして(検証上、大事)、Adobe AIR for Androidから傾き情報を受けて無事連動しました。

image_20151220_114028_4

Raspberry PiでWebSocketを見るサーバーを立ててlittleBitsを連携させる

Raspberry PiでWebSocketを見るサーバーを立ててlittleBitsを連携させます。

ws npm本家のサイトの「echo.websocket.org demo」サンプルをベースに組み立てていきます。

まず、NodeJSでWebSocketとserialportと連動するサーバーを立てます。

// Serial Port ///////////////////////////////

var serialport = require('serialport');
var portName = '/dev/ttyACM0'; // Win環境
var sp = new serialport.SerialPort(portName, {
    baudRate: 9600,
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false,
    parser: serialport.parsers.readline("\n")
});

var timerID;
var accelerometerValue = 0;

var WebSocket = require('ws');
var ws = new WebSocket('ws://demo-1ft-ws-adcal2015flash.herokuapp.com/');

ws.on('open', function open() {
    console.log('connected');
    ws.send(Date.now().toString(), {mask: true});
});

ws.on('close', function close() {
    console.log('disconnected');
    clearInterval(timerID);
});

ws.on('message', function message(data, flags) {
    console.log('----');
    var _data = JSON.parse(data);
    if( _data.type == 'accelerometer' ){
        if( _data.message.z ) {
            // 傾き情報をリアルタイムに受け取る(100ミリ秒=0.1秒)
            accelerometerValue = Math.abs(Math.floor(_data.message.y * 9));
        }
    }
});

// Raspberry PiからlittleBits(Arduino)には1秒ごとに伝える
timerID = setInterval(
    function () {
        console.log(accelerometerValue);
        sp.write(String(accelerometerValue), function (err, results) {
        })
    },
    1000
);

Arduinoの中身は以下のように書いてます。ざざっと書いたので文字列でやりとりしてるので数字に変換がまどっこしいコードですがご容赦ください。


// 入力ポート
int portInputD0 = 0;
int portInputA0 = A0;
int portInputA1 = A1;
// 出力ポート
int portOutputD1 = 1;
int portOutputD5 = 5;
int portOutputD9 = 9;
// 入力の状態記録
int stateInput1 = LOW;
int stateInput2 = LOW;
int stateInput3 = LOW;
// USBから入ってくる値
int inputUSBByte = 0;
int value = 0;

void setup() {
  // 出力のピン
  pinMode(portOutputD1, OUTPUT);
  pinMode(portOutputD5, OUTPUT);
  pinMode(portOutputD9, OUTPUT);
  // 入力のピン
  pinMode(portInputD0, INPUT);
  pinMode(portInputA0, INPUT);
  pinMode(portInputA1, INPUT);

  Serial.begin(9600);
}

void loop() {
  // USBから入ってくる値を監視(1文字)
  if(Serial.available() > 0){
      inputUSBByte = Serial.read();
      value = 0;
      // 文字列でやりとりしてるので数字に変換
      if( inputUSBByte == '1' ){
        value = 1;
      }
       if( inputUSBByte == '2' ){
        value = 2;
      }
       if( inputUSBByte == '3' ){
        value = 3;
      }
       if( inputUSBByte == '4' ){
        value = 4;
      }
       if( inputUSBByte == '5' ){
        value = 5;
      }
       if( inputUSBByte == '6' ){
        value = 6;
      }
       if( inputUSBByte == '7' ){
        value = 7;
      }
       if( inputUSBByte == '8' ){
        value = 8;
      }
       if( inputUSBByte == '9' ){
        value = 9;
      }
      // 実際の連動部分
      analogWrite( portOutputD1 , 255 * 0.1 * value );
      analogWrite( portOutputD5 , 255 * 0.1 * value );
      Serial.println( value );
      Serial.println(255 * 0.1 * value );
  }
  // 基礎ループ
  delay(1000);
}

実際に動かしてみる

さてここまで出来ましたら連動させてみます。Android(Nexus7)と傾けると、littleBitsのサーボが連動します!

おわりに

ということで、Adobe AIR for AndroidとlittleBitsがWebSocket経由で連動できることがわかりました。

スマートフォンはセンサーの塊なので、今回の傾きセンサーのようにいろいろな情報を取得することができるので、このように吸いだすことができれば、スマホを振り回すと一気にイルミネーションがついたり、バッテリーが少なくなるとデバイスが通知してくれたりと面白いアクションが考えられそうです。

それではよき、WebSocket & Adobe AIR & littleBits Lifeを!