I'm pretty novice at both arduino, esp-idf, and programming in general, but I am working on a project to take EMG signals (muscle activity) and send it over WiFi to a computer for analysis. So far, I seem to have gotten it working overall, except for the fact that I cannot get a sample rate faster than 125 Hz! Ideally, I need to reach at least 1000 Hz sample rate to get a good signal.
I have tried interrupts, and rtos for multitasking, but nothing has worked. I have even tried an empty loop simply printing micros() since the last loop, and even that only goes ~600 Hz Everywhere I look online, everyone is able to reach 30k+ Hz sample rate. What am I doing wrong?
I've attached my code that uses interrupts (again, much of this is pasted from resources online). Using the adafruit feather board, wroom-32
Thank you!
Code: Select all
// Include Libraries
#include "Arduino.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include "SparkFunLSM6DS3.h"
#include "Wire.h"
#include "SPI.h"
#include <MadgwickAHRS.h>
#include "esp_wpa2.h" //wpa2 library for connections to Enterprise networks
LSM6DS3 myIMU(SPI_MODE,21); //Default constructor is I2C, addr 0x6B
Madgwick filter;
float EMA_a = 0.3; //initialization of EMA alpha
uint16_t EMA_S = 0; //initialization of EMA S
#define EAP_ANONYMOUS_IDENTITY "anonymous@example.com"
#define EAP_IDENTITY "******"
#define EAP_PASSWORD "*******"
const char* ssid = "*****"; // Eduroam SSID
//const char* host = "arduino.php5.sk"; //external server domain for HTTP connection after authentification
uint16_t counter = 0;
bool wifistat = false;
WiFiClient client;
unsigned long microsPerReading, microsPrevious, timer, microfreq, currentaccel, currentemg, currentprint, previousaccel=millis(), previousemg=millis(), previousprint=millis();
//// Set these to your desired credentials.
//const char *ssid = "GGesp32";
//const char *password = "capstone";
WiFiServer server(80);
//Timer Interrupts
hw_timer_t *acceltimer = NULL;
hw_timer_t *emgtimer = NULL;
hw_timer_t *printtimer = NULL;
bool updateEMG = false;
bool updateAccel = false;
bool updatePrint = false;
// Initialize Analog Pins
uint16_t EMGLeftRA_pin = 39; //A3
uint16_t EMGRightRA_pin = 34; //A2
uint16_t EMGLeftOb_pin = 36; //A4
uint16_t EMGRightOb_pin = 33; //33
uint16_t EMGErect_pin = 32; //32
// Initialize EMG Aquisition Variables
uint16_t EMGleftRA=0;
uint16_t EMGrightRA=0;
uint16_t EMGleftob=0;
uint16_t EMGrightob=0;
uint16_t EMGerect=0;
// Initialize Mapping for EMG data
uint16_t Min = 0;
uint16_t Max = 4095;
uint16_t Map_Min= 0;
uint16_t Map_Max= 2200;
//Initialize Accelerometer Data
float AccelX=0;
float AccelY=0;
float AccelZ=0;
float roll, pitch, heading;
//Initialize Gyrometer Data
float GyroX=0;
float GyroY=0;
float GyroZ=0;
/*
* setup function
*/
double modifiedMap(double x, double in_min, double in_max, double out_min, double out_max)
{
return round(((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)*10)/10;
}
void IRAM_ATTR onEMGTimer(){
updateEMG = true;
}
void IRAM_ATTR onAccelTimer(){
updateAccel = true;
}
void startTimer(){
acceltimer = timerBegin(0,80,true);
emgtimer = timerBegin(3,80,true);
timerAttachInterrupt(acceltimer,&onAccelTimer,true);
timerAttachInterrupt(emgtimer,&onEMGTimer,true);
timerAlarmWrite(acceltimer,1000000/26,true);
timerAlarmWrite(emgtimer,10000000/1000,true);
timerAlarmEnable(acceltimer);
timerAlarmEnable(emgtimer);
}
// Setup the essentials for your circuit to work. It runs first every time your circuit is powered with electricity.
void setup()
{
Serial.begin(1000000);
delay(10);
Serial.println();
Serial.print("Connecting to network: ");
Serial.println(ssid);
WiFi.disconnect(true); //disconnect form wifi to set new wifi connection
WiFi.mode(WIFI_STA); //init wifi mode
esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_ANONYMOUS_IDENTITY, strlen(EAP_ANONYMOUS_IDENTITY));
esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY));
esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD));
esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); //set config settings to default
esp_wifi_sta_wpa2_ent_enable(&config); //set config settings to enable function
WiFi.begin(ssid); //connect to wifi
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
counter++;
if(counter>=60){ //after 30 seconds timeout - reset board
ESP.restart();
}
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address set: ");
Serial.println(WiFi.localIP()); //print LAN IP
myIMU.settings.gyroRange = 125; //Max deg/s. Can be: 125, 245, 500, 1000, 2000
myIMU.settings.gyroSampleRate = 26; //Hz. Can be: 13, 26, 52, 104, 208, 416, 833, 1666
myIMU.settings.gyroBandWidth = 50; //Hz. Can be: 50, 100, 200, 400;
myIMU.settings.accelRange = 2; //Max G force readable. Can be: 2, 4, 8, 16
myIMU.settings.accelSampleRate = 26; //Hz. Can be: 13, 26, 52, 104, 208, 416, 833, 1666, 3332, 6664, 13330
myIMU.settings.accelBandWidth = 50; //Hz. Can be: 50, 100, 200, 400;
myIMU.begin();
filter.begin(26);
// initialize variables to pace updates to correct rate
microsPerReading = 1000000 / 26;
microsPrevious = micros();
// //Start Servers
server.begin();
// Start Timers
startTimer();
}
// Main logic of your circuit. It defines the interaction between the components you selected. After setup, it runs over and over again, in an eternal loop.
void loop()
{
if (WiFi.status() == WL_CONNECTED && wifistat == false) { //if we are connected to Eduroam network
counter = 0; //reset counter
Serial.println("Wifi is still connected with IP: ");
Serial.println(WiFi.localIP()); //inform user about his IP address
wifistat = true;
}else if (WiFi.status() != WL_CONNECTED) { //if we lost connection, retry
WiFi.begin(ssid);
wifistat = false;
}
while (WiFi.status() != WL_CONNECTED) { //during lost connection, print dots
delay(500);
Serial.print(".");
counter++;
if(counter>=60){ //30 seconds timeout - reset board
ESP.restart();
}
}
client = server.available();
delay(1);
if (client) { // if you get a client,
//Serial.println("New Client."); // print a message out the serial port
//String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (updateAccel == true){
// Defining Positional Data
AccelX=myIMU.readFloatAccelX();
AccelY=myIMU.readFloatAccelY();
AccelZ=myIMU.readFloatAccelZ();
// Defining Positional Data
GyroX=myIMU.readFloatGyroX();
GyroY=myIMU.readFloatGyroY();
GyroZ=myIMU.readFloatGyroZ();
filter.updateIMU(GyroX,GyroY,GyroZ,AccelX,AccelY,AccelZ);
roll = filter.getRoll();
pitch = filter.getPitch();
heading = filter.getYaw();
EMA_S = (EMA_a*heading)+((1-EMA_a)*EMA_S);
heading = heading - EMA_S;
AccelX=heading;
AccelY=pitch;
AccelZ=roll;
updateAccel = false;
}
if (updateEMG ==true){
// //Method 1 EMG, adding false gain
EMGleftRA=analogRead(EMGLeftRA_pin);
EMGrightRA=analogRead(EMGRightRA_pin);
EMGleftob=analogRead(EMGLeftOb_pin);
EMGrightob=analogRead(EMGRightOb_pin);
EMGerect=analogRead(EMGErect_pin);
EMGleftRA = constrain(EMGleftRA*1.814,Min,Max);
EMGrightRA = constrain(EMGrightRA*1.814,Min,Max);
EMGleftob = constrain(EMGleftob*2.165,Min,Max);
EMGrightob = constrain(EMGrightob*2.165,Min,Max);
EMGerect = constrain(EMGerect*2.268,Min,Max);
// Maping vaues from 0-4095 to 0-2200Mv
EMGleftRA=modifiedMap(EMGleftRA,Min,Max,Map_Min,Map_Max);
EMGrightRA=modifiedMap(EMGrightRA,Min,Max,Map_Min,Map_Max);
EMGleftob=modifiedMap(EMGleftob,Min,Max,Map_Min,Map_Max);
EMGrightob=modifiedMap(EMGrightob,Min,Max,Map_Min,Map_Max);
EMGerect=modifiedMap(EMGerect,Min,Max,Map_Min,Map_Max);
// SENDING RAW EMG DATA TO LABVIEW
// Initialize buffer for the ASCII String
char a[6]="";
char b[6]="";
char c[6]="";
char d[6]="";
char e[6]="";
// Initializing Buffer for ASCII String for Accel Data
char Ax[6]="";
char Ay[6]="";
char Az[6]="";
// Initializing Buffer for ASCII String for Accel Data
char Gx[6]="";
char Gy[6]="";
char Gz[6]="";
// Converting RAW emg data to a string
String str1= String(EMGleftRA);
String str2= String(EMGrightRA);
String str3= String(EMGleftob);
String str4= String(EMGrightob);
String str5= String(EMGerect);
// Converting Accel Data to Strings
String Axstr= String(AccelX);
String Aystr= String(AccelY);
String Azstr= String(AccelZ);
// Converting Accel Data to Strings
String Gyxstr= String(GyroX);
String Gyystr= String(GyroY);
String Gyzstr= String(GyroZ);
// Converts 5 bytes of data in str to a char array e
str1.toCharArray(a,5);
str2.toCharArray(b,5);
str3.toCharArray(c,5);
str4.toCharArray(d,5);
str5.toCharArray(e,5);
// Converting Strings to Char Array
Axstr.toCharArray(Ax,6);
Aystr.toCharArray(Ay,6);
Azstr.toCharArray(Az,6);
// Converting Strings to Char Array
Gyxstr.toCharArray(Gx,6);
Gyystr.toCharArray(Gy,6);
Gyzstr.toCharArray(Gz,6);
//
// //Writing all to server EMG first then Accel then Gyro
client.write(a);
Serial.print(a);
client.write(",");
Serial.print(",");
client.write(b);
Serial.print(b);
client.write(",");
Serial.print(",");
client.write(c);
Serial.print(c);
client.write(",");
Serial.print(",");
client.write(d);
Serial.print(d);
client.write(",");
Serial.print(",");
client.write(e);
Serial.print(e);
client.write(",");
Serial.print(",");
client.write(Ax);
Serial.print(Ax);
client.write(",");
Serial.print(",");
client.write(Ay);
Serial.print(Ay);
client.write(",");
Serial.print(",");
client.write(Az);
Serial.println(Az);
//ENDING DATA TRANSMISSION
client.write("\r");
}
//close the connection
client.stop();
Serial.println("Client Disconnected.");
}
}