How to read EMG characteristics from Myo armband using Arduino BLE library

Hello,

I connected an Arduino nano 33 IoT to the Myo armband and tried to read EMG data from the Myo sensors. I am using the Arduino BLE library to read the EMG characteristics but I didn't succeed to read the real data.

First, I am not sure about the right functions to use. I have to notify the characteristics and then read them. Here is my code:


void armband::get_emg_data(BLEDevice peripheral){
  BLEService EmgDataService = peripheral.service("d5060005-a904-deb9-4748-2c7f4a124842");


    if (EmgDataService) {
      // use the service
       Serial.println("Peripheral has EMG service");

      
      BLECharacteristic EmgData0Characteristic = peripheral.characteristic("d5060105-a904-deb9-4748-2c7f4a124842");
      BLECharacteristic EmgData1Characteristic = peripheral.characteristic("d5060205-a904-deb9-4748-2c7f4a124842");
      BLECharacteristic EmgData2Characteristic = peripheral.characteristic("d5060305-a904-deb9-4748-2c7f4a124842");
      BLECharacteristic EmgData3Characteristic = peripheral.characteristic("d5060405-a904-deb9-4748-2c7f4a124842");

      // subscribe to emg characteristic
      Serial.println("Subscribing to EMG char");
      if (!EmgData0Characteristic && !EmgData1Characteristic && !EmgData2Characteristic && !EmgData3Characteristic){
         Serial.println("no EMG Char found");
         peripheral.disconnect();
         return;
      }else if(!EmgData0Characteristic.subscribe() && !EmgData1Characteristic.subscribe() && !EmgData2Characteristic.subscribe() && !EmgData3Characteristic.subscribe()){
        Serial.println("subscription failed!");
        peripheral.disconnect();
        return;
      }else{
        Serial.println("Subscribed!");
      }

      while(peripheral.connected()){
        //while the peripheral is connected 
        // armband::emgdata0 = EmgData0Characteristic.value();
         EmgData0Characteristic.readValue(emgdata0); //stores incoming data in the value byte.
         EmgData0Characteristic.readValue(emgdata1); //stores incoming data in the value byte.
         EmgData0Characteristic.readValue(emgdata2); //stores incoming data in the value byte.
         EmgData0Characteristic.readValue(emgdata3); //stores incoming data in the value byte.
         
         emg_callback(emgdata0);
         emg_callback(emgdata1);
         emg_callback(emgdata2);
         emg_callback(emgdata3);
  
      }
    
    
    }else{
      Serial.println("EMG service not found");
      peripheral.disconnect();
    }
}

void armband::print_emg_sample(int8_t *sample, size_t len)
{

  for (int i = 0; i < len; i++)
  {
  
   Serial.print(sample[i]);
   Serial.print("\t");
  
  }
  Serial.println();
  
}

void armband::emg_callback(uint8_t pData)
{
  
  myohw_emg_data_t *emg_data = (myohw_emg_data_t *)pData;
  print_emg_sample(emg_data->sample1, myohw_num_emg_sensors);
  //Serial.println("");
}

I got this data when I read from only one characteristic

10:55:09.801 -> -4	127	0	32	1	6	0	0	
10:55:10.051 -> -4	127	0	32	1	6	0	0	
10:55:10.284 -> -4	127	0	32	1	6	0	0	
10:55:10.518 -> -4	127	0	32	1	6	0	0	
10:55:10.782 -> -4	127	0	32	1	6	0	0	
10:55:11.015 -> -4	127	0	32	1	6	0	0	
10:55:11.282 -> -4	127	0	32	1	6	0	0	
10:55:11.514 -> -4	127	0	32	1	6	0	0

Looks like you will need to decode the bytes of the characteristics. Maybe the following GitHub will be helpful:

https://github.com/cortinico/myonnaise

You will need to dig a bit trough the code. It very likely has the answer.

I think all the characteristics are readable as bytes, I am able to read the battery level characteristic for example without decoding the bytes, I used readValue() method

But when I subscribe to an EMG characteristic doesn't seem to work.

Do you know how the data can be read from 8 sensors using only 4 characteristics?

All characteristics are just a collection of bytes because that is what is transferred. BLE uses simple packets
Preamble - Address - Header - Length - Data - CRC
Length tells the receiver how many data bytes are in the packet. No other information e.g., what the data type is.

The designer of the characteristic specifies what these bytes are. Sometimes they are just signed or unsigned 8-bit integer but they can be anything. If the characteristic has two bytes it could be two 8-bit or one 16-bit value. Somebody will create a specification. There are some available directly from the Bluetooth SiG but anyone can make something up. You do not have the spec and the GitHub I linked very likely has the answer.

You can also try to reverse engineer what the data could be. Use the original app and see what kind of data is displayed. How many values, range, data type ... Then try to match these values to the raw data you have.

I would try to dig through the GitHub source code. It seems very clean and has comments in it as well. You can use the search function in Github to search for symbols you have found in one file to look where they are used in another.

1 Like

Thanks a lot for the thorough reply.

I started looking at the GitHub repo, there is indeed a nice approach on how to read the bytes from the characteristics but before that, I just realized that I have an issue with the subscription itself! the EMG characteristics subscription is failing and is not subscribed properly.

Do you know what could be the reason?

Unfortunately can't help with that part - but if you are looking for wireless EMG sensor which just works - I can recommend uMyo :slight_smile: We just finished its development, it works in Arduino+nRF24 and ESP32 (BLE) radio modes, with available Arduino libraries that handle reception of sensor data - both EMG and IMU - and support up to 12 simultaneous sensors in current version

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.