「アルプスのセンサネットワークモジュールをラズパイ3と3GPIで使ってみる(其の2 C言語によるBLEソフト)」でC言語により、センサネットワークモジュールの環境センサを使ったプログラムを作成しましたが、今回は、Pythonインタフェース「bluepy」を使用して、Raspberry Pi 3に接続したアルプスのセンサネットワークモジュールの地磁気センサと加速度センサからモーションデータを取得します。アルプスのセンサネットワークモジュールは、Bluetooth Low Energy(BLE)を用いて、気圧、温度・湿度などの環境データと共に、モーションデータを取得できます。今回は、センサネットワークモジュールを、BLEを用いて、Raspberry Pi 3と接続しました。
なお、今回使用するbluepyに関しては、「IanHarvey/bluepy」を参照してください。
Pythonインタフェース「bluepy」のインストール
次のコマンドでソースコードを取得して、インストールしてビルドします。
$ sudo apt-get install python-pip libglib2.0-dev $ sudo pip install bluepy $ sudo apt-get install git build-essential libglib2.0-dev $ git clone https://github.com/IanHarvey/bluepy.git $ cd bluepy $ sudo python setup.py build $ sudo python setup.py install
bluepyには、sensortag用のサンプルコードsensortag.pyが用意されています。しかし、そのまま実行するとimport処理でエラーとなるので、「bluepy/bluepy/sensortag.py」の1行目の「from .btle import UUID, Peripheral, DefaultDelegate」を「from btle import UUID, Peripheral, DefaultDelegate」に変更します。
アルプスのセンサネットワークモジュールでモーションデータの取得
インストールされた「btle.py」を用いて、センサネットワークモジュールで地磁気センサ(Geo-Magnetic)と加速度センサ(Acceleration)を用いて、100msごとにモーションデータを取得します。
次に、Raspberry Pi 3上で、アルプスのセンサネットワークモジュールからBLEを用いてモーションデータを取得する「alpsensor.py」のコードを示します。btle.pyファイルの「Peripheral」クラスを継承した「AlpsSensor」を使用します。BLE通信は「writeCharacteristic」メソッドを使用し、センサネットワークモジュールのコマンドガイド「Sensor Network Module評価キットApplication Note Command Guide」に従って、100msごとにモーションデータを送信してくるように設定します。Notificationメッセージは、setDelegateメソッドにより設定された NtfyDelegateメソッドにより受信します。
alpsensor.py
# -*- coding: utf-8 -*- from btle import Peripheral import struct import btle import binascii class NtfyDelegate(btle.DefaultDelegate): def __init__(self, params): btle.DefaultDelegate.__init__(self) # ... initialise here def handleNotification(self, cHandle, data): # ... perhaps check cHandle # ... process 'data' cal = binascii.b2a_hex(data) #print u'handleNotification : {0}-{1}:'.format(cHandle, cal) if int((cal[0:2]), 16) == 0xf2: #print 'cal:{0}'.format(type(cal)) GeoMagnetic_X = int((cal[6:8] + cal[4:6]), 16) * 0.15 GeoMagnetic_Y = int((cal[10:12] + cal[8:10]), 16) * 0.15 GeoMagnetic_Z = int((cal[14:16] + cal[12:14]), 16) * 0.15 print 'Geo-Magnetic X:{0:.3f} Y:{1:.3f} Z:{2:.3f}'.format(GeoMagnetic_X, GeoMagnetic_Y, GeoMagnetic_Z) Acceleration_X = int((cal[18:20] + cal[16:18]), 16) / 4096 Acceleration_Y = int((cal[22:24] + cal[20:22]), 16) / 4096 Acceleration_Z = int((cal[26:28] + cal[24:26]), 16) / 4096 print 'Acceleration X:{0:.3f} Y:{1:.3f} Z:{2:.3f}'.format(Acceleration_X, Acceleration_Y, Acceleration_Z) class AlpsSensor(Peripheral): def __init__(self,addr): Peripheral.__init__(self,addr) self.result = 1 def main(): alps = AlpsSensor("28:A1:83:E1:58:96") alps.setDelegate( NtfyDelegate(btle.DefaultDelegate) ) #モーション(動き)検知 100ms間隔(モーション系センサのみ) alps.writeCharacteristic(0x0013, struct.pack('<bb', 0x01, 0x00), True) alps.writeCharacteristic(0x0016, struct.pack('<bb', 0x01, 0x00), True) alps.writeCharacteristic(0x0018, struct.pack('<bbb', 0x2F, 0x03, 0x03), True) alps.writeCharacteristic(0x0018, struct.pack('<bbb', 0x01, 0x03, 0x03), True) alps.writeCharacteristic(0x0018, struct.pack('<bbb', 0x04, 0x03, 0x01), True) alps.writeCharacteristic(0x0018, struct.pack('<bbbb', 0x06, 0x04, 0x64, 0x00), True) # 100msec alps.writeCharacteristic(0x0018, struct.pack('<bbb', 0x2F, 0x03, 0x01), True) alps.writeCharacteristic(0x0018, struct.pack('<bbb', 0x20, 0x03, 0x01), True) # Main loop -------- while True: if alps.waitForNotifications(1.0): # handleNotification() was called continue print "Waiting..." # Perhaps do something else here if __name__ == "__main__": main()
インストールされた「btle.py」と同じディレクトリで、上記の作成したpythonコードを実行します。Geo-Magnetic X,Y,ZとAcceleration X,Y,Zに、それぞれ磁気センサと加速度センサから取得したX,Y,Z方向のモーションデータが表示されます。
$ cd bluepy/bluepy $ sudo python alpsensor.py Geo-Magnetic X:9793.350 Y:9821.250 Z:11.100 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.450 Y:9820.800 Z:10.800 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9793.050 Y:9821.250 Z:11.250 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.750 Y:9821.250 Z:11.400 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.150 Y:9821.400 Z:10.950 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9793.200 Y:9820.950 Z:10.950 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9794.100 Y:9820.950 Z:11.100 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.900 Y:9821.550 Z:11.100 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9793.050 Y:9820.950 Z:11.400 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9793.350 Y:9821.250 Z:10.950 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.750 Y:9820.800 Z:11.250 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.600 Y:9821.400 Z:11.100 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.450 Y:9821.100 Z:10.950 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.750 Y:9820.950 Z:11.400 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.750 Y:9821.250 Z:10.500 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9793.200 Y:9821.250 Z:11.400 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.750 Y:9821.700 Z:10.950 Acceleration X:1.000 Y:0.000 Z:0.000 Geo-Magnetic X:9792.600 Y:9821.100 Z:11.400 Acceleration X:1.000 Y:0.000 Z:0.000
アルプスのセンサネットワークモジュールがGATTRequesterで接続できない件
「Pythonを使ったアルプスのセンサネットワークモジュールの接続」でインストールしたpybluezの「GATTRequester」を使用して、アルプスのセンサネットワークモジュールを接続したところ、「self.connect()」の実行でエラー「RuntimeError: Could not update HCI connection: Input/output error」が表示されて接続できませんでした。ちなみに、TIのSensorTagでは正常に接続できました。このため、上記に示したようにbluepyを使用してアルプスのセンサネットワークモジュールに接続しています。
pythonのプログラムは「karulis/pybluez」からダウンロードしました。
#!/usr/bin/python # -*- mode: python; coding: utf-8 -*- # Copyright (C) 2014, Oscar Acena <oscaracena@gmail.com> # This software is under the terms of GPLv3 or later. from __future__ import print_function import sys from bluetooth.ble import GATTRequester class Reader(object): def __init__(self, address): self.requester = GATTRequester(address, False) self.connect() self.request_data() def connect(self): print("Connecting...", end=' ') sys.stdout.flush() self.requester.connect(True) print("OK!") def request_data(self): data = self.requester.read_by_uuid( "00002a00-0000-1000-8000-00805f9b34fb")[0] try: print("Device name: " + data.decode("utf-8")) except AttributeError: print("Device name: " + data) if __name__ == '__main__': if len(sys.argv) < 2: print("Usage: {} <addr>".format(sys.argv[0])) sys.exit(1) Reader(sys.argv[1]) print("Done.")
アルプスのセンサネットワークモジュールを実行した結果を次に示します。
$ sudo python sensor_tag.py 28:A1:83:E1:58:96 Connecting... Traceback (most recent call last): File "sensor_tag.py", line 40, inReader(sys.argv[1]) File "sensor_tag.py", line 16, in __init__ self.connect() File "sensor_tag.py", line 23, in connect self.requester.connect(True) RuntimeError: Could not update HCI connection: Input/output error
TIのSensorTagでは、次のように表示され正常に終了しました。
$ sudo python sensor_tag.py B4:99:4C:64:CD:DF Connecting... OK! Device name: TI BLE Sensor Tag Done.