From 18e38241c692844f2ed140ca0cff6171c9af9437 Mon Sep 17 00:00:00 2001 From: MyoWareMaker Date: Tue, 27 Feb 2024 23:07:04 -0500 Subject: [PATCH 1/2] Release commit (v1.0.0) --- ISSUE_TEMPLATE.md | 18 ++ LICENSE => LICENSE.md | 11 +- README.md | 37 ++- .../MyoWareBLECentral/MyoWareBLECentral.ino | 250 ++++++++++++++++++ .../MyoWareBLEPeripheral.ino | 175 ++++++++++++ examples/MyoWareBLEUART/MyoWareBLEUART.ino | 234 ++++++++++++++++ .../ReadMyoWareVoltage/ReadMyoWareVoltage.ino | 86 ++++++ .../TestMyoWareSamplingRate.ino | 78 ++++++ library.properties | 10 + src/MyoWare.cpp | 88 ++++++ src/MyoWare.h | 179 +++++++++++++ 11 files changed, 1161 insertions(+), 5 deletions(-) create mode 100644 ISSUE_TEMPLATE.md rename LICENSE => LICENSE.md (70%) create mode 100644 examples/MyoWareBLECentral/MyoWareBLECentral.ino create mode 100644 examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino create mode 100644 examples/MyoWareBLEUART/MyoWareBLEUART.ino create mode 100644 examples/ReadMyoWareVoltage/ReadMyoWareVoltage.ino create mode 100644 examples/TestMyoWareSamplingRate/TestMyoWareSamplingRate.ino create mode 100644 library.properties create mode 100644 src/MyoWare.cpp create mode 100644 src/MyoWare.h diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..4f9cd64 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,18 @@ +### Subject of the issue +Describe your issue here. + +### Your workbench +* What development board or microcontroller are you using? +* What version of hardware or breakout board are you using? +* How is the breakout board wired to your microcontroller? +* How is everything being powered? +* Are there any additional details that may help us help you? + +### Steps to reproduce +Tell us how to reproduce this issue. Please post stripped down example code demonstrating your issue. + +### Expected behavior +Tell us what should happen + +### Actual behavior +Tell us what happens instead diff --git a/LICENSE b/LICENSE.md similarity index 70% rename from LICENSE rename to LICENSE.md index 1c7d2ac..57471c8 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,9 +1,14 @@ -MIT License +Advancer Technologies License Information +============================ + +**Advancer Technologies code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** + +The MIT License (MIT) Copyright (c) 2024 Advancer Technologies Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal +of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is @@ -12,7 +17,7 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER diff --git a/README.md b/README.md index baaca7e..cd44bc9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# MyoWare-Arduino-Library -Arduino library for the MyoWare Muscle Sensor and Ecosystem +# MyoWare Arduino Library + +This library provides a simple interface for interacting with the [MyoWare 2.0 Ecosystem](https://www.sparkfun.com/myoware) using Arduino. + +### MyoWare Wireless Shield Examples +- [MyoWareBLEPeripheral](examples/MyoWareBLEPeripheral): An example of how to setup a MyoWare 2.0 Wireless Shield as a BLE peripheral device using the ArduinoBLE and MyoWare Arduino libraries. +- [MyoWareBLECentral](examples/MyoWareBLECentral): An example of how to setup a MyoWare 2.0 Wireless Shield as a BLE central device using the ArduinoBLE and MyoWare Arduino libraries. +- [MyoWareBLEUART](examples/MyoWareBLEUART): An example of how to setup a MyoWare 2.0 Wireless Shield to send data to mobile apps such as [Adafruit Blufruit app](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect&hl=en_US&gl=US&pli=1) as a BLEUART device using the ESP32 BLE Arduino and MyoWare Arduino libraries. + +### Other Examples +- [ReadMyoWareVoltage](examples//ReadMyoWareVoltage): An example of how to read and convert data from a MyoWare 2.0 Muscle Sensor using the MyoWare Arduino Library. +- [TestMyoWareSamplingRate](examples/TestMyoWareSamplingRate): An example of how a simple way to calculate your Arduino device's sampling rate. Note: The MyoWare 2.0 Muscle Sensor is an analog device so your sampling rate wholly depends on your Arduino device and code, not the sensor itself. + + +## MyoWare 2.0 Ecosystem + +The MyoWare 2.0 ecosystem consists of shields that easily interface with the [MyoWare 2.0 Muscle Sensor](https://www.sparkfun.com/products/21265), which is a low-cost, Arduino-compatible, all-in-one electromyography (EMG) sensor from [Advancer Technologies](https://myoware.com). The innovative connector system allows users to easily snap shields together with a compact low profile and connect to a microcontroller's analog input to measure raw, filtered, and rectified electrical activity of a target muscle. This eliminates the need to solder connections between boards. + +### Documentation + +- [Getting Started with the MyoWare 2.0 Muscle Sensor Ecosystem](https://learn.sparkfun.com/tutorials/getting-started-with-the-myoware-20-muscle-sensor-ecosystem/all) +- [MyoWare 2.0 Quick Start Guide](https://myoware.com/wp-content/uploads/2022/03/MyoWare_v2_QuickStartGuide.pdf) +- [MyoWare 2.0 Advanced Guide](https://myoware.com/wp-content/uploads/2022/03/MyoWare_v2_AdvancedGuide-Updated.pdf) + +## Support + +[MyoWare 2.0 Ecosystem](https://www.sparkfun.com/myoware) technical support is now handled via [r/MyoWare on Reddit](https://www.reddit.com/r/MyoWare/)! Technical Support moderators will be monitoring the Subreddit during weekdays. Additionally, you can get help through [SparkFun Electronics support and forums](https://forum.sparkfun.com/viewforum.php?f=143). + +## License + +This open source code is licensed under the MIT license (see [LICENSE](LICENSE.md) +for details). + +The MyoWare 2.0 Ecosystem is a collaboration between [Advancer Technologies](https://myoware.com) and [Sparkfun Electronics](https://www.sparkfun.com), please support future MyoWare development by purchasing products from +[Sparkfun Electronics](https://www.sparkfun.com/myoware)! diff --git a/examples/MyoWareBLECentral/MyoWareBLECentral.ino b/examples/MyoWareBLECentral/MyoWareBLECentral.ino new file mode 100644 index 0000000..1dedeba --- /dev/null +++ b/examples/MyoWareBLECentral/MyoWareBLECentral.ino @@ -0,0 +1,250 @@ +/* + MyoWare BLE Central Example Code + Advancer Technologies, LLC + Brian Kaminski + 8/01/2023 + + This example sets up a BLE Central device, Then, it connects + to up to four MyoWare 2.0 Wireless Shields that are reading the ENV and RAW + outputs of a MyoWare Muscle sensor. It then streams the selected output data + (ENVELOPE or RAW) from all sensors on the Serial Terminal. + + Note, in BLE, you have services, characteristics and values. + Read more about it here: + https://www.arduino.cc/reference/en/libraries/arduinoble/ + + Note, before it begins checking the data and printing it, + It first sets up some BLE stuff: + 1. sets up as a central + 2. scans for and connects to any MyoWare 2.0 Wireless Shields for 10 seconds + + In order for this example to work, you will need a MyoWare 2.0 Wireless Shield, + and it will need to be programmed with the MyoWare BLEnPeripheral code, + and advertizing with the unique and correlating characteristic UUID. + + Note, both the service and the characteristic need unique UUIDs and each + MyoWare 2.0 Wireless Shield needs a unique name (e.g. MyoWareSensor1, MyoWareSensor2) + + This "BLE Central", will read each MyoWare 2.0 Wireless Sensor, + aka the "BLE Peripheral", charactieristic, parse it for the ENV and RAW values, + and print them to the serial terminal. + + Hardware: + BLE device (e.g. Artemis Redboard) + USB from BLE device to Computer. + + ** For consistent BT connection follow these steps: + ** 1. Reset Peripheral + ** 2. Wait 5 seconds + ** 3. Reset Central + ** 4. Enjoy BT connection + ** + ** ArduinoBLE does not support RE-connecting two devices. + ** If you loose connection, you must follow this hardware reset sequence again. + ** + ** ArduinoBLE does not support connecting more than four peripheral devices. + + This example code is in the public domain. +*/ + +#include +#include +#include + +// debug parameters +const bool debugLogging = false; // set to true for verbose logging to serial + +std::vector vecMyoWareShields; + +// MyoWare class object +MyoWare myoware; + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate + // when a central is connected + + // begin initialization + if (!BLE.begin()) + { + Serial.println("Starting BLE failed!"); + + while (1); + } + + if (debugLogging) + { + Serial.println("MyoWare BLE Central"); + Serial.println("-------------------"); + } + + // start scanning for MyoWare Wireless Shields + if (debugLogging) + { + Serial.print("Scanning for MyoWare Wireless Shields: "); + Serial.println(MyoWareBLE::uuidMyoWareService.c_str()); + } + + BLE.scanForUuid(MyoWareBLE::uuidMyoWareService.c_str(), true); + + // scan for Wireless Shields for 10sec + const long startMillis = millis(); + while (millis() - startMillis < 10000) + { + myoware.blinkStatusLED(); + + BLEDevice peripheral = BLE.available(); + if (peripheral && std::find(vecMyoWareShields.begin(), vecMyoWareShields.end(), peripheral) == vecMyoWareShields.end()) + { + if (debugLogging) + { + Serial.print("Connecting to "); + PrintPeripheralInfo(peripheral); + } + + // connect to the peripheral + BLE.stopScan(); + if (peripheral.connect()) + { + if (!peripheral.discoverAttributes()) + { + Serial.println("Discovering Attributes... Failed!"); + if (!peripheral.discoverAttributes()) + { + Serial.println("Discovering Attributes... Failed!"); + Serial.print("Disconnecting... "); + PrintPeripheralInfo(peripheral); + peripheral.disconnect(); + Serial.println("Disconnected"); + continue; + } + } + vecMyoWareShields.push_back(peripheral); + } + else + { + Serial.print("Failed to connect: "); + PrintPeripheralInfo(peripheral); + } + BLE.scanForUuid(MyoWareBLE::uuidMyoWareService.c_str(), true); + } + } + BLE.stopScan(); + + if (vecMyoWareShields.empty()) + { + Serial.println("No MyoWare Wireless Shields found!"); + while (1); + } + + digitalWrite(myoware.getStatusLEDPin(), HIGH); // turn on the LED to indicate a + // connection + + for (auto shield : vecMyoWareShields) + { + auto ritr = vecMyoWareShields.rbegin(); + if (ritr != vecMyoWareShields.rend() && shield != (*ritr)) + { + Serial.print(shield.localName()); + Serial.print("\t"); + } + else + { + Serial.println(shield.localName()); + } + } +} + +void loop() +{ + for (auto shield : vecMyoWareShields) + { + if (!shield) + { + Serial.print("Invalid MyoWare Wireless Shields pointer! MAC Address: "); + Serial.println(shield); + auto itr = std::find(vecMyoWareShields.begin(), vecMyoWareShields.end(), shield); + if (itr != vecMyoWareShields.end()) + vecMyoWareShields.erase(itr); + continue; + } + + if (debugLogging) + { + Serial.print("Updating "); + PrintPeripheralInfo(shield); + } + + if (!shield.connected()) + { + // output zero if the Wireless shield gets disconnected + // this ensures data capture can continue for the + // other shields that are connected + Serial.print("0.0"); + Serial.print("\t"); + continue; + } + + BLEService myoWareService = shield.service(MyoWareBLE::uuidMyoWareService.c_str()); + if (!myoWareService) + { + Serial.println("Failed finding MyoWare BLE Service!"); + shield.disconnect(); + continue; + } + + // get sensor data + BLECharacteristic sensorCharacteristic = myoWareService.characteristic(MyoWareBLE::uuidMyoWareCharacteristic.c_str()); + + const double sensorValue = ReadBLEData(sensorCharacteristic); + Serial.print(sensorValue); + + if (vecMyoWareShields.size() > 1) + Serial.print(","); + } + Serial.println(""); +} + +// Read the sensor values from the characteristic +double ReadBLEData(BLECharacteristic& dataCharacteristic) +{ + if (dataCharacteristic) + { + if (dataCharacteristic.canRead()) + { + // read the characteristic value as string + char characteristicValue[20]; + dataCharacteristic.readValue( &characteristicValue,20); + const String characteristicString(characteristicValue); + + return characteristicString.toDouble(); + } + else + { + if (debugLogging) + { + Serial.print("Unable to read characteristic: "); + Serial.println(dataCharacteristic.uuid()); + } + return 0.0; + } + } + else + { + if (debugLogging) + Serial.println("Characteristic not found!"); + } + return 0.0; +} + +void PrintPeripheralInfo(BLEDevice peripheral) +{ + Serial.print(peripheral.address()); + Serial.print(" '"); + Serial.print(peripheral.localName()); + Serial.print("' "); + Serial.println(peripheral.advertisedServiceUuid()); +} \ No newline at end of file diff --git a/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino b/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino new file mode 100644 index 0000000..4959d51 --- /dev/null +++ b/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino @@ -0,0 +1,175 @@ +/* + MyoWare BLE Peripheral Example Code + Advancer Technologies, LLC + Brian Kaminski + 8/01/2023 + + This example sets up a MyoWare 2.0 Wireless Shield, and then reads the ENV, RAW, + and REF data from the attached MyoWare 2.0 Muscle Sensor. The MyoWare 2.0 + Wireless Shield (the Peripheral) sends this data to a second BLE Device + (the Central) over BLE. + + This MyoWare 2.0 Wireless Shield, aka the "BLE Peripheral", will read the sensor's + output on A3-A5 where A3 is ENV, A4 is RAW, and A5 is REF. It will then store + them in a single 32-bit variable, and then update that value to the + "bluetooth bulliten board". + + Note, in BLE, you have services, characteristics and values. + Read more about it here: + + https://www.arduino.cc/reference/en/libraries/arduinoble/ + + Note, before it begins reading the ADC and updating the data, + It first sets up some BLE stuff: + 1. sets up as a peripheral + 2. sets up a service and characteristic (the data) + -Note, Services and characteristics have unique 128-bit UUID, + -These must match the UUIDs in the code on the central device. + 3. advertises itself + + In order for this example to work, you will need a Artemis boad, + and it will need to be programmed with the provided code specific to + being a central device, looking for this specific service/characteristic. + + Note, both the service and the characteristic get unique UUIDs. + + The "BLE Central", will subscribe to the MyoWare 2.0 Wireless + Shield's charactieristic, read it, and parse it into 4 separate bytes, + then print the values to the serial terminal. + + Hardware: + MyoWare 2.0 Wireless Shield + MyoWare 2.0 Muscle Sensor + USB from BLE Device to Computer. + + ** For consistent BT connection follow these steps: + ** 1. Reset Peripheral + ** 2. Wait 5 seconds + ** 3. Reset Central + ** 4. Enjoy BT connection + ** + ** ArduinoBLE does not support RE-connecting two devices. + ** If you loose connection, you must follow this hardware reset sequence again. + ** + ** ArduinoBLE does not support connecting more than four peripheral devices. + + This example code is in the public domain. +*/ + +#include +#include + +const String localName = "MyoWareSensor1"; // recommend making this unique for + // each Wireless shield (e.g. MyoWareSensor1, + // MyoWareSensor2, ...) + +MyoWare::OutputType outputType = MyoWare::ENVELOPE; // select which output to print to serial + // EMG envelope (ENVELOPE) or Raw EMG (RAW)) + +// debug parameters +const bool debugLogging = false; // set to true for verbose logging +const bool debugOutput = true; // set to true to print output values to serial + +// MyoWare class object +MyoWare myoware; + +// BLE Service +BLEService myoWareService(MyoWareBLE::uuidMyoWareService.c_str()); + +// BLE Muscle Sensor Characteristics +BLEStringCharacteristic sensorCharacteristic(MyoWareBLE::uuidMyoWareCharacteristic.c_str(), BLERead | BLENotify, 128); + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + myoware.setConvertOutput(false); // Set to true to convert ADC output to the amplitude of + // of the muscle activity as it appears at the electrodes + // in millivolts + myoware.setGainPotentiometer(50.); // Gain potentiometer resistance in kOhms. + // adjust the potentiometer setting such that the + // max muscle reading is below 3.3V then update this + // parameter to the measured value of the potentiometer + myoware.setENVPin(A3); // Arduino pin connected to ENV (defult is A3 for Wireless Shield) + myoware.setRAWPin(A4); // Arduino pin connected to RAW (defult is A4 for Wireless Shield) + myoware.setREFPin(A5); // Arduino pin connected to REF (defult is A5 for Wireless Shield) + + pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate + // when a central is connected + digitalWrite(myoware.getStatusLEDPin(), HIGH); + + // begin initialization + bool error = !BLE.begin(); + if (error) + { + Serial.println("FAILED - BLE Initialization!"); + + while (error); + } + + BLE.setLocalName(localName.c_str()); + BLE.setAdvertisedService(myoWareService); + myoWareService.addCharacteristic(sensorCharacteristic); + BLE.addService(myoWareService); + + // set initial values for the characteristics + sensorCharacteristic.writeValue(""); + + BLE.advertise(); + + if (debugLogging) + { + Serial.println("Setup Complete!"); + Serial.print(BLE.address()); + Serial.print(" '"); + Serial.print(localName.c_str()); + Serial.print("' "); + Serial.print(myoWareService.uuid()); + Serial.println(); + Serial.print("Waiting to connect..."); + } + + digitalWrite(myoware.getStatusLEDPin(), LOW); +} + +void loop() +{ + // wait for a BLE central + BLEDevice central = BLE.central(); + if (central) + { + if (debugLogging) + { + Serial.print("Connected to central: "); + Serial.println(central.address()); + } + + digitalWrite(myoware.getStatusLEDPin(), HIGH); // turn on the LED to indicate the + // connection + + while (central.connected()) + { + // Read sensor output + const String strValue = String(myoware.readSensorOutput(outputType)); + if (debugOutput) + Serial.println(strValue.c_str()); + + // "post" to "BLE bulletin board" + sensorCharacteristic.writeValue(strValue); + } + + // when the central disconnects, turn off the LED: + digitalWrite(myoware.getStatusLEDPin(), LOW); + + if (debugLogging) + { + Serial.print("Disconnected from central: "); + Serial.println(central.address()); + } + } + else + { + myoware.blinkStatusLED(); + } +} \ No newline at end of file diff --git a/examples/MyoWareBLEUART/MyoWareBLEUART.ino b/examples/MyoWareBLEUART/MyoWareBLEUART.ino new file mode 100644 index 0000000..cc9ccd6 --- /dev/null +++ b/examples/MyoWareBLEUART/MyoWareBLEUART.ino @@ -0,0 +1,234 @@ +/* + MyoWare BLE UART Example Code + Advancer Technologies, LLC + Brian Kaminski + 12/16/2023 + + This example sets up a MyoWare 2.0 Wireless Shield to connect to the free app + Bluefruit Connect (https://learn.adafruit.com/bluefruit-le-connect/) from + Adafruit Industries. The code reads the ENV, RAW, and REF data from the + attached MyoWare 2.0 Muscle Sensor and sends the data to the Bluefruit Connect + app over BLE UART. + + This MyoWare 2.0 Wireless Shield, aka the "BLE Server", will read the sensor's + output on A3-A5 where A3 is ENV, A4 is RAW, and A5 is REF. It then removes + the DC offset from the RAW data using the REF value and notifies the + "BLE Client" which is your smartphone running the Bluefruit Connect app. + + Note, in BLE, you have services, characteristics and values. + Read more about BLE here: + https://www.arduino.cc/reference/en/libraries/arduinoble/ + + This example uses Nordic UART Service (NUS) UUIDs for the service and the characteristics. + Read more about Nordic UART Service here: + https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v14.0.0%2Fble_sdk_app_nus_eval.html + + Note, before it begins reading the ADC and updating the data, + It first sets up some BLE stuff: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service + 6. Start advertising + + In order for this example to work, you will need a smartphone, with Bluetooth + turned on, and the Bluefruit Connect app installed. + 1. Open the Bluefruit Connect app + 2. The device list will display all BLE devices discovered by the app + 3. Find the device named "MyoW1" and connect + * The device name is defined by variable shieldDeviceName below + * If using multiple MyoWare IoT Shields, use "Multiple UART mode" + 4. Once connected, you can choose UART or Plotter module to view + incoming data as text or graphically + + Hardware: + MyoWare 2.0 Wireless Shield (or ESP32-based device) + MyoWare 2.0 Muscle Sensor + Smartphone with Bluefruit Connect app installed + + ** For consistent BT connection follow these steps: + ** 1. Reset Server + ** 2. Wait 5 seconds + ** 3. Reset Client + ** 4. Enjoy BT connection + + This example code is in the public domain. +*/ + +#include +#include +#include +#include +#include + +// user-definable parameters +const String myowareShieldName = "MyoW1"; // device name can be customized + // and is the name that will show + // up in the Bluefruit Connect app's + // device list. recommend making this + // unique for each Wireless shield + // (e.g. MyoW1, MyoW2, ...) + +// debug parameters +const bool debugLogging = false; // set to true for verbose logging +const bool debugOutput = false; // set to true to print output values to serial + +// MyoWare class object +MyoWare myoware; + +// misc. parameters +bool isConnected = false; +bool previousConnected = false; + +BLEServer* pServer = NULL; +BLECharacteristic* pTXCharacteristic = NULL; +BLECharacteristic* pRXCharacteristic = NULL; + +class ServerCallbacks: public BLEServerCallbacks +{ + void onConnect(BLEServer* pServer) + { + isConnected = true; + } + + void onDisconnect(BLEServer* pServer) + { + isConnected = false; + } +}; + +void setup() +{ + Serial.begin(115200); + + myoware.setConvertOutput(false); // Set to true to convert ADC output to the amplitude of + // of the muscle activity as it appears at the electrodes + // in millivolts + myoware.setGainPotentiometer(50.); // Gain potentiometer resistance in kOhms. + // adjust the potentiometer setting such that the + // max muscle reading is below 3.3V then update this + // parameter to the measured value of the potentiometer + myoware.setENVPin(A3); // Arduino pin connected to ENV (defult is A3 for Wireless Shield) + myoware.setRAWPin(A4); // Arduino pin connected to RAW (defult is A4 for Wireless Shield) + myoware.setREFPin(A5); // Arduino pin connected to REF (defult is A5 for Wireless Shield) + + pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate + // when a central is connected + digitalWrite(myoware.getStatusLEDPin(), HIGH); + + // Create the BLE Device + BLEDevice::init(myowareShieldName.c_str()); + + // Create the BLE Server + pServer = BLEDevice::createServer(); + if (!pServer) + { + Serial.println("Error creating Server!"); + while(!pServer); + } + pServer->setCallbacks(new ServerCallbacks()); + + // Create the BLE Service + BLEService* pService = pServer->createService(MyoWareBLE::uuidUARTService.c_str()); + if (!pService) + { + Serial.println("Error creating UART Service!"); + while(!pService); + } + + // Create the BLE TX Characteristic + pTXCharacteristic = + pService->createCharacteristic(MyoWareBLE::uuidUARTTXCharacteristic.c_str(), + BLECharacteristic::PROPERTY_NOTIFY); + if (!pTXCharacteristic) + { + Serial.println("Error creating TX characteristic!"); + while(!pTXCharacteristic); + } + pTXCharacteristic->addDescriptor(new BLE2902()); + + // Create the BLE RX Characteristic + pRXCharacteristic = + pService->createCharacteristic(MyoWareBLE::uuidUARTRXCharacteristic.c_str(), + BLECharacteristic::PROPERTY_WRITE); + if (!pRXCharacteristic) + { + Serial.println("Error creating RX characteristic!"); + while(!pRXCharacteristic); + } + + // Start the service + pService->start(); + + /// Start advertising + BLEAdvertising* pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(MyoWareBLE::uuidUARTService.c_str()); + pAdvertising->setScanResponse(false); + pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter + BLEDevice::startAdvertising(); + + if (debugLogging) + { + Serial.println("Setup Complete!"); + Serial.println("Waiting to connect..."); + } + + digitalWrite(myoware.getStatusLEDPin(), LOW); +} + +void loop() +{ + // if connected... read the sensor value, update the transmit characteristic + // value, and notify that the value changed + if (isConnected) + { + digitalWrite(myoware.getStatusLEDPin(), HIGH); // turn on the LED to indicate the + // connection + + // Read sensor output + const String strValue = ReadSensorData() + "\n"; + if (debugOutput) + Serial.println(strValue.c_str()); + + if (pTXCharacteristic) + { + pTXCharacteristic->setValue(strValue.c_str()); + pTXCharacteristic->notify(); + } + } + // blink status LED while not connected + else + { + myoware.blinkStatusLED(); + } + + // if the shield disconnected, restart advertising and blink the status LED + if (!isConnected && previousConnected) + { + delay(500); + + // restart advertising + pServer->startAdvertising(); + + // blink status LED while not connected + if (debugLogging) + Serial.println("Waiting to reconnect..."); + myoware.blinkStatusLED(); + previousConnected = isConnected; + } + // if the shield just connected, update the previousConnected flag + else if (isConnected && !previousConnected) + { + previousConnected = isConnected; + } +} + +// reads MyoWare Sensor output values and returns them as a comma delimited string +String ReadSensorData() +{ + const double env = myoware.readSensorOutput(MyoWare::ENVELOPE); + const double raw = myoware.readSensorOutput(MyoWare::RAW); + + return String(env) + "," + String(raw); +} \ No newline at end of file diff --git a/examples/ReadMyoWareVoltage/ReadMyoWareVoltage.ino b/examples/ReadMyoWareVoltage/ReadMyoWareVoltage.ino new file mode 100644 index 0000000..f7640d6 --- /dev/null +++ b/examples/ReadMyoWareVoltage/ReadMyoWareVoltage.ino @@ -0,0 +1,86 @@ +/* + Read MyoWare Voltage Example Code + Advancer Technologies, LLC + Brian Kaminski + 1/12/2024 + + This example reads a MyoWare 2.0 Muscle Sensor output on A0-A3 where A0 is ENV, + A1 is RAW, A2 is RECT, and A3 is REF. It then converts the reading to the amplitude of the + muscle activity as it appears at the electrodes in millivolts. + + MyoWare Muscle Sensor Analog Output: + 1. Raw EMG Output (RAW) - This is the raw amplified and filtered output: + * We will first remove the DC voltage offset using the REF value, converts its + value to volts based on the ADC parameters, and remove the gain applied by the + sensor using the RAW gain equation which is fixed at 200. + + 2. Rectified EMG Output (RECT) - This is the full-ware rectified RAW output: + * We will first convert its value to volts based on the ADC parameters and remove + the gain applied by the sensor using the RAW gain equation which is fixed at 200. + + 3. EMG Envelope (ENV) - This is the amplified envelope of the RECT output: + * We will first convert its value to volts based on the ADC parameters and remove + the gain applied the sensor using the ENV gain equation, see below. ENV has an second + amplification stage which is adjustable using the gain potentiometer. We will need + the gain potentiometer's resistance in kOhms to calcuate the gain. + + Read more about the MyoWare 2.0 Muscle Sensor & electromyography (EMG) output here: + https://myoware.com/learn/tutorials-guides/ + + In order for this example to work, you will need a MyoWare 2.0 Muscle Sensor + with the Vin and GND pins connected to 5V and GND pins on an Arduino compatible + board. The ENV, RAW, and REF pins will need to connect to the A0, A1, and A2 pins + on the Arduino compatible board, respectively. + + Hardware: + MyoWare 2.0 Muscle Sensor + Arduino compatible board (e.g Uno, Mega, etc.) + USB Cable + + Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu). + + This example code is in the public domain. +*/ + +#include + +// MyoWare class object +MyoWare myoware; + +// the setup routine runs once when you press reset: +void setup() +{ + // initialize serial communication at 9600 bits per second: + Serial.begin(9600); + + // output conversion parameters - modify these values to match your setup + myoware.setConvertOutput(true); // Set to true to convert ADC output to the amplitude of + // of the muscle activity as it appears at the electrodes + // in millivolts + myoware.setADCResolution(12.); // ADC bits (shield default = 12-bit) + myoware.setADCVoltage(3.3); // ADC reference voltage (shield default = 3.3V) + myoware.setGainPotentiometer(50.); // Gain potentiometer resistance in kOhms. + // adjust the potentiometer setting such that the + // max muscle reading is below 3.3V then update this + // parameter to the measured value of the potentiometer + myoware.setENVPin(A0); // Arduino pin connected to ENV + myoware.setRAWPin(A1); // Arduino pin connected to RAW + myoware.setREFPin(A2); // Arduino pin connected to REF + myoware.setRECTPin(A3); // Arduino pin connected to RECT +} + +// the loop routine runs over and over again forever: +void loop() +{ + // read the sensor's analog output pins + const double envMillivolts = myoware.readSensorOutput(MyoWare::ENVELOPE); + const double rawMillivolts = myoware.readSensorOutput(MyoWare::RAW); + const double rectMillivolts = myoware.readSensorOutput(MyoWare::RECTIFIED); + + // print output in millivolts: + Serial.print(envMillivolts); + Serial.print(","); + Serial.print(rawMillivolts); + Serial.print(","); + Serial.println(rectMillivolts); +} diff --git a/examples/TestMyoWareSamplingRate/TestMyoWareSamplingRate.ino b/examples/TestMyoWareSamplingRate/TestMyoWareSamplingRate.ino new file mode 100644 index 0000000..ab6cbfa --- /dev/null +++ b/examples/TestMyoWareSamplingRate/TestMyoWareSamplingRate.ino @@ -0,0 +1,78 @@ +/* + Test MyoWare Sample Rate Example Code + Advancer Technologies, LLC + Brian Kaminski + 2/24/2024 + + This example calculates the sampling rate of a microcontroller reading muscle + activity from a MyoWare Muscle Sensor. + + The MyoWare Muscle Sensor is an analog sensor therefore the sampling rate + will be entirely determined by the hardware specifications of the Arduino and the + performance of the code used. + + For the most accurate sampling rate, insert your code inside the loop indicated + below. This will more closely mirror your intended use case to see how additional + commands/calls would impact the sampling rate. + + Hardware: + MyoWare 2.0 Muscle Sensor + Arduino-compatible Microcontroller + + This example code is in the public domain. +*/ + +#include + +const long samples = 1000000; // number of samples + +// MyoWare class object +MyoWare myoware; + +void setup() +{ + Serial.begin(115200); + while(!Serial); + Serial.println("Sampling Test"); + Serial.println("------------------------------"); + + myoware.setENVPin(A3); // Arduino pin connected to ENV + + pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate + // when a central is connected + digitalWrite(myoware.getStatusLEDPin(), LOW); +} + +void loop() +{ + // initialize variables + int testValue = 0; + + digitalWrite(myoware.getStatusLEDPin(), HIGH); + Serial.println("Start Time:\t" + String(micros()) + " microsec"); + + // perform numerous read actions + // modify this to read all the output pins on the MyoWare Muscle Sensor that + // you are planning to use in your setup. + unsigned long startMicros = micros(); // variable for starting time in microseconds + for (long i = 0; i < samples; i++) + { + + // INSERT YOUR CODE HERE + + testValue = myoware.readSensorOutput(MyoWare::ENVELOPE); + } + const unsigned long endMicros = micros(); + + Serial.println("Finish Time:\t" + String(endMicros) + " microsec"); + digitalWrite(myoware.getStatusLEDPin(), LOW); + + // calculate the microseconds per sample (elapsed_time / number_of_samples) + // then convert to seconds + const double secondsPerSample = (endMicros - startMicros) / samples; + + // write out the sampling rate in Hz + Serial.println("Sampling Rate:\t" + String((1.0 / secondsPerSample) * 1000000) + " Hz"); + Serial.println("------------------------------"); + delay(1000); +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..57424f3 --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=MyoWare Arduino Library +version=1.0.0 +author=Advancer Technologies +maintainer=Advancer Technologies +sentence=Arduino library for the MyoWare 2.0 Muscle Sensor and Ecosystem. +paragraph=This library helps users interact with the MyoWare 2.0 Muscle Sensor, MyoWare 2.0 Wireless Shield, and more. +category=Sensors +url=https://github.com/AdvancerTechnologies/MyoWare-Arduino-Library +architectures=* +depends=SparkFun Toolkit, ArduinoBLE diff --git a/src/MyoWare.cpp b/src/MyoWare.cpp new file mode 100644 index 0000000..c59c6ff --- /dev/null +++ b/src/MyoWare.cpp @@ -0,0 +1,88 @@ +/* + MyoWare Class + Advancer Technologies, LLC + Brian Kaminski + 2/25/2024 + + MIT license, all text here must be included in any redistribution. +*/ + +#include "MyoWare.h" +#include "Arduino.h" + +double MyoWare::getENVGain() const +{ + return m_rawGain * (1. + m_gainPotentiometer); +} + +double MyoWare::getADC2Voltage() const +{ + return m_adcVoltage / (pow(2., m_adcBits) - 1.); +} + +double MyoWare::readSensorOutput(const OutputType type) const +{ + switch (type) + { + case OutputType::ENVELOPE: + { + // read the sensor's analog pins + const int envValue = analogRead(m_envPin); + if (!m_convertOutput) + return envValue; + + // convert the analog reading to a voltage (0 - 3.3V): + const double envVolts = envValue * getADC2Voltage(); + + // remove the sensor's gain and convert to millivolts + return envVolts / getENVGain() * 1000.; + } + + case OutputType::RAW: + { + // read the sensor's analog pins + const int rawValue = analogRead(m_rawPin); + const int refValue = analogRead(m_refPin); + if (!m_convertOutput) + return rawValue - refValue; + + // convert the analog reading to a voltage (0 - 3.3V): + const double rawVolts = (rawValue - refValue) * getADC2Voltage(); + + // remove the sensor's gain and convert to millivolts + return rawVolts / m_rawGain * 1000.; + } + + case OutputType::RECTIFIED: + { + // read the sensor's analog pins + const int rectValue = analogRead(m_rectPin); + if (!m_convertOutput) + return rectValue; + + // convert the analog reading to a voltage (0 - 3.3V): + const double rectVolts = rectValue * getADC2Voltage(); + + // remove the sensor's gain and convert to millivolts + return rectVolts / m_rawGain * 1000.; + } + + default: + return -9999.; + } + + return -9999.; +} + +void MyoWare::blinkStatusLED(const int duration) +{ + if (millis() - m_ledMillis > duration) // duration in ms + { + if (m_toggleLED) + digitalWrite(m_statusLEDPin, HIGH); + else + digitalWrite(m_statusLEDPin, LOW); + m_ledMillis = millis(); + m_toggleLED = !m_toggleLED; + } +} diff --git a/src/MyoWare.h b/src/MyoWare.h new file mode 100644 index 0000000..d2ed7b7 --- /dev/null +++ b/src/MyoWare.h @@ -0,0 +1,179 @@ +/* + MyoWare Class + Advancer Technologies, LLC + Brian Kaminski + 2/25/2024 + + MIT license, all text here must be included in any redistribution. +*/ + +#ifndef MyoWare_h +#define MyoWare_h +#include "Arduino.h" + +namespace MyoWareBLE +{ + // BLE UART service / characteristics parameters + const String uuidUARTService = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; + const String uuidUARTRXCharacteristic = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; + const String uuidUARTTXCharacteristic = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; + + // MyoWare service / characteristics parameters + const String uuidMyoWareService = "EC3AF789-2154-49F4-A9FC-BC6C88E9E930"; + const String uuidMyoWareCharacteristic = "F3A56EDF-8F1E-4533-93BF-5601B2E91308"; +} + +class MyoWare +{ +public: + MyoWare() = default; + ~MyoWare() = default; + + enum OutputType { ENVELOPE = 0, // EMG envelope (ENV pin) + RAW, // Amplified and filtered EMG (RAW pin) + RECTIFIED }; // Full-wave rectified, amplified, and filtered EMG (RECT pin) + + // \brief Reads MyoWare Sensor output values and returns the desired output | + // NOTE: The RAW output will have the reference voltage offset removed + // + // \param[in] type: OutputType value of the desired output type + // \return double value of the desired output | Note: will be converted to millivolts if + // setConvertOutput is set to true + double readSensorOutput(const OutputType type = OutputType::ENVELOPE) const; + + // \brief Blinks the status LED on/off + // \param[in] duration: Integer value of the duration of the on/off cycle in milliseconds | + // Note: Default is 1000 ms + // \return none + void blinkStatusLED(const int duration = 1000); + + // \brief Sets the flag to convert ADC output to the amplitude of the muscle + // activity as it appears at the electrodes in millivolts + // \param[in] flag: Boolean value of the flag to have output converted to millivolts + // as it appears at the electrodes in millivolts + // \return none + void setConvertOutput(const bool flag) { m_convertOutput = flag; } + + // \brief Defines the Arduino pin that is connected to the MyoWare Sensor ENV pin + // \param[in] pin: Integer value of the Arduino pin that is connected to the MyoWare Sensor ENV pin + // \return none + void setENVPin(const int pin) { m_envPin = pin; } + + // \brief Gets the Arduino pin that is connected to the MyoWare Sensor ENV pin + // \param none + // \return Integer value of the Arduino pin that is connected to the MyoWare Sensor ENV pin + int getENVPin() const { return m_envPin; } + + // \brief Defines the Arduino pin that is connected to the MyoWare Sensor RAW pin + // \param[in] pin: Integer value of the Arduino pin that is connected to the MyoWare Sensor RAW pin + // \return none + void setRAWPin(const int pin) { m_rawPin = pin; } + + // \brief Gets the Arduino pin that is connected to the MyoWare Sensor RAW pin + // \param none + // \return Integer value of the Arduino pin that is connected to the MyoWare Sensor RAW pin + int getRAWPin() const { return m_rawPin; } + + // \brief Defines the Arduino pin that is connected to the MyoWare Sensor REF pin + // \param[in] pin: Integer value of the Arduino pin that is connected to the MyoWare Sensor REF pin + // \return none + void setREFPin(const int pin) { m_refPin = pin; } + + // \brief Gets the Arduino pin that is connected to the MyoWare Sensor REF pin + // \param none + // \return Integer value of the Arduino pin that is connected to the MyoWare Sensor REF pin + int getREFPin() const { return m_refPin; } + + // \brief Defines the Arduino pin that is connected to the MyoWare Sensor RECT pin | + // NOTE: Currently not connected by default by the Wireless Shield + // \param[in] pin: Integer value of the Arduino pin that is connected to the MyoWare Sensor RECT pin + // \return none + void setRECTPin(const int pin) { m_rectPin = pin; } + + // \brief Gets the Arduino pin that is connected to the MyoWare Sensor RECT pin + // \param none + // \return Integer value of the Arduino pin that is connected to the MyoWare Sensor RECT pin + int getRECTPin() const { return m_rectPin; } + + // \brief Defines the Arduino pin that is connected to an LED used as status indicator + // \param[in] pin: Integer value of the Arduino status indicator pin + // \return none + void setStatusLEDPin(const int pin) { m_statusLEDPin = pin; } + + // \brief Gets the Arduino pin that is connected to an LED used as status indicator + // \param none + // \return Integer value of the Arduino status indicator pin + int getStatusLEDPin() const { return m_statusLEDPin; } + + // \brief Define the Arduino ADC resolution in number of bits (Wireless Shield is 12-bit) + // \param[in] bits: double value of the Arduino ADC resolution in number of bits + // \return none + void setADCResolution(const double bits) { m_adcBits = bits; } + + // \brief Gets the Arduino ADC resolution value in number of bits + // \param none + // \return double value of Arduino ADC resolution in bits + double getADCResolution() const { return m_adcBits; } + + // \brief Define the Arduino ADC reference voltage (Wireless Shield is 3.3V) + // \param[in] bits: double value of the Arduino ADC reference voltage in volts + // \return none + void setADCVoltage(const double voltage) { m_adcVoltage = voltage; } + + // \brief Gets the Arduino ADC voltage value + // \param none + // \return double value of Arduino ADC voltage in volts + double getADCVoltage() const { return m_adcVoltage; } + + // \brief Define the MyoWare Sensor gain potentiomenter resistance in kOhms | + // NOTE: The MyoWare Sensor gain potentiometer resistance should be adjusted such that the + // max muscle reading is below the ADC Voltage then update this + // \param[in] resistance: double value of the MyoWare Sensor gain potentiomenter resistance in kOhms + // \return none + void setGainPotentiometer(const double resistance) { m_gainPotentiometer = resistance; } + + // \brief Gets the MyoWare Sensor gain potentiomenter resistance + // \param none + // \return double value of the MyoWare Sensor gain potentiomenter resistance in kOhms + double getGainPotentiometer() const { return m_gainPotentiometer; } + + // \brief Gets the calculated gain of the ENV output | + // NOTE: ENV gain depends on the gain potentiometer resistance + // \param none + // \return double value of the calculated gain of the ENV output + double getENVGain() const; + + // \brief Gets the calculated value to convert ADC to volts | + // NOTE: Depends on the ADC Voltage and ADC Bits + // \param none + // \return double value to convert ADC to volts + double getADC2Voltage() const; + +private: + + int m_envPin = 0; // Arduino pin connected to ENV (Set to A3 for Wireless Shield) + int m_rawPin = 0; // Arduino pin connected to RAW (Set to A4 for Wireless Shield) + int m_refPin = 0; // Arduino pin connected to REF (Set to A5 for Wireless Shield) + int m_rectPin = 0; // Arduino pin connected to RECT (not connected for Wireless Shield) + + bool m_convertOutput = false; // Flag to enable output conversion to millivolts + +#ifdef LED_BUILTIN + int m_statusLEDPin = LED_BUILTIN; +#else + int m_statusLEDPin = 13; // status LED pin (Wireless Shield uses pin 13) +#endif + + long m_ledMillis = 0; + bool m_toggleLED = true; + + double m_adcBits = 12.; // ADC bits (Wireless Shield is 12-bit) + double m_adcVoltage = 3.3; // ADC reference voltage (Wireless Shield is 3.3V) + const double m_rawGain = 200.; // RAW output has a set gain of 200 + double m_gainPotentiometer = 50.; // gain potentiometer resistance in kOhms. + // adjust the potentiometer setting such that the + // max muscle reading is below 3.3V then update this + // parameter to the measured value of the potentiometer +}; + +#endif From f668db6413202b32ddbe2b20b1067ab2a675da41 Mon Sep 17 00:00:00 2001 From: bboyho Date: Tue, 5 Mar 2024 22:53:20 -0700 Subject: [PATCH 2/2] Minor Updates to Comments --- LICENSE.md | 2 +- README.md | 4 +- .../MyoWareBLECentral/MyoWareBLECentral.ino | 2 +- .../MyoWareBLEPeripheral.ino | 55 ++++++++++--------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 57471c8..4a1324c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ Advancer Technologies License Information ============================ -**Advancer Technologies code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** +**Advancer Technologies code, firmware, and software is released under the [MIT License](http://opensource.org/licenses/MIT).** The MIT License (MIT) diff --git a/README.md b/README.md index cd44bc9..eee257e 100644 --- a/README.md +++ b/README.md @@ -31,5 +31,5 @@ The MyoWare 2.0 ecosystem consists of shields that easily interface with the [My This open source code is licensed under the MIT license (see [LICENSE](LICENSE.md) for details). -The MyoWare 2.0 Ecosystem is a collaboration between [Advancer Technologies](https://myoware.com) and [Sparkfun Electronics](https://www.sparkfun.com), please support future MyoWare development by purchasing products from -[Sparkfun Electronics](https://www.sparkfun.com/myoware)! +The MyoWare 2.0 Ecosystem is a collaboration between [Advancer Technologies](https://myoware.com) and [SparkFun Electronics](https://www.sparkfun.com), please support future MyoWare development by purchasing products from +[SparkFun Electronics](https://www.sparkfun.com/myoware)! diff --git a/examples/MyoWareBLECentral/MyoWareBLECentral.ino b/examples/MyoWareBLECentral/MyoWareBLECentral.ino index 1dedeba..b8f8945 100644 --- a/examples/MyoWareBLECentral/MyoWareBLECentral.ino +++ b/examples/MyoWareBLECentral/MyoWareBLECentral.ino @@ -30,7 +30,7 @@ and print them to the serial terminal. Hardware: - BLE device (e.g. Artemis Redboard) + BLE device (e.g. ESP32) USB from BLE device to Computer. ** For consistent BT connection follow these steps: diff --git a/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino b/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino index 4959d51..a519759 100644 --- a/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino +++ b/examples/MyoWareBLEPeripheral/MyoWareBLEPeripheral.ino @@ -4,19 +4,20 @@ Brian Kaminski 8/01/2023 - This example sets up a MyoWare 2.0 Wireless Shield, and then reads the ENV, RAW, - and REF data from the attached MyoWare 2.0 Muscle Sensor. The MyoWare 2.0 - Wireless Shield (the Peripheral) sends this data to a second BLE Device + This example sets up a MyoWare 2.0 Wireless Shield, and then reads the ENV, RAW, + and REF data from the attached MyoWare 2.0 Muscle Sensor. The MyoWare 2.0 + Wireless Shield (the Peripheral) sends this data to a second BLE Device (the Central) over BLE. This MyoWare 2.0 Wireless Shield, aka the "BLE Peripheral", will read the sensor's output on A3-A5 where A3 is ENV, A4 is RAW, and A5 is REF. It will then store - them in a single 32-bit variable, and then update that value to the - "bluetooth bulliten board". + them in a single 32-bit variable, and then update that value to the + "bluetooth bulletin board". When uploading to the MyoWare 2.0 Wireless Shield + make sure to select "ESP32 Dev Module" as the board definition. Note, in BLE, you have services, characteristics and values. Read more about it here: - + https://www.arduino.cc/reference/en/libraries/arduinoble/ Note, before it begins reading the ADC and updating the data, @@ -27,12 +28,12 @@ -These must match the UUIDs in the code on the central device. 3. advertises itself - In order for this example to work, you will need a Artemis boad, - and it will need to be programmed with the provided code specific to + In order for this example to work, you will need a ESP32 board, + and it will need to be programmed with the provided code specific to being a central device, looking for this specific service/characteristic. Note, both the service and the characteristic get unique UUIDs. - + The "BLE Central", will subscribe to the MyoWare 2.0 Wireless Shield's charactieristic, read it, and parse it into 4 separate bytes, then print the values to the serial terminal. @@ -59,7 +60,7 @@ #include #include -const String localName = "MyoWareSensor1"; // recommend making this unique for +const String localName = "MyoWareSensor1"; // recommend making this unique for // each Wireless shield (e.g. MyoWareSensor1, // MyoWareSensor2, ...) @@ -79,7 +80,7 @@ BLEService myoWareService(MyoWareBLE::uuidMyoWareService.c_str()); // BLE Muscle Sensor Characteristics BLEStringCharacteristic sensorCharacteristic(MyoWareBLE::uuidMyoWareCharacteristic.c_str(), BLERead | BLENotify, 128); -void setup() +void setup() { Serial.begin(115200); while (!Serial); @@ -95,13 +96,13 @@ void setup() myoware.setRAWPin(A4); // Arduino pin connected to RAW (defult is A4 for Wireless Shield) myoware.setREFPin(A5); // Arduino pin connected to REF (defult is A5 for Wireless Shield) - pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate + pinMode(myoware.getStatusLEDPin(), OUTPUT); // initialize the built-in LED pin to indicate // when a central is connected digitalWrite(myoware.getStatusLEDPin(), HIGH); - + // begin initialization bool error = !BLE.begin(); - if (error) + if (error) { Serial.println("FAILED - BLE Initialization!"); @@ -115,7 +116,7 @@ void setup() // set initial values for the characteristics sensorCharacteristic.writeValue(""); - + BLE.advertise(); if (debugLogging) @@ -133,23 +134,23 @@ void setup() digitalWrite(myoware.getStatusLEDPin(), LOW); } -void loop() +void loop() { // wait for a BLE central BLEDevice central = BLE.central(); - if (central) - { + if (central) + { if (debugLogging) { Serial.print("Connected to central: "); - Serial.println(central.address()); + Serial.println(central.address()); } - - digitalWrite(myoware.getStatusLEDPin(), HIGH); // turn on the LED to indicate the + + digitalWrite(myoware.getStatusLEDPin(), HIGH); // turn on the LED to indicate the // connection - - while (central.connected()) - { + + while (central.connected()) + { // Read sensor output const String strValue = String(myoware.readSensorOutput(outputType)); if (debugOutput) @@ -158,18 +159,18 @@ void loop() // "post" to "BLE bulletin board" sensorCharacteristic.writeValue(strValue); } - + // when the central disconnects, turn off the LED: digitalWrite(myoware.getStatusLEDPin(), LOW); if (debugLogging) { Serial.print("Disconnected from central: "); - Serial.println(central.address()); + Serial.println(central.address()); } } else { myoware.blinkStatusLED(); } -} \ No newline at end of file +}