Bluetooth®でNano 33 BLEデバイスを接続する
i
このチュートリアルは、すでに製品ライフサイクルの終了(EOL)を迎えた製品を対象としています。

Bluetooth®の歴史と、Bluetooth®Low Energyの動作原理、2台のNano BLEデバイスをBluetooth®で接続する方法を学びます。


Author:Nefeli AlushiLast revision:2022/03/18

はじめに

このチュートリアルでは、Bluetooth® Low Energyを通じて、Nano 33 BLEとNano 33 BLE Senseの2台のArduinoボード間で情報を交換する方法を学びます。これには、ArduinoBLEライブラリを使います。

目的

  • Bluetooth® Low Energyの基礎を学びます。
  • ArduinoBLEライブラリ"を使います。
  • 2台のArduinoボード間で、Bluetooth® Low Energyを通じて情報を交換します。

必要なハードウェアとソフトウェア

Bluetooth®の歴史

Bluetooth®規格は20年以上前の、1994年に、エリクソンのJaarp Haartsen博士により考案されました。この規格は、10 世紀にデンマークとノルウェーを統一した有名なバイキングのKing Harald Gormssonから名付けられました。Haartsen博士はRS-232規格を置き換える近距離無線通信規格を開発するよう命じられました。RS-232は、1960年代に考案され、今も利用されている有線通信規格です。

Bluetooth®は、短距離無線技術として知られる技術を使っています。これは、免許不要ですが、規格化されている2.4GHzから2.485GHz帯を使い、2台以上のデバイスを接続・通信するのに、無線を使います。Bluetooth®は、周波数ホッピング方式に基づいています。この方式は、1940年代に、女優のHedy Lamarrと作曲家のGeorge Antheilにより、最初に説明されました。LamarrとAntheilは、無線誘導魚雷が妨害されない方法を作ろうと考えました。Bluetooth®は、本質的には、ピコネットと呼ばれる短距離無線ネットワークです。

1994年には、エリクソンのほかに、インテルやノキア、IBM、東芝などの企業も電子機器間での短距離無線通信接続のアイデアを持っていました。この時点でこれらの企業が理解したのは、異なる電子機器間で短距離無線接続するには、プロトコルが標準化され、一般的に利用される必要があるということです。1996年に、これらの企業は、Bluetooth® Special Interest Group (SIG)を結成し、最終的に1998年に設立されました。SIGは5人のメンバーで開始しましたが、最初の年の終わりには4000人に達しました。今は30000人以上となっています。

Bluetooth®の目的は、King Harald Gormssonがデンマークの民族を一つの王国に統一したように、機器を統一することです。

Bluetooth® 1.0が1999年ごろにリリースされ、それ以降、2004年にバージョン2.0、2007年にバージョン2.1、2009年にバージョン3.0、2010年にバージョン4.0、2013年にバージョン4.1、2014年にバージョン4.2、2016年にバージョン5.0、2019年にバージョン5.1がリリースされました(かなりの作業量です)。

Bluetooth® 3.0の仕様を見ると、この仕様には3つの動作モード、BR、EDR、HS(AMP)があることがわかります。これら3つの動作モードは、通常、クラシックBluetooth®と便宜上呼ばれています。2010年に、SIGは、ノキアとNordicセミコンダクターなどが開発した無線技術のWibreeを取り込みました。これらの企業の目的は、電子機器向けの低電力無線通信技術を見つけることでした。SIGは、WibreeをBluetooth® Low Energyと改名しました。Bluetooth® Low Energyは、Bluetooth®無線がオンになっているそう時間を削減することで、劇的に消費電力を削減するために設計されました。クラシックBluetooth®とBluetooth® Low Energyは両方とも、Bluetooth® 4.0仕様から含まれていますが、以下の問題があります。クラシックBluetooth®とBluetooth® Low Energyは異なる動作なので、互換性がありません。

さらに、クラシックBluetooth®とBluetooth® Low Energyは、異なる物理層の変調・復調方式を採用しています。これは、クラシックBluetooth®とBluetooth® Low Energyは相互に動作しないことを意味しています。一般に、クラシックBluetooth®は主にオーディをアプリケーション(例えばワイヤレスヘッドフォン)に使われ、一方、Bluetooth® Low Energyは、電力制限のあるアプリケーション(例えば、ウェアラブルやIoTデバイス)でより多く使われています。

Bluetooth® Low Energyの動作原理

Bluetooth® Low Energyの動作を理解するには、Bluetooth®で接続される2つのデバイスの役割と責任を説明する必要があります。全てのBluetooth®接続では、セントラル(Central)とペリフェラル(Perihperal)という、2つの役割が演じられます。セントラルの役割を持つデバイスはサーバーとも呼ばれ、ペリフェラルの役割を持つデバイスはクライアントとも呼ばれます。

Bluetooth®接続が確立すると、ペリフェラルデバイスは、自身の情報を近隣のデバイスにアドバタイズ (advertise)もしくはブロードキャスト(broadcast)します。同時に、セントラルは、スキャンし、(複数の)デバイスが情報をブロードキャストしているか監視します。広告しているペリフェラルデバイスからの情報をセントラルデバイスが取得するとすぐに、ペリフェラルデバイスとの接続を試みます。接続が確立すると、セントラルデバイスは、ペリフェラルデバイスが持つ利用可能な情報を交換します。この情報交換は、サービスと呼ばれる機能を使って行われます。

サービスとキャラクタリスティック

サービス(Service)は、ケイパビリティ(Capabilities)の集合です。例えば、スマートウォッチは、心拍数を測定し、一日の身体活動を監視し、睡眠パターンを監視します。例えば、これらの3つのケイパビリティは、ヘルスサービスというサービス内に存在します。ケイパビリティをサービスでグループ化することで、セントラルデバイスは、ペリフェラルデバイスがを必要なサービスを、迅速に発見・選択・通信することができます。全てのサービスは、UUIDと呼ばれる一意の識別子を持ちます。この識別子は、公式のBluetooth®規格のサービスでは、16ビット長か32ビット長で、非公式のBluetooth®サービス(我々が開発できるもの)は128ビット長です。UUIDはランダムに生成されます。プロファイル(Profile)は、サービスの集合です。

各サービスには、キャラクタリスティックのリストが存在します。個々のキャラクタリスティックはセントラルデバイスの独自ケイパビリティを表します。前の例では、ヘルスサービスは3つのキャラクタリスティック(心拍、身体活動、睡眠パターン)を持ちます。ペリフェラルデバイスがこれらのキャラクタリスティックを発見すれば、情報を書き込んだり、情報を要求したり、キャラクタリスティックからの更新を予約することができます。サービスなどの全てのキャラクタリスティックは、16ビット長もしくは128ビット長のUUIDを持ちます。

Bluetooth® Low Energyでの情報交換

接続した2つのデバイス間でデータを交換するには、読み取り(Read)と書き込み(Write)、通知(Notify)の3種類があります。読み取りは、ペリフェラルデバイスがセントラルデバイスに対して、特定の情報を要求したときに起こります。スマートフォンがスマートウォッチに身体活動に関する情報を要求することを考えてください。これが読み取りの例です。書き込みは、ペリフェラルデバイスがセントラルデバイスに特定の情報を書くときに起こります。スマートフォンがスマートウォッチのパスワードを変更することを考えてください。これが書き込みの例です。通知は、セントラルデバイスがペリフェラルデバイスに通知を使って情報を要求すると起こります。スマートウォッチがスマートフォンに対して、バッテリ容量の低下を通知し、充電が必要だと知らせることを考えてください。

これが、Bluetooth® Low Energyについて、現時点で知っておく必要があることです。 Bluetooth®規格は多岐にわたりますが、読んで学ぶのは興味深いことです。Bluetooth® Low Energyについて、さらに知りたい場合は、Getting Started with Bluetooth® Low Energy by Kevin Townsend, Carles Cufí, Akiba, and Robert Davidsonを参照してください。

Bluetooth® Low EnergyとArduinoの利用

Arduinoで、Bluetooth® Low Energyを使ってみましょう。この例では、Nano 33 BLEとNano 33 BLE Senseの、2台のArduinoボードを使い、それらの間で情報を交換します。ボードの一方のボードであるNano 33 BLE Senseはセントラルデバイスとして、もう一方のボードのNano 33 BLEは、ペリフェラルデバイスとして設定します。ボード間で共有する情報は、Nano 33 BLE Senseの組込みジェスチャーセンサーの情報です。このため、gesture_typeという一つのキャラクタリスティックを持つ、gestureServiceというサービスを作成します。

セントラルデバイス(Nano 33 BLE Sense)は、ペリフェラルデバイス(Nano 33 BLE)に接続し、gestureServiceというサービスを探します。セントラルデバイスとペリフェラルデバイス間で接続が確立後、セントラルデバイスがジェスチャーセンサーでジェスチャーを検出すると、gestureServiceのgesture_typeキャラクタリスティックに、センサーで検出したジェスチャーのタイプを、書きます。すると、gesture_typeキャラクタリスティック内に格納された値に応じて、ペリフェラルデバイス(Nano 33 BLE)が、gesture_typeに格納された色に従って、内蔵RGB LEDの特定の色を点灯させます。

ボードのプログラミング

  1. まず、Nano 33 BLEボード用のドライバーがインストールされていることを確認します。オンラインIDEを使っているときは、何もインストールする必要はありません。オフラインIDEを使っているときは、インストールする必要があります。ツール > ボード > ボードマネージャ… で、Arduino Mbed OS Nano Boardsを検索し、インストールします。
  2. また、必要なすべてのライブラリがインストールされていることを確認してください。オンラインIDEを使っているときは、何もインストールする必要はありません。オフラインIDEを使っているときは、ツール > ライブラリを管理… で、ArduinoBLEとArduino_APDS9960を検索し、両方ともインストールします。

セントラルデバイスのプログラミング

セントラルデバイスの完全なコードを以下に示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
  BLE_Central_Device.ino

  This program uses the ArduinoBLE library to set-up an Arduino Nano 33 BLE Sense 
  as a central device and looks for a specified service and characteristic in a 
  peripheral device. If the specified service and characteristic is found in a 
  peripheral device, the last detected value of the on-board gesture sensor of 
  the Nano 33 BLE Sense, the APDS9960, is written in the specified characteristic. 

  The circuit:
  - Arduino Nano 33 BLE Sense. 

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#include <Arduino_APDS9960.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

int gesture = -1;
int oldGestureValue = -1;   

void setup() {
  Serial.begin(9600);
  while (!Serial);
  
  if (!APDS.begin()) {
    Serial.println("* Error initializing APDS9960 sensor!");
  } 

  APDS.setGestureSensitivity(80); 
  
  if (!BLE.begin()) {
    Serial.println("* Starting Bluetooth® Low Energy module failed!");
    while (1);
  }
  
  BLE.setLocalName("Nano 33 BLE (Central)"); 
  BLE.advertise();

  Serial.println("Arduino Nano 33 BLE Sense (Central Device)");
  Serial.println(" ");
}

void loop() {
  connectToPeripheral();
}

void connectToPeripheral(){
  BLEDevice peripheral;
  
  Serial.println("- Discovering peripheral device...");

  do
  {
    BLE.scanForUuid(deviceServiceUuid);
    peripheral = BLE.available();
  } while (!peripheral);
  
  if (peripheral) {
    Serial.println("* Peripheral device found!");
    Serial.print("* Device MAC address: ");
    Serial.println(peripheral.address());
    Serial.print("* Device name: ");
    Serial.println(peripheral.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(peripheral.advertisedServiceUuid());
    Serial.println(" ");
    BLE.stopScan();
    controlPeripheral(peripheral);
  }
}

void controlPeripheral(BLEDevice peripheral) {
  Serial.println("- Connecting to peripheral device...");

  if (peripheral.connect()) {
    Serial.println("* Connected to peripheral device!");
    Serial.println(" ");
  } else {
    Serial.println("* Connection to peripheral device failed!");
    Serial.println(" ");
    return;
  }

  Serial.println("- Discovering peripheral device attributes...");
  if (peripheral.discoverAttributes()) {
    Serial.println("* Peripheral device attributes discovered!");
    Serial.println(" ");
  } else {
    Serial.println("* Peripheral device attributes discovery failed!");
    Serial.println(" ");
    peripheral.disconnect();
    return;
  }

  BLECharacteristic gestureCharacteristic = peripheral.characteristic(deviceServiceCharacteristicUuid);
    
  if (!gestureCharacteristic) {
    Serial.println("* Peripheral device does not have gesture_type characteristic!");
    peripheral.disconnect();
    return;
  } else if (!gestureCharacteristic.canWrite()) {
    Serial.println("* Peripheral does not have a writable gesture_type characteristic!");
    peripheral.disconnect();
    return;
  }
  
  while (peripheral.connected()) {
    gesture = gestureDetectection();

    if (oldGestureValue != gesture) {  
      oldGestureValue = gesture;
      Serial.print("* Writing value to gesture_type characteristic: ");
      Serial.println(gesture);
      gestureCharacteristic.writeValue((byte)gesture);
      Serial.println("* Writing value to gesture_type characteristic done!");
      Serial.println(" ");
    }
  
  }
  Serial.println("- Peripheral device disconnected!");
}
  
int gestureDetectection() {
  if (APDS.gestureAvailable()) {
    gesture = APDS.readGesture();

    switch (gesture) {
      case GESTURE_UP:
        Serial.println("- UP gesture detected");
        break;
      case GESTURE_DOWN:
        Serial.println("- DOWN gesture detected");
        break;
      case GESTURE_LEFT:
        Serial.println("- LEFT gesture detected");
        break;
      case GESTURE_RIGHT:
        Serial.println("- RIGHT gesture detected");
        break;
      default:
        Serial.println("- No gesture detected");
        break;
      }
    }
    return gesture;
}

ペリフェラルデバイスのプログラミング

ペリフェラルデバイスの完全なコードを以下に示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
  BLE_Peripheral.ino

  This program uses the ArduinoBLE library to set-up an Arduino Nano 33 BLE 
  as a peripheral device and specifies a service and a characteristic. Depending 
  of the value of the specified characteristic, an on-board LED gets on. 

  The circuit:
  - Arduino Nano 33 BLE. 

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
      
enum {
  GESTURE_NONE  = -1,
  GESTURE_UP    = 0,
  GESTURE_DOWN  = 1,
  GESTURE_LEFT  = 2,
  GESTURE_RIGHT = 3
};

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

int gesture = -1;

BLEService gestureService(deviceServiceUuid); 
BLEByteCharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite);


void setup() {
  Serial.begin(9600);
  while (!Serial);  
  
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
  digitalWrite(LED_BUILTIN, LOW);

  
  if (!BLE.begin()) {
    Serial.println("- Starting Bluetooth® Low Energy module failed!");
    while (1);
  }

  BLE.setLocalName("Arduino Nano 33 BLE (Peripheral)");
  BLE.setAdvertisedService(gestureService);
  gestureService.addCharacteristic(gestureCharacteristic);
  BLE.addService(gestureService);
  gestureCharacteristic.writeValue(-1);
  BLE.advertise();

  Serial.println("Nano 33 BLE (Peripheral Device)");
  Serial.println(" ");
}

void loop() {
  BLEDevice central = BLE.central();
  Serial.println("- Discovering central device...");
  delay(500);

  if (central) {
    Serial.println("* Connected to central device!");
    Serial.print("* Device MAC address: ");
    Serial.println(central.address());
    Serial.println(" ");

    while (central.connected()) {
      if (gestureCharacteristic.written()) {
         gesture = gestureCharacteristic.value();
         writeGesture(gesture);
       }
    }
    
    Serial.println("* Disconnected to central device!");
  }
}

void writeGesture(int gesture) {
  Serial.println("- Characteristic <gesture_type> has changed!");
  
   switch (gesture) {
      case GESTURE_UP:
        Serial.println("* Actual value: UP (red LED on)");
        Serial.println(" ");
        digitalWrite(LEDR, LOW);
        digitalWrite(LEDG, HIGH);
        digitalWrite(LEDB, HIGH);
        digitalWrite(LED_BUILTIN, LOW);
        break;
      case GESTURE_DOWN:
        Serial.println("* Actual value: DOWN (green LED on)");
        Serial.println(" ");
        digitalWrite(LEDR, HIGH);
        digitalWrite(LEDG, LOW);
        digitalWrite(LEDB, HIGH);
        digitalWrite(LED_BUILTIN, LOW);
        break;
      case GESTURE_LEFT:
        Serial.println("* Actual value: LEFT (blue LED on)");
        Serial.println(" ");
        digitalWrite(LEDR, HIGH);
        digitalWrite(LEDG, HIGH);
        digitalWrite(LEDB, LOW);
        digitalWrite(LED_BUILTIN, LOW);
        break;
      case GESTURE_RIGHT:
        Serial.println("* Actual value: RIGHT (built-in LED on)");
        Serial.println(" ");
        digitalWrite(LEDR, HIGH);
        digitalWrite(LEDG, HIGH);
        digitalWrite(LEDB, HIGH);
        digitalWrite(LED_BUILTIN, HIGH);
        break;
      default:
        digitalWrite(LEDR, HIGH);
        digitalWrite(LEDG, HIGH);
        digitalWrite(LEDB, HIGH);
        digitalWrite(LED_BUILTIN, LOW);
        break;
    }      
}

コードのテスト

コードが完成したら、双方のスケッチをボードにアップロードします。まず、セントラルデバイス(Arduino nano 33 BLE Sense)の正しいポートを選択し、シリアルモニタを開いて、セントラルデバイスが想定通りに動作しているか確認します。シリアルモニタには、以下が表示されます。

電源を入れた後、セントラルデバイスは指定したサービスとキャラクタリスティックを持つペリフェラルデバイスの検索を開始します。指定したサービスとキャラクタリスティックを持つデバイスを発見すると、シリアルモニタには、以下が表示されます。

セントラルデバイスから、以下のフィードバックが得られます。

  • ペリフェラルデバイスのMACアドレス
  • ペリフェラルデバイスのローカルネーム
  • ペリフェラルデバイスのアドバータイズサービスUUID

その後、セントラルデバイスは、ペリフェラルデバイスと接続を確立しようとします。また、前に指定したサービスとキャラクタリスティックを発見しようとします。両方とも成功すると、Nano 33 BLE Senseボードの内蔵ジェスチャーセンサーを起動できます。Nano 33 BLE SenseボードのUSBポートを下に向け、正面に立てた状態で安定させます。そして、手を上・下・右・左と手を動かします。ジェスチャーセンサーがジェスチャーを検出すると、シリアルモニタには、以下が表示されます。

セントラルデバイスから、以下のフィードバックが得られます。

  • 検出したジェスチャータイプ(UP、DOWN、RIGHT、LEFT)。
  • ペリフェラルデバイスのgestureサービスのgesture_typeキャラクタリスティックに書いた値。

また、検出したジェスチャーに応じて、ペリフェラルデバイスの内蔵LEDが光ります。

  • 上向けジェスチャーを検出: 赤色LEDが点灯
  • 下向けジェスチャーを検出: 緑色LEDが点灯
  • 右向けジェスチャーを検出: 内蔵LEDが点灯
  • 左向けジェスチャーを検出: 青色LEDが点灯

ペリフェラルポートから、シリアルポート経由でもフィードバックが得られます。フィードバックにより、ペリフェラルデバイス(Arduino nano 33 BLE)の正しいポートを選択し、シリアルモニタを開いて、ペリフェラルデバイスが想定通りに動作しているか確認します。シリアルモニタには、以下が表示されます。

ペリフェラルデバイスから、以下のフィードバックが得られます。

  • セントラルデバイスのMACアドレス
  • セントラルデバイスのローカルネーム
  • gesture_typeキャラクタリスティックの実際の値と点灯している内蔵LED。

トラブルシュート

エラーが起きることもあります。コードが動作しないときはいくつかの共通の問題があり、解決できます。

  • 括弧やセミコロンが抜けている。
  • Arduinoボードが、間違ったポートに接続されている。
  • ケーブル接続の予期しない切断。
  • プログラムを初期化するためにシリアルモニタを開いていない。

おわりに

このチュートリアルでは、 Bluetooth® Low Energy経由で、Nano 33 BLEとNano 33 BLE Senseの2台のArduino間で情報を交換する方法を学びました。また、Bluetooth® Low Energyの基礎と、動作方法、サービスとキャラクタリスティックとは何か、Bluetooth® Low Energyでの情報交換方法を学びました。最後に、Nano 33 BLE Senseから送信される値(内蔵ジェスチャーセンサーを使って定義されます)に応じて、Arduino Nano 33 BLEの内蔵RGB LEDの異なる色を点灯させました。

オリジナルのページ

https://docs.arduino.cc/tutorials/nano-33-ble-sense/ble-device-to-device/

最終更新日

August 16, 2026

inserted by FC2 system