JINS MEMEのデータをtcp socket通信で出力、Processingに流してグラフ化してみる

# What's JINS MEME
以前まとめたものがありますので、そちらをご参考ください。
http://qiita.com/mito_log/items/020a87996ed2b9d793e6

# Why 
前回、[JINS MEMEのデータをxx秒おきにGoogle SpreadSheetに流す](http://qiita.com/mito_log/items/09df58a6deb926bb58ea)をやりましたが、それはリアルタイムデータの取得&解析用といった感じなので今度はリアルタイムに且つ視覚的にデータを見てみようと思います。今回もRxSwiftで書きました。

ちなみに...
ios上でのグラフ化は[AdventCalendar3日目](http://shoya.io/blog/meme-logger/)がよくできています！今回は可視化という部分で重複しますが、tcp socket通信の部分も含みますので、とりあえず進めてみました。

# What I created

 - JINS MEMEのリアルタイムモードのデータをtcpソケット通信で特定のIP/Portに出力
 - 受け側のアプリを[Processing](https://processing.org/)で作成しグラフ化

というものを作りました。

※ 検討段階ではwebsocketやudpで~と思いましたが過去の遺産を漁ってみたらtcpが楽そうだったのでとりあえずそれでやっています

# github
https://github.com/mitolog/JINSMEMESampler

※ 今回のソースは[Processingのフォルダ配下](https://github.com/mitolog/JINSMEMESampler/tree/master/JINSMEMESampler/Processing)

# Screenshots

ios
![JINSMEME_Processing_iphone.png](https://qiita-image-store.s3.amazonaws.com/0/46489/bb9f1d40-5a05-b74c-6d68-ae72c2172ac1.png)

Proecssing
![JINSMEME_Proecssing_ps.png](https://qiita-image-store.s3.amazonaws.com/0/46489/2b3d682e-ecc0-d999-3d06-760164cfa1b3.png)


# How to Use

![JINSMEMESample_Processing.png](https://qiita-image-store.s3.amazonaws.com/0/46489/e88f8aba-3bbe-8ebe-9223-9e826042c52d.png)

1. まずiOSデバイスとProcessingの走るマシンを同じローカルエリアネットワーク内に参加させます。
2. ProcessingのJava applet(サーバ)から立ち上げ、次にiOSアプリ(クライアント)を起動します。
3. 起動したら、iOS側でサーバのIPとポートを指定して、スタートボタンを押すと通信が開始されます。


## Miscellaneous
 - IPとポートのTextFieldにバリデーションを入れていて、IPは4つのセグメントがないといけません、ポートはtcpの自由割当ポート(49152から65535)の中に収まっていないといけません
 - Processingでは、画面上をクリックすると、ソケット通信をON/OFFできます。
 - Processingでは、fpsを左下にプロットしていて、JINS MEMEの通信速度20Hz(20fps)を下回るとデータ落ちしますので、遅延がひどくかんじられます

# Recap
## About RxSwift
### Validation, Sync multiple inputs with `combineLatest`
`combineLatest`は、複数のObservableを引数にとり、どちらか一方の引数で最新の値が来ると、それをトリガーにして最終引数にセットされたクロージャに値が引き渡されます。クロージャでそれらの値をよしなに処理してreturnすると、ObservableでラップされてsubscribeするObserverに値が渡されます。

![combinelatest.png](https://qiita-image-store.s3.amazonaws.com/0/46489/32af0772-de58-7798-a419-ea646d2f2442.png)
画像: [RxSwiftのPlayground](https://github.com/ReactiveX/RxSwift/tree/master/Rx.playground)より

```swift:Playground(Combining_Observables)
example("combineLatest 1") {
    let intOb1 = PublishSubject<String>()
    let intOb2 = PublishSubject<Int>()

    _ = combineLatest(intOb1, intOb2) {
        "\($0) \($1)"
        }
        .subscribe {
            print($0)
        }

    intOb1.on(.Next("A"))

    intOb2.on(.Next(1))

    intOb1.on(.Next("B"))

    intOb2.on(.Next(2))
}

/*
Codes above will prints like below:
Next(A 1)
Next(B 1)
Next(B 2)  
*/
```

今回は、この`combineLatest`の、**引数としてとる値が少なくとも1回以上publishされていないとクロージャに処理が回ってこない。**という性質を利用しました。具体的には、

 - IPアドレスとポートをきちんと入力しないと通信開始ボタンが押せないようにする
 - 通信開始ボタン、tcpソケット接続完了、JINS MEMEのデータ取得のタイミングが揃ったタイミングでcsvデータをProcessingに送信

という機能を実現するために`combineLatest`を使っています。

## About socket communication
### Tcp socket communication using NSStream
今回、tcpソケット通信を行うクラスとして、`TcpSocketManager`というクラスを作りました。そこでは、NSStreamとNSOperationを組み合わせて新規にスレッドを作成し、そこでrunloopを回して、socketデータのI/Oを管理しています。

基本的には、以下のサイトを参考しています。
[NSStreamを利用してiRemoconと通信する](http://blog.ishkawa.org/2013/05/19/iremocon-operation/)
[Setting Up Socket Streams](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/NetworkStreams.html)

ソース中でautoreleasepoolディレクティブを使っている箇所は、データ更新頻度が多いため、ARCでなるべく早いタイミングでメモリ解放させるためにセットされているかと思います。

また、ちょっとトリッキーなところとしては、main関数の中で、

```swift:TcpSocketManager.swift
repeat{
    autoreleasepool {
        self.runloop.runUntilDate(NSDate(timeIntervalSinceNow:0.1))
    }
} while (_executing)
```

とすることで、実行中0.1秒ごとにrunloopが延命され、その間はずっとstreamが維持される仕組みになっています。

## About Processing
### Server (Processing built-in socket communication library)
Processingには[Server](https://processing.org/reference/libraries/net/Server.html)というtcpソケット通信を可能にするクラスがネットワークライブラリの一部としてデフォルトで備わっています。使い方は簡単で、以下のように使うことができます。

```java
	
import processing.net.*;

Server myServer;
int val = 0;

void setup() {
  size(200, 200);
  // Starts a myServer on port 5204
  myServer = new Server(this, 5204); 
}

void draw() {
  val = (val + 1) % 255;
  background(val);
  myServer.write(val);
}
```

ServerがあるのでClientもありますが、今回は使っていません。
ライブラリのリファレンスは[こちら](https://processing.org/reference/libraries/net/)からどうぞ。

## About JINS MEME
### Yaw value is...
グラフ化してみるとわかるのですが、頭のx,y,z軸方向の回転量を示すroll, pitch, yawの値のうち、yawがどうもおかしいようです。値が連続的ではなく急に変化しています。具体的には、0度から急に-300~くらいの値になってしまいます。

本来は[こちらの記事](http://d.hatena.ne.jp/bs-wp7/20111130/1322611487)と同じで、

roll: 0° -> 90° -> 0° -> -90° -> 0°
pitch: 0° -> 90° -> -180°/180° -> -90° -> 0°
yaw: 0° -> 90 -> 180 -> 270 -> 360°

となるはずですが、yawの値にマイナスがついてしまっています。310~320くらいでマイナスに転じているので、符号化bit云々の話かもしれません。そこはちょっと内部の処理になりますので組込な方がいれば教えて欲しいところです。もしくはSDKの改善に期待です。

### EyeBlink :) , Eyemove :(
大体どちらの値もメガネをかけてしばらくすると安定してデータが取れるようになります。
グラフでみると、まばたきの検知は結構感度いいですが、目線の移動はそこまで正確にとれないようで、こちらもSDKの改善に期待したいと思います。

### todo 
yaw値がグラフからはみ出ていますが、上記のyaw値の関係で一旦スルーして、0を中心に+180, -180°の範囲にしています。ここはyaw値が修正され次第修正したいと思います。

# References

[IRMCommandOperation](https://github.com/ishkawa/IRMCommandOperation)
Tcpソケット通信のクラスを作る上でベースにさせていただきました。ありがとうございます。