Подключение двух Arduino через BLE 5.0

arduino-nano sensors bluetooth ble arduino-nano-33-iot

У меня возникла проблема при передаче данных датчика с платы Nano Sense Rev 2 (передатчик) на плату Nano 33 BLE Rev 2 (приёмник). Приёмник постоянно не может обнаружить передатчик и подключиться к нему, выдавая ошибку «Истек тайм-аут сканирования», из-за чего сканирование останавливается через несколько секунд. Обратите внимание, что мне удалось подключиться к своему передатчику с помощью приложения на телефоне. Это код моего передатчика:

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

// Пользовательские 128-битные UUID для сервиса и характеристик
BLEService sensorService("12345678-1234-5678-1234-56789abcdef0");  // Пользовательский UUID службы

BLECharacteristic pressureCharacteristic("12345678-1234-5678-1234-56789abcdef1", BLERead | BLENotify, sizeof(float));  // Пользовательский UUID характеристики давления
BLECharacteristic temperatureCharacteristic("12345678-1234-5678-1234-56789abcdef2", BLERead | BLENotify, sizeof(float)); // UUID пользовательской температурной характеристики
BLECharacteristic humidityCharacteristic("12345678-1234-5678-1234-56789abcdef3", BLERead | BLENotify, sizeof(float)); // Пользовательский UUID характеристики влажности
BLECharacteristic lightIntensityCharacteristic("12345678-1234-5678-1234-56789abcdef4", BLERead | BLENotify, sizeof(int)); // Пользовательский UUID характеристики интенсивности света

void setup() {
  // Запустить последовательный монитор
  Serial.begin(9600);
  while (!Serial);

  // Инициализация датчиков
  if (!BARO.begin()) {
    Serial.println("Failed to initialize pressure sensor!");
    while (1);
  }

  if (!HS300x.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }

  if (!APDS.begin()) {
    Serial.println("Error initializing APDS9960 sensor.");
  }

  // Инициализация BLE
  if (!BLE.begin()) {
    Serial.println("BLE initialization failed!");
    while (1);
  }

  BLE.setLocalName("Nano33BLESense");

  // Добавить характеристики в пользовательский сервис
  sensorService.addCharacteristic(pressureCharacteristic);
  sensorService.addCharacteristic(temperatureCharacteristic);
  sensorService.addCharacteristic(humidityCharacteristic);
  sensorService.addCharacteristic(lightIntensityCharacteristic);

  // Добавить службу к периферийному устройству BLE
  BLE.addService(sensorService);

  // Начните рекламировать службу BLE (и повторяйте, чтобы она оставалась активной)
  BLE.advertise();
  Serial.println("BLE Peripheral started advertising.");
}

void loop() {
  // Считать данные датчика
  float pressure = BARO.readPressure();
  float temperature = HS300x.readTemperature();
  float humidity = HS300x.readHumidity();

  int r, g, b;
  while (!APDS.colorAvailable()) {
    delay(5);
  }
  APDS.readColor(r, g, b);
  int lightIntensity = r + g + b;

  // Вывести значения датчика на последовательный монитор (для отладки)
  Serial.print("Pressure: ");
  Serial.println(pressure);
  Serial.print("Temperature: ");
  Serial.println(temperature);
  Serial.print("Humidity: ");
  Serial.println(humidity);
  Serial.print("Light Intensity: ");
  Serial.println(lightIntensity);

  // Преобразовать значения с плавающей точкой в массивы байтов
  byte pressureBytes[sizeof(float)];
  memcpy(pressureBytes, &pressure, sizeof(float));

  byte temperatureBytes[sizeof(float)];
  memcpy(temperatureBytes, &temperature, sizeof(float));

  byte humidityBytes[sizeof(float)];
  memcpy(humidityBytes, &humidity, sizeof(float));

  byte lightIntensityBytes[sizeof(int)];
  memcpy(lightIntensityBytes, &lightIntensity, sizeof(int));

  // Обновите характеристики BLE с использованием последних данных датчиков
  pressureCharacteristic.setValue(pressureBytes, sizeof(pressureBytes));
  temperatureCharacteristic.setValue(temperatureBytes, sizeof(temperatureBytes));
  humidityCharacteristic.setValue(humidityBytes, sizeof(humidityBytes));
  lightIntensityCharacteristic.setValue(lightIntensityBytes, sizeof(lightIntensityBytes));

  // Библиотека BLE будет автоматически обрабатывать уведомления при вызове `setValue`
  // поскольку BLENotify включен на характеристиках.

  // Продолжайте рекламировать, чтобы убедиться, что сервис BLE остается видимым
  BLE.advertise();
  
  delay(1000);  // Подождать 1 секунду перед отправкой следующих данных
}

а это код приемника:

#include <ArduinoBLE.h>

// Define the UUIDs for the custom service and characteristics
#define SENSOR_SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0"
#define PRESSURE_CHAR_UUID "12345678-1234-5678-1234-56789abcdef1"
#define TEMPERATURE_CHAR_UUID "12345678-1234-5678-1234-56789abcdef2"
#define HUMIDITY_CHAR_UUID "12345678-1234-5678-1234-56789abcdef3"
#define LIGHT_INTENSITY_CHAR_UUID "12345678-1234-5678-1234-56789abcdef4"

// Declare BLE objects with proper UUIDs
BLEService sensorService(SENSOR_SERVICE_UUID);
BLECharacteristic pressureCharacteristic(PRESSURE_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic temperatureCharacteristic(TEMPERATURE_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic humidityCharacteristic(HUMIDITY_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic lightIntensityCharacteristic(LIGHT_INTENSITY_CHAR_UUID, BLERead | BLENotify, sizeof(int));

unsigned long scanStartTime;
bool scanInProgress = true;
int maxScanAttempts = 5;  // Max number of scan attempts before stopping
int scanAttempts = 0;     // Counter for scan attempts
void setup() {
  // Start Serial Monitor
  Serial.begin(9600);
  while (!Serial);

  // Initialize BLE
  if (!BLE.begin()) {
    Serial.println("BLE initialization failed!");
    while (1);
  }

  BLE.setLocalName("BLEReceiver");
  Serial.println("BLEReceiver started. Scanning for devices...");

  // Start scanning for devices advertising the sensor service
  BLE.scanForUuid(SENSOR_SERVICE_UUID);  // Scan for the service
  scanStartTime = millis();  // Start the scan timer
}
void loop() {
  BLEDevice central = BLE.available();
  
  if (central) {
    // Device found, print address and attempt to connect
    Serial.print("Found BLE Device: ");
    Serial.println(central.address());

    // Stop scanning and attempt to connect
    BLE.stopScan();
    delay(100);  // Small delay before attempting to connect
    if (central.connect()) {
      Serial.println("Connected to device.");

      BLEService sensorService = central.service(SENSOR_SERVICE_UUID);
      if (sensorService) {
        Serial.println("Sensor service found.");

        // Discover characteristics
        pressureCharacteristic = sensorService.characteristic(PRESSURE_CHAR_UUID);
        temperatureCharacteristic = sensorService.characteristic(TEMPERATURE_CHAR_UUID);
        humidityCharacteristic = sensorService.characteristic(HUMIDITY_CHAR_UUID);
        lightIntensityCharacteristic = sensorService.characteristic(LIGHT_INTENSITY_CHAR_UUID);

        if (pressureCharacteristic && temperatureCharacteristic && humidityCharacteristic && lightIntensityCharacteristic) {
          Serial.println("Characteristics found. Reading values...");

          while (central.connected()) {
            if (pressureCharacteristic.canRead()) {
              float pressure;
              memcpy(&pressure, pressureCharacteristic.value(), sizeof(pressure));
              Serial.print("Pressure: ");
              Serial.println(pressure);
            }

            if (temperatureCharacteristic.canRead()) {
              float temperature;
              memcpy(&temperature, temperatureCharacteristic.value(), sizeof(temperature));
              Serial.print("Temperature: ");
              Serial.println(temperature);
            }

            if (humidityCharacteristic.canRead()) {
              float humidity;
              memcpy(&humidity, humidityCharacteristic.value(), sizeof(humidity));
              Serial.print("Humidity: ");
              Serial.println(humidity);
            }

            if (lightIntensityCharacteristic.canRead()) {
              int lightIntensity;
              memcpy(&lightIntensity, lightIntensityCharacteristic.value(), sizeof(lightIntensity));
              Serial.print("Light Intensity: ");
              Serial.println(lightIntensity);
            }

            delay(1000);  // Wait for 1 second before reading again
          }
        } else {
          Serial.println("Failed to find required characteristics.");
        }
      } else {
        Serial.println("Sensor service not found.");
      }

      // Disconnect once done
      central.disconnect();
      Serial.println("Disconnected from device.");
      scanAttempts = 0;  // Reset scan attempts after successful connection
    } else {
      Serial.println("Failed to connect to device.");
    }
  }

  // Check scan timeout and limit scan attempts
  if (scanInProgress && millis() - scanStartTime > 10000) {  // 10 seconds timeout
    Serial.println("Scan timeout reached. Stopping scan.");
    BLE.stopScan();
    scanInProgress = false;
    scanAttempts++;

    // If max scan attempts reached, stop scanning and wait for user intervention
    if (scanAttempts >= maxScanAttempts) {
      Serial.println("Max scan attempts reached. Please reset the device.");
    } else {
      Serial.println("Resuming scan...");
      BLE.scanForUuid(SENSOR_SERVICE_UUID);  // Restart scanning after timeout
      scanStartTime = millis();  // Reset the scan timer
      scanInProgress = true;  // Set scanInProgress back to true
    }
  }

  // Continue scanning only if it is still ongoing and hasn't timed out
  if (scanInProgress && !central) {
    BLEDevice central = BLE.available();
  }
}

Два устройства находятся на расстоянии 1 метра друг от друга. Это мой последовательный монитор (приемник).

14:52:23.321 -> Resuming scan...
14:52:33.314 -> Scan timeout reached. Stopping scan.
14:52:33.314 -> Resuming scan...
14:52:43.338 -> Scan timeout reached. Stopping scan.
14:52:43.387 -> Resuming scan...
14:52:53.379 -> Scan timeout reached. Stopping scan.
14:52:53.425 -> Max scan attempts reached. Please reset the device.

Почему я не могу подключиться?

, 👍0

Обсуждение

какой у вас вопрос?, @jsotola

Выполняли ли вы последовательное соединение с обоими устройствами одновременно во время своих тестов?, @timemage

@timemage Да, я подключил их к отдельному компьютеру одновременно и в разное время, чтобы убедиться, что я нацелился на рекламное окно., @Anwar Elhadad

По умолчанию библиотека ArduinoBLE использует случайные приватные адреса. Это может привести к тому, что устройства не будут обнаруживать друг друга стабильно., @liaifat85


1 ответ


1

Отсутствие BLE.setAdvertisedService(sensorService); бросается в глаза сразу. В ходе тестирования я разместил его, как в следующем фрагменте:

  // Добавить службу к периферийному устройству BLE
  BLE.addService(sensorService);

  // Включить интересующую услугу в рекламные данные
  // для другой стороны использовать с `BLE.scanForUuid(SENSOR_SERVICE_UUID);`
  BLE.setAdvertisedService(sensorService);

Благодаря этому изменению принимающая сторона теперь сообщает:

BLEReceiver started. Scanning for devices...

Found BLE Device: xx:xx:xx:xx:xx:xx

Connected to device.
Sensor service not found.
Disconnected from device.

... где xx содержал OUI моего Nano BLE.

Короче говоря, когда вы вызываете BLE.advertise();, ваше устройство начинает сообщать о своём существовании. Оно может делать это с помощью небольшого объёма рекламных данных, которые могут включать некоторые (обычно не все) UUID своих сервисов. BLE.scanForUuid(SENSOR_SERVICE_UUID); ищет именно рекламируемую службу. Пока вы не взаимодействуете с устройством (кроме получения рекламы), вы не можете знать о каких-либо службах, не включённых в рекламные данные. Таким образом, без рекламируемого UUID сервиса вам пришлось бы дополнительно опрашивать каждое найденное устройство в рамках сеанса .scan() без использования UUID. Таким образом, эти рекламируемые UUID сервисов делают сканирование нужных вам устройств более эффективным.


В коде приемника у вас есть BLEDevice central = BLE.available(); .available() здесь возвращает периферийное устройство, найденное во время сканирования. На самом деле это должно быть BLEDevice periferial = . В любом случае, после вызова .connect() вы используете .service(). Здесь отсутствует один шаг, который вы можете увидеть в этой документации и этом примере. Пока вы не вызовете .discoverAttributes(), у вас не будет локальной копии всех служб, характеристик и т. д., которые есть у периферийного устройства. Вот почему .service() дает сбой.

Не сомневаюсь, что есть и другие проблемы. Похоже, это то, что мог бы выдать генератор кода на основе искусственного интеллекта. Если это так, остановитесь и прочтите документацию и примеры.

,

Хорошо, попробую завтра. Кстати, вы не реализовали никаких служб? Из-за этого пишет «Служба датчика не найдена» или это какая-то другая проблема?, @Anwar Elhadad

Я сейчас добавлю кое-что для решения этой проблемы. Но ответ, как есть, касается «того, с чем вы сталкиваетесь немедленно». Другими словами, первой из потенциально многих проблем, с которыми вы можете столкнуться. Это поиск устройства. Я не собираюсь исправлять весь ваш проект., @timemage