Hello everybody! I found project of smart glove on instructables made by Matlek.
But I want to receive gesture "Stop" on ESP32 by getting high signal on pin D7 on Nano 33 BLE Sense.
As I understand value of object "ledCharacteristic" is transmitting to ESP32.
I added lines to the code, but it doesn't work so far. I commented out the added lines this way // ***** ADDED string/strings of code ****
I don't even see my added values in the com port monitor. Where am I going wrong?
This is changed code for 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/GestureToEmoji/ArduinoSketches/IMU_Classifier/IMU_Classifier.ino.
*/
#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;
//******************** ADDED strings **************************
// variables for button
const int buttonPin = 7;
int oldButtonState = LOW;
//******************** ADDED strings **************************
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);
digitalWrite(22, HIGH);
digitalWrite(23, HIGH);
digitalWrite(24, HIGH);
//******************** ADDED strings **************************
// configure the button pin as input
pinMode(buttonPin, INPUT);
//******************** ADDED strings **************************
// 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()) {
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);
}
//********* ADDED string *************
//comment out these lines of code
/*
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);
}
}
//******************** ADDED strings **************************
// read the button pin
int buttonState = digitalRead(buttonPin);
if (oldButtonState != buttonState) {
// button changed
oldButtonState = buttonState;
if (buttonState) {
Serial.println("button pressed");
// button is pressed, write 0x03 to turn the LED on
ledCharacteristic.writeValue((byte)0x03);
} else {
Serial.println("button released");
}
}
//******************** ADDED strings **************************
}
// 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);
}
}
This is original (unmodified) code for ESP32:
/*
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
}
}
This is photo of connection tact switch to Nano 33 BLE Sense.