低功耗蓝牙(在 ESP32 和 Android 智能手机之间):数据传输速度很慢

Bluetooth Low Energy (between ESP32 and Android smartphone): Data transmission quite slow

这是我在这个版块上提出的第一个问题

项目简述:

5 sensors, connected with an esp32 board are transmitting 1000 samples/second, each sample has 16 bit. Those values should be transmitted via BLE (With the BLE Arduino library and an ESP32). The connected device (Smartphone) should read those values and do something with them (Also via BLE, with the following library: https://github.com/RobotPajamas/Blueteeth). The ESP32 is the Server! Java is used in Android Studio!

问题:

While testing the BLE connection a simple "hello world" was transmitted as the value for a characteristic. Every time i received the "hello world" on the android-device-side, a variable was incremented: The problem is, the variable only got incremented 4 times in one second. This means (assuming 1 char in a string equals 1 byte) 11byte*4(1/s)=44byte/s are being transmitted. -> This clearly is not enough (should not BLE transmit ~2MBit/s (minus the protocol-data))

代码片段

ESP32: BLE-Server that transmits value

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>


#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        Serial.println("*********");
        Serial.print("New value: ");
        for (int i = 0; i < value.length(); i++)
          Serial.print(value[i]);

        Serial.println();
        Serial.println("*********");
      }
    }
};

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

  BLEDevice::init("MyESP32");
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  pCharacteristic->setValue("Hello World");
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}

Android Studio Code (Snippet of the receiving source):

try
        {
            while(sampleBluetoothData)
            {
                this.selectedDevice.readCharacteristic(MainActivity.characteristicUUID, MainActivity.serviceUUID, (response, data) ->
                {
                    if (response != BlueteethResponse.NO_ERROR) {
                            return;
                    }
                    Log.d("AUSGANG", new String(data) + "times: "+ i);
                    i++;
                });
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

ESP32端写的是Arduino的空白示例代码IDE,Android端读的是BLE-Library publisher做的。是的,Log.d 会影响性能,但不会降低太多。

The variable "data" of the Android code is the received char-array. The bluetooth-reading runs on a background thread.

我现在问自己的问题:

提前致谢!

我正在阅读 BLE 维基百科页面,最低数据速率是 125Kbit/s,所以我认为在你的情况下是可行的,因为你只会传输 16Kbit/s。看看 BLE wikipedia.

BLE 绝对可以每秒传输超过 4 个 11 字节的部分。

阅读方式:

  1. 一般来说,一直持续读取并不是预期的 BLE 方式 - 最好订阅数据更改,因此 ESP32 只会在需要时通知(例如 selectedDevice.subscribeToCharacteristic 一次,而不是循环读取,但 ESP32 代码应相应更改)
  2. 我猜 selectedDevice.readCharacteristic 请求异步 BLE 读取,当您在 while(sampleBluetoothData) 中调用它时,您的蓝牙库正在添加越来越多的读取请求。也许只在上一次读取完成后请求新的读取才是明智的——在读取回调中添加 if(sampleBluetoothData) { this.readAgain(); }

考虑根据这个 kickstart 示例制作测试原型:BLEProof on github - Android & ESP32,读取,写入,通知(但它仅使用系统API没有蓝牙库,你的方法更好,使用这个库更简单更安全。

还有什么要检查的:

  1. Android 方面:你确定你的代码没有进入 if (response != BlueteethResponse.NO_ERROR) 吗?
  2. Android 方面:为确保蓝牙库不会因读取请求而过载,请尝试在读取循环中添加 50 毫秒的延迟(只是为了检查,这不是解决方案)
  3. Android 方:您确定在读取这些数据时没有其他 BLE read/writes 吗?
  4. ESP32 端:使用较短的 BLE 连接间隔 (BLE throughput article) - 在 pAdvertising->start(); 之前添加 pAdvertising->setMinPreferred(0x06);pAdvertising->setMaxPreferred(0x20);(但仅设置“首选”间隔,Android 可以忽略)

使用读取请求,您主要受限于传输速度的连接间隔 - 即请求 + 响应的 2 个间隔。

例如,如果您的客户端的连接间隔为 50 毫秒,您应该期望每秒读取 10 次最多 20 字节的特征。

如果另一个客户端的连接间隔为 30 毫秒,则此速率提高到每秒 16.6 次读取。

最快的可协商连接间隔为 7.5 毫秒,每秒最多读取 66.6 次(读取 20 字节时为 10.7kbps)。