Arduinoとスマートフォンの間でデータのやり取りをしたい場合、Wifi通信を使う方法やBLE通信を使う方法が一般的です。ここではBLE Nanoと呼ばれるモジュールを使ってArduinoとiPhoneの間でデータ通信をしてみたいと思います。
Wifiを使って通信をする場合はESP-WROOM-02というモジュールを使うのが簡単です。このモジュールの使い方は次の記事にまとめているので参考にして下さい。
nn-hokuson.hatenablog.com
今回の記事の内容は次のようになります。
BLEモジュールを選定する
Arduinoには標準ではBLEがついていないため、次の3つの方法のいずれかでBLEを使うことになります。
- BLEつきのArduinoを使う
- BLEモジュールをArduinoに追加する
- BLEモジュールをArduinoとして使う
BLEモジュールをArduinoに追加する
こちらはArduinoに外付けでBLEモジュールを追加する方法です。スマートフォンと通信する場合は浅草ギ研のBLE Serialモジュールが良さそうです。ホームページでもスマートフォンとの接続方法やプログラムなども公開されており、簡単に始められます。お値段は4000円。
www.robotsfx.com
BLEモジュールをArduinoとして使う
最後の選択肢は、BLEモジュールをArduinoとして使う方法です。これはRedBearLabのBLENano キット V2を使用します。このモジュールはArduinoのエディタからプログラムを書き込むことができ、プログラムもArduinoと同じように作ることができます。この記事ではこのBLENanoを使ってスマートフォンと通信する方法を紹介します。BLENanoは2018年1月現在、SWITCH SCIENCEから3888円で販売されています。
www.switch-science.com
ArduinoでBLENanoを使う準備
BLENanoのキットを使うことで簡単にiPhoneやAndroidと通信するプログラムを作ることができます。BLENanoのキットはライター(DAPLink)とBLEモジュールの2つで構成されています。使用するときはライターから取り外してBLEモジュールのみで使うことができます。
BLENano v2をArduinoの開発環境で使うために、まずはパッケージをインストールする必要があります。使用するパッケージはnRF52832用のもので、BLENano v1で使用しているnRF51822とは異なるので注意して下さい。
少し古いサイトだとnRF51822のパッケージを使用する方法がかかれていますが、このパッケージではBLENanoにプログラムを正しく書き込むことはできないので注意して下さい。
Arduinoを起動し、メニューバーから「Arduino→Preferences」を選択、追加のボードマネージャーのURLの欄に次のURLを入力して下さい。
https://redbear.github.io/arduino/package_redbear_nRF5x_index.json.
続いてメニューバーから「ツール→ボード→ボードマネージャー」を選択して、ボードマネージャウインドウを開いて下さい。リストから「RedBear nRF52832 Boards」を選択し、インストールして下さい。
最後にメニューバーから「ツール→ボード」から「BLENano2」、「ツール→書き込み装置」から「RBL_DAPLINK」を選択します。
これでBLENano v2を使う準備は完了です。いよいよArduinoとスマートフォンを繋ぐBLE通信システムを作っていきましょう!
今回作成するBLE通信システム概要
今回はBLENano(Arduino)がペリフェラル、iPhoneがセントラルになるようなシステムを作ります。ペリフェラル側(BLENano)のボタンを押したら、1byteのデータがセントラル(iPhone)に送信されます。
ペリフェラル・セントラルというのはBLE通信でよく使われる言葉で、ペリフェラル=クライアント、セントラル=サーバみたいなものです。BLE通信の概要はクラゲのIoTテクノロジーさんの「開発視点の超簡単BLE入門」で非常にわかりやすく説明されているので、一度読んでおくと、BLE開発の主要な用語と流れがつかめると思います。
jellyware.jp
ペリフェラル側を作る
まずはBLENanoにペリフェラルのプログラムを書き込みましょう。Arduinoを開いて次のプログラムを入力してください。
#include <nRF5x_BLE_API.h>
#define DEVICE_NAME "Simulated RFduino"
#define TXRX_BUF_LEN 20
BLE ble;
Timeout timeout;
Ticker ticker_task1;
int prev = HIGH;
static const uint8_t service1_uuid[] = { 0x00, 0x00, 0x22, 0x20, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_tx_uuid[] = { 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_rx_uuid[] = { 0x00, 0x00, 0x22, 0x21, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_uuid_rev[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x20, 0x22, 0x00, 0x00 } ;
uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};
GattCharacteristic characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );
GattCharacteristic characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};
GattService uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
void periodicCallback()
{
static uint8_t value = 0x30;
int v = digitalRead(D2);
if( v == LOW && prev == HIGH){
ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), (uint8_t *)&value, 1);
value++;
}
prev = v;
}
void setup()
{
Serial.begin(9600);
pinMode(D2, INPUT_PULLUP);
ticker_task1.attach(periodicCallback, 0.1);
ble.init();
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
(const uint8_t *)"TXRX", sizeof("TXRX") - 1);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
(const uint8_t *)service1_uuid_rev, sizeof(service1_uuid_rev));
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.addService(uartService);
ble.setDeviceName((const uint8_t *) DEVICE_NAME);
ble.setTxPower(4);
ble.setAdvertisingInterval(160);
ble.setAdvertisingTimeout(0);
ble.startAdvertising();
Serial.println("Advertising Start!");
}
void loop() {
ble.waitForEvent();
}
ここではサービスとキャラクタリスティクスのUUIDを次のように定義しました。
Service UUID |
00002220-0000-1000-8000-00805f9b34fb |
Characteristics1 |
00002221-0000-1000-8000-00805f9b34fb |
Characteristics2 |
00002222-0000-1000-8000-00805f9b34fb |
プログラムが書き込めたら、BLENanoを書き込み装置から取り外して、次のような回路を作成します。ここではボタンが押された場合にBLENanoのD2端子がLOWになるようにしています。
回路に電源を入れたらBLENanoはペリフェラルとしての動作を自動的に開始し、アドバタイズメントのパケットを送信しはじめます。
セントラル側をつくる
続いてスマートフォンで動くセントラルアプリを作成します。ここではUnityを使ってセントラル側のプログラムを作ります。iOS/Androidのネイティブプログラムでセントラルを作りたい場合は↓を参考にしてみてください。
Unityには、「Bluetooth LE for iOS, tvOS and Android」という超便利なアセットがすでに用意されています。これは、名前の通りiOSやAndroidのBLE通信コードをラップしたPluginです。C#だけでAndroidでもiOSでも簡単にBLE通信のプログラムを作ることができます。
ここでも、「Bluetooth LE for iOS, tvOS and Android」のアセットに付属するサンプルコードを使いましょう。上記アセットをインポートした後、Asset/Example/SimpleTestにある「SimpleTest.unity」をダブルクリックしてシーンを開いてください。
SimpleTest.csがBLE通信のプログラムです。ヒエラルキービューでMain Cameraを選択し、インスペクタからSimple Testのパラメータを設定します。先ほどペリフェラルに書き込んだDevice Name、Service UUID、Characteristicを指定しましょう。ここでは次のように設定しました。
UUIDは短縮で記述することができます。短縮する場合はUUIDの4文字目から8文字目までを指定します。サービスのUUIDは00002220-0000-1000-8000-00805f9b34fbですので、短縮で記述すると「2220」になります。UUIDの短縮についてはこちらもクラゲのIoTテクノロジーさんの「UUID詳細」が参考になります。
jellyware.jp
サンプルについてくるSimpleTestスクリプトでは動かないことがあるようなので、UpdateメソッドのScanのcase文を次のように書き換えて下さい。
case States.Scan:
string[] serviceIDs = { ServiceUUID };
BluetoothLEHardwareInterface.ScanForPeripheralsWithServices (serviceIDs, (address, name) => {
if (!_rssiOnly)
{
{
BluetoothLEHardwareInterface.StopScan ();
_deviceAddress = address;
SetState (States.Connect, 0.5f);
}
}
}, (address, name, rssi, bytes) => {
{
if (_rssiOnly)
{
_rssi = rssi;
}
else
{
BluetoothLEHardwareInterface.StopScan ();
_deviceAddress = address;
SetState (States.Connect, 0.5f);
}
}
}, _rssiOnly);
if (_rssiOnly)
SetState (States.ScanRSSI, 0.5f);
break;
設定が完了したら、スマートフォンにアプリを書き込んでください。指定したService UUIDをアドバタイズしているペリフェラルに自動的に接続し、待機状態になります。待機状態になると次のような画面(左)がスマートフォン上に表示されます。
この状態でペリフェラル側のスイッチを押してみて下さい。スマートフォンに「30」と表示(画面右)されれば成功です!
トラブルシューティング
スマートフォン側が正しく動かない場合、まずはペリフェラルが動いているかをチェックしましょう。BLE Scanner 4.0などのアプリが用意されているので、ちゃんとペリフェラルに接続できるか試してみると良いです。
おまけ:ネイティブプログラムを作りたい場合のオススメ
スマートフォンをセントラルとして動かすプログラムを作るにはiOSの場合はCore Bleutoothのリファレンスが参考になります。このCoreBluetoothのリファレンス、かなーりサンプルコードがしっかりと書かれているので、このとおり作っていけば簡単にセントラルのプログラムが作成できます。
iOS用にBLEの通信プログラムを作る場合は次の「iOSxBLE Core Bluetoothプログラミング」が非常に参考になりました。
[asin:4883379736:detail]
また、AndroidでBLEの通信プログラムを作る場合はこちらのサイトが参考になります。
qiita.com