今回は、「Raspberry Pi」と「SONY toio(トイオ)」のコラボ、また、「Raspberry Pi」と「micro:bit」のコラボで、ロボットを動かして見たいと思います。
- Raspberry Pi と「SONY toio」間をBluetoothで接続し、Python3(bluepy)でプログラミングします。
- Raspberry Pi と「micro:bit」間をBluetoothで接続し、Python3(bluepy)でプログラミングします。
★★★★★ ★★★★★ ★★★★★
Raspberry Pi(ラズベリーパイ)は、イギリスのラズベリーパイ財団で開発された教育用のマイコンボードです。※Raspberry Pi はラズベリーパイ財団の登録商標です。
micro:bit(マイクロビット)は、イギリスの放送局BBCで開発された教育用のマイコンボードです。※micro:bitは、micro:bit教育財団の登録商標です。
★★★★★ ★★★★★ ★★★★★
Raspberry PiからBluetoothでtoioコアキューブを動かそう!-その1
当初、Windows10でJavaScript でtoioコアキューブを動かそうとしたが、力量不足のため途中で挫折してしまった。そこで、Raspberry Pi でPython3の方が感覚的に動かせるような気がしたのでトライして見ました。
①.Raspberry pi で、「bluepy」を利用可能にする
Raspberry Pi は、「bluepy」モジュールが標準ではインストールされていないので、以下のようにしてインストール必要がある。
LXTerminal を立ち上げます。
# python3 の場合 $ sudo apt install libbluetooth3-dev libglib2.0 libboost-python-dev libboost-thread-dev $ sudo apt install python3-pip $ cd /usr/lib/arm-linux-gnueabihf/ $ sudo ln libboost_python-py35.so libboost_python-py34.so $ sudo pip3 install gattlib $ sudo pip3 install bluepy $ sudo systemctl daemon-reload $ sudo service bluetooth restart
コマンドの3行目と4行目は不要かも知れません。
②.toio コアキューブの address を調べる
「bluepy」モジュールでは、BLEデバイスに対して、address を直接指定する必要があるので、以下のようなPythonスクリプトを使って、address を調べる。
サンプルプログラムを作成して見る。
「Thonny Python IDE」か 「mu」でプログラム記述
find_toio.py というファイル名にします。
import bluepy scaner = bluepy.btle.Scanner(0) devices = scaner.scan(3) # scan時間は3秒 for device in devices: for (adType, desc, value) in device.getScanData(): if "toio Core Cube" in value: print('toio Core Cube Address=%s , RSSI=%s' % (device.addr, device.rssi))
ファイルをSAVEし、「再起動」しておく。
コアキューブの電源を入れて、LXTerminal を立ち上げます。
find_toio.py を実行します。
$ sudo python3 find_toio.py [Enter]
実行結果は下図の通りです。
toio Core Cube Address=**:**:**:**:**:** , RSSI=-38 # 実際には、コアキューブのアドレスが返る toio Core Cube Address=**:**:**:**:**:** , RSSI=-68
※上図の場合は、コアキューブが2個の例です。
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
③.コアキューブをコントロールする
サンプルプログラムを作成して見る。
「Thonny Python IDE」か 「mu」でプログラム記述
sample_coreCube.py というファイル名にします。
import bluepy import time import sys from coreCube import CoreCube if __name__ == "__main__": toio = CoreCube() if len(sys.argv) == 1: toio_addr = toio.cubeFinder() print("Connect to " + toio_addr) else: toio_addr = sys.argv[1] toio.connect(toio_addr, bluepy.btle.ADDR_TYPE_RANDOM) time.sleep(1) # Light は、(30ms, Red), (30ms, Green) を3回繰り返す # Sound は、(30ms,ド), (30ms,レ), (30ms,ミ) を2回繰り返す toio.lightSequence( 3, ( (30,(255,0,0)), (30,(0,255,0)) ) ) toio.soundSequence( 2, ( (30,60), (30,62), (30,64) ) ) time.sleep(2) # Light は Redを点灯 # Sound は、id = 0 を再生 toio.lightOn((255,0,0), 0) toio.soundId(0) time.sleep(1) # Light は Greenを点灯 # Sound は、id = 1 を再生 toio.lightOn((0,255,0), 0) toio.soundId(1) time.sleep(1) # Light は Bleuを点灯 # Sound は、id = 2 を再生 toio.lightOn((0,0,255), 0) toio.soundId(2) time.sleep(1) # 左右=(50,50)で進む # 左右=(-50,-50)で進む(後退する) # 左右 (50, -50)で進む(回転する) toio.lightOff() toio.motor((50, 50), 0) time.sleep(1) toio.motor((-50, -50), 0) time.sleep(1) toio.motor((50, -50), 0) time.sleep(1) toio.motor((0, 0), 0) time.sleep(1) # Battery/BLE Version print("Battery: %d" % toio.battery()) print("BLE Version : " + toio.bleVersion()) # MATのID情報を毎秒10回読み取る print("Please put coreCube on MAT …") for i in range(10,0,-1): id = toio.id() if id == 1: print("%d: id=1 x=%d, y=%d, dir=%d" % (i, toio.x, toio.y, toio.dir)) elif id == 2: print("%d: id=2 stdid=%d, dir=%d" % (i, toio.stdid, toio.dir)) else: print("%d: id=%d" % (i, id)) time.sleep(1) toio.disconnect()
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_coreCube.py を実行します。「パラメータ」を入力するのを忘れないようにして下さい。
$ python3 sample_coreCube.py **:**:**:**:**:** # コアキューブのアドレスを指定 または $ sudo python3 sample_coreCube.py # 一番近くのコアキューブに自動接続
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
また、サンプルプログラムを作成して見る。
「Thonny Python IDE」か 「mu」でプログラム記述
sample_coreCube1.py というファイル名にします。
import bluepy import binascii import time import sys class CoreCube(bluepy.btle.Peripheral): HANDLE_TOIO_MTR = 0x11 HANDLE_TOIO_LED = 0x14 HANDLE_TOIO_SND = 0x17 def __init__(self): bluepy.btle.Peripheral.__init__(self) # ---------------- Motor Control def motor(self, speeds, duration): data = "01" if duration == 0 else "02" data = data + "01" + ("01" if speeds[0] >= 0 else "02") + ("{:02x}".format(abs(speeds[0]))) data = data + "02" + ("01" if speeds[1] >= 0 else "02") + ("{:02x}".format(abs(speeds[1]))) if duration != 0: data = data + ("{:02x}".format(duration)) self.writeCharacteristic(self.HANDLE_TOIO_MTR, binascii.a2b_hex(data)) # ---------------- Light Control def lightOn(self, color, duration): data = "03{:02x}0101{:02x}{:02x}{:02x}".format(duration, color[0], color[1], color[2]) self.writeCharacteristic(self.HANDLE_TOIO_LED, binascii.a2b_hex(data)) def lightSequence(self, times, operations): data = "04{:02x}".format(times) data = data + "{:02x}".format(len(operations)) for ope in operations: data = data + "{:02x}0101{:02x}{:02x}{:02x}".format(ope[0], ope[1][0], ope[1][1], ope[1][2]) self.writeCharacteristic(self.HANDLE_TOIO_LED, binascii.a2b_hex(data)) def lightOff(self): data = "01" self.writeCharacteristic(self.HANDLE_TOIO_LED, binascii.a2b_hex(data)) # ---------------- Sound Control def soundId(self, id): data = "02{:02x}FF".format(id) self.writeCharacteristic(self.HANDLE_TOIO_SND, binascii.a2b_hex(data)) def soundSequence(self, times, operations): data = "03{:02x}".format(times) data = data + "{:02x}".format(len(operations)) for ope in operations: data = data + "{:02x}{:02x}FF".format(ope[0], ope[1]) self.writeCharacteristic(self.HANDLE_TOIO_SND, binascii.a2b_hex(data)) def soundStop(self): data = "01" self.writeCharacteristic(self.HANDLE_TOIO_SND, binascii.a2b_hex(data)) if __name__ == "__main__": if len(sys.argv) == 1: print('Usage: sample_coreCube1.py BLE_DEVICE_ADDRESS') sys.exit() TOIO_ADDR = sys.argv[1] try: toio = CoreCube() toio.connect(TOIO_ADDR, bluepy.btle.ADDR_TYPE_RANDOM) except: print("device connect error") sys.exit() time.sleep(1) # Light は、(300ms, Red), (300ms, Green) を3回繰り返す toio.lightSequence( 3, ( (30,(255,0,0)), (30,(0,255,0)) ) ) # Sound は、(300ms,ド), (300ms,レ), (300ms,ミ) を2回繰り返す toio.soundSequence( 2, ( (30,60), (30,62), (30,64) ) ) time.sleep(2) # Light は Redを点灯 # Sound は、id = 0 を再生 toio.lightOn((255,0,0), 0) toio.soundId(0) time.sleep(1) # Light は Greenを点灯 # Sound は、id = 1 を再生 toio.lightOn((0,255,0), 0) toio.soundId(1) time.sleep(1) # Light は Blueを点灯 # Sound は、id = 2 を再生 toio.lightOn((0,0,255), 0) toio.soundId(2) time.sleep(1) toio.lightOff() # 左右=(50,50)で進む # 左右=(-50,-50)で進む(後退する) # 左右=(50, -50)で進む(その場で回転する) toio.motor((50, 50), 0) time.sleep(1) toio.motor((-50, -50), 0) time.sleep(1) toio.motor((50, -50), 0) time.sleep(1) toio.motor((0, 0), 0) time.sleep(1) toio.disconnect()
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_coreCube1.py を実行します。「パラメータ」を入力するのを忘れないようにして下さい。
$ python3 sample_coreCube1.py **:**:**:**:**:** # コアキューブのアドレスを指定 または $ sudo python3 sample_coreCube1.py # 一番近くのコアキューブに自動接続
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
※実行結果は、実際に動きました!(感動)
(後述)参考に、sample_coreCube1.py を実行するときに、「パラメータ」を入力するのを忘れることが考えられるときには、
プログラムの記述の中で、sample_coreCube1.py を下記のように書き換えて、
if __name__ == "__main__": # if len(sys.argv) == 1: # print('Usage: sample_coreCube1.py BLE_DEVICE_ADDRESS') # sys.exit() # TOIO_ADDR = sys.argv[1] TOIO_ADDR = "**:**:**:**:**:**" try:
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_coreCube1.py を実行します。
$ sudo python3 sample_coreCube1.py [Enter]
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
Raspberry PiからBluetoothでtoioコアキューブを動かそう!-その2
- ID Information / 読み取りセンサー
- Sensor Information / モーションセンサー
- Battery Information / バッテリー残量
- Motor Control / モーター
- Light Control / ライト
- Sound Control / サウンド
サンプルプログラム(sample_matsu1.py)の実行
サンプルプログラムを作成して見る。
- “カエルの歌” をコアキューブで独唱する
- コアキューブの移動
- ライト(赤、緑、青)点灯
- コアキューブの「傾斜」と「追突」の検知
「Thonny Python IDE」か 「mu」でプログラム記述
sample_matsu1.py というファイル名にします。
from coreCube import CoreCube import time import bluepy import sys import struct if __name__ == "__main__": # --- コアキューブへの接続(自動接続を行うには、rootで実行する必要あり) toio = CoreCube() if len(sys.argv) == 1: toio_addr = toio.cubeFinder() print("Connect to " + toio_addr) else: toio_addr = sys.argv[1] toio.connect(toio_addr, bluepy.btle.ADDR_TYPE_RANDOM) time.sleep(1) print("BLE Version : " + toio.bleVersion()) print("Battery: %d" % toio.battery()) time.sleep(1) toio.moveTo(100, 100, 60) toio.id() print("X,Y,dir = (" + str(toio.x) + "," + str(toio.y) + "), " + str(toio.dir)) toio.soundId(3) time.sleep(1) toio.moveTo(400, 400, 60) toio.id() print("X,Y,dir = (" + str(toio.x) + "," + str(toio.y) + "), " + str(toio.dir)) toio.soundId(3) time.sleep(1) toio.moveTo(100, 300, 60) toio.id() print("X,Y,dir = (" + str(toio.x) + "," + str(toio.y) + "), " + str(toio.dir)) toio.soundId(3) time.sleep(1) toio.moveTo(300, 100, 60) toio.id() print("X,Y,dir = (" + str(toio.x) + "," + str(toio.y) + "), " + str(toio.dir)) toio.soundId(3) time.sleep(1) toio.moveTo(250, 250, 60) toio.id() print("X,Y,dir = (" + str(toio.x) + "," + str(toio.y) + "), " + str(toio.dir)) toio.soundId(3) time.sleep(1) # Light は、(30ms, Red), (30ms, Green) を3回繰り返す # Sound は、(30ms,ド), (30ms,レ), (30ms,ミ) を2回繰り返す toio.lightSequence( 3, ( (30,(255,0,0)), (30,(0,255,0)) ) ) toio.soundSequence( 2, ( (30,60), (30,62), (30,64) ) ) time.sleep(2) # Light は Redを点灯 # Sound は、id = 0 を再生 toio.lightOn((255,0,0), 0) toio.soundId(0) time.sleep(1) # Light は Greenを点灯 # Sound は、id = 1 を再生 toio.lightOn((0,255,0), 0) toio.soundId(1) time.sleep(1) # Light は Bleuを点灯 # Sound は、id = 2 を再生 toio.lightOn((0,0,255), 0) toio.soundId(2) time.sleep(1) MELODY_LENGTH = 0.5 MELODY_FLOG = [60, 62, 64, 65, 64, 62, 60, 128, 64, 65, 67, 69, 67, 65, 64, 128, 60, 128, 60, 128, 60, 128, 60, 128, 60, 62, 64, 65, 64, 62, 60, 128, 128, 128, 128, 128, 128, 128, 128, 128] time.sleep(1) for i in range(len(MELODY_FLOG)): toio.soundMono(0xFF, MELODY_FLOG[i]) # if i >=8: # toio2.soundMono(0xFF, MELODY_FLOG[i-8]) time.sleep(MELODY_LENGTH) # --- ボタンが押されるまでループ while True: if toio.sensor() == 0: time.sleep(1) else: toio.sensor() time.sleep(1) if toio.horizon ==1: horizon = "水平" else: horizon = "傾斜" if toio.collision ==1: collision = "追突" else: collision = "通常" print("SENSOR: HORIZON=" + str(horizon) + ", COLLISION=" + str(collision)) time.sleep(1) toio.soundStop() toio.disconnect()
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_matsu1.py を実行します。
$ python3 sample_matsu1.py **:**:**:**:**:** # コアキューブのアドレスを指定
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
実行結果は下図の通りです。
$ sudo python3 sample_matsu1.py Connect to **:**:**:**:**:** X,Y,dir = (104,98), 175 X,Y,dir = (397,398), 39 X,Y,dir = (101,300), 195 X,Y,dir = (298,102), 311 X,Y,dir = (252,248), 116 SENSOR: HORIZON=傾斜, COLLISION=追突 SENSOR: HORIZON=水平, COLLISION=通常 SENSOR: HORIZON=傾斜, COLLISION=通常 SENSOR: HORIZON=水平, COLLISION=追突 SENSOR: HORIZON=水平, COLLISION=追突 SENSOR: HORIZON=傾斜, COLLISION=通常 SENSOR: HORIZON=傾斜, COLLISION=通常 SENSOR: HORIZON=傾斜, COLLISION=追突 :
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
Raspberry Piで2つのtoioコアキューブの同時制御
“カエルの歌” を2台のコアキューブで輪唱させる
サンプルプログラム(sample_flog.py)の実行
せっかく、今回 CoreCube クラスを定義したし、toio に2つのキューブが入っているので、2台を同時に接続して、輪唱させてみた。以下のような動作をするソースコード
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
sample_flog.py というファイル名にします。
from coreCube import CoreCube import time import bluepy toio1_addr = '**:**:**:**:**:**' # 実際には、コアキューブのアドレス toio2_addr = '**:**:**:**:**:**' toio1 = CoreCube() toio1.connect(toio1_addr, bluepy.btle.ADDR_TYPE_RANDOM) toio2 = CoreCube() toio2.connect(toio2_addr, bluepy.btle.ADDR_TYPE_RANDOM) MELODY_LENGTH = 0.5 MELODY_FLOG = [60, 62, 64, 65, 64, 62, 60, 128, 64, 65, 67, 69, 67, 65, 64, 128, 60, 128, 60, 128, 60, 128, 60, 128, 60, 62, 64, 65, 64, 62, 60, 128, 128, 128, 128, 128, 128, 128, 128, 128] time.sleep(1) for i in range(len(MELODY_FLOG)): toio1.soundMono(0xFF, MELODY_FLOG[i]) if i >=8: toio2.soundMono(0xFF, MELODY_FLOG[i-8]) time.sleep(MELODY_LENGTH) toio1.soundStop() toio1.disconnect() toio2.soundStop() toio2.disconnect()
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_flog.py を実行します。
$ sudo python3 sample_flog.py [Enter]
実行結果
“カエルの歌” を2台のコアキューブで輪唱させた。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
Raspberry PiでtoioコアキューブのID(位置情報)検知
toio CoreCube のfirmware がアップデートされ、機能追加と安定性向上が図られました。(2020年1月)
# BLE Version = ['2.0.0', '2.1.0'] HANDLE_TOIO_ID = [0x0d, 0x0d] HANDLE_TOIO_MTR = [0x11, 0x11] HANDLE_TOIO_LED = [0x14, 0x15] HANDLE_TOIO_SND = [0x17, 0x18] HANDLE_TOIO_SEN = [0x1a, 0x1b] HANDLE_TOIO_BTN = [0x1e, 0x1f] HANDLE_TOIO_BAT = [0x22, 0x23] HANDLE_TOIO_CFG = [0x26, 0x27]
今回は、toio ビジュアルプログラミングで提供されている Scratch のコマンドの「指定した (X座標, Y座標) に動かす」とか、「xx 度に向く」というようなコマンドを実現した。
もともと、技術仕様で公開されているコマンドは、単に車輪の速さを指定するだけで、指示された位置に移動することや、指定角度に回転するコマンドがない。
toio には、技術仕様だけではなく、ビジュアルプログラミングのソースコードも公開されている。こちらを見て、どうやっているのかを確認したが、正直、よく解らなかった。(やっぱり、JavaScriptはよく解らない・・・) 解ったことと言えば、目的の位置や角度になるまで、両輪の値を変えるようなループにしているという。
- turnTo メソッド(指定された角度を向く)
- moveTo メソッド(指定された座標に移動する)
①.サンプルプログラム(sample_turnto.py)の実行
turnTo メソッドは、指定した角度にコアキューブを向けるメソッドです。
サンプルプログラムを作成して見る。
* コアキューブを、270度に向けて、sound id = 4 を再生する。
* これを2秒ごとに、10回繰り返す。
「Thonny Python IDE」か 「mu」でプログラム記述
sample_turnto.py というファイル名にします。
from coreCube import CoreCube import time import sys toio_addr = CoreCube.cubeSearch() if len(toio_addr) != 1: print("1台のコアキューブの電源を入れてください") sys.exit() toio = CoreCube() toio.connect(toio_addr[0]) time.sleep(1) for k in range(10): toio.turnTo(270) # 角度を270度にする toio.id() # XY座標、角度を読み込む print("dir = %d" % toio.dir) toio.soundId(4) time.sleep(2) toio.disconnect()
CoreCubeクラスに cubeSearch() という、近くのコアキューブを見つけるメソッドも追加した。(ちなみに、root で実行する必要がある)
cubeSearch()メソッドの中身は、こんな感じ。
# coreCube を探して、アドレスを返す。ただし、root で実行する必要がある。 # 戻り値は、近い順にソートされている # (既にconnect中のものがあるとdisconnectされるので注意) @classmethod def cubeSearch(self): if os.environ.get('USER') == 'root': scaner = bluepy.btle.Scanner(0) devices = scaner.scan(3) finds = [] for device in devices: for (adType, desc, value) in device.getScanData(): if "toio Core Cube" in value: finds.append((device.rssi, device.addr)) ret = [] if len(finds) != 0: finds.sort(key = lambda rssi:rssi[0], reverse=True) for i in finds: ret.append(i[1]) return ret else: raise PermissionError('You need to execute this command as root')
turnTo()メソッドの中身は、こんな感じ。
# 指定角度を向く # 細かいパラメータ: def turnTo(self, tdir): for i in range(20): # --- 20回繰り返す self.id() diff_dir = tdir - self.dir if (abs(diff_dir) <= 15 ): # --- 目的の角度に近くなったら停止 self.motor( (0, 0), 0) break else: if diff_dir > 180: diff_dir -= 360 if diff_dir < -180: diff_dir += 360 sp = max(int(diff_dir/4), 10) if diff_dir > 0 else min(int(diff_dir/4), -10) self.motor( (sp, -sp), 10) time.sleep(0.02)
考え方としては、現在の角度と目的の角度の差を計算し、回転方向と回転速度を決めている。差が大きければ、回転速度を早くしている。また、モーターの最低速度は 10 なので、それより小さくならないようにしている。
ファイルをSAVEし、コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_turnto.py を実行します。
$ sudo python3 sample_turnto.py [Enter]
実行結果は下図の通りです。
$ sudo python3 sample_turnto.py # 一番近くのコアキューブに自動接続 dir = 272 dir = 267 dir = 266 dir = 270 dir = 267 dir = 267 dir = 266 dir = 272 dir = 267 dir = 268
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
②.サンプルプログラム(sample_moveto.py)の実行
moveTo メソッドは、指定したXY座標にコアキューブを移動させるメソッドです。
サンプルプログラムを作成して見る。
* (100, 100) に速度60 で移動し、sound id = 3 を再生する。
* これをXY座標を変えて、数回繰り返す。
「Thonny Python IDE」か 「mu」でプログラム記述
sample_moveto.py というファイル名にします。
from coreCube import CoreCube import time import bluepy import sys toio_addr = CoreCube.cubeSearch() if len(toio_addr) == 0: print("コアキューブの電源を入れてください") sys.exit() toio = CoreCube() toio.connect(toio_addr[0]) time.sleep(1) toio.moveTo(100, 100, 60) toio.id() print("(x, y) = (%d, %d)" % (toio.x, toio.y) ) toio.soundId(3) time.sleep(1) toio.moveTo(400, 400, 60) toio.id() print("(x, y) = (%d, %d)" % (toio.x, toio.y) ) toio.soundId(3) time.sleep(1) toio.moveTo(100, 300, 60) toio.id() print("(x, y) = (%d, %d)" % (toio.x, toio.y) ) toio.soundId(3) time.sleep(1) toio.moveTo(300, 100, 60) toio.id() print("(x, y) = (%d, %d)" % (toio.x, toio.y) ) toio.soundId(3) time.sleep(1) toio.disconnect()
moveTo()メソッドの中身は、こんな感じ。
# 指定位置に向かう def moveTo(self, tx, ty, speed): STOP = 10 SLOW = speed while True: if self.id() != 1: break # --- 指定位置に近づいた? dist = math.sqrt((tx - self.x)**2 + (ty - self.y)**2) ds = 1.0 # --- 減速係数 if dist < STOP: # --- 指定位置からSTOP範囲に入ったら、終了 break if dist < SLOW: # --- 指定位置からSLOW範囲に入ったら、減速 ds = max(dist / SLOW, 0.3) # --- 現在位置から、指定位置までの角度を計算 tdir = int(math.acos( (tx - self.x) / dist ) * 180.0 / math.pi) if ty - self.y < 0: tdir *= -1 # --- 角度補正値計算 diff_dir = tdir - self.dir if diff_dir > 180: diff_dir -= 360 if diff_dir < -180: diff_dir += 360 dr = abs(int(diff_dir / 2)) + 1 if diff_dir > 0 else 0 dl = abs(int(diff_dir / 2)) + 1 if diff_dir < 0 else 0 # --- move sl = max(int((speed - dl) * ds ), 10) sr = max(int((speed - dr) * ds ), 10) if sl+sr == 20: # --- 最低速度だと差が出ないので・・・ sl = sl + 1 if dr != 0 else sl sr = sr + 1 if dl != 0 else sr self.motor( (sl, sr), 0 ) time.sleep(0.03) self.motor( (0, 0), 0 )
ファイルをSAVEします。
こちらの考え方としては、
- 現在の位置と目的の位置の距離を計算し、STOP閾値よりも小さければ、目的についたとして停止する
- 距離がSLOW閾値よりも小さくなったら、減速させる(減速係数を計算)
- 今向いている方向と、現在位置と目的の位置の角度の差を計算し、左右の車輪の速度差を決定する
- 左右の速度差と、減速係数をもとに、車輪の速度を決めて、モーターを回す
- この繰り返し
これも、いろいろ試してみた結果となっている。
特に、減速については、移動速度を速くすると、うまく止まらず、目的値を通り過ぎてしまったりするため、考慮が必要になった。また、減速区間についても、4行目の SLOW = speed
が表すように、固定値ではなく、速度によって変えた。これで、かなり近いところで止まるようになった。
コアキューブの電源を入れて、LXTerminal を立ち上げます。
sample_moveto.py を実行します。
$ sudo python3 sample_moveto.py [Enter]
実行結果は下図の通りです。
$ sudo python3 sample_moveto.py (x, y) = (104, 105) (x, y) = (395, 398) (x, y) = (105, 300) (x, y) = (298, 106)
こちらも、誤差は+/-5ぐらいになった。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
Raspberry PiからBluetoothでtoioコアキューブを動かそう!-その3
- LED/チカチカ
- モータ/モータ制御
- モータ/加速度センサ
- モータ/読み取りセンサ
①.サンプルプログラム(toio_Lchika.py)の実行
Light ControlというRGB LEDを光らせる機能を選び、点滅させせるコマンドを送ります。正しく送れたら、本体裏にある指定した色のLEDが点滅します。正しくなかったら、青色のLEDが点滅します。
「ランプ」の仕様に書かれているように、キャラUUID=10B20103-5B3B-4571-9508-CF3EFCD7BBAEを探し、プロパティが書き込み属性なので、サンプルにあるようにコマンドをバイナリで送ります。
handleは実行時にふられます。commandList は、順に、連続的な点灯・消灯、繰り返しは複数回、Operationは二つ、ランプを制御する時間は500ms、ランプの数は1、IDは1、REDは最大輝度、GREENは消灯、BLUEも消灯、制御期間は180ms、ランプの数は1、IDは1、REDは消灯、GREENは最大輝度、BLUEは消灯です。
commandList =
[0x04,0x00,0x02,0x1e,0x01,0x01,0xff,0x00,0x00,0x10,0x01,0x01,0x00,0xff,0x00]
★★★★★ ★★★★★ ★★★★★
ソースプログラム(toio_Lchika.py)
from bluepy import btle toio_Service_UUID = "10B20100-5B3B-4571-9508-CF3EFCD7BBAE" Light_Characteristic_UUID = "10B20103-5B3B-4571-9508-CF3EFCD7BBAE" #deviceAddr = "c3:f0:86:ef:c7:62" deviceAddr = "e4:11:d3:89:53:36" commandList = [0x04,0x00,0x02,0x1e,0x01,0x01,0xff,0x00,0x00,0x10,0x01,0x01,0x00,0xff,0x00] peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) chara = peri.getCharacteristics() for ch in chara: print('===') print("uuid= ", ch.uuid) print(ch.propertiesToString()) if ch.uuid == Light_Characteristic_UUID: handle = ch.getHandle() print(handle) #ch.getDescriptors()) print("send command to Light") ch.peripheral.writeCharacteristic(handle, bytearray(commandList), True) break peri.disconnect()
★★★★★ ★★★★★ ★★★★★
コアキューブの電源を入れて、LXTerminal を立ち上げます。
$ sudo python3 toio_Lchika.py [Enter]
実行結果は下図の通りです。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
②.サンプルプログラム(toio_motor_1.py)の実行
モータを動かします。単に二つあるモータを動かす機能だけでなく、速度、速度の変化などのパラメータも用意されています。
技術資料のモータの最初のサンプル、0x01、0x01、0x01、0x64、0x02、0x02、0x14は、モータ制御、左のモータのID、回転方向「前」、速度指示値「100」、右モータのID、回転方向「後ろ」、速度指示値「20」を打ち込み(バイト列なので、0x01010164020214)、Write without responsをクリックすると、toio本体が同じ場所で回転し始めます。Disconnectで通信を切るまで続きます。
commandList =
[0x01,0x01,0x01,0x64,0x02,0x02,0x14]
★★★★★ ★★★★★ ★★★★★
ソースプログラム(toio_motor_1.py)
from bluepy import btle Motor_Characteristic_UUID = "10B20102-5B3B-4571-9508-CF3EFCD7BBAE" #deviceAddr = "c3:f0:86:ef:c7:62" deviceAddr = "e4:11:d3:89:53:36" commandList = [0x01,0x01,0x01,0x64,0x02,0x02,0x14] peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) MotorControl = peri.getCharacteristics(uuid=Motor_Characteristic_UUID)[0] print("send command to motor") MotorControl.write(bytearray(commandList)) peri.disconnect() print("done")
★★★★★ ★★★★★ ★★★★★
コアキューブの電源を入れて、LXTerminal を立ち上げます。
$ sudo python3 toio_motor_1.py [Enter]
実行結果は下図の通りです。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
ついでに応用問題で〜す。
toio本体が前進、後退を2回繰り返します。最後にDisconnectで通信を切断します。
★★★★★ ★★★★★ ★★★★★
ソースプログラム(toio_motor_3.py)
from bluepy import btle import time Motor_Characteristic_UUID = "10B20102-5B3B-4571-9508-CF3EFCD7BBAE" #deviceAddr = "c3:f0:86:ef:c7:62" deviceAddr = "e4:11:d3:89:53:36" # 前進 commandList = [0x01,0x01,0x01,0x16,0x02,0x01,0x16] # 後退 commandList_1 = [0x01,0x01,0x02,0x16,0x02,0x02,0x16] # 前進 commandList_2 = [0x01,0x01,0x01,0x16,0x02,0x01,0x16] # 後退 commandList_3 = [0x01,0x01,0x02,0x16,0x02,0x02,0x16] peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) MotorControl = peri.getCharacteristics(uuid=Motor_Characteristic_UUID)[0] print("send command to motor") MotorControl.write(bytearray(commandList)) time.sleep(5) MotorControl.write(bytearray(commandList_1)) time.sleep(5) MotorControl.write(bytearray(commandList_2)) time.sleep(5) MotorControl.write(bytearray(commandList_3)) time.sleep(3) peri.disconnect() print("done")
★★★★★ ★★★★★ ★★★★★
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
③.サンプルプログラム(toio_butukari.py)の実行
toioには、外部の情報を知るには、読み取りセンサもしくはモーション(加速度)センサが利用できます。超音波などを利用して進行方向などの障害物を検知するセンサは搭載されていません。
モーション・センサには、読み取ったデータに「衝突」という項目があります。ここでは、モータを駆動して前進し、壁にぶつかったら引き返すという動作を考えます。
●イベント駆動
衝突するという現象は、いつも監視していなくてはなりません。二つの方法があります。
RPi.GPIOライブラリを使ったとき、GPIOの設定したピンがLow->Highに変化すると、何かの処理を行う、というのは割り込み処理です。 もう一つは、ポーリングという方法で、プログラムのループの中で、常にGPIOピンを監視するという方法です。ループが大きくなると、監視する間隔があくので、ピンの変化を見逃してしまうという欠点があります。 |
ここではpigpioライブラリ(インストールされている)のソフトウェア割り込みを使います。
- 衝突が起こったらevent_triggerでイベントを発生させる
- イベントが発生したらモータを逆向きに動かす関数event_callbackを記述しておく
- 上記の二つを関連づけるcb1 = pi.event_callback(イベントの数字, 呼び出す関数名)を記述
これらを動かす前に、pigpiodというデーモンを動かしておきます。
$ sudo pigpiod [Enter]
●モーション・センサのインスタンス
モーション・センサのプロパティは、readとnotifyなので、常にデータが更新されているので、読み出したら、それが最新データです。
Sensor_Characteristic_UUID = "10B20106-5B3B-4571-9508-CF3EFCD7BBAE" peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) SensorInformation = peri.getCharacteristics(uuid=Sensor_Characteristic_UUID)[0]
SensorInformation のインスタンスを使ってセンサのvalueをリードできます。衝突の情報は3番目に書かれています。ぶつかると1で、そうでないときは0です。
●プログラム
メインのプログラムはcollision()関数にしました。モーション・センサのvalueを読み出し、衝突の項目が1だったら、イベントの「2」を発生させます。
イベントの「2」が発生すると、callback_kaihi(event,tick)関数が呼び出されます。ここでは、モータを逆向きに回転させ、ぶつかった壁から退避します。それだけなので、退避中に別の壁にぶつかると動けなくなります。
readSensor = SensorInformation.read()は、2回実行しています。これは、読み出しでエラーがおきたからです。2回目は必ず成功します。なので、最初の読み出しの前にtime.sleep(0.01)を置くと、1回目の読み出しでもエラーが出なくなりました。
★★★★★ ★★★★★ ★★★★★
ソースプログラム(toio_butukari.py)
sudo pigpiod import pigpio from bluepy import btle import time Sensor_Characteristic_UUID = "10B20106-5B3B-4571-9508-CF3EFCD7BBAE" Motor_Characteristic_UUID = "10B20102-5B3B-4571-9508-CF3EFCD7BBAE" #deviceAddr = "c3:f0:86:ef:c7:62" deviceAddr = "e4:11:d3:89:53:36" readSensor = [] massugu = [0x01,0x01,0x01,0x32,0x02,0x01,0x32] back = [0x02,0x01,0x02,0x32,0x02,0x02,0x28,0x30] kaihi = [0x03,0x00,0x03,0x00,0x64,0x00,0x02bc,0x0182,0x005a] peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) SensorInformation = peri.getCharacteristics(uuid=Sensor_Characteristic_UUID)[0] MotorControl = peri.getCharacteristics(uuid=Motor_Characteristic_UUID)[0] pi = pigpio.pi() readSensor = [] #callback def callback_kaihi(event,tick): print(" kaihi", tick) MotorControl.write(bytearray(back)) print("back") def collision(): while 1: try: time.sleep(0.01) readSensor = SensorInformation.read() except: readSensor = SensorInformation.read() if readSensor[2]: # butukatta print("butukatta") pi.event_trigger(2) #main print("start") MotorControl.write(bytearray(massugu)) cb1 = pi.event_callback(2, callback_kaihi) print("start2") collision() print('end') cb1.event_cancel()
★★★★★ ★★★★★ ★★★★★
コアキューブの電源を入れて、LXTerminal を立ち上げます。
$ sudo python3 toio_butukari.py [Enter]
実行結果は下図の通りです。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
④.サンプルプログラム(toio_yomitori.py)の実行
toio本体は小さく、距離センサは備えていませんが、底面に光学センサがあり、読み取りセンサという名称がついています。この装置で遊ぶときのキーになっているように見えます。しかし、「Position IDキューブが Position ID から受け取った情報を、以下に示す構成のデータで取得できます。」
読み取り用のプログラムを作り、床に線を描いた付属のシートを貼って動作を確認します。
●プログラム
読み出せる値は、
- 情報の種類
- キューブの中心の X 座標値、Y 座標値、キューブの角度
- 読み取りセンサの X 座標値、Y 座標値、読み取りセンサの角度
最初の情報の種類以外は2バイトのデータです。角度は水平面で、X軸方向に対してと説明されています。
「toio コア キューブ(単体)付属の簡易プレイマット」を使うと、情報の種類は0x01でPosition IDが読み出されます。この用紙を使うと、座標値は、仕様から次のようになります。
角度は0から360度です。
★★★★★ ★★★★★ ★★★★★
ソースプログラム(toio_yomitori.py)
from bluepy import btle readSensor_Characteristic_UUID = "10B20101-5B3B-4571-9508-CF3EFCD7BBAE" #deviceAddr = "c3:f0:86:ef:c7:62" deviceAddr = "e4:11:d3:89:53:36" readSensor = [] peri = btle.Peripheral() peri.connect(deviceAddr, btle.ADDR_TYPE_RANDOM) idInformation = peri.getCharacteristics(uuid=readSensor_Characteristic_UUID)[0] print("read sensor data") while 1: readSensor = idInformation.read() #print(readSensor)print('Cx=', int.from_bytes(readSensor[1:3], 'little'),
'Cy=', int.from_bytes(readSensor[3:5], 'little'),
'Cth=', int.from_bytes(readSensor[5:7], 'little'),
'Sx=', int.from_bytes(readSensor[7:9], 'little'),
'Sy=', int.from_bytes(readSensor[9:11], 'little'),
'Sth=', int.from_bytes(readSensor[11:13],'little')
)
peri.disconnect() print("done")
★★★★★ ★★★★★ ★★★★★
●読み取ったデータ
上記のプログラムを動かし、シートの中心にtoioを置き、手で動かします。上方向、下方向、右方向、左方向、その場で回転したときのデータです。図は、それらを整理した座標です。「キューブの中心」と「読み取りセンサ」の座標は5~8くらいの差が出ます。角度はほとんど同じ値になります。
つねに、座標を管理しておけば、壁にぶつかったり、シートからはみ出したりせずにすみます。
コアキューブの電源を入れて、LXTerminal を立ち上げます。
$ sudo python3 toio_yomitori.py [Enter]
実行結果は下図の通りです。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
Raspberry PiからBluetoothでmicro:bitを動かそう!
Raspberry Pi はBluetoothを内蔵しているので、Bluetoothでmicro:bitと接続してみる。
micro:bitでScratchでプログラム作成
Bluetoothのサービス開始だけをしておく。
①.Raspberry Pi 側で、Makecode for micro:bit を起動し、「拡張機能」をクリックします。
②.下図の画面が表示されるので、「bluetooth」をクリックします。
③.下図の画面が表示されますので、「一部の拡張機能を削除してbluetoothを追加する」をクリックします。
④.下図の画面が表示されます。「bluetooth」ブロックが追加されます。
「bluetooth」に関するブロックを組み上げて行きます。
⑤画面右上の「その他」をクリックします。
⑥.そしてペアリングしなくてもコネクションできるように設定するために、
⑦.「プロジェクトの設定」から No Paring Required: Anyone can connect via Bluetooth.
を有効にして、ファイル名を「bluetooth_1.hex」という名前にして、「保存」をクリックします。
⑧.Raspberry Pi とmicro:bit をUSBで接続します。
⑨.先程作成した「bluetooth_1.hex」ファイルをコピーします。
⑩.micro:bit に「K」の文字が表示されます。
⑪.次に、Raspberry Pi とmicro:bitを、Bluetoothで接続するために、画面右下の「bluetooth」マークをクリックします。
⑫.「Add New Devices…」をクリックした後、「Add New Devices…」画面で、「BBC micro:bit [zituz]」を選択し、「Pair」をクリックします。
⑬.micro:bit に「Hello World !」の文字が右から左に流れながら表示されます。
⑭.最後に、Raspberry Pi とmicro:bitの、Bluetoothを切断するために、画面右下の「bluetooth」マークをクリックします。
⑮.「disconnect」をクリックします。Bluetoothが切断されると、micro:bit に「X」の文字が表示されます。
★★★★★ ★★★★★ ★★★★★
Raspberry Pi でPythonでプログラミングするための準備
PythonからBluetoothを使うための「bluepy」モジュールをインストールします。
Raspberry Pi の LXTerminal を立ち上げます。
$ sudo pip3 install bluepy [Enter]
★★★★★ ★★★★★ ★★★★★
①.micro:bitのアドレスを探す
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
scan.py というファイル名にします。
import bluepy scanner = bluepy.btle.Scanner(0) devices = scanner.scan(3) for device in devices : print("-----------------------------------") print("address : %s" % device.addr) print("addrType : %s" % device.addrType) print("RSSI : %s" % device.rssi) print("Adv data :") for (adtype, desc, value) in device.getScanData() : print(" (%3s) %s : %s " %(adtype, desc, value))
ファイルをSAVEし、LXTerminal を立ち上げます。
$ sudo python3 scan.py [Enter]
実行結果は下図の通りです。
(注意)micro:bit のアドレスが見つからないときは、Microsoft MakeCode for micro:bit のソフトの拡張機能でbluetoothのペアリング設定になっているので、ペアリングを外すこと!
----------------------------------- address : **:**:**:**:**:** #e4:1e:1f:1f:f4:49 addrType : random RSSI : -45 Adv data : ( 1) Flags : 06 ( 9) Complete Local Name : BBC micro:bit [tazaz]
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。
これでアドレスが分かりました。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
②.UUIDを調べる
アドレスが分かったので、そこへ接続してUUIDを調べます。
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
getHandle.py というファイル名にします。
import sys import bluepy def main() : try: peri = bluepy.btle.Peripheral() peri.connect(devadr, bluepy.btle.ADDR_TYPE_RANDOM) except: print("device connect error") sys.exit() charas = peri.getCharacteristics() for chara in charas : print("------------------------------------------") print(" UUID : %s" % chara.uuid ) print(" Handle %04X : %s" %(chara.getHandle(), chara.propertiesToString())) peri.disconnect() if __name__ == "__main__" : if len(sys.argv) == 1: print("Usage: getHandle.py BLE_DEVICE_ADDRESS") sys.exit() devadr = sys.argv[1] main()
ファイルをSAVEし、LXTerminal を立ち上げます。
$ python3 getHandle.py **:**:**:**:**:** # アドレスを指定
(注釈) **:**:**:**:**:** の箇所は、** の部分は数字とアルファベット小文字の2文字です。 (例)d7:a6:5f:ce:bf:34
実行結果は下図の通りです。
省略 ------------------------------------------ UUID : e95dd91d-251d-470a-a062-fa1922dfa9a8 ------------------------------------------ UUID : e95d7b77-251d-470a-a062-fa1922dfa9a8 Handle 0033 : READ WRITE ------------------------------------------ UUID : e95d93ee-251d-470a-a062-fa1922dfa9a8 Handle 0035 : WRITE ------------------------------------------ 省略
※実行結果は、実際に動きました!(感動)
ここまでで、デバイスについて以下の情報が分かった。
- address
- addrType
- 特性UUID の一覧
- 特性のGATT Handle
addressとaddrType を使って、デバイスを特定し、接続することができる。
特性UUIDは、デバイスが提供するサービスについての情報のキーになる。
特性を利用するときに、GATT Handle を使って、利用したい特性を指定し、コマンドを送受信させる。
★★★★★ ★★★★★ ★★★★★
■ Python を使って、micro:bit に命令を送ってみる
micro:bit のLED を制御(write)
micro:bit には、LEDにアスキー文字をスクロールさせて表示させるサービスがある。こちらを利用して、”Hello! 39″と表示させる。
micro:bitのLEDに”Hello! 39″と表示する
micro:bitのプロファイルのサイト から、LEDに文字列を表示させるサービスの特性UUIDを調べると、「E95D93EE251D470AA062FA1922DFA9A8」だと分かる。
先の実行結果の中に
====================================================== UUID : e95d93ee-251d-470a-a062-fa1922dfa9a8 Handle 003a: WRITE ======================================================
という行があるので、GATT Handle は、「0x003a」であることが分かる。
最低限、以下のコードで、micro:bit に命令を送ることができる。
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
writeLed.py というファイル名にします。
import time import bluepy HANDLE_LED = 0x003a devadr = "d7:a6:5f:ce:bf:34" # 実際にはmicro:bit のアドレスを記述 def main(): peri = bluepy.btle.Peripheral() peri.connect(devadr, bluepy.btle.ADDR_TYPE_RANDOM) peri.writeCharacteristic(HANDLE_LED, b'Hello! 39' ) time.sleep(5) peri.disconnect() if __name__ == "__main__": main()
ファイルをSAVEし、LXTerminal を立ち上げます。
$ python3 writeLed.py [Enter]
実行結果
LEDに”Hello! 39″と表示された
Bluetoothを使ってmicro:bitをコントロール出来るようになった。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
micro:bitのLEDに”Hello ! 123456789″ と表示する
LEDのサービスUUIDから、TEXT出力用UUIDを取得して、そこに出力することでLEDに表示が出来る。
micro:bitのプロファイルのサイト から、LEDに文字列を表示させるサービスの特性UUIDを調べると、
Service led は、「E95DD91D251D470AA062FA1922DFA9A8」
Led text は、「E95DD93EE251D470AA062FA1922DFA9A8」
だと分かる。
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
writeLed2.py というファイル名にします。
import time from bluepy import btle devadr = "d7:a6:5f:ce:bf:34" uuid_service_led = "e95dd91d-251d-470a-a062-fa1922dfa9a8" uuid_led_text = "e95d93ee-251d-470a-a062-fa1922dfa9a8" per = btle.Peripheral(devadr, btle.ADDR_TYPE_RANDOM) svcLed = per.getServiceByUUID(uuid_service_led) chLedText = svcLed.getCharacteristics(uuid_led_text)[0] chLedText.write("Hello World ! 123456789".encode("utf-8")) time.sleep(5) per.disconnect()
ファイルをSAVEし、LXTerminal を立ち上げます。
$ python3 writeLed2.py [Enter]
実行結果
LEDに”Hello World ! 123456789″と表示された
Bluetoothを使ってmicro:bitをコントロール出来るようになった。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
micro:bitのLEDに”Hello! 9876″ と表示する
LEDのサービスUUIDから、TEXT出力用UUIDを取得して、そこに出力することでLEDに表示が出来る。
micro:bitのプロファイルのサイト から、LEDに文字列を表示させるサービスの特性UUIDを調べると、
Service led は、「E95DD91D251D470AA062FA1922DFA9A8」
Led text は、「E95DD93EE251D470AA062FA1922DFA9A8」
だと分かる。
「Thonny Python IDE」か 「mu」でプログラム記述
サンプルプログラムを作成して見る。
writeLed3.py というファイル名にします。
import time from bluepy import btle devadr = "d7:a6:5f:ce:bf:34" uuid_service_led = "e95dd91d-251d-470a-a062-fa1922dfa9a8" uuid_led_text = "e95d93ee-251d-470a-a062-fa1922dfa9a8" per = btle.Peripheral(devadr, btle.ADDR_TYPE_RANDOM) svcLed = per.getServiceByUUID(uuid_service_led) chLedText = svcLed.getCharacteristics(uuid_led_text)[0] chLedText.write("Hello! 9876".encode("utf-8")) time.sleep(5) per.disconnect()
ファイルをSAVEし、LXTerminal を立ち上げます。
$ python3 writeLed3.py [Enter]
実行結果
LEDに”Hello! 9876″と表示された
BlueToothを使ってmicro:bitをコントロール出来るようになった。
※実行結果は、実際に動きました!(感動)
★★★★★ ★★★★★ ★★★★★
PWM Control
IO PIN SERVICE & IO PIN SERVICE-CHARACTERISTICS
Pin IO Configuration
★★★★★ ★★★★★ ★★★★★