Mac <-> micro:bitをBLEによるUARTで通信する

今回、Macmicro:bit(mbed)のBLEによるUART通信を試みたので、記録に残しとく。Mac側はPython
www.youtube.com

micro:bit

上記公式サイトだとポーリングによる手法しか載っておらず、イベントを利用したコールバックのほうがそれっぽいかなと思って実装してみた。

仕様- 3バイト送られてくる毎にコールバック

  • 送られきたバイト列を文字列としてディスプレイに表示
main.cpp
#include "MicroBit.h"
#include "MicroBitUARTService.h"

MicroBit uBit;
MicroBitUARTService *uart;

void onConnected(MicroBitEvent)
{
    uBit.display.printAsync("C");
    
    uart->eventAfter(3);
}

void onDisconnected(MicroBitEvent)
{
    uBit.display.printAsync("D");
}

void onDataReceived(MicroBitEvent)
{
    uint8_t buf[3];
    uart->read(buf, 3);
    char* cbuf = (char*) buf;
    uBit.display.scrollAsync(ManagedString(cbuf));
    
    uart->eventAfter(3);
}

int main()
{
    uBit.init();
    
    uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, onConnected);
    uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, onDisconnected);
    uBit.messageBus.listen(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH, onDataReceived);
    
    uart = new MicroBitUARTService(*uBit.ble, 32, 32);
    uBit.display.printAsync("U");
    
    release_fiber();
}
config.json
{
    "microbit-dal": {
        "bluetooth": {
            "enabled": 1,
            "open": 1,
            "whitelist": 0,
            "pairing_mode": 0,
            "advertising_timeout": 0,
            "tx_power": 0,
            "dfu_service": 0,
            "event_service": 0,
            "device_info_service": 1
        },
        "gatt_table_size": "0x600"
    }
}

ハマりどころとしては以下3つ。

  • イベント発火元がMICROBIT_ID_BLE_UART
  • eventAfterは1度呼ばれたら終わりなので毎回メソッド呼び出す必要がある
  • オフラインコンパイル時にconfig.jsonはプロジェクトのルートに置かないと反映されない

Mac

仕様

  • BLEのdevice nameに"micro:bit"が含まれているデバイスに接続
  • 複数台に接続
  • 5秒ごとに3文字のランダムな大文字アルファベットを送信
# coding: utf-8

import atexit
import time
import uuid
import sys
import random

import Adafruit_BluefruitLE
from Adafruit_BluefruitLE.services import UART

# Define service and characteristic UUIDs used by the UART service.
UART_SERVICE_UUID = uuid.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
TX_CHAR_UUID      = uuid.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E')
RX_CHAR_UUID      = uuid.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E')

microbits = dict()
known_devices = set()

ble = Adafruit_BluefruitLE.get_provider()
ble.initialize()

def main():
    ble.clear_cached_data()
    ble.list_adapters()
    ble.list_devices()
    
    adapter = ble.get_default_adapter()
    adapter.power_on()
    print('Using adapter: {0}'.format(adapter.name))
    print('Disconnecting any connected UART devices...')
    ble.disconnect_devices([UART_SERVICE_UUID])
    time.sleep(1.0)

    adapter.start_scan()
    atexit.register(adapter.stop_scan)
    print('Searching for UART devices...')
    
    txs = []
    rxs = []
    counter = 0
    
    while True:
        found = set(ble.find_devices())
        new = found - known_devices
        for device in new:
            print('Found devices: {0} [{1}]'.format(device.name, device.id))
            if device.name is not None and "micro:bit" in device.name:
                print('Connect to microbit')
                device.connect()
                device.discover([UART_SERVICE_UUID], [TX_CHAR_UUID, RX_CHAR_UUID])
                uart = device.find_service(UART_SERVICE_UUID)
                txs.append(uart.find_characteristic(RX_CHAR_UUID))
                rxs.append(uart.find_characteristic(TX_CHAR_UUID))
        known_devices.update(new)
        time.sleep(1.0)
        
        if len(txs) > 0:
            counter += 1
            if counter % 5 == 0:
                for tx in txs:
                    value = ""
                    for i in range(3):
                        value += chr(random.randrange(65,90))
                    print(value)
                    tx.write_value(value)

ble.run_mainloop_with(main)

みんなのPython 第4版

みんなのPython 第4版

oscpyの使い方

GitHub - kivy/oscpy: An efficient OSC implementation compatible with python2.7 and 3.5+
Python2.7でもちゃんと使えてまだコードが読めるレベルのOSCライブラリを探したら、記事執筆時点ではoscpyぐらい。ただ、githubのREADMEが間違ってたので、使い方のサンプル載せときます。大変簡単です。*1

from oscpy.server import OSCThreadServer
from oscpy.client import OSCClient

try:
    print('Starting osc server...')
    osc_server = OSCThreadServer()
    osc_client = OSCClient('localhost', 10000)
    sock = osc_server.listen(port=8000, default=True)
    
    @osc_server.address(b'/m')
    def callback(*values):
    	print(values)
    	osc_client.send_message(b'/m', [0, 200, "Hello World"])

    while True:
        pass

finally:
    osc_server.stop(sock)

*1:もったいないので後でプルリク送るかも

『Rotary Objects』

はじめに

カメラ付きの携帯電話が普及しきった今、出先でなにかが起きた時、写真を撮るのは当たり前の行為となりました。その結果、人々は2つの目を持ったといえます。自分自身の目と機械の目です。普段は機械側が人間の目による見た目に近づけているため、その違いに気づきにくいのですが、シチュエーションによってその違いが出てくることがあります。例えば、日が傾き薄暗くなってきた頃にスマートフォンやデジカメで写真を撮ろうとすると、画面上では自分の目で見るよりも明るい状態の被写体が見えることがあります。機械側の方が人間よりも高感度なセンサを持っているために起きる現象です。

このような人間の目と機械の違いから生じる現象の中に、ローリングシャッター現象と呼ばれているものがあります。今回、僕はこの現象を利用したメディアアート作品『Rotary Objects』の制作に参加*1し、中国の上海にある高層ビルである上海環球金融中心*2で行われた中国Hondaスポンサードの現代美術展覧会『混合HYBRID』にて展示*3を行いました。この記事では本作品の紹介とローリングシャッター現象の解説をします。

作品

『Rotary Objects』はローリングシャッター現象を利用した作品です。高速で回転することで、人間の目と機械の目に対して異なった見え方をもたらします。


展示の様子

f:id:miso_engine:20151224042700j:plain
f:id:miso_engine:20151224163712j:plain
f:id:miso_engine:20151224154413j:plain

ローリングシャッター現象

 この現象は高速で移動する物体を撮ると、被写体が歪んだイメージが出力される現象です。飛行機のプロペラはこの現象がわかりやすく出る代表例と言えます。また、より身近な例だと電車で車窓を撮影すると線路の横にある電信柱が歪む、などもローリングシャッター現象です。

Airplane Prop + CMOS Rolling Shutter = WTFwww.flickr.com
Soren Ragsdale CC By 2.0

 ローリングシャッター現象の原因は、現在デジタルカメラに広く使われるCMOSセンサの特性にあります。CMOSセンサはセンサの画素を時間差がある状態で走査するため、画面全体として同時に光を取得することが出来ません。そのため、高速で動く被写体は現実とは異なる形で記録されるのです。下のアニメーションは、CMOSセンサで回転する物体を撮影した時に、どのように写真が出来ていくかを示したものです。

f:id:miso_engine:20160425170106g:plain
cmglee CC By 3.0

 より詳しくは下記リンク等を見てください。
CMOSセンサーについて| 技術情報 | サポート | HDV | 映像制作機材 | プロフェッショナル/業務用製品情報 | ソニー

反応など

f:id:miso_engine:20151224154210j:plain
f:id:miso_engine:20151224163719j:plain
 台の上に「携帯のカメラで見てみてください」というキャプションを置いていました。そのキャプションを見てスマートフォンをかざし、「おお!」という人もいれば、そのキャプションに気づかずにただ写真を撮ろうとした時に現れた時に小さく叫んで驚く人もいるという会場の雰囲気でした。原理的にカメラの位置、センサの向きで見え方が変わるため、複数人で体験するとそれぞれのスマートフォンを見比べる楽しみもあるようで、色々試して盛り上がっているグループも多く見受けられました。
http://weibo.com/2141100877/DaQPHBwH0?type=comment#_rnd1461577916488
 SNS上の反応では、ウェイポー上でいくつか投稿されていて、結構反応されてるようです。中国語が全然わからないので、コメントがたくさんついてることくらいしかわからないのが残念です。Google翻訳かけようとしても出来ないので……。

ミニ&改善バージョン

f:id:miso_engine:20180731225036j:plainf:id:miso_engine:20180731225803j:plain
Rotary Objects Mini

 本作品はビデオで見るとCMOSの目を通してしまい体験出来ない構造的問題があります。そこで、弊社(アートアンドプログラム株式会社)で展示するためのミニバージョンを作りました。弊社にお越しの際は、ぜひ自分自身の目で体験してみてください。このバージョンでは回転制御を追加したため、安定した見え方になりました。また、異なる回転体を置くことも出来ます。

はじめにの前に

 この記事を書き始めたのが2016年の1月で、それから現在(2018年8月)まで塩漬けにしておりました……。というのも作品のミニ&改良バージョンを作ってたら2年半経っていた、という次第です。

*1:ISHII 2BIT + Friends名義

*2:森ビルの建物で上海のヒルズのようなところ。上海で現在2番目に高いビル

*3:2015/12/24-2016/1/5