Skip to content
Published on

Seeed Studio XIAO nRF52840 完全ガイド — BLE IoTプロジェクト実践

Authors
  • Name
    Twitter
XIAO nRF52840

はじめに

XIAO nRF52840 — 21mm × 17.5mmのサイズにBLE 5.0、6軸IMU、マイク、256KB RAMを搭載した超小型ボード。ウェアラブル、IoTセンサー、TinyMLデバイスに最適です。

スペック比較

項目XIAO nRF52840XIAO nRF52840 SenseXIAO ESP32C3
プロセッサARM Cortex-M4F 64MHzARM Cortex-M4F 64MHzRISC-V 160MHz
RAM256KB256KB400KB
Flash1MB + 2MB QSPI1MB + 2MB QSPI4MB
ワイヤレスBLE 5.0BLE 5.0Wi-Fi + BLE 5.0
IMUなしあり(LSM6DS3TR-C)なし
マイクなしあり(PDM)なし
バッテリーリチウム充電回路内蔵リチウム充電回路内蔵なし
サイズ21×17.5mm21×17.5mm21×17.5mm
価格~$5.99~$15.99~$4.99

開発環境の構築

Arduino IDE

1. ボードマネージャURLを追加:
   https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json

2. ボードマネージャ → "Seeed nRF52 mbed-enabled Boards" をインストール

3. ボード選択:"Seeed XIAO BLE - nRF52840"

4. 注意:ブートローダモードへの入り方:RSTピンを素早く2回タッチ
   → オレンジ色LEDのフェード = ブートローダモード

BLE(Bluetooth Low Energy)プログラミング

BLEの基本概念

BLE構造:
├── GAP(Generic Access Profile) — 接続管理
│   ├── Peripheral(サーバー):データを提供(センサー)
│   └── Central(クライアント):データを要求(スマートフォン)
└── GATT(Generic Attribute Profile) — データ構造
    ├── Service:機能グループ(例:温度サービス)
    │   ├── Characteristic:データポイント(例:温度値)
    │   │   ├── Value:実際のデータ
    │   │   ├── Properties:Read/Write/Notify
    │   │   └── Descriptor:メタデータ
    │   └── Characteristic:...
    └── Service:...

BLEセンサーサーバー(Peripheral)

#include <ArduinoBLE.h>

// カスタムサービス + キャラクタリスティック定義
BLEService envService("181A");  // Environmental Sensing

BLEFloatCharacteristic tempChar("2A6E", BLERead | BLENotify);
BLEFloatCharacteristic humChar("2A6F", BLERead | BLENotify);
BLEByteCharacteristic ledChar("2A57", BLERead | BLEWrite);

void setup() {
    Serial.begin(115200);
    BLE.begin();

    // デバイス設定
    BLE.setLocalName("XIAO-Sensor");
    BLE.setAdvertisedService(envService);

    // キャラクタリスティック追加
    envService.addCharacteristic(tempChar);
    envService.addCharacteristic(humChar);
    envService.addCharacteristic(ledChar);
    BLE.addService(envService);

    // 初期値
    tempChar.writeValue(0.0f);
    humChar.writeValue(0.0f);
    ledChar.writeValue(0);

    // LED制御コールバック
    ledChar.setEventHandler(BLEWritten, onLedWrite);

    BLE.advertise();
    Serial.println("BLE Sensor Ready!");
}

void onLedWrite(BLEDevice central, BLECharacteristic characteristic) {
    byte value = ledChar.value();
    digitalWrite(LED_BUILTIN, value ? LOW : HIGH);
    Serial.print("LED: "); Serial.println(value ? "ON" : "OFF");
}

void loop() {
    BLEDevice central = BLE.central();

    if (central) {
        Serial.print("Connected: "); Serial.println(central.address());

        while (central.connected()) {
            // センサー読み取り(例:アナログ)
            float temp = analogRead(A0) * 0.1;  // 実際にはDHT22などを使用
            float hum = analogRead(A1) * 0.1;

            tempChar.writeValue(temp);
            humChar.writeValue(hum);

            delay(1000);
        }
        Serial.println("Disconnected");
    }
}

Python BLEクライアント(Central)

import asyncio
from bleak import BleakClient, BleakScanner
import struct

DEVICE_NAME = "XIAO-Sensor"
TEMP_UUID = "00002a6e-0000-1000-8000-00805f9b34fb"
HUM_UUID = "00002a6f-0000-1000-8000-00805f9b34fb"
LED_UUID = "00002a57-0000-1000-8000-00805f9b34fb"

async def main():
    # スキャン
    print("Scanning...")
    device = await BleakScanner.find_device_by_name(DEVICE_NAME)
    if not device:
        print("Device not found!")
        return

    # 接続
    async with BleakClient(device) as client:
        print(f"Connected: {device.address}")

        # Notify購読
        def on_temp(sender, data):
            temp = struct.unpack('<f', data)[0]
            print(f"  Temperature: {temp:.1f}°C")

        await client.start_notify(TEMP_UUID, on_temp)

        # LEDオン
        await client.write_gatt_char(LED_UUID, bytes([1]))

        await asyncio.sleep(30)  # 30秒モニタリング

asyncio.run(main())

低消費電力設計

#include <nrf_power.h>

// ディープスリープモード(System OFF — 0.5μA!)
void enterDeepSleep(int wakeupPin) {
    // ウェイクアップピン設定
    nrf_gpio_cfg_sense_input(
        digitalPinToInterrupt(wakeupPin),
        NRF_GPIO_PIN_PULLUP,
        NRF_GPIO_PIN_SENSE_LOW
    );

    // System OFF
    NRF_POWER->SYSTEMOFF = 1;
    // ここで停止 — ウェイクアップ時にリブート
}

// ライトスリープ(System ON + WFE — 1.5μA)
void lightSleep(uint32_t ms) {
    delay(ms);  // WFEベース、BLE接続を維持
}

// バッテリー寿命の計算:
// 110mAh LiPo、平均消費50μA(スリープ + 定期的BLEアドバタイジング)
// 寿命 = 110mAh / 0.05mA = 2,200時間 = 約91日!

センサーメッシュネットワーク

XIAO #1(リビング)     XIAO #2(寝室)         XIAO #3(キッチン)
  温度/湿度               照度                   ガスセンサー
    │                      │                      │
    └──── BLE ─────────────┴──── BLE ─────────────┘
                    Raspberry Pi(ゲートウェイ)
                    MQTTHome Assistant
                      ダッシュボード / アラート

TinyML(XIAO Sense)

// 内蔵IMUによるジェスチャー認識!
#include <LSM6DS3.h>
#include <gesture_model.h>  // TensorFlow Liteモデル

LSM6DS3 imu(I2C_MODE, 0x6A);
tflite::MicroInterpreter* interpreter;

void loop() {
    float ax, ay, az, gx, gy, gz;
    imu.readAcceleration(ax, ay, az);
    imu.readGyroscope(gx, gy, gz);

    // モデル入力
    input->data.f[0] = ax; input->data.f[1] = ay; input->data.f[2] = az;
    input->data.f[3] = gx; input->data.f[4] = gy; input->data.f[5] = gz;

    interpreter->Invoke();

    // ジェスチャー判定
    int gesture = output->data.f[0] > 0.8 ? WAVE :
                  output->data.f[1] > 0.8 ? PUNCH : IDLE;
    Serial.println(gestureName[gesture]);
}

クイズ — XIAO nRF52840 & BLE IoT(クリックして確認!)

Q1. BLEにおけるPeripheralとCentralの違いは? ||Peripheral(サーバー):データを提供しアドバタイズする側(センサー)。Central(クライアント):スキャンして接続し、データを要求する側(スマートフォン)||

Q2. GATTのService、Characteristic、Descriptorの関係は? ||Service:機能グループ(温度サービス)。Characteristic:実際のデータポイント(温度値)。Descriptor:メタデータ(単位、説明)。Service > Characteristic > Descriptorの階層構造||

Q3. XIAO nRF52840のSystem OFFモードの電流は? ||0.5μA。110mAhバッテリーで約91日動作可能。ウェイクアップ時にリブート(RAM内容は消失)||

Q4. BLE NotifyとReadの違いは? ||Read:Centralが要求したときのみ値を送信(ポーリング)。Notify:値が変更されるとPeripheralが自動的にプッシュ(イベント駆動)。Notifyの方が電力・遅延の面で効率的||