RN-42 Bluetoothモジュールの使い方3


Pocket

「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使うと簡単に作れました。

1# -*- coding: utf-8 -*-
2 
3import serial
4import struct
5import guippy
6import time
7 
8ser = serial.Serial(3, 115200)
9print ser.name
10gp = guippy.Guippy()
11 
12isDragLeft = False
13isDragRight = False
14 
15old_key = 0x0000
16 
17while True:
18    cmd = ser.read()
19    print cmd
20     
21    old_time = time.clock()
22    if cmd == 'M':
23        x,y = struct.unpack('hh', ser.read(4))
24        gp.jump(x,y,True,False)
25        print x,y
26    elif cmd == 'R':
27        gp.click(guippy.mouse.RIGHT)
28    elif cmd == 'L':
29        gp.click(guippy.mouse.LEFT)
30    elif cmd == 'O':
31        n, = struct.unpack('b', ser.read())
32        gp.wheel(n)
33        print n
34    elif cmd == 'U':
35        isDragLeft = True
36        gp.drag(guippy.mouse.LEFT)
37    elif cmd == 'I':
38        isDragRight = True
39        gp.drag(guippy.mouse.RIGHT)
40    elif cmd == 'J':
41        if isDragLeft: gp.drop(guippy.mouse.LEFT)
42        if isDragRight: gp.drop(guippy.mouse.RIGHT)
43    elif cmd == 'G':
44        key, = struct.unpack('h', ser.read(2))
45        print key
46         
47        if old_key - key <> 0:
48            if key&0x2000 > 0: #START
49                gp.enter()
50            if key&0x1000 > 0: #ESC
51                gp.escape()
52            if key&0x0800 > 0: #UP
53                gp.push(38)
54            else:
55                gp.release(38)
56            if key&0x0400 > 0: #DOWN
57                gp.push(40)
58            else:
59                gp.release(40)
60            if key&0x0200 > 0: #LEFT
61                gp.push(37)
62            else:
63                gp.release(37)
64            if key&0x0100 > 0: #RIGHT
65                gp.push(39)
66            else:
67                gp.release(39)
68            if key&0x0080 > 0: #Combo1
69                gp.punch('o')
70                gp.push(39)
71                gp.release(39)
72                gp.push(40)
73                gp.release(40)
74                gp.push(39)
75                gp.release(39)
76                gp.punch('u')
77 
78                gp.push(40)
79                gp.push(39)
80                gp.release(40)
81                gp.release(39)
82                gp.push(40)
83                gp.push(39)
84                gp.release(40)
85                gp.release(39)
86                gp.punch('o')
87 
88            if key&0x0040 > 0: #P1
89                gp.push(85)
90            else:
91                gp.release(85)
92            if key&0x0020 > 0: #P2
93                gp.push(73)
94            else:
95                gp.release(73)
96            if key&0x0010 > 0: #P3
97                gp.push(79)
98            else:
99                gp.release(79)
100            if key&0x0008 > 0: #Combo2
101                gp.push(40)
102                gp.push(39)
103                gp.release(40)
104                gp.push(79)
105                gp.release(39)
106 
107            if key&0x0004 > 0: #K1
108                gp.push(74)
109            else:
110                gp.release(74)
111            if key&0x0002 > 0: #K2
112                gp.push(75)
113            else:
114                gp.release(75)
115            if key&0x0001 > 0: #K3
116                gp.push(76)
117            else:
118                gp.release(76)
119            old_key = key
120 
121    elif cmd == 'E':
122        break
123 
124    new_time = time.clock()
125    elapsed = new_time - old_time
126    print elapsed
127    old_time = new_time
128 
129ser.close()

一番苦労したのは68-86行目、100-105行目のコンボのところですね(笑

あと、ゲームパッドモードの操作は結局キーボード操作(ゲーム側でUは弱パンチとかに設定している)にしているんですが・・・
Guippyのキーボード操作(push,releaseなど)が処理完了までに200msぐらいかかかるようで、格闘ゲームにはまったく使えなかったという。
#かろうじて波動拳、昇竜拳コマンドはいけました

 

動かしてみたよ

さっそく動かしてみました。

やったー!動いた!

・・・まぁ、あまり実用的ではないですが。

 

あとがき

3回にわたってRN42 Bluetoothモジュールの使い方を書いてみました。
基本的な使い方は理解できたかなと思います。

サンプルで作ったプログラムは、あまり実用的ではないですが、スマホをリモコン代わりに使えるようにしたら、もっと実用的にできるかなとも思いました。
例えば、ボタンひとつで、
・メーラーを立ち上げ自動読み上げ
・YouTubeを開いてプレイリストを自動再生
・PCのシャットダウン
とかは、簡単に実装できそうです。

今回のサンプルプログラムは下記においておきますね。
https://github.com/workpiles/BtSample
では。

 
 

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です