「RN-42Bluetoothモジュールの使い方2」の続きです。
最後にタブレットからPCのマウス、キーボードを遠隔操作してみたいと思います。
タブレットとRN42モジュールとはSPP通信を行い、タブレットからユーザ操作(スライドやタップなど)を送信して、PC側で信号の解読&マウス、キーボード操作を行います。
タブレット側には
・マウスモード
・キーボードモード
・ゲームパッドモード
を作って、それぞれ操作する対象を切り替えられるようにしたいと思います。
システム構成
ざっくりしたシステム構成です。
PC側のプログラムはPythonで記述しています。使用するライブラリは下記の通りです。
- Pyserial2.7 : シリアル通信をするために使用しています。
- ctypes1.0.2 : PythonからCで書かれたライブラリを呼び出すことができます。マウスやキーボード操作のために、WindowsのDLLを呼び出すのに使用しています。
- Guippy0.1.1 : WinwosGUIを簡単に操作するためのライブラリ。ctypesのラッパー。
通信仕様
Bluetooth SPP通信でやり取りするメッセージ仕様です。
とりあえず使いそうな操作を適当に決めてしまいます^^;
Mode | 操作 | message | 補足 |
---|---|---|---|
マウス | マウス移動 | ‘M’ (x) (y) | x=X軸の移動量(2byte), y=Y軸の移動量(2byte) |
右クリック | ‘R’ | ||
左クリック | ‘L’ | ||
ホイール | ‘O’ (d) | d=まわした量(手前<0, 奥>0) | |
右ドラッグ | ‘I’ | ドラッグ状態にする | |
左ドラッグ | ‘U’ | ドラッグ状態にする | |
ドロップ | ‘J’ | 左右のドラッグ状態を解除 | |
ゲームパッド | パッド操作 | ‘G’ (a) (b) | ボタン操作 1=On, 0=Off a(1byte): **000000 = 未使用 00*00000 = Start 000*0000 = Esc 0000*000 = 上 00000*00 = 下 000000*0 = 左 0000000* = 右 b(1byte): *0000000 = コンボ1 0*000000 = パンチ1 00*00000 = パンチ2 000*0000 = パンチ3 0000*000 = コンボ2 00000*00 = キック1 000000*0 = キック2 0000000* = キック3 |
キーボード | *未実装* | *未実装* | 時間の関係上、キーボードモードは未実装。 |
ゲームパッドモードは完全にストリートファイターV専用仕様にしてます。
キーボードモードは今回は未実装です・・・手抜きかな?
クライアントプログラムの実装
Bluetooth通信部分は、「RN-42Bluetoothモジュールの使い方2」と同じです。
後は、UI部分を実装するだけ。超簡単(適当)なので割愛。gitHub見てね。
今回送信するメッセージは最大でも5byteなので、最大送信時間は40/115200=0.00034s。
クライアント側で4mm以下で連続送信しないようにしてあげれば問題なさそうです。
サーバプログラムの実装
こちらもpyserialとguippy使うと簡単に作れました。
# -*- coding: utf-8 -*- import serial import struct import guippy import time ser = serial.Serial(3, 115200) print ser.name gp = guippy.Guippy() isDragLeft = False isDragRight = False old_key = 0x0000 while True: cmd = ser.read() print cmd old_time = time.clock() if cmd == 'M': x,y = struct.unpack('hh', ser.read(4)) gp.jump(x,y,True,False) print x,y elif cmd == 'R': gp.click(guippy.mouse.RIGHT) elif cmd == 'L': gp.click(guippy.mouse.LEFT) elif cmd == 'O': n, = struct.unpack('b', ser.read()) gp.wheel(n) print n elif cmd == 'U': isDragLeft = True gp.drag(guippy.mouse.LEFT) elif cmd == 'I': isDragRight = True gp.drag(guippy.mouse.RIGHT) elif cmd == 'J': if isDragLeft: gp.drop(guippy.mouse.LEFT) if isDragRight: gp.drop(guippy.mouse.RIGHT) elif cmd == 'G': key, = struct.unpack('h', ser.read(2)) print key if old_key - key <> 0: if key&0x2000 > 0: #START gp.enter() if key&0x1000 > 0: #ESC gp.escape() if key&0x0800 > 0: #UP gp.push(38) else: gp.release(38) if key&0x0400 > 0: #DOWN gp.push(40) else: gp.release(40) if key&0x0200 > 0: #LEFT gp.push(37) else: gp.release(37) if key&0x0100 > 0: #RIGHT gp.push(39) else: gp.release(39) if key&0x0080 > 0: #Combo1 gp.punch('o') gp.push(39) gp.release(39) gp.push(40) gp.release(40) gp.push(39) gp.release(39) gp.punch('u') gp.push(40) gp.push(39) gp.release(40) gp.release(39) gp.push(40) gp.push(39) gp.release(40) gp.release(39) gp.punch('o') if key&0x0040 > 0: #P1 gp.push(85) else: gp.release(85) if key&0x0020 > 0: #P2 gp.push(73) else: gp.release(73) if key&0x0010 > 0: #P3 gp.push(79) else: gp.release(79) if key&0x0008 > 0: #Combo2 gp.push(40) gp.push(39) gp.release(40) gp.push(79) gp.release(39) if key&0x0004 > 0: #K1 gp.push(74) else: gp.release(74) if key&0x0002 > 0: #K2 gp.push(75) else: gp.release(75) if key&0x0001 > 0: #K3 gp.push(76) else: gp.release(76) old_key = key elif cmd == 'E': break new_time = time.clock() elapsed = new_time - old_time print elapsed old_time = new_time ser.close()
一番苦労したのは68-86行目、100-105行目のコンボのところですね(笑
あと、ゲームパッドモードの操作は結局キーボード操作(ゲーム側でUは弱パンチとかに設定している)にしているんですが・・・
Guippyのキーボード操作(push,releaseなど)が処理完了までに200msぐらいかかかるようで、格闘ゲームにはまったく使えなかったという。
#かろうじて波動拳、昇竜拳コマンドはいけました
動かしてみたよ
さっそく動かしてみました。
やったー!動いた!
・・・まぁ、あまり実用的ではないですが。
あとがき
3回にわたってRN42 Bluetoothモジュールの使い方を書いてみました。
基本的な使い方は理解できたかなと思います。
サンプルで作ったプログラムは、あまり実用的ではないですが、スマホをリモコン代わりに使えるようにしたら、もっと実用的にできるかなとも思いました。
例えば、ボタンひとつで、
・メーラーを立ち上げ自動読み上げ
・YouTubeを開いてプレイリストを自動再生
・PCのシャットダウン
とかは、簡単に実装できそうです。
今回のサンプルプログラムは下記においておきますね。
https://github.com/workpiles/BtSample
では。