Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -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
11 changes: 8 additions & 3 deletions LICENSE → LICENSE.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)!
250 changes: 250 additions & 0 deletions examples/MyoWareBLECentral/MyoWareBLECentral.ino
Original file line number Diff line number Diff line change
@@ -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. ESP32)
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 <ArduinoBLE.h>
#include <MyoWare.h>
#include <vector>

// debug parameters
const bool debugLogging = false; // set to true for verbose logging to serial

std::vector<BLEDevice> 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());
}
Loading