Передача данных по bluetooth (BLE)

Nathan
Offline
Зарегистрирован: 29.08.2017

Здравствуйте. Нашёл проект умной перчатки для велосипедистов. Мне нужно, чтобы вместо жеста торможения было нажатие кнопки на стороне Nano 33 BLE Sense и вызывалась бы функция ScrollText_Stop() на ESP32. Насколько я понял передаётся значение объекта "ledCharacteristic", данное значение присваивается в условии if (oldNbGesture != nbGesture)в коде для Nano 33 BLE Sense. Поэтому я попробовал передавать значение для вызова функции ScrollText_Stop() на ESP32 в цикле while (peripheral.connected()).

В коде для Nano 33 BLE Sense я добавил только эти строки:

int BUTTON_PIN = 7;
pinMode(BUTTON_PIN, INPUT);

if (digitalRead(BUTTON_PIN) == HIGH) {
          ledCharacteristic.writeValue((byte)0x03);
          Serial.println("Stop");
        }

Таким образом, код для Nano 33 BLE Sense стал таким:

/*
 Smartglove for cyclists: https://www.instructables.com/member/Matlek/
 This code is made for an Arduino Nano 33 BLE Sense board:
 it detects left hand gestures, and sends the gestures information through BLE (to another microcontroller with an LED matrix);
 It is a mix of the following codes, after a few modifications:
   -"LED" example from the "ArduinoBLE" library (Peripheral>LED).
   -"IMU_Classifier" found here: https://github.com/arduino/ArduinoTensorFlowLiteTutorials/blob/master/Ge....
*/

#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>
#include <TensorFlowLite.h>
#include <tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h>
#include <tensorflow/lite/experimental/micro/micro_error_reporter.h>
#include <tensorflow/lite/experimental/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>
#include "model.h"
const float gyroscopeThreshold = 300;
const int numSamples = 64;
int samplesRead = numSamples;
// global variables used for TensorFlow Lite (Micro)
tflite::MicroErrorReporter tflErrorReporter;
// pull in all the TFLM ops, you can remove this line and
// only pull in the TFLM ops you need, if would like to reduce
// the compiled size of the sketch.
tflite::ops::micro::AllOpsResolver tflOpsResolver;
const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tflInterpreter = nullptr;
TfLiteTensor* tflInputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;
// Create a static memory buffer for TFLM, the size may need to
// be adjusted based on the model you are using
constexpr int tensorArenaSize = 8 * 1024;
byte tensorArena[tensorArenaSize];
// array to map gesture index to a name
const char* GESTURES[] = {
 "Left arm",
 "Brake",
 "Hand front rotation",
 "Hand back rotation",
 "Hand left",
 "Hand right"
};
#define NUM_GESTURES (sizeof(GESTURES) / sizeof(GESTURES[0]))
int nbGesture = 0;
int oldNbGesture = 0;
int gestureTriggered;
int BUTTON_PIN = 7;

void setup() {
 Serial.begin(115200);
 if (!IMU.begin()) {
   Serial.println("Failed to initialize IMU!");
   while (1);
 }
 // print out the samples rates of the IMUs
 Serial.print("Accelerometer sample rate = ");
 Serial.print(IMU.accelerationSampleRate());
 Serial.println(" Hz");
 Serial.print("Gyroscope sample rate = ");
 Serial.print(IMU.gyroscopeSampleRate());
 Serial.println(" Hz");
 Serial.println();
 // get the TFL representation of the model byte array
 tflModel = tflite::GetModel(model);
 if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
   Serial.println("Model schema mismatch!");
   while (1);
 }
 // Create an interpreter to run the model
 tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
 // Allocate memory for the model's input and output tensors
 tflInterpreter->AllocateTensors();
 // Get pointers for the model's input and output tensors
 tflInputTensor = tflInterpreter->input(0);
 tflOutputTensor = tflInterpreter->output(0);

 pinMode(22, OUTPUT);
 pinMode(23, OUTPUT);
 pinMode(24, OUTPUT);
 pinMode(BUTTON_PIN, INPUT);
 digitalWrite(22, HIGH);
 digitalWrite(23, HIGH);
 digitalWrite(24, HIGH);

 // initialize the BLE hardware
 BLE.begin();
 Serial.println("BLE Central - LED control");

 // start scanning for peripherals
 //BLE.scanForUuid("e4297ee0-8c88-11ea-bc55-0242ac130003");
 BLE.scan();
}

void loop() {
 BLEDevice peripheral = BLE.available();
 if (peripheral) {
   // discovered a peripheral, print out address, local name, and advertised service
   Serial.print("Found ");
   Serial.print(peripheral.address());
   Serial.print(" '");
   Serial.print(peripheral.localName());
   Serial.print("' ");
   Serial.print(peripheral.advertisedServiceUuid());
   Serial.println();
   if (peripheral.localName() != "MySmartglove") {
     return;
   }
   BLE.stopScan();
   // connect to the peripheral
   Serial.println("Connecting ...");

   if (peripheral.connect()) {
     Serial.println("Connected");
   } else {
     Serial.println("Failed to connect!");
     return;
   }

   // discover peripheral attributes
   Serial.println("Discovering attributes ...");
   if (peripheral.discoverAttributes()) {
     Serial.println("Attributes discovered");
   } else {
     Serial.println("Attribute discovery failed!");
     peripheral.disconnect();
     return;
   }

   // retrieve the LED characteristic
   BLECharacteristic ledCharacteristic = peripheral.characteristic("e4297ee1-8c88-11ea-bc55-0242ac130003");

   if (!ledCharacteristic) {
     Serial.println("Peripheral does not have LED characteristic!");
     peripheral.disconnect();
     return;
   } else if (!ledCharacteristic.canWrite()) {
     Serial.println("Peripheral does not have a writable LED characteristic!");
     peripheral.disconnect();
     return;
   }

   while (peripheral.connected()) {
     
   if (digitalRead(BUTTON_PIN) == HIGH) {
         ledCharacteristic.writeValue((byte)0x03);
         Serial.println("Stop");
       }


     
     float aX, aY, aZ, gX, gY, gZ;
     // wait for significant motion
     while (samplesRead == numSamples) {
       if (IMU.gyroscopeAvailable()) {
         IMU.readGyroscope(gX, gY, gZ);
         // sum up the absolutes
         float gSum = fabs(gX) + fabs(gY) + fabs(gZ);
         // check if it's above the threshold
         if (gSum >= gyroscopeThreshold) {
           // reset the sample read count
           samplesRead = 0;
           break;
         }
       }
     }
     // check if the all the required samples have been read since
     // the last time the significant motion was detected
     oldNbGesture = nbGesture;
     while (samplesRead < numSamples) {
       // check if new acceleration AND gyroscope data is available
       if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
         // read the acceleration and gyroscope data
         IMU.readAcceleration(aX, aY, aZ);
         IMU.readGyroscope(gX, gY, gZ);
         // normalize the IMU data between 0 to 1 and store in the model's
         // input tensor
         tflInputTensor->data.f[samplesRead * 6 + 0] = (aX + 4.0) / 8.0;
         tflInputTensor->data.f[samplesRead * 6 + 1] = (aY + 4.0) / 8.0;
         tflInputTensor->data.f[samplesRead * 6 + 2] = (aZ + 4.0) / 8.0;
         tflInputTensor->data.f[samplesRead * 6 + 3] = (gX + 2000.0) / 4000.0;
         tflInputTensor->data.f[samplesRead * 6 + 4] = (gY + 2000.0) / 4000.0;
         tflInputTensor->data.f[samplesRead * 6 + 5] = (gZ + 2000.0) / 4000.0;
         samplesRead++;
         if (samplesRead == numSamples) {
           // Run inferencing
           TfLiteStatus invokeStatus = tflInterpreter->Invoke();
           if (invokeStatus != kTfLiteOk) {
             while (1);
             return;
           }
           // Loop through the output tensor values from the model
           for (int i = 0; i < NUM_GESTURES; i++) {
             Serial.print(GESTURES[i]);
             Serial.print(": ");
             Serial.println(tflOutputTensor->data.f[i], 6);
             if ((tflOutputTensor->data.f[i]) > 0.6) {
               gestureTriggered = i;
               nbGesture++;
             }
           }
         }
       }
     }
     Serial.print("The gesture is :");
     Serial.println(GESTURES[gestureTriggered]);
     if (oldNbGesture != nbGesture) {
       if (gestureTriggered == 0) {
         ledCharacteristic.writeValue((byte)0x00);
         colors(0);
       }
       //        if (gestureTriggered == 1) {
       //          ledCharacteristic.writeValue((byte)0x01);
       //          colors(1);
       //        }
       if (gestureTriggered == 2) {
         ledCharacteristic.writeValue((byte)0x02);
         colors(2);
       }
       if (gestureTriggered == 3) {
         ledCharacteristic.writeValue((byte)0x03);
         colors(3);
       }
       if (gestureTriggered == 4) {
         ledCharacteristic.writeValue((byte)0x04);
         colors(4);
       }
       if (gestureTriggered == 5) {
         ledCharacteristic.writeValue((byte)0x05);
         colors(5);
       }
     }
   }
   // peripheral disconnected, start scanning again
   //BLE.scanForUuid("e4297ee0-8c88-11ea-bc55-0242ac130003");
   BLE.scan();
 }
}

int colors (int i) {
 if (i == 0) {
   for (int it1 = 0; it1 <= 1; it1++) {
     digitalWrite(22, LOW);
     digitalWrite(23, LOW);
     delay(500);
     digitalWrite(22, HIGH);
     digitalWrite(23, HIGH);
     delay(500);
   }
 }
 if (i == 1) {
   for (int it1 = 0; it1 <= 1; it1++) {
     digitalWrite(22, LOW);
     delay(500);
     digitalWrite(22, HIGH);
     delay(500);
   }
 }
 if (i == 2) {
   digitalWrite(23, LOW);
   delay(500);
   digitalWrite(23, HIGH);
   delay(500);
 }
 if (i == 3) {
   digitalWrite(22, LOW);
   delay(500);
   digitalWrite(22, HIGH);
 }
 if (i == 4) {
   digitalWrite(22, LOW);
   delay(500);
   digitalWrite(23, LOW);
   delay(500);
   digitalWrite(22, HIGH);
   digitalWrite(23, HIGH);
 }
 if (i == 5) {
   digitalWrite(23, LOW);
   delay(500);
   digitalWrite(22, LOW);
   delay(500);
   digitalWrite(22, HIGH);
   digitalWrite(23, HIGH);
 }
}

Но в итоге я ничего не вижу в мониторе com порта при нажатии кнопки. На 7 пин у меня приходит 3,3В, как рекомендуется в спецификации для данной платы (5 страница)

Код для ESP32 не изменял. Но меня здесь также смущает условие if (gestureNb != old_gestureNb):

/*
    Smartglove for cyclists: https://www.instructables.com/member/Matlek/
    This code is made for an ESP32 microcontroller, to control an LED matrix through BLE.
    It is a mix of the following codes, after a few modifications:
    -"BLE_Write" example from the "BLE ESP32 ARDUINO" library.
    -"MatrixGFXDemo64" example from the "FastLED NeoMatrix" library.
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
String gestureValue = "0";
int gestureNb = 0;
int old_gestureNb = 0;
BLEServer *pServer = NULL;
bool deviceConnected = false;
unsigned long previousMillis = 0;
const long interval = 1000;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID        "e4297ee0-8c88-11ea-bc55-0242ac130003"
#define CHARACTERISTIC_UUID "e4297ee1-8c88-11ea-bc55-0242ac130003"
#define DISABLE_WHITE
#include <Adafruit_GFX.h>
#include <FastLED_NeoMatrix.h>
#include <FastLED.h>
// Allow temporaly dithering, does not work with ESP32 right now
#ifndef ESP32
#define delay FastLED.delay
#endif
#define PIN 33
#define BRIGHTNESS 64
#define mw 20
#define mh 8
#define NUMMATRIX (mw*mh)
CRGB leds[NUMMATRIX];
// Define matrix width and height.
FastLED_NeoMatrix *matrix = new FastLED_NeoMatrix(leds, mw, mh,
    NEO_MATRIX_BOTTOM     + NEO_MATRIX_RIGHT +
    NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG);

void matrix_show() {
  matrix->show();
}

// This could also be defined as matrix->color(255,0,0) but those defines
// are meant to work for adafruit_gfx backends that are lacking color()
#define LED_BLACK    0

#define LED_RED_VERYLOW   (3 <<  11)
#define LED_RED_LOW     (7 <<  11)
#define LED_RED_MEDIUM    (15 << 11)
#define LED_RED_HIGH    (31 << 11)

#define LED_GREEN_VERYLOW (1 <<  5)
#define LED_GREEN_LOW     (15 << 5)
#define LED_GREEN_MEDIUM  (31 << 5)
#define LED_GREEN_HIGH    (63 << 5)

#define LED_BLUE_VERYLOW  3
#define LED_BLUE_LOW    7
#define LED_BLUE_MEDIUM   15
#define LED_BLUE_HIGH     31

#define LED_ORANGE_VERYLOW  (LED_RED_VERYLOW + LED_GREEN_VERYLOW)
#define LED_ORANGE_LOW    (LED_RED_LOW     + LED_GREEN_LOW)
#define LED_ORANGE_MEDIUM (LED_RED_MEDIUM  + LED_GREEN_MEDIUM)
#define LED_ORANGE_HIGH   (LED_RED_HIGH    + LED_GREEN_HIGH)

#define LED_PURPLE_VERYLOW  (LED_RED_VERYLOW + LED_BLUE_VERYLOW)
#define LED_PURPLE_LOW    (LED_RED_LOW     + LED_BLUE_LOW)
#define LED_PURPLE_MEDIUM (LED_RED_MEDIUM  + LED_BLUE_MEDIUM)
#define LED_PURPLE_HIGH   (LED_RED_HIGH    + LED_BLUE_HIGH)

#define LED_CYAN_VERYLOW  (LED_GREEN_VERYLOW + LED_BLUE_VERYLOW)
#define LED_CYAN_LOW    (LED_GREEN_LOW     + LED_BLUE_LOW)
#define LED_CYAN_MEDIUM   (LED_GREEN_MEDIUM  + LED_BLUE_MEDIUM)
#define LED_CYAN_HIGH   (LED_GREEN_HIGH    + LED_BLUE_HIGH)

#define LED_WHITE_VERYLOW (LED_RED_VERYLOW + LED_GREEN_VERYLOW + LED_BLUE_VERYLOW)
#define LED_WHITE_LOW   (LED_RED_LOW     + LED_GREEN_LOW     + LED_BLUE_LOW)
#define LED_WHITE_MEDIUM  (LED_RED_MEDIUM  + LED_GREEN_MEDIUM  + LED_BLUE_MEDIUM)
#define LED_WHITE_HIGH    (LED_RED_HIGH    + LED_GREEN_HIGH    + LED_BLUE_HIGH)

void matrix_clear() {
  // clear does not work properly with multiple matrices connected via parallel inputs
  memset(leds, 0, sizeof(leds));
}

void ScrollText_Left() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  for (int8_t x = 0; x >= -60; x--) {
    yield();
    matrix_clear();
    matrix->setCursor(x, 0);
    matrix->setTextColor(LED_ORANGE_HIGH);
    matrix->print("<<<<<<<<<<<<<<");
    matrix_show();
    delay(50);
  }
  matrix->setCursor(0, 0);
}

void ScrollText_Merci() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  for (int8_t x = 20; x >= -30; x--) {
    yield();
    matrix_clear();
    matrix->setCursor(x, 0);
    matrix->setTextColor(LED_PURPLE_HIGH);
    matrix->print("Merci");
    matrix_show();
    delay(70);
  }
  matrix->setCursor(0, 0);
}

void ScrollText_Hello() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  for (int8_t x = 20; x >= -30; x--) {
    yield();
    matrix_clear();
    matrix->setCursor(x, 0);
    matrix->setTextColor(LED_CYAN_HIGH);
    matrix->print("Hello!");
    matrix_show();
    delay(70);
  }
  matrix->setCursor(0, 0);
}

void ScrollText_Right() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  for (int8_t x = -60; x <= 0 ; x++) {
    yield();
    matrix_clear();
    matrix->setCursor(x, 0);
    matrix->setTextColor(LED_ORANGE_HIGH);
    matrix->print(">>>>>>>>>>>>>>");
    matrix_show();
    delay(50);
  }
  matrix->setCursor(0, 0);
}

void ScrollText_Wait() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  yield();
  matrix_clear();
  matrix->setCursor(2, 0);
  matrix->setTextColor(LED_ORANGE_HIGH);
  matrix->print("o");
  matrix_show();
  delay(500);
  yield();
  matrix_clear();
  matrix->setCursor(2, 0);
  matrix->setTextColor(LED_ORANGE_HIGH);
  matrix->print("oo");
  matrix_show();
  delay(500);
  yield();
  matrix_clear();
  matrix->setCursor(2, 0);
  matrix->setTextColor(LED_ORANGE_HIGH);
  matrix->print("ooo");
  matrix_show();
  delay(500);
  yield();
  matrix_clear();
  matrix->setCursor(0, 0);
  matrix->setTextColor(LED_BLACK);
  matrix_show();
  delay(500);
}

void ScrollText_Stop() {
  matrix_clear();
  matrix->setTextWrap(false);  // we don't wrap text so it scrolls nicely
  matrix->setTextSize(1);
  matrix->setRotation(0);
  yield();
  matrix_clear();
  matrix->setCursor(2, 0);
  matrix->setTextColor(LED_RED_HIGH);
  matrix->print("!!!");
  matrix_show();
  delay(1000);
  yield();
  matrix_clear();
  matrix->setCursor(0, 0);
  matrix->setTextColor(LED_BLACK);
  matrix->print("STOP");
  matrix_show();
  delay(500);
}

void ScrollText_Straight() {
  uint8_t size = max(int(mw / 8), 1);
  matrix->setRotation(3);
  matrix->setTextSize(size);
  matrix->setTextColor(LED_GREEN_HIGH);
  for (int16_t x = -10; x <= 6; x++) {
    yield();
    matrix_clear();
    matrix->setCursor(x, ((mw / 2 - size * 4) + 1));
    matrix->print(">");
    matrix_show();
    delay(100 / size);
  }
  matrix->setRotation(0);
  matrix->setCursor(0, 0);
  matrix_show();
}

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      Serial.println("      deviceConnected = true;");
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      Serial.println("      deviceConnected = false;");
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    //public:
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();
      if (value.length() > 0) {
          gestureValue = int(value[0]);
        gestureNb++;
      }
    }
};

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<NEOPIXEL, PIN>(  leds, NUMMATRIX  ).setCorrection(TypicalLEDStrip);
  delay(1000);
  matrix->begin();
  matrix->setTextWrap(false);
  matrix->setBrightness(BRIGHTNESS);
#ifndef DISABLE_WHITE
  matrix->fillScreen(LED_WHITE_HIGH);
  matrix_show();
  delay(5000);
  matrix_clear();
#endif
  BLEDevice::init("MySmartglove");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  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() {

  if (deviceConnected) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      ScrollText_Straight();
    }
      Serial.print("gestureValue : ");
      Serial.println(gestureValue);
    if (gestureNb != old_gestureNb)
    {

      if (gestureValue == "0" || gestureValue == "4") {
        ScrollText_Left();
      }
      if (gestureValue == "5") {
        ScrollText_Right();
      }
      if (gestureValue == "3") {
        ScrollText_Stop();
      }
      if (gestureValue == "2") {
        ScrollText_Merci();
      }
      old_gestureNb = gestureNb;
    }
  }
  if (!deviceConnected) {
    ScrollText_Wait();
    pServer->startAdvertising(); // restart advertising
  }
}
brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Класс :) А вопрос в чем ? 

1. Если хотите, что бы сделали за вас, то есть тема "ищу исполнителя", там вам возможно помогут за деньги.

2. Можете попробовать обратится напрямую к автору кода, вдруг он поможет бесплатно.

3. Если решили САМИ доработать код, то описывая, то что вы сделали, рассказывайте, что не так. 

Logik
Offline
Зарегистрирован: 05.08.2014

Nathan пишет:

Нашёл проект умной перчатки для велосипедистов. Мне нужно, чтобы вместо жеста торможения было нажатие кнопки ...

Ни надо его прогонять! Процесс отладки обещает быть кровавым

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Logik пишет:
Процесс отладки обещает быть кровавым

Ну так, бег с барьерами был бы более зрелищным видом спорта, если бы барьеры были намертво прикручены к полу.