「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
では。





