1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【M5Stack】BLEのRSSIがリアルタイムに更新できない時の原因と解決法

Posted at

まとめ

BLEを使ってRSSIを取得したいけど、よく分からないという方向けの記事です。
RSSIをリアルタイムに取得するためには、対象のBLEデバイスを検出するたびにBLE.stopScan();BLE.scan();で再スキャンする必要がある。

やりたかったこと

M5Stack Core2を2台用いて、デバイス同士が近づいたか遠くなったかを検出したかった。
そのため、片方のデバイスからBLEでアドバタイズを発信し続け、そのRSSIを監視することで実現しようと考えた。
単純に以下のコードで確認していたが、RSSIの更新が分オーダーとなってしまい、とてもリアルタイムな更新とは言えなかった。

セントラル側の処理

#include <M5Core2.h>
#include <ArduinoBLE.h>

void setup() {
  M5.begin();
  M5.Lcd.setTextSize(2);
  M5.Lcd.clear();
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println("RSSI Monitor");

  BLE.begin();
  BLE.scanForUuid("180D");  // 180DのUUIDをスキャンする
}

void loop() {

  // BLEデバイスを検出したらRSSIを取得し、LCDに表示する
  BLEDevice peripheral = BLE.available();
  if (peripheral) {
    
    int rssi = peripheral.rssi();

    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.printf("RSSI: %d dBm\n", rssi);
    M5.Lcd.printf("Device: %s", peripheral.address().c_str());
  }
}

原因

BLE.scanForUuid("180D");の仕様上、対象のデバイスを見つけたらその情報をキューに入れて処理が完了する仕様のよう。(BLE.scan();も同じ仕様っぽい)
そのため、最新の情報に更新したい場合は一度スキャンを止めて、再スキャンする必要がある。
ちなみに以下が公式リファレンスだが、この仕様に関しては明記しておらず、そこまで詳しく書いてなかった。

修正後のソースコード

ペリフェラル側処理

シンプルに20ms間隔でアドバタイズを送り続ける処理。
今回はRSSIが知りたいだけなので、データ部は指定しない。

#include <M5Core2.h>
#include <ArduinoBLE.h>
#include "esp_bt.h" // ESP32 Arduinoコアに含まれる

void setup() {
  // M5Stack Core2の初期化
  M5.begin();
  
  // BLEの初期化
  BLE.begin();

  // LCDの初期設定
  M5.Lcd.setTextSize(2);
  M5.Lcd.clear();
  M5.Lcd.setCursor(0, 0);

  // 距離が離れていても検出するようにBLE出力パワーを最大に設定
  // ※効果があるのか謎
  if (esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9) == ESP_OK) {
    M5.Lcd.println("BLE Power Up");
  }

  // BLE設定
  BLE.setLocalName("M5Stack-Core2");
  BLE.setAdvertisedServiceUuid("180D"); // UUIDの指定。任意でOK(他とIDが被らないように)
  BLE.setAdvertisingInterval(32); // アドバタイズ間隔(0.625ms単位)
  BLE.advertise();

  // デバイスアドレスをLCDに表示
  String address = BLE.address();
  M5.Lcd.printf("Device Address:\n%s", address.c_str());
}

void loop() {
  // アドバタイズのみのため処理なし
  delay(10);
}

セントラル側処理

こちらもシンプルに、アドバタイズをスキャンしてデバイスを見つけたらRSSIを取得するのみの処理。
デバイスを見つけたタイミングで、再スキャンする処理を入れている。
近くにBLEデバイスが多かったのでUUIDを指定してスキャンしているが、指定せずにスキャンするにはBLE.scan();を用いる。

#include <M5Core2.h>
#include <ArduinoBLE.h>

void setup() {
  M5.begin();
  M5.Lcd.setTextSize(2);
  M5.Lcd.clear();
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println("RSSI Monitor");

  BLE.begin();
  BLE.scanForUuid("180D");  // 必要に応じてBLE.scan()に変更可能
}

void loop() {
  BLEDevice peripheral = BLE.available();
  if (peripheral) {
    // 追加箇所:再スキャンを開始(ESP32 BLEライブラリの仕様により必要)
    BLE.stopScan();
    BLE.scanForUuid("180D");
    
    int rssi = peripheral.rssi();

    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.printf("RSSI: %d dBm\n", rssi);
    M5.Lcd.printf("Device: %s", peripheral.address().c_str());
  }
}

まとめ

以上の方法により、約40ms間隔でRSSI情報を更新できた。
LCDへの表示処理を消せばもう少し早くなるかもしれない。
スキャンの仕様に関して少し調べても出てこなかったため、備忘録として投稿する。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?