Python WebSocket Client


WebSocket は、コネクションレス型の http プロトコルに代わる、コネクション型の新しいプロトコルです。
Python には、WebSocket の実装がいくつかあるようです。
今回は websocket-client を使用します。

インストール

pip install websocket-client
pip install six
pip install backports.ssl_match_hostname

実行例
サンプルコード echo_client.py
20150323_python_websocket

参考
Python の WebSocket ライブラリ
websocket client for python


WebSocket – node.js


WebSocket は、コネクションレス型の http プロトコルに代わる、コネクション型の新しいプロトコルです。
node.js には、WebSocket の実装がいくつかあるようです。
今回は ws を使用します。

インストール

npm install ws

コード
サンプルコードを少し修正して、エコーサーバーを作る。

server.js

var WebSocketServer = require('ws').Server
  , wss = new WebSocketServer({port: 8080});
wss.on('connection', function(ws) {
    ws.on('message', function(message) {
        console.log('received: %s', message);
        ws.send(message);
    });
});
console.log('Server running at 8080');

client.js

var WebSocket = require('ws');
var ws = new WebSocket('ws://localhost:8080');
ws.on('open', function open() {
  console.log('connected');
  ws.send(Date.now().toString());
});
ws.on('close', function close() {
  console.log('disconnected');
});
ws.on('message', function message(data) {
  console.log( (Date.now() - parseInt(data)) + 'ms: ' + data);
  setTimeout(function timeout() {
    ws.send(Date.now().toString());
  }, 500);
});
console.log('Client running');

実行例
20150321_ws_server 20150321_ws_client

参考
WebSocket の導入: ウェブにソケットを実装する
The fastest RFC-6455 WebSocket implementation for Node.js
ws – Node.js/JavaScript入門


JY-MCU BT BOARD の動作確認 – 安定性


JY-MCU BT BOARD の動作確認 – Arduino にて、基本的な確認はできたので、
細かいところも確認します。

20150313_bt_arduino_stability

安定性
Android 端末から連続してデータを送信します。
Arduino に、BT BOARD から受信したデータをエコーバックするスケッチを書きます。
Android 端末で正しく受信したかを確認します。

電気的な接続
BT BOARD は 3.3V信号で、Arduino は 5V信号です。
直結でも動作しますが、レベル変換を行います。
5V -> 3.3V 方向は、過電圧が気になるので、抵抗分割を入れました。
3.3V -> 5V 方向は、スレッシュホールドが気になりますが、レベル変換を行わず、直結しました。

ボーレート
BT BOARD は、デフォルトは 9600 bps です。
ATコマンドでボーレートの変更ができます。
例:115200 bps を設定する

AT+BAUD8

Arduino のハードシリアルの最高速度である 115200 bps を試してみましたが、安定して動作しました。

ソフトシリアル
Arduino のソフトシリアルやAltSoftSerialを使用して、BT BOARD と接続して、安定して動作するか確認しました。
ソフトシリアルは、文字化けが多く、実用に耐えません。
AltSoftSerialは、9600bps では安定して動作しましたが、115200bps では文字化けが発生しました。

9600 115200
ハードシリアル
ソフトシリアル × ×
AltSoftSerial ×

参考
3.3V系-5V系デジタル回路の簡易レベルシフト回路
BluetoothChat の問題と対策
Arduino ソフトシリアルの検証
Arduino AtlSoftSerial の検証


JY-MCU BT BOARD の動作確認 – Arduino


JY-MCU BT BOARD
BT BOARD は、Bluetooth SPP をシリアル通信 (調歩同期) に変換するモジュールです。
端子は、VCC(3.6~6V)、GND、TXD(送信)、RXD(受信) の4本です。
詳細は Bluetoothシリアル変換モジュール(スレーブ) を参照ください。

全体構成
Arduino + BT BOARD と Android 端末で動作確認をします。
JY-MCU BT BOARD の動作確認 – MAC での USB Serial アダプタを、Arduino に置き換えています。
Arduino のハードシリアル端子 (TX, RX) を USB 経由で MAC に接続します。
Arduino のIO端子 (D8, D9) を BT BOARD に接続し、ソフトシリアルを使用します。
BT BOARD は 3.3V信号で、Arduino は 5V信号ですが、短時間の確認なので、直結しています。
なお、ソフトシリアルは負荷が高いと 取りこぼし が発生します。
今回は、簡易的な疎通確認なので、使用しています。
20150304_bt_arduino

動作確認
(1) Arduino側
ハードシリアルとソフトシリアルを使用して、TX – D8, RX – D9 のように通信します。
スケッチは Bluetoothシリアル変換モジュール(スレーブ) を参照ください。

(2) Android 端末
(3) 相互通信
JY-MCU BT BOARD の動作確認 – MAC と同じです。


JY-MCU BT BOARD の動作確認 – MAC


20150304_bt_front

JY-MCU BT BOARD
BT BOARD は、Bluetooth SPP をシリアル通信 (調歩同期) に変換するモジュールです。
端子は、VCC(3.6~6V)、GND、TXD(送信)、RXD(受信) の4本です。
詳細は Bluetoothシリアル変換モジュール(スレーブ) を参照ください。

全体構成
MAC + BT BOARD と Android 端末で動作確認をします。
MAC と BT BOARD は FTDI USB Serial アダプタ を介して接続します。
BT BOARD の TXD、RXD は 3.3V信号で、USB Serial アダプタは 5V信号ですが、短時間の確認なので、直結しています。
20150304_bt_mac

動作確認
(1) MAC側
MAC と BT BOARD を USB Serial アダプタ を介して接続します。
(2) Android 端末
Android 端末に Bluetooth Terminal アプリ を入れる。
(3) 相互通信
Android と BT BOARD を Bluetooth ペアリングする。
キーは「1234」です。
Android から文字を送信して、MAC で受信する。
MAC から文字を送信して、Android で受信する。
相互に通信できることを、確認する。


BluetoothChat の問題と対策


多くの方は Bluetooth の通信には、BluetoothChat をベースにして使っていると思います。
Bluetooth の性能評価をしていたときに、通信抜けがあることに気がつきました。

問題と対策
BluetoothChatService から BluetoothChat に受信データを渡すときに、Handler を介していますが、この部分で、抜けが生じていています。
通常は、BluetoothChatService -> Handler -> BluetoothChat という流れで、受信データは直ちに処理されます。
受信データの到着する間隔に対して、BluetoothChat の処理が遅れると、Handler がキューイングされます。
このとき、BluetoothChatService で用意している受信バッファが1つしかないために、前のHandler のバッファの内容が、次の Handler のバッファの内容に上書きされます。
Handler のバッファは、値を保持するのではなく、アドレスポインタを保持しているようです。
対策としては、受信バッファを複数面にすればいいことになります。
20150310_bluetooth_problem

対策の効果
そこで、受信バッファの面数と、通信の誤り率を、測定してみました。
2台のAndroid端末を用意して、1台は受信したデータをそのまま送信するエコーバックに設定します。もう1台は、数字を1,2,3..と連続して送信して、受信したデータが1,2,3..と連続しているかを照合します。
20150310_bluetooth_system

送信する間隔を1msから100msまで変化させて、受信したデータの誤り率を測定します。
測定結果は、下図のようになりました。
送信間隔30ms以下では、受信バッファの面数により、顕著な違いがあることが分かります。
20150310_bluetooth_result

対策の考察
受信バッファの面数を増やす利点は、分かりましたが。
欠点はないでしょうか。
考えられのは、メモリの使用量です。
受信バッファ1面は、1024バイトなので、1KB強のメモリを使います。
Android 4.0以降では、アプリに使用できるメモリ量は 64MB です。
あまり気にしなくてよさそうです。

なお、実際の運用を考えると、通信で誤りを起こすのは、上記の部分だけではありません。
Bluetooth などの無線経路は不確かなものです。
誤りがあることを前提に、システム全体やアプリを設計すべきですね。

ソースコード
今回の検証に使用したアプリを Gitbhub に公開しています。

BluetoothChatService.java

// 追加
private static final int NUM_PLANE = 32;
// ここまで
...
private class ConnectedThread extends Thread {
    ...
    public void run() {
        // 追加
        byte[][] buffers = new byte[ NUM_PLANE ][ 1024 ];
        int plane = 0;
        // ここまで
        byte[] buffer = new byte[1024];
        int bytes;
        while (true) {
            try {
                // 追加
                buffer = buffers[ plane ];
                if ( plane >= NUM_PLANE ) {
                    plane = 0;
                }
                // ここまで
                bytes = mmInStream.read(buffer);
                mHandler.obtainMessage(
                    BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                    .sendToTarget();
            }
            ... 

20150310_bluetooth_screenshot_2


Arduino AtlSoftSerial の検証


Arduino には、ソフトウェアでシリアル通信のエミュレートをするソフトシリアルという機能があります。
標準ライブラリ の他に、AtlSoftSerial というライブラリがあります。
標準ライブラリと違いは
(1) 16 ビットタイマーを使用している。
(2) 送信と受信の同時動作が可能。
(3) ピンアサインが受信 8ピン, 送信 9ピンに固定されている。

標準ライブラリと同様の検証 を行いました。
Arduino をもう1台用意して、送信専用にします。
数字を 0,1,2,… と順番に送ります。
被試験側の Arduino の AltSoftSerial で受信して、シリアルモニタに表示します。
20150308_altsoftserila_schematics_verification 20150308_altsoftserila_device_verification_2

AltSoftSerial のスケッチ

#include <AltSoftSerial.h>
AltSoftSerial altSerial;
void setup() {
    Serial.begin( 9600 );
    altSerial.begin(9600);
}
void loop() {
    if ( altSerial.available() ) {
        int c = altSerial.read();
        Serial.write( c );
        altSerial.write( c );
    }	
}

結果は、特に取りこぼしなく、1000 以上まで受信できました。

0
1
...
999
1000
....

結論
ハードシリアルと同等に使えそうです。


Arduino ソフトシリアルの検証


Arduino には、ソフトウェアでシリアル通信のエミュレートをする ソフトシリアル という機能があります。

実機確認
(1) 相互通信
ソフトシリアルのIOピンに USB シリアルアダプタをつける。
ハードシリアルは、Arudino IDE のシリアルモニタに表示する。
USBシリアルアダプタは、MAC の screen コマンドで表示する。
相互に通信できることを確認した。

ソフトシリアルのスケッチ

#include <SoftwareSerial.h>
SoftwareSerial softSerial( 2, 3 );
void setup() {
    Serial.begin( 9600 );
    softSerial.begin( 9600 );
}
void loop() {
    if ( Serial.available() ) {
        softSerial.write( Serial.read() );
    }
    if ( softSerial.available() ) {
        Serial.write( softSerial.read() );
    }	
}

20150307_softserila_schematics_mutual20150307_softserila_device_mutual

(2) 直結
ソフトシリアルのTXピンとRXピンを直結したときは、動きませんでした。
送信と受信が同時には動作しないと思われます。
20150307_softserila_schematics_direct 20150307_softserila_device_direct

性能検証
そこで、受信の性能を検証してみました。
Arduino をもう1台用意して、送信専用にします。
数字を 0,1,2,… と順番に送ります。
被試験側の Arduino のソフトシリアルで受信して、シリアルモニタに表示します。

数字発生のスケッチ

int cnt = 0;
void setup() {
    Serial.begin( 9600 );
}
void loop() {
    Serial.println( cnt );
    cnt ++;	
}

20150307_softserila_schematics_verification 20150307_softserila_device_verification

結果は、下記のように、正しく受信できない文字がありました。

41
42
43
4 
45
4
47
4
49

さらに、受信と同時に送信を行うと、文字化けしてしまいます。

0
É5*šjRDjRTˆÈ©Hè©HSHSHS()SP¦¦!¡¦¦!LMCBLCBLM
…17

結論
ソフトシリアルは、取りこぼしや文字化けがある。
それが許容されるときに使うべきです。