スクラッチくらぶ上級編ーRaspberry-Pi

今回は、「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が読み出されます。この用紙を使うと、座標値は、仕様から次のようになります。

左上 X 座標
左上 Y 座標
右下 X 座標
右下 Y 座標
98
142
402
358

 角度は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 を起動し、「拡張機能」をクリックします。

https://makecode.microbit.org

②.下図の画面が表示されるので、「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

★★★★★ ★★★★★ ★★★★★