Receive new product information directly to your email
Quote from alikhodrali on 06.08.2024, 23:35Hi there,
I finally figured out how to send the data from the ArdEEG over TCP (because my access point receiver, my bionic prosthetic arm, is using TCP and so is my other transmitter). My problem is the way I send data is different from the example code on GitHub. Once you look at my code you'll understand exactly how I want my data sent. The problem with this is that I don't understand how to take "output" and convert it into meaningful values that I can store in variables before sending it off to my receiver using "client.print()". I'd like to be able to store the data in the following variables leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4. This will allow me to use a serial plotter on the receiving end and be able to manipulate the data so that I can close a fist. It would be nice to have an example code on GitHub for another arduino which demonstrates how we can output meaningful values after we receive the data.
Below is the code I have to transmit.
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG true// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_500HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;WiFiClient client;EMGFilters brainEEGFilter;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place one on the elbow as our reference signal, or anywhere else where there is little to no muscle.// Place the other two spaced apart from each other by 2cm on the point of the muscle being measured where there is the most atrophy when flexing.// Then release your muscles and wait a few seconds for the signal to normalize.// Select the max value as the EMGThreshold. Any value under EMGThreshold will be set to zerostatic int brainEEGFilterThreshold = 0;int brainEEGSensorValue, brainEEGSensorValueFiltered, brainEEGSensorValueFilteredAmplified;unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;byte leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;int a = 30;int sampleCount = 0;//ADC//#define button_pin 7const int button_pin = 7;const int chip_select = 10; // Assuming SPI chip select pinint test_DRDY = 5;int button_state = 0;const int size_of_data = 1350; //864;byte output[size_of_data] = {};void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//ADCpinMode(button_pin, INPUT); //initialize the led pin as outputpinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilter.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arms Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == size_of_data) {Serial.println("Sample Count = Size of Data!");for (int i = 0; i < size_of_data; i++) {switch (i) {case 0:leftEar = output[i];break;case 1:rightEar = output[i];break;case 2:leftFrontalLobeFP1 = output[i];break;case 3:rightFrontalLobeFP2 = output[i];break;case 4:leftMotorCortexC3 = output[i];break;case 5:rightMotorCortexC4 = output[i];break;case 6:leftOccipitalLobeO1 = output[i];break;case 7:rightOccipitalLobeO2 = output[i];break;case 8:leftTemporalLobeT3 = output[i];break;case 9:rightTemporalLobeT4 = output[i];break;}if (BRAIN_EEG_DEBUG) {Serial.print("Size of Data: "); Serial.println(size_of_data);Serial.print("Left Ear: "); Serial.print(leftEar);Serial.print("\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving fromSerial.print(size_of_data);client.print(leftEar); client.print(",");client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();//Serial.println("Data sent to Bionic Prosthetic Arm");sampleCount = 0; // Reset the index after sending data}}//delay(20);}}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}
Hi there,
I finally figured out how to send the data from the ArdEEG over TCP (because my access point receiver, my bionic prosthetic arm, is using TCP and so is my other transmitter). My problem is the way I send data is different from the example code on GitHub. Once you look at my code you'll understand exactly how I want my data sent. The problem with this is that I don't understand how to take "output" and convert it into meaningful values that I can store in variables before sending it off to my receiver using "client.print()". I'd like to be able to store the data in the following variables leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4. This will allow me to use a serial plotter on the receiving end and be able to manipulate the data so that I can close a fist. It would be nice to have an example code on GitHub for another arduino which demonstrates how we can output meaningful values after we receive the data.
Below is the code I have to transmit.
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG true// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_500HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;WiFiClient client;EMGFilters brainEEGFilter;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place one on the elbow as our reference signal, or anywhere else where there is little to no muscle.// Place the other two spaced apart from each other by 2cm on the point of the muscle being measured where there is the most atrophy when flexing.// Then release your muscles and wait a few seconds for the signal to normalize.// Select the max value as the EMGThreshold. Any value under EMGThreshold will be set to zerostatic int brainEEGFilterThreshold = 0;int brainEEGSensorValue, brainEEGSensorValueFiltered, brainEEGSensorValueFilteredAmplified;unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;byte leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;int a = 30;int sampleCount = 0;//ADC//#define button_pin 7const int button_pin = 7;const int chip_select = 10; // Assuming SPI chip select pinint test_DRDY = 5;int button_state = 0;const int size_of_data = 1350; //864;byte output[size_of_data] = {};void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//ADCpinMode(button_pin, INPUT); //initialize the led pin as outputpinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilter.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arms Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == size_of_data) {Serial.println("Sample Count = Size of Data!");for (int i = 0; i < size_of_data; i++) {switch (i) {case 0:leftEar = output[i];break;case 1:rightEar = output[i];break;case 2:leftFrontalLobeFP1 = output[i];break;case 3:rightFrontalLobeFP2 = output[i];break;case 4:leftMotorCortexC3 = output[i];break;case 5:rightMotorCortexC4 = output[i];break;case 6:leftOccipitalLobeO1 = output[i];break;case 7:rightOccipitalLobeO2 = output[i];break;case 8:leftTemporalLobeT3 = output[i];break;case 9:rightTemporalLobeT4 = output[i];break;}if (BRAIN_EEG_DEBUG) {Serial.print("Size of Data: "); Serial.println(size_of_data);Serial.print("Left Ear: "); Serial.print(leftEar);Serial.print("\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving fromSerial.print(size_of_data);client.print(leftEar); client.print(",");client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();//Serial.println("Data sent to Bionic Prosthetic Arm");sampleCount = 0; // Reset the index after sending data}}//delay(20);}}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}
Quote from PiEEG on 07.08.2024, 01:36Hi Alikhodrali, really nice to meet you and thank you for your detailed email.
To receive data via wi-fi I used this script for Windows
https://github.com/Ildaron/ardEEG/blob/main/software/python/1.Alpha_real_time.pyDoes it make sense?
If you would like to use Arduino to control some external objects probably be better not to send EEG data (if you don't use ML) and you can try signal processing and feature extraction directly in Arduino and send already via wifi only control signal for external object
I will answer your post in the forum a little later, that you so much for your post.
Hi Alikhodrali, really nice to meet you and thank you for your detailed email.
To receive data via wi-fi I used this script for Windows
https://github.com/Ildaron/ardEEG/blob/main/software/python/1.Alpha_real_time.py
Does it make sense?
If you would like to use Arduino to control some external objects probably be better not to send EEG data (if you don't use ML) and you can try signal processing and feature extraction directly in Arduino and send already via wifi only control signal for external object
I will answer your post in the forum a little later, that you so much for your post.
Quote from alikhodrali on 07.08.2024, 06:03Hi there,
No problem!
I checked out your Python code for receiving and tried to convert it to arduino code as best as I could. I am now able to send a bunch of zero values to my bionic prosthetic arm. You are right that it would be better to do the processing directly on the Arduino. I have code below that works better to send data the way I want it over TCP. It is now based on your code for the Arduino and your Python code for Windows. The problem is that I'm still not sure how to manipulate the data before sending it. I tried, and so far, this is what I have in the code below, but I don't believe it works. I thought it did at one point because I was getting values between 0 and 255 but I couldn't reproduce it. In your arduino code, we send the "output" byte array over wifi in your Arduino code example, but how do we simply receive the values in variables such as "channel1" to "channel 8" or "leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4"? Could you help me modify my code to accomplish this? Or at least create code to do onboard processing on the Arduino?
Thanks!
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG true#define BRAIN_EEG_SERIAL_PLOTTER_DEBUG false// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_500HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;WiFiClient client;EMGFilters brainEEGFilter;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place the two clips on your ears.// Then think really hard and wait a few seconds for the signal to normalize.// Select the max value as the brainEEGFilterThreshold. Any value under brainEEGFilterThreshold will be set to zerostatic int brainEEGFilterThreshold = 0;int brainEEGSensorValue, brainEEGSensorValueFiltered, brainEEGSensorValueFilteredAmplified;unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;byte leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;// Constantsconst int data_length = 1350; // Example length, adjust according to your needsconst int sample_length = 50;float result[data_length] = {0};float data_before_1[50] = {0};float data_before_2[50] = {0};float data_before_3[50] = {0};float data_before_4[50] = {0};float data_before_5[50] = {0};float data_before_6[50] = {0};float data_before_7[50] = {0};float data_before_8[50] = {0};float channel1[50] = {0};float channel2[50] = {0};float channel3[50] = {0};float channel4[50] = {0};float channel5[50] = {0};float channel6[50] = {0};float channel7[50] = {0};float channel8[50] = {0};float channel9[50] = {0};uint32_t data_test = 0x7FFFFF;uint32_t data_check = 0xFFFFFF;uint32_t voltage_1 = 0;uint32_t convert_voltage = 0;uint32_t voltage_1_after_convert = 0;int channel_num = 0;int a = 30;int sampleCount = 0;//ADC//#define button_pin 7const int button_pin = 7;const int chip_select = 10; // Assuming SPI chip select pinint test_DRDY = 5;int button_state = 0;const int size_of_data = 1350; //864;byte output[size_of_data] = {};void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//ADCpinMode(button_pin, INPUT); //initialize the led pin as outputpinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilter.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arms Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == size_of_data) {int dataLength = sizeof(output) / sizeof(output[0]);// Create a new array to hold the individual bytesbyte dataList[dataLength];// Populate the new arrayfor (int i = 0; i < dataLength; i++) {dataList[i] = output[i];}}for (int c = 0; c < size_of_data; c += 27) {for (int a = 0; a < 26; a += 3) {voltage_1 = (output[a + c] << 8) | output[a + 1 + c];voltage_1 = (voltage_1 << 8) | output[a + 2 + c];convert_voltage = voltage_1 | data_test;if (convert_voltage == data_check) {voltage_1_after_convert = 16777214 - voltage_1;} else {voltage_1_after_convert = voltage_1;}channel_num = a / 3;result[channel_num] = roundToDecimal(1000000 * 4.5 * (voltage_1_after_convert / 16777215.0), 2);}channel1[c / 27] = result[1];channel2[c / 27] = result[2];channel3[c / 27] = result[3];channel4[c / 27] = result[4];channel5[c / 27] = result[5];channel6[c / 27] = result[6];channel7[c / 27] = result[7];channel8[c / 27] = result[8];if ((c / 27) == sample_length - 1) {// Plot values to Serial Plotterfor (int i = 0; i < sample_length; i++) {// Serial.print(channel1[i]);// Serial.print("\t");// Serial.print(channel2[i]);// Serial.print("\t");// Serial.print(channel3[i]);// Serial.print("\t");// Serial.print(channel4[i]);// Serial.print("\t");// Serial.print(channel5[i]);// Serial.print("\t");// Serial.print(channel6[i]);// Serial.print("\t");// Serial.print(channel7[i]);// Serial.print("\t");// Serial.print(channel8[i]);// Serial.println();leftFrontalLobeFP1 = channel1[i];rightFrontalLobeFP2 = channel2[i];leftMotorCortexC3 = channel3[i];rightMotorCortexC4 = channel4[i];leftOccipitalLobeO1 = channel5[i];rightOccipitalLobeO2 = channel6[i];leftTemporalLobeT3 = channel7[i];rightTemporalLobeT4 = channel8[i];if (BRAIN_EEG_DEBUG) {Serial.print("Size of Data: "); Serial.println(size_of_data);Serial.print("Left Ear: "); Serial.print(leftEar);Serial.print("\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);}// Make sure to set all other debugs to falseif (BRAIN_EEG_SERIAL_PLOTTER_DEBUG) {Serial.print(leftEar); Serial.print(" ");Serial.print(rightEar); Serial.print(" ");Serial.print(leftFrontalLobeFP1); Serial.print(" ");Serial.print(rightFrontalLobeFP2); Serial.print(" ");Serial.print(leftMotorCortexC3); Serial.print(" ");Serial.print(rightMotorCortexC4); Serial.print(" ");Serial.print(leftOccipitalLobeO1); Serial.print(" ");Serial.print(rightOccipitalLobeO2); Serial.print(" ");Serial.print(leftTemporalLobeT3); Serial.print(" ");Serial.print(rightTemporalLobeT4); Serial.print(" ");Serial.println();}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving from//client.print(leftEar); client.print(",");//client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();}// Reset arraysmemset(channel1, 0, sample_length * sizeof(float));memset(channel2, 0, sample_length * sizeof(float));memset(channel3, 0, sample_length * sizeof(float));memset(channel4, 0, sample_length * sizeof(float));memset(channel5, 0, sample_length * sizeof(float));memset(channel6, 0, sample_length * sizeof(float));memset(channel7, 0, sample_length * sizeof(float));memset(channel8, 0, sample_length * sizeof(float));//Serial.println("Data sent to Bionic Prosthetic Arm");sampleCount = 0; // Reset the index after sending data}}delay(20);}}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}// Function to round a float to a specified number of decimal placesfloat roundToDecimal(float value, int decimalPlaces) {float multiplier = pow(10.0, decimalPlaces);returnround(value * multiplier) / multiplier;}
Hi there,
No problem!
I checked out your Python code for receiving and tried to convert it to arduino code as best as I could. I am now able to send a bunch of zero values to my bionic prosthetic arm. You are right that it would be better to do the processing directly on the Arduino. I have code below that works better to send data the way I want it over TCP. It is now based on your code for the Arduino and your Python code for Windows. The problem is that I'm still not sure how to manipulate the data before sending it. I tried, and so far, this is what I have in the code below, but I don't believe it works. I thought it did at one point because I was getting values between 0 and 255 but I couldn't reproduce it. In your arduino code, we send the "output" byte array over wifi in your Arduino code example, but how do we simply receive the values in variables such as "channel1" to "channel 8" or "leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4"? Could you help me modify my code to accomplish this? Or at least create code to do onboard processing on the Arduino?
Thanks!
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG true#define BRAIN_EEG_SERIAL_PLOTTER_DEBUG false// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_500HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;WiFiClient client;EMGFilters brainEEGFilter;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place the two clips on your ears.// Then think really hard and wait a few seconds for the signal to normalize.// Select the max value as the brainEEGFilterThreshold. Any value under brainEEGFilterThreshold will be set to zerostatic int brainEEGFilterThreshold = 0;int brainEEGSensorValue, brainEEGSensorValueFiltered, brainEEGSensorValueFilteredAmplified;unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;byte leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;// Constantsconst int data_length = 1350; // Example length, adjust according to your needsconst int sample_length = 50;float result[data_length] = {0};float data_before_1[50] = {0};float data_before_2[50] = {0};float data_before_3[50] = {0};float data_before_4[50] = {0};float data_before_5[50] = {0};float data_before_6[50] = {0};float data_before_7[50] = {0};float data_before_8[50] = {0};float channel1[50] = {0};float channel2[50] = {0};float channel3[50] = {0};float channel4[50] = {0};float channel5[50] = {0};float channel6[50] = {0};float channel7[50] = {0};float channel8[50] = {0};float channel9[50] = {0};uint32_t data_test = 0x7FFFFF;uint32_t data_check = 0xFFFFFF;uint32_t voltage_1 = 0;uint32_t convert_voltage = 0;uint32_t voltage_1_after_convert = 0;int channel_num = 0;int a = 30;int sampleCount = 0;//ADC//#define button_pin 7const int button_pin = 7;const int chip_select = 10; // Assuming SPI chip select pinint test_DRDY = 5;int button_state = 0;const int size_of_data = 1350; //864;byte output[size_of_data] = {};void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//ADCpinMode(button_pin, INPUT); //initialize the led pin as outputpinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilter.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arms Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == size_of_data) {int dataLength = sizeof(output) / sizeof(output[0]);// Create a new array to hold the individual bytesbyte dataList[dataLength];// Populate the new arrayfor (int i = 0; i < dataLength; i++) {dataList[i] = output[i];}}for (int c = 0; c < size_of_data; c += 27) {for (int a = 0; a < 26; a += 3) {voltage_1 = (output[a + c] << 8) | output[a + 1 + c];voltage_1 = (voltage_1 << 8) | output[a + 2 + c];convert_voltage = voltage_1 | data_test;if (convert_voltage == data_check) {voltage_1_after_convert = 16777214 - voltage_1;} else {voltage_1_after_convert = voltage_1;}channel_num = a / 3;result[channel_num] = roundToDecimal(1000000 * 4.5 * (voltage_1_after_convert / 16777215.0), 2);}channel1[c / 27] = result[1];channel2[c / 27] = result[2];channel3[c / 27] = result[3];channel4[c / 27] = result[4];channel5[c / 27] = result[5];channel6[c / 27] = result[6];channel7[c / 27] = result[7];channel8[c / 27] = result[8];if ((c / 27) == sample_length - 1) {// Plot values to Serial Plotterfor (int i = 0; i < sample_length; i++) {// Serial.print(channel1[i]);// Serial.print("\t");// Serial.print(channel2[i]);// Serial.print("\t");// Serial.print(channel3[i]);// Serial.print("\t");// Serial.print(channel4[i]);// Serial.print("\t");// Serial.print(channel5[i]);// Serial.print("\t");// Serial.print(channel6[i]);// Serial.print("\t");// Serial.print(channel7[i]);// Serial.print("\t");// Serial.print(channel8[i]);// Serial.println();leftFrontalLobeFP1 = channel1[i];rightFrontalLobeFP2 = channel2[i];leftMotorCortexC3 = channel3[i];rightMotorCortexC4 = channel4[i];leftOccipitalLobeO1 = channel5[i];rightOccipitalLobeO2 = channel6[i];leftTemporalLobeT3 = channel7[i];rightTemporalLobeT4 = channel8[i];if (BRAIN_EEG_DEBUG) {Serial.print("Size of Data: "); Serial.println(size_of_data);Serial.print("Left Ear: "); Serial.print(leftEar);Serial.print("\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);}// Make sure to set all other debugs to falseif (BRAIN_EEG_SERIAL_PLOTTER_DEBUG) {Serial.print(leftEar); Serial.print(" ");Serial.print(rightEar); Serial.print(" ");Serial.print(leftFrontalLobeFP1); Serial.print(" ");Serial.print(rightFrontalLobeFP2); Serial.print(" ");Serial.print(leftMotorCortexC3); Serial.print(" ");Serial.print(rightMotorCortexC4); Serial.print(" ");Serial.print(leftOccipitalLobeO1); Serial.print(" ");Serial.print(rightOccipitalLobeO2); Serial.print(" ");Serial.print(leftTemporalLobeT3); Serial.print(" ");Serial.print(rightTemporalLobeT4); Serial.print(" ");Serial.println();}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving from//client.print(leftEar); client.print(",");//client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();}// Reset arraysmemset(channel1, 0, sample_length * sizeof(float));memset(channel2, 0, sample_length * sizeof(float));memset(channel3, 0, sample_length * sizeof(float));memset(channel4, 0, sample_length * sizeof(float));memset(channel5, 0, sample_length * sizeof(float));memset(channel6, 0, sample_length * sizeof(float));memset(channel7, 0, sample_length * sizeof(float));memset(channel8, 0, sample_length * sizeof(float));//Serial.println("Data sent to Bionic Prosthetic Arm");sampleCount = 0; // Reset the index after sending data}}delay(20);}}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}// Function to round a float to a specified number of decimal placesfloat roundToDecimal(float value, int decimalPlaces) {float multiplier = pow(10.0, decimalPlaces);returnround(value * multiplier) / multiplier;}
Quote from PiEEG on 07.08.2024, 12:13Hi Alikhodrali,
You said that you getting values between 0 and 255, which is a good sign, you need to know to convert this digital value to voltage.
for a in range (0,26,3):
voltage_1=(output[a+c]<<8)| output[a+1+c]
voltage_1=(voltage_1<<8)| output[a+2+c]
convert_voktage=voltage_1|data_testif convert_voktage==data_check:
voltage_1_after_convert=(16777214-voltage_1)
else:
voltage_1_after_convert=voltage_1let me shortly explain how it works
1. ADS1299 it is 8 channel 24 bits analog-digital converter2. It means for every channel we have 24 bits, so 3 bytes for one channel.
3. When we read the signal in ardEEG we convert the voltage to the digital value of 24 bits, but we count these values byte by byte
4. For one reading session ADS1299 reads 27 bytes, the first 3 bytes are status bytes, other 24 bytes it are 8 channels which we are sending from Arduino
5. Every channel has 3 bytes (1_bytes, 2_bytes, 3_bytes) so to convert them to voltage.
6. First you need to summarize them by shifting them to the left
Ch1 = 1_bytes << 2_bytes << 3_bytes ,
now you need to convert them to Voltagebut before that
need to make a test for a sign, ArdEEG has a bipolar voltage for ADC so it is means we should check the first bite of the reading data to understand if it is a negative measurement or positive
if Ch1 ==data_check:
Ch1 =(Ch1 -16777214)
else:
Ch1 =Ch1and finally convert data to microvolts
"""converts raw EEG data from a 24-bit ADC (ranging from 0 to 16777215) into microvolts by normalizing the data,scaling it to a 4.5V reference voltage, and converting to microvolts,then rounding to two decimal places. This transformation is necessary for accurately interpreting EEG signals, which are typically measured in microvolts"""eeg_data = round(1000000*4.5*(Ch1 /16777216),2) # 2 to the power of 24 = 16777216in Arduino ADS1299 you can find more details about that from TI datasheet
Do you send data from Arduino to Arduino ? in my example I just send data to a laptop via wi-fi and with Python it is much easier to make manipulation with data
Hi Alikhodrali,
You said that you getting values between 0 and 255, which is a good sign, you need to know to convert this digital value to voltage.
for a in range (0,26,3):
voltage_1=(output[a+c]<<8)| output[a+1+c]
voltage_1=(voltage_1<<8)| output[a+2+c]
convert_voktage=voltage_1|data_testif convert_voktage==data_check:
voltage_1_after_convert=(16777214-voltage_1)
else:
voltage_1_after_convert=voltage_1
let me shortly explain how it works
1. ADS1299 it is 8 channel 24 bits analog-digital converter
2. It means for every channel we have 24 bits, so 3 bytes for one channel.
3. When we read the signal in ardEEG we convert the voltage to the digital value of 24 bits, but we count these values byte by byte
4. For one reading session ADS1299 reads 27 bytes, the first 3 bytes are status bytes, other 24 bytes it are 8 channels which we are sending from Arduino
5. Every channel has 3 bytes (1_bytes, 2_bytes, 3_bytes) so to convert them to voltage.
6. First you need to summarize them by shifting them to the left
Ch1 = 1_bytes << 2_bytes << 3_bytes ,
now you need to convert them to Voltage
but before that
need to make a test for a sign, ArdEEG has a bipolar voltage for ADC so it is means we should check the first bite of the reading data to understand if it is a negative measurement or positive
if Ch1 ==data_check:
Ch1 =(Ch1 -16777214)
else:
Ch1 =Ch1
and finally convert data to microvolts
"""converts raw EEG data from a 24-bit ADC (ranging from 0 to 16777215) into microvolts by normalizing the data,scaling it to a 4.5V reference voltage, and converting to microvolts,then rounding to two decimal places. This transformation is necessary for accurately interpreting EEG signals, which are typically measured in microvolts"""eeg_data = round(1000000*4.5*(Ch1 /16777216),2) # 2 to the power of 24 = 16777216
in Arduino ADS1299 you can find more details about that from TI datasheet
Do you send data from Arduino to Arduino ? in my example I just send data to a laptop via wi-fi and with Python it is much easier to make manipulation with data
Quote from alikhodrali on 07.08.2024, 16:12Hi,
Thank you so much for your help in explaining the code. I only need you to explain the following lines of code:
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1I'm not sure what data_after_1 is? Is it also an array? What about dataset_1 and data_before1? If they are arrays, then what size are they? Do they change size in the for loop?
Finally, I got the code working to output the values for all 8 channels on the Arduino Serial Plotter on my receiving end. I even ran through the EEG channels through an EMG filter. The problem is that there are random spikes occasionally even with the headcap not on my head. Is this normal behaviour? Here's a link to a video showing you what I mean: video.
The only thing I have left to do now is to finish programming the highpass and lowpass Butterworth filters, but I've been working non-stop on this all day and night, so I need some rest first. Here's my current code below:
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#include <vector>#include <cmath>#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG false#define BRAIN_EEG_SERIAL_PLOTTER_DEBUG false#define BRAIN_EEG_FILTER_ADVANCED true// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_1000HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;IPAddress localIP(192, 168, 1, 184);IPAddress gateway(192, 168, 1, 1);IPAddress subnet(255, 255, 255, 0);// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place the two clips on your ears.// Then think really hard and wait a few seconds for the signal to normalize.// Select the max value as the brainEEGFilterThreshold. Any value under brainEEGFilterThreshold will be set to zerostatic int brainEEGFilterThresholdChannel1 = 0;static int brainEEGFilterThresholdChannel2 = 0;static int brainEEGFilterThresholdChannel3 = 0;static int brainEEGFilterThresholdChannel4 = 0;static int brainEEGFilterThresholdChannel5 = 0;static int brainEEGFilterThresholdChannel6 = 0;static int brainEEGFilterThresholdChannel7 = 0;static int brainEEGFilterThresholdChannel8 = 0;long brainEEGSensorValueChannel1, brainEEGSensorValueFilteredChannel1, brainEEGSensorValueFilteredAmplifiedChannel1;long brainEEGSensorValueChannel2, brainEEGSensorValueFilteredChannel2, brainEEGSensorValueFilteredAmplifiedChannel2;long brainEEGSensorValueChannel3, brainEEGSensorValueFilteredChannel3, brainEEGSensorValueFilteredAmplifiedChannel3;long brainEEGSensorValueChannel4, brainEEGSensorValueFilteredChannel4, brainEEGSensorValueFilteredAmplifiedChannel4;long brainEEGSensorValueChannel5, brainEEGSensorValueFilteredChannel5, brainEEGSensorValueFilteredAmplifiedChannel5;long brainEEGSensorValueChannel6, brainEEGSensorValueFilteredChannel6, brainEEGSensorValueFilteredAmplifiedChannel6;long brainEEGSensorValueChannel7, brainEEGSensorValueFilteredChannel7, brainEEGSensorValueFilteredAmplifiedChannel7;long brainEEGSensorValueChannel8, brainEEGSensorValueFilteredChannel8, brainEEGSensorValueFilteredAmplifiedChannel8;float dataButterHighpassFilterChannel1[50] = {0};float dataButterHighpassFilterChannel2[50] = {0};float dataButterHighpassFilterChannel3[50] = {0};float dataButterHighpassFilterChannel4[50] = {0};float dataButterHighpassFilterChannel5[50] = {0};float dataButterHighpassFilterChannel6[50] = {0};float dataButterHighpassFilterChannel7[50] = {0};float dataButterHighpassFilterChannel8[50] = {0};float dataButterHighpassLowpassFilterChannel1[50] = {0};float dataButterHighpassLowpassFilterChannel2[50] = {0};float dataButterHighpassLowpassFilterChannel3[50] = {0};float dataButterHighpassLowpassFilterChannel4[50] = {0};float dataButterHighpassLowpassFilterChannel5[50] = {0};float dataButterHighpassLowpassFilterChannel6[50] = {0};float dataButterHighpassLowpassFilterChannel7[50] = {0};float dataButterHighpassLowpassFilterChannel8[50] = {0};unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;const int samplingFrequency = 250; // Hzconst double highpassCutoffFrequency = 8; // Cut-off frequency (-3 dB) (Hz)const double lowpassCutoffFrequency = 12; // Cut-off frequency (-3 dB) (Hz)const double normalizedHighpassCutoffFrequency = 2 * highpassCutoffFrequency / samplingFrequency; // Normalized cut-off frequency (Hz)const double normalizedLowpassCutoffFrequency = 2 * lowpassCutoffFrequency / samplingFrequency; // Normalized cut-off frequency (Hz)long leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;// Constantsconst int chip_select = 10; // Assuming SPI chip select pinconst int numberOfChannels = 8; // Number of EEG Channels being readconst int bytesPerSample = 3; // Number of bytes per sample for each channelconst int samplesPerRead = 27; // Number of bytes read in each cycleconst int sampleSize = samplesPerRead / bytesPerSample; // Number of samples read per cycleconst int dataLength = 1350; //864const int sampleLength = 50;byte output[dataLength] = {}; // Array to store raw SPI datalong channelData[numberOfChannels][sampleSize]; // 2D array to store decoded data for each channellong result[dataLength] = {0};float dataBefore1[sampleLength] = {0};float dataBefore2[sampleLength] = {0};float dataBefore3[sampleLength] = {0};float dataBefore4[sampleLength] = {0};float dataBefore5[sampleLength] = {0};float dataBefore6[sampleLength] = {0};float dataBefore7[sampleLength] = {0};float dataBefore8[sampleLength] = {0};float dataAfter1[sampleLength] = {0};float dataAfter2[sampleLength] = {0};float dataAfter3[sampleLength] = {0};float dataAfter4[sampleLength] = {0};float dataAfter5[sampleLength] = {0};float dataAfter6[sampleLength] = {0};float dataAfter7[sampleLength] = {0};float dataAfter8[sampleLength] = {0};float datasetChannel1[sampleLength] = {0};float datasetChannel2[sampleLength] = {0};float datasetChannel3[sampleLength] = {0};float datasetChannel4[sampleLength] = {0};float datasetChannel5[sampleLength] = {0};float datasetChannel6[sampleLength] = {0};float datasetChannel7[sampleLength] = {0};float datasetChannel8[sampleLength] = {0};float datasetChannel9[sampleLength] = {0};// std::vector<byte> channel1;// std::vector<byte> channel2;// std::vector<byte> channel3;// std::vector<byte> channel4;// std::vector<byte> channel5;// std::vector<byte> channel6;// std::vector<byte> channel7;// std::vector<byte> channel8;long channel1[sampleLength] = {0};long channel2[sampleLength] = {0};long channel3[sampleLength] = {0};long channel4[sampleLength] = {0};long channel5[sampleLength] = {0};long channel6[sampleLength] = {0};long channel7[sampleLength] = {0};long channel8[sampleLength] = {0};uint32_t dataTest = 0x7FFFFF;uint32_t dataCheck = 0xFFFFFF;uint32_t voltage = 0;long voltageToBeConverted = 0;long voltageConverted = 0;long voltageConvertedScaledNormalized = 0;int channelNumber = 0;int a = 30;int sampleCount = 0;WiFiClient client;EMGFilters brainEEGFilterChannel1;EMGFilters brainEEGFilterChannel2;EMGFilters brainEEGFilterChannel3;EMGFilters brainEEGFilterChannel4;EMGFilters brainEEGFilterChannel5;EMGFilters brainEEGFilterChannel6;EMGFilters brainEEGFilterChannel7;EMGFilters brainEEGFilterChannel8;struct ButterworthFilter {floata[3];floatb[3];floatx[3];floaty[3];};ButterworthFilter butterHighpass[8];ButterworthFilter butterLowpass[8];void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);pinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//WiFi.config(localIP, gateway, subnet);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilterChannel1.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel2.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel3.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel4.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel5.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel6.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel7.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel8.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arm Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {//Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == dataLength) {Serial.println("sampleCount == dataLength");for (int c = 0; c < dataLength; c += 27) {for (int a = 0; a < 26; a += 3) {voltage = (output[a + c] << 8) | output[a + 1 + c];voltage = (voltage << 8) | output[a + 2 + c];voltageToBeConverted = voltage | dataTest;if (voltageToBeConverted == dataCheck) {voltageConverted = 16777214 - voltage;} else {voltageConverted = voltage;}// Serial.print("Voltage: "); Serial.println(voltageConverted);voltageConvertedScaledNormalized = round(1000000 * 4.5 * (voltageConverted / 16777215.0) * 100) / 100;//Serial.print("Voltage (Scaled & Normalized): "); Serial.println(voltageConvertedScaledNormalized);channelNumber = a / 3;result[channelNumber] = voltageConvertedScaledNormalized;}int indexVal = c / 27;//Serial.print("c / 27 = "); Serial.println(indexVal);channel1[c / 27] = result[1];channel2[c / 27] = result[2];channel3[c / 27] = result[3];channel4[c / 27] = result[4];channel5[c / 27] = result[5];channel6[c / 27] = result[6];channel7[c / 27] = result[7];channel8[c / 27] = result[8];if ((c / 27) == sampleLength - 1) {// Plot values to Serial Plotterfor (int i = 0; i < sampleLength; i++) {if (BRAIN_EEG_FILTER_ADVANCED) {// Getting Brain Electroencephalography EEG Sensor ValuesbrainEEGSensorValueChannel1 = channel1[i];brainEEGSensorValueChannel2 = channel2[i];brainEEGSensorValueChannel3 = channel3[i];brainEEGSensorValueChannel4 = channel4[i];brainEEGSensorValueChannel5 = channel5[i];brainEEGSensorValueChannel6 = channel6[i];brainEEGSensorValueChannel7 = channel7[i];brainEEGSensorValueChannel8 = channel8[i];// Brain Electroencephalography EEG filter processing /////////////////////////////////brainEEGSensorValueFilteredChannel1 = brainEEGFilterChannel1.update(brainEEGSensorValueChannel1);brainEEGSensorValueFilteredChannel2 = brainEEGFilterChannel2.update(brainEEGSensorValueChannel2);brainEEGSensorValueFilteredChannel3 = brainEEGFilterChannel3.update(brainEEGSensorValueChannel3);brainEEGSensorValueFilteredChannel4 = brainEEGFilterChannel4.update(brainEEGSensorValueChannel4);brainEEGSensorValueFilteredChannel5 = brainEEGFilterChannel5.update(brainEEGSensorValueChannel5);brainEEGSensorValueFilteredChannel6 = brainEEGFilterChannel6.update(brainEEGSensorValueChannel6);brainEEGSensorValueFilteredChannel7 = brainEEGFilterChannel7.update(brainEEGSensorValueChannel7);brainEEGSensorValueFilteredChannel8 = brainEEGFilterChannel8.update(brainEEGSensorValueChannel8);// Square the EEG Filter ValuesbrainEEGSensorValueFilteredAmplifiedChannel1 = (brainEEGSensorValueFilteredChannel1);brainEEGSensorValueFilteredAmplifiedChannel2 = (brainEEGSensorValueFilteredChannel2);brainEEGSensorValueFilteredAmplifiedChannel3 = (brainEEGSensorValueFilteredChannel3);brainEEGSensorValueFilteredAmplifiedChannel4 = (brainEEGSensorValueFilteredChannel4);brainEEGSensorValueFilteredAmplifiedChannel5 = (brainEEGSensorValueFilteredChannel5);brainEEGSensorValueFilteredAmplifiedChannel6 = (brainEEGSensorValueFilteredChannel6);brainEEGSensorValueFilteredAmplifiedChannel7 = (brainEEGSensorValueFilteredChannel7);brainEEGSensorValueFilteredAmplifiedChannel8 = (brainEEGSensorValueFilteredChannel8);// Any value under brainEEGFilterThreshold will be set to zerobrainEEGSensorValueFilteredAmplifiedChannel1 = (brainEEGSensorValueFilteredAmplifiedChannel1 > brainEEGFilterThresholdChannel1) ? brainEEGSensorValueFilteredAmplifiedChannel1 : 0;brainEEGSensorValueFilteredAmplifiedChannel2 = (brainEEGSensorValueFilteredAmplifiedChannel2 > brainEEGFilterThresholdChannel2) ? brainEEGSensorValueFilteredAmplifiedChannel2 : 0;brainEEGSensorValueFilteredAmplifiedChannel3 = (brainEEGSensorValueFilteredAmplifiedChannel3 > brainEEGFilterThresholdChannel3) ? brainEEGSensorValueFilteredAmplifiedChannel3 : 0;brainEEGSensorValueFilteredAmplifiedChannel4 = (brainEEGSensorValueFilteredAmplifiedChannel4 > brainEEGFilterThresholdChannel4) ? brainEEGSensorValueFilteredAmplifiedChannel4 : 0;brainEEGSensorValueFilteredAmplifiedChannel5 = (brainEEGSensorValueFilteredAmplifiedChannel5 > brainEEGFilterThresholdChannel5) ? brainEEGSensorValueFilteredAmplifiedChannel5 : 0;brainEEGSensorValueFilteredAmplifiedChannel6 = (brainEEGSensorValueFilteredAmplifiedChannel6 > brainEEGFilterThresholdChannel6) ? brainEEGSensorValueFilteredAmplifiedChannel6 : 0;brainEEGSensorValueFilteredAmplifiedChannel7 = (brainEEGSensorValueFilteredAmplifiedChannel7 > brainEEGFilterThresholdChannel7) ? brainEEGSensorValueFilteredAmplifiedChannel7 : 0;brainEEGSensorValueFilteredAmplifiedChannel8 = (brainEEGSensorValueFilteredAmplifiedChannel8 > brainEEGFilterThresholdChannel8) ? brainEEGSensorValueFilteredAmplifiedChannel8 : 0;leftFrontalLobeFP1 = brainEEGSensorValueFilteredAmplifiedChannel1;rightFrontalLobeFP2 = brainEEGSensorValueFilteredAmplifiedChannel2;leftMotorCortexC3 = brainEEGSensorValueFilteredAmplifiedChannel3;rightMotorCortexC4 = brainEEGSensorValueFilteredAmplifiedChannel4;leftOccipitalLobeO1 = brainEEGSensorValueFilteredAmplifiedChannel5;rightOccipitalLobeO2 = brainEEGSensorValueFilteredAmplifiedChannel6;leftTemporalLobeT3 = brainEEGSensorValueFilteredAmplifiedChannel7;rightTemporalLobeT4 = brainEEGSensorValueFilteredAmplifiedChannel8;} else {leftFrontalLobeFP1 = channel1[i];rightFrontalLobeFP2 = channel2[i];leftMotorCortexC3 = channel3[i];rightMotorCortexC4 = channel4[i];leftOccipitalLobeO1 = channel5[i];rightOccipitalLobeO2 = channel6[i];leftTemporalLobeT3 = channel7[i];rightTemporalLobeT4 = channel8[i];//////////////////////////////////////////////////////////////////// dataAfter1[i] = channel1[i];// datasetChannel1[i] = dataBefore1[i] + dataBefore1[i] + dataBefore1[i] + dataAfter1[i];// dataBefore1[i] = dataAfter1[i];// dataButterHighpassFilterChannel1[i] = butterHighpassFilter(datasetChannel1[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel1[i] = butterLowpassFilter(datasetChannel1[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter2[i] = channel2[i];// datasetChannel2[i] = dataBefore2[i] + dataBefore2[i] + dataBefore2[i] + dataAfter2[i];// dataBefore2[i] = dataAfter2[i];// dataButterHighpassFilterChannel2[i] = butterHighpassFilter(datasetChannel2[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel2[i] = butterLowpassFilter(datasetChannel2[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter3[i] = channel3[i];// datasetChannel3[i] = dataBefore3[i] + dataBefore3[i] + dataBefore3[i] + dataAfter3[i];// dataBefore3[i] = dataAfter3[i];// dataButterHighpassFilterChannel3[i] = butterHighpassFilter(datasetChannel3[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel3[i] = butterLowpassFilter(datasetChannel3[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter4[i] = channel4[i];// datasetChannel4[i] = dataBefore4[i] + dataBefore4[i] + dataBefore4[i] + dataAfter4[i];// dataBefore4[i] = dataAfter4[i];// dataButterHighpassFilterChannel4[i] = butterHighpassFilter(datasetChannel4[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel4[i] = butterLowpassFilter(datasetChannel4[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter5[i] = channel5[i];// datasetChannel5[i] = dataBefore5[i] + dataBefore5[i] + dataBefore5[i] + dataAfter5[i];// dataBefore5[i] = dataAfter5[i];// dataButterHighpassFilterChannel5[i] = butterHighpassFilter(datasetChannel5[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel5[i] = butterLowpassFilter(datasetChannel5[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter6[i] = channel6[i];// datasetChannel6[i] = dataBefore6[i] + dataBefore6[i] + dataBefore6[i] + dataAfter6[i];// dataBefore6[i] = dataAfter6[i];// dataButterHighpassFilterChannel6[i] = butterHighpassFilter(datasetChannel6[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel6[i] = ButterLowpassFilter(datasetChannel6[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter7[i] = channel7[i];// datasetChannel7[i] = dataBefore7[i] + dataBefore7[i] + dataBefore7[i] + dataAfter7[i];// dataBefore7[i] = dataAfter7[i];// dataButterHighpassFilterChannel7[i] = butterHighpassFilter(datasetChannel7[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel7[i] = butterLowpassFilter(datasetChannel7[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter8[i] = channel8[i];// datasetChannel8[i] = dataBefore8[i] + dataBefore8[i] + dataBefore8[i] + dataAfter8[i];// dataBefore8[i] = dataAfter8[i];// dataButterHighpassFilterChannel8[i] = butterHighpassFilter(datasetChannel8[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel8[i] = butterLowpassFilter(datasetChannel8[i], lowpassCutoffFrequency, samplingFrequency);// leftFrontalLobeFP1 = dataButterHighpassLowpassFilterChannel1[i];// rightFrontalLobeFP2 = dataButterHighpassLowpassFilterChannel2[i];// leftMotorCortexC3 = dataButterHighpassLowpassFilterChannel3[i];// rightMotorCortexC4 = dataButterHighpassLowpassFilterChannel4[i];// leftOccipitalLobeO1 = dataButterHighpassLowpassFilterChannel5[i];// rightOccipitalLobeO2 = dataButterHighpassLowpassFilterChannel6[i];// leftTemporalLobeT3 = dataButterHighpassLowpassFilterChannel7[i];// rightTemporalLobeT4 = dataButterHighpassLowpassFilterChannel8[i];}//////////////////////////////////////////////////////////////////////if (BRAIN_EEG_DEBUG) {// Serial.print("Size of Data: "); Serial.println(dataLength);// Serial.print("Left Ear: "); Serial.print(leftEar);// Serial.print("\t\t\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);Serial.print("\n");}if (BRAIN_EEG_SERIAL_PLOTTER_DEBUG) {// Serial.print(leftEar); Serial.print(" ");// Serial.print(rightEar); Serial.print(" ");Serial.print(leftFrontalLobeFP1); Serial.print(" ");Serial.print(rightFrontalLobeFP2); Serial.print(" ");Serial.print(leftMotorCortexC3); Serial.print(" ");Serial.print(rightMotorCortexC4); Serial.print(" ");Serial.print(leftOccipitalLobeO1); Serial.print(" ");Serial.print(rightOccipitalLobeO2); Serial.print(" ");Serial.print(leftTemporalLobeT3); Serial.print(" ");Serial.print(rightTemporalLobeT4); Serial.print(" ");Serial.println();}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving from//client.print(leftEar); client.print(",");//client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();// Brain Electroencephalography EEG Filter Timing Debug// If time cost of the loop is less than brainEEGFilterTimeBudget, then you still have (brainEEGFilterTimeBudget - brainEEGFilterTimeStamp) for code execution.// If time cost of the loop more than brainEEGFilterTimeBudget, then the sample rate needs to be reduced to SAMPLE_FREQ_500HZbrainEEGFilterTimeStamp = micros() - brainEEGFilterTimeStamp;brainEEGFilterTimeLeft = brainEEGFilterTimeBudget - brainEEGFilterTimeStamp;if (BRAIN_EEG_FILTER_DEBUG) {Serial.print("Brain Electroencephalography EEG Filters Time Cost: "); Serial.println(brainEEGFilterTimeStamp); // The filter costs an average of around 520 usSerial.print("Time Left from EEG Filter Time Budget: "); Serial.println(brainEEGFilterTimeLeft);Serial.print("\n");} else {//Serial.print("\n\n");}}}}sampleCount = 0; // Reset the index after sending data}}delay(40);}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}// Function to round a float to a specified number of decimal placesfloat roundToDecimal(float value, int decimalPlaces) {float multiplier = pow(10.0, decimalPlaces);returnround(value * multiplier) / multiplier;}void initButterworthFilters() {for (int i = 0; i < 8; i++) {// Initialize highpass filter coefficientsbutterHighpass[i].a[0] = 1.0;butterHighpass[i].a[1] = -1.995856;butterHighpass[i].a[2] = 0.9960625;butterHighpass[i].b[0] = 0.99803125;butterHighpass[i].b[1] = -1.9960625;butterHighpass[i].b[2] = 0.99803125;// Initialize lowpass filter coefficientsbutterLowpass[i].a[0] = 1.0;butterLowpass[i].a[1] = -1.5610180758;butterLowpass[i].a[2] = 0.6413515381;butterLowpass[i].b[0] = 0.0200833656;butterLowpass[i].b[1] = 0.0401667312;butterLowpass[i].b[2] = 0.0200833656;// Initialize filter statesfor (int j = 0; j < 3; j++) {butterHighpass[i].x[j] = 0.0;butterHighpass[i].y[j] = 0.0;butterLowpass[i].x[j] = 0.0;butterLowpass[i].y[j] = 0.0;}}}float butterHighpassFilter(ButterworthFilter* filter, float input) {// Shift old samplesfilter->x[2] = filter->x[1];filter->x[1] = filter->x[0];filter->x[0] = input;filter->y[2] = filter->y[1];filter->y[1] = filter->y[0];// Calculate new outputfilter->y[0] = (filter->b[0] * filter->x[0] + filter->b[1] * filter->x[1] + filter->b[2] * filter->x[2]- filter->a[1] * filter->y[1] - filter->a[2] * filter->y[2]) / filter->a[0];returnfilter->y[0];}float butterLowpassFilter(ButterworthFilter* filter, float input) {// Shift old samplesfilter->x[2] = filter->x[1];filter->x[1] = filter->x[0];filter->x[0] = input;filter->y[2] = filter->y[1];filter->y[1] = filter->y[0];// Calculate new outputfilter->y[0] = (filter->b[0] * filter->x[0] + filter->b[1] * filter->x[1] + filter->b[2] * filter->x[2]- filter->a[1] * filter->y[1] - filter->a[2] * filter->y[2]) / filter->a[0];returnfilter->y[0];}
Hi,
Thank you so much for your help in explaining the code. I only need you to explain the following lines of code:
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1
I'm not sure what data_after_1 is? Is it also an array? What about dataset_1 and data_before1? If they are arrays, then what size are they? Do they change size in the for loop?
Finally, I got the code working to output the values for all 8 channels on the Arduino Serial Plotter on my receiving end. I even ran through the EEG channels through an EMG filter. The problem is that there are random spikes occasionally even with the headcap not on my head. Is this normal behaviour? Here's a link to a video showing you what I mean: video.
The only thing I have left to do now is to finish programming the highpass and lowpass Butterworth filters, but I've been working non-stop on this all day and night, so I need some rest first. Here's my current code below:
#include <WiFiS3.h>#include <WiFiClient.h>#include <Arduino.h>#include <SPI.h>#include "EMGFilters.h"#include <vector>#include <cmath>#define BRAIN_EEG_DEBUG true#define BRAIN_EEG_FILTER_DEBUG false#define BRAIN_EEG_SERIAL_PLOTTER_DEBUG false#define BRAIN_EEG_FILTER_ADVANCED true// Discrete filters must work with fixed sample frequency// EMG filter only supports "SAMPLE_FREQ_500HZ" or "SAMPLE_FREQ_1000HZ". Other EMGFilterSampleRate inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_SAMPLE_RATE SAMPLE_FREQ_1000HZconst int brainEEGFilterSampleRate = 500;// For countries where power transmission is at 50 Hz, change to "NOTCH_FREQ_50HZ"// EMG filter only supports 50Hz and 60Hz input. Other inputs will bypass the EMG_FILTER#define BRAIN_EEG_FILTER_HUM_FREQUENCY NOTCH_FREQ_60HZ // For countries where power transmission is at 60 Hzconst int brainEEGFilterHumFrequency = 60;char* ssid = "BIONIC_PROSTHETIC_ARM";char* password = "RoboticsIsCool123";const char* serverIP = "192.168.4.1";const uint16_t serverPort = 80;IPAddress localIP(192, 168, 1, 184);IPAddress gateway(192, 168, 1, 1);IPAddress subnet(255, 255, 255, 0);// Self-signed certificate for testing (replace with valid certificate for production)const char* server_cert = R"EOF(-----BEGIN CERTIFICATE-----MIIC+TCCAeGgAwIBAgIJALIVf0/ZUHq9MA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTAeFw0yMTAxMDEwMDAwMDBaFw0yMjAxMDEwMDAwMDBaMCMxITAfBgNVBAMTGG15ZXhhbXBsZS5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDXN7dtF0lqTIgkS82ZkziKZ1X1Rq2c3BXzJZZDHj3OUqNq7bRH07S1+1cMB/N0+4iUdsiC7M8/j5sVWiZ/XJmZAgMBAAGjUDBOMB0GA1UdDgQWBBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAfBgNVHSMEGDAWgBTkKk1Z5R5z/1YB0Q0OlxAHdP3R8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAIBbMaXZcAigb0xe5F/I0idQ6XitP/QFmQoyNf8K0/rOB3Lt3uukWbT8xFZ+6BUpEctGGpD7HBsD8fv/JfO8PQf1K2w==-----END CERTIFICATE-----)EOF";// Brain EEG Sensor Headcap and Electroencephalography EEG Filter Variables ///////////////////////////////////////// Calibration:// Put on the EEG headcap.// Place the two clips on your ears.// Then think really hard and wait a few seconds for the signal to normalize.// Select the max value as the brainEEGFilterThreshold. Any value under brainEEGFilterThreshold will be set to zerostatic int brainEEGFilterThresholdChannel1 = 0;static int brainEEGFilterThresholdChannel2 = 0;static int brainEEGFilterThresholdChannel3 = 0;static int brainEEGFilterThresholdChannel4 = 0;static int brainEEGFilterThresholdChannel5 = 0;static int brainEEGFilterThresholdChannel6 = 0;static int brainEEGFilterThresholdChannel7 = 0;static int brainEEGFilterThresholdChannel8 = 0;long brainEEGSensorValueChannel1, brainEEGSensorValueFilteredChannel1, brainEEGSensorValueFilteredAmplifiedChannel1;long brainEEGSensorValueChannel2, brainEEGSensorValueFilteredChannel2, brainEEGSensorValueFilteredAmplifiedChannel2;long brainEEGSensorValueChannel3, brainEEGSensorValueFilteredChannel3, brainEEGSensorValueFilteredAmplifiedChannel3;long brainEEGSensorValueChannel4, brainEEGSensorValueFilteredChannel4, brainEEGSensorValueFilteredAmplifiedChannel4;long brainEEGSensorValueChannel5, brainEEGSensorValueFilteredChannel5, brainEEGSensorValueFilteredAmplifiedChannel5;long brainEEGSensorValueChannel6, brainEEGSensorValueFilteredChannel6, brainEEGSensorValueFilteredAmplifiedChannel6;long brainEEGSensorValueChannel7, brainEEGSensorValueFilteredChannel7, brainEEGSensorValueFilteredAmplifiedChannel7;long brainEEGSensorValueChannel8, brainEEGSensorValueFilteredChannel8, brainEEGSensorValueFilteredAmplifiedChannel8;float dataButterHighpassFilterChannel1[50] = {0};float dataButterHighpassFilterChannel2[50] = {0};float dataButterHighpassFilterChannel3[50] = {0};float dataButterHighpassFilterChannel4[50] = {0};float dataButterHighpassFilterChannel5[50] = {0};float dataButterHighpassFilterChannel6[50] = {0};float dataButterHighpassFilterChannel7[50] = {0};float dataButterHighpassFilterChannel8[50] = {0};float dataButterHighpassLowpassFilterChannel1[50] = {0};float dataButterHighpassLowpassFilterChannel2[50] = {0};float dataButterHighpassLowpassFilterChannel3[50] = {0};float dataButterHighpassLowpassFilterChannel4[50] = {0};float dataButterHighpassLowpassFilterChannel5[50] = {0};float dataButterHighpassLowpassFilterChannel6[50] = {0};float dataButterHighpassLowpassFilterChannel7[50] = {0};float dataButterHighpassLowpassFilterChannel8[50] = {0};unsigned long brainEEGFilterTimeStamp;unsigned long brainEEGFilterTimeBudget;unsigned long brainEEGFilterTimeLeft;const int samplingFrequency = 250; // Hzconst double highpassCutoffFrequency = 8; // Cut-off frequency (-3 dB) (Hz)const double lowpassCutoffFrequency = 12; // Cut-off frequency (-3 dB) (Hz)const double normalizedHighpassCutoffFrequency = 2 * highpassCutoffFrequency / samplingFrequency; // Normalized cut-off frequency (Hz)const double normalizedLowpassCutoffFrequency = 2 * lowpassCutoffFrequency / samplingFrequency; // Normalized cut-off frequency (Hz)long leftEar, rightEar, leftFrontalLobeFP1, rightFrontalLobeFP2, leftMotorCortexC3, rightMotorCortexC4, leftOccipitalLobeO1, rightOccipitalLobeO2, leftTemporalLobeT3, rightTemporalLobeT4;// Constantsconst int chip_select = 10; // Assuming SPI chip select pinconst int numberOfChannels = 8; // Number of EEG Channels being readconst int bytesPerSample = 3; // Number of bytes per sample for each channelconst int samplesPerRead = 27; // Number of bytes read in each cycleconst int sampleSize = samplesPerRead / bytesPerSample; // Number of samples read per cycleconst int dataLength = 1350; //864const int sampleLength = 50;byte output[dataLength] = {}; // Array to store raw SPI datalong channelData[numberOfChannels][sampleSize]; // 2D array to store decoded data for each channellong result[dataLength] = {0};float dataBefore1[sampleLength] = {0};float dataBefore2[sampleLength] = {0};float dataBefore3[sampleLength] = {0};float dataBefore4[sampleLength] = {0};float dataBefore5[sampleLength] = {0};float dataBefore6[sampleLength] = {0};float dataBefore7[sampleLength] = {0};float dataBefore8[sampleLength] = {0};float dataAfter1[sampleLength] = {0};float dataAfter2[sampleLength] = {0};float dataAfter3[sampleLength] = {0};float dataAfter4[sampleLength] = {0};float dataAfter5[sampleLength] = {0};float dataAfter6[sampleLength] = {0};float dataAfter7[sampleLength] = {0};float dataAfter8[sampleLength] = {0};float datasetChannel1[sampleLength] = {0};float datasetChannel2[sampleLength] = {0};float datasetChannel3[sampleLength] = {0};float datasetChannel4[sampleLength] = {0};float datasetChannel5[sampleLength] = {0};float datasetChannel6[sampleLength] = {0};float datasetChannel7[sampleLength] = {0};float datasetChannel8[sampleLength] = {0};float datasetChannel9[sampleLength] = {0};// std::vector<byte> channel1;// std::vector<byte> channel2;// std::vector<byte> channel3;// std::vector<byte> channel4;// std::vector<byte> channel5;// std::vector<byte> channel6;// std::vector<byte> channel7;// std::vector<byte> channel8;long channel1[sampleLength] = {0};long channel2[sampleLength] = {0};long channel3[sampleLength] = {0};long channel4[sampleLength] = {0};long channel5[sampleLength] = {0};long channel6[sampleLength] = {0};long channel7[sampleLength] = {0};long channel8[sampleLength] = {0};uint32_t dataTest = 0x7FFFFF;uint32_t dataCheck = 0xFFFFFF;uint32_t voltage = 0;long voltageToBeConverted = 0;long voltageConverted = 0;long voltageConvertedScaledNormalized = 0;int channelNumber = 0;int a = 30;int sampleCount = 0;WiFiClient client;EMGFilters brainEEGFilterChannel1;EMGFilters brainEEGFilterChannel2;EMGFilters brainEEGFilterChannel3;EMGFilters brainEEGFilterChannel4;EMGFilters brainEEGFilterChannel5;EMGFilters brainEEGFilterChannel6;EMGFilters brainEEGFilterChannel7;EMGFilters brainEEGFilterChannel8;struct ButterworthFilter {floata[3];floatb[3];floatx[3];floaty[3];};ButterworthFilter butterHighpass[8];ButterworthFilter butterLowpass[8];void setup() {// Wire.begin(SDA_PIN, SCL_PIN);// Wire.setClock(500000); // 400kHz I2C clock. Comment this line if having compilation difficulties\Serial.begin(115200);pinMode(chip_select, OUTPUT);digitalWrite(chip_select, LOW);SPI.begin();SPI.beginTransaction(SPISettings(600000, MSBFIRST, SPI_MODE1));sendCommand(0x02); // wakeupsendCommand(0x0A); // stopsendCommand(0x06); // resetsendCommand(0x11); // sdatac// Write configurationswriteByte(0x01, 0x96);writeByte(0x02, 0xD4);writeByte(0x03, 0xFF);writeByte(0x04, 0x00);writeByte(0x0D, 0x00);writeByte(0x0E, 0x00);writeByte(0x0F, 0x00);writeByte(0x10, 0x00);writeByte(0x11, 0x00);writeByte(0x15, 0x20);writeByte(0x17, 0x00);writeByte(0x05, 0x00);writeByte(0x06, 0x00);writeByte(0x07, 0x00);writeByte(0x08, 0x00);writeByte(0x09, 0x00);writeByte(0x0A, 0x00);writeByte(0x0B, 0x00);writeByte(0x0C, 0x00);writeByte(0x14, 0x80);sendCommand(0x10);sendCommand(0x08);// Initializing WiFi connection to bionic prosthetic armWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Enabling WiFi on EMG Headcap...");}Serial.println("Succesfully Enabled WiFi on EMG Headcap!");//WiFi.config(localIP, gateway, subnet);// Initializing the Electroencephalography EEG Filter /////////////////brainEEGFilterChannel1.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel2.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel3.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel4.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel5.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel6.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel7.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);brainEEGFilterChannel8.init(BRAIN_EEG_FILTER_SAMPLE_RATE, BRAIN_EEG_FILTER_HUM_FREQUENCY, true, true, true);// Setup for time cost measure of the EEG Filter using micros()// micros will overflow and auto return to zero every 70 minutesbrainEEGFilterTimeBudget = 1e6 / brainEEGFilterSampleRate;//////////////////////////////////////////////////////////////////////Serial.println("Reading events");}void loop() {if (!client.connected()) {Serial.println("Connecting to Bionic Prosthetic Arm Server...");if (client.connect(serverIP, serverPort)) { // Connect to the serverSerial.println("Connected to Bionic Prosthetic Arm Server");} else {Serial.println("Connection to Bionic Prosthetic Arm failed.");delay(1000);return;}}if (client.connected()) {//Serial.println("Client connected!");// In order to meet the ADC sample frequency of the EEG filter,// The time cost of the code in the loop should be measured at each iteration.brainEEGFilterTimeStamp = micros();for (int i = 0; i < 27; i++) {output[sampleCount] = SPI.transfer(0xFF); // 0xFF is a dummy byte to trigger the readsampleCount = sampleCount + 1;}if (sampleCount == dataLength) {Serial.println("sampleCount == dataLength");for (int c = 0; c < dataLength; c += 27) {for (int a = 0; a < 26; a += 3) {voltage = (output[a + c] << 8) | output[a + 1 + c];voltage = (voltage << 8) | output[a + 2 + c];voltageToBeConverted = voltage | dataTest;if (voltageToBeConverted == dataCheck) {voltageConverted = 16777214 - voltage;} else {voltageConverted = voltage;}// Serial.print("Voltage: "); Serial.println(voltageConverted);voltageConvertedScaledNormalized = round(1000000 * 4.5 * (voltageConverted / 16777215.0) * 100) / 100;//Serial.print("Voltage (Scaled & Normalized): "); Serial.println(voltageConvertedScaledNormalized);channelNumber = a / 3;result[channelNumber] = voltageConvertedScaledNormalized;}int indexVal = c / 27;//Serial.print("c / 27 = "); Serial.println(indexVal);channel1[c / 27] = result[1];channel2[c / 27] = result[2];channel3[c / 27] = result[3];channel4[c / 27] = result[4];channel5[c / 27] = result[5];channel6[c / 27] = result[6];channel7[c / 27] = result[7];channel8[c / 27] = result[8];if ((c / 27) == sampleLength - 1) {// Plot values to Serial Plotterfor (int i = 0; i < sampleLength; i++) {if (BRAIN_EEG_FILTER_ADVANCED) {// Getting Brain Electroencephalography EEG Sensor ValuesbrainEEGSensorValueChannel1 = channel1[i];brainEEGSensorValueChannel2 = channel2[i];brainEEGSensorValueChannel3 = channel3[i];brainEEGSensorValueChannel4 = channel4[i];brainEEGSensorValueChannel5 = channel5[i];brainEEGSensorValueChannel6 = channel6[i];brainEEGSensorValueChannel7 = channel7[i];brainEEGSensorValueChannel8 = channel8[i];// Brain Electroencephalography EEG filter processing /////////////////////////////////brainEEGSensorValueFilteredChannel1 = brainEEGFilterChannel1.update(brainEEGSensorValueChannel1);brainEEGSensorValueFilteredChannel2 = brainEEGFilterChannel2.update(brainEEGSensorValueChannel2);brainEEGSensorValueFilteredChannel3 = brainEEGFilterChannel3.update(brainEEGSensorValueChannel3);brainEEGSensorValueFilteredChannel4 = brainEEGFilterChannel4.update(brainEEGSensorValueChannel4);brainEEGSensorValueFilteredChannel5 = brainEEGFilterChannel5.update(brainEEGSensorValueChannel5);brainEEGSensorValueFilteredChannel6 = brainEEGFilterChannel6.update(brainEEGSensorValueChannel6);brainEEGSensorValueFilteredChannel7 = brainEEGFilterChannel7.update(brainEEGSensorValueChannel7);brainEEGSensorValueFilteredChannel8 = brainEEGFilterChannel8.update(brainEEGSensorValueChannel8);// Square the EEG Filter ValuesbrainEEGSensorValueFilteredAmplifiedChannel1 = (brainEEGSensorValueFilteredChannel1);brainEEGSensorValueFilteredAmplifiedChannel2 = (brainEEGSensorValueFilteredChannel2);brainEEGSensorValueFilteredAmplifiedChannel3 = (brainEEGSensorValueFilteredChannel3);brainEEGSensorValueFilteredAmplifiedChannel4 = (brainEEGSensorValueFilteredChannel4);brainEEGSensorValueFilteredAmplifiedChannel5 = (brainEEGSensorValueFilteredChannel5);brainEEGSensorValueFilteredAmplifiedChannel6 = (brainEEGSensorValueFilteredChannel6);brainEEGSensorValueFilteredAmplifiedChannel7 = (brainEEGSensorValueFilteredChannel7);brainEEGSensorValueFilteredAmplifiedChannel8 = (brainEEGSensorValueFilteredChannel8);// Any value under brainEEGFilterThreshold will be set to zerobrainEEGSensorValueFilteredAmplifiedChannel1 = (brainEEGSensorValueFilteredAmplifiedChannel1 > brainEEGFilterThresholdChannel1) ? brainEEGSensorValueFilteredAmplifiedChannel1 : 0;brainEEGSensorValueFilteredAmplifiedChannel2 = (brainEEGSensorValueFilteredAmplifiedChannel2 > brainEEGFilterThresholdChannel2) ? brainEEGSensorValueFilteredAmplifiedChannel2 : 0;brainEEGSensorValueFilteredAmplifiedChannel3 = (brainEEGSensorValueFilteredAmplifiedChannel3 > brainEEGFilterThresholdChannel3) ? brainEEGSensorValueFilteredAmplifiedChannel3 : 0;brainEEGSensorValueFilteredAmplifiedChannel4 = (brainEEGSensorValueFilteredAmplifiedChannel4 > brainEEGFilterThresholdChannel4) ? brainEEGSensorValueFilteredAmplifiedChannel4 : 0;brainEEGSensorValueFilteredAmplifiedChannel5 = (brainEEGSensorValueFilteredAmplifiedChannel5 > brainEEGFilterThresholdChannel5) ? brainEEGSensorValueFilteredAmplifiedChannel5 : 0;brainEEGSensorValueFilteredAmplifiedChannel6 = (brainEEGSensorValueFilteredAmplifiedChannel6 > brainEEGFilterThresholdChannel6) ? brainEEGSensorValueFilteredAmplifiedChannel6 : 0;brainEEGSensorValueFilteredAmplifiedChannel7 = (brainEEGSensorValueFilteredAmplifiedChannel7 > brainEEGFilterThresholdChannel7) ? brainEEGSensorValueFilteredAmplifiedChannel7 : 0;brainEEGSensorValueFilteredAmplifiedChannel8 = (brainEEGSensorValueFilteredAmplifiedChannel8 > brainEEGFilterThresholdChannel8) ? brainEEGSensorValueFilteredAmplifiedChannel8 : 0;leftFrontalLobeFP1 = brainEEGSensorValueFilteredAmplifiedChannel1;rightFrontalLobeFP2 = brainEEGSensorValueFilteredAmplifiedChannel2;leftMotorCortexC3 = brainEEGSensorValueFilteredAmplifiedChannel3;rightMotorCortexC4 = brainEEGSensorValueFilteredAmplifiedChannel4;leftOccipitalLobeO1 = brainEEGSensorValueFilteredAmplifiedChannel5;rightOccipitalLobeO2 = brainEEGSensorValueFilteredAmplifiedChannel6;leftTemporalLobeT3 = brainEEGSensorValueFilteredAmplifiedChannel7;rightTemporalLobeT4 = brainEEGSensorValueFilteredAmplifiedChannel8;} else {leftFrontalLobeFP1 = channel1[i];rightFrontalLobeFP2 = channel2[i];leftMotorCortexC3 = channel3[i];rightMotorCortexC4 = channel4[i];leftOccipitalLobeO1 = channel5[i];rightOccipitalLobeO2 = channel6[i];leftTemporalLobeT3 = channel7[i];rightTemporalLobeT4 = channel8[i];//////////////////////////////////////////////////////////////////// dataAfter1[i] = channel1[i];// datasetChannel1[i] = dataBefore1[i] + dataBefore1[i] + dataBefore1[i] + dataAfter1[i];// dataBefore1[i] = dataAfter1[i];// dataButterHighpassFilterChannel1[i] = butterHighpassFilter(datasetChannel1[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel1[i] = butterLowpassFilter(datasetChannel1[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter2[i] = channel2[i];// datasetChannel2[i] = dataBefore2[i] + dataBefore2[i] + dataBefore2[i] + dataAfter2[i];// dataBefore2[i] = dataAfter2[i];// dataButterHighpassFilterChannel2[i] = butterHighpassFilter(datasetChannel2[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel2[i] = butterLowpassFilter(datasetChannel2[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter3[i] = channel3[i];// datasetChannel3[i] = dataBefore3[i] + dataBefore3[i] + dataBefore3[i] + dataAfter3[i];// dataBefore3[i] = dataAfter3[i];// dataButterHighpassFilterChannel3[i] = butterHighpassFilter(datasetChannel3[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel3[i] = butterLowpassFilter(datasetChannel3[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter4[i] = channel4[i];// datasetChannel4[i] = dataBefore4[i] + dataBefore4[i] + dataBefore4[i] + dataAfter4[i];// dataBefore4[i] = dataAfter4[i];// dataButterHighpassFilterChannel4[i] = butterHighpassFilter(datasetChannel4[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel4[i] = butterLowpassFilter(datasetChannel4[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter5[i] = channel5[i];// datasetChannel5[i] = dataBefore5[i] + dataBefore5[i] + dataBefore5[i] + dataAfter5[i];// dataBefore5[i] = dataAfter5[i];// dataButterHighpassFilterChannel5[i] = butterHighpassFilter(datasetChannel5[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel5[i] = butterLowpassFilter(datasetChannel5[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter6[i] = channel6[i];// datasetChannel6[i] = dataBefore6[i] + dataBefore6[i] + dataBefore6[i] + dataAfter6[i];// dataBefore6[i] = dataAfter6[i];// dataButterHighpassFilterChannel6[i] = butterHighpassFilter(datasetChannel6[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel6[i] = ButterLowpassFilter(datasetChannel6[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter7[i] = channel7[i];// datasetChannel7[i] = dataBefore7[i] + dataBefore7[i] + dataBefore7[i] + dataAfter7[i];// dataBefore7[i] = dataAfter7[i];// dataButterHighpassFilterChannel7[i] = butterHighpassFilter(datasetChannel7[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel7[i] = butterLowpassFilter(datasetChannel7[i], lowpassCutoffFrequency, samplingFrequency);// dataAfter8[i] = channel8[i];// datasetChannel8[i] = dataBefore8[i] + dataBefore8[i] + dataBefore8[i] + dataAfter8[i];// dataBefore8[i] = dataAfter8[i];// dataButterHighpassFilterChannel8[i] = butterHighpassFilter(datasetChannel8[i], highpassCutoffFrequency, samplingFrequency);// dataButterHighpassLowpassFilterChannel8[i] = butterLowpassFilter(datasetChannel8[i], lowpassCutoffFrequency, samplingFrequency);// leftFrontalLobeFP1 = dataButterHighpassLowpassFilterChannel1[i];// rightFrontalLobeFP2 = dataButterHighpassLowpassFilterChannel2[i];// leftMotorCortexC3 = dataButterHighpassLowpassFilterChannel3[i];// rightMotorCortexC4 = dataButterHighpassLowpassFilterChannel4[i];// leftOccipitalLobeO1 = dataButterHighpassLowpassFilterChannel5[i];// rightOccipitalLobeO2 = dataButterHighpassLowpassFilterChannel6[i];// leftTemporalLobeT3 = dataButterHighpassLowpassFilterChannel7[i];// rightTemporalLobeT4 = dataButterHighpassLowpassFilterChannel8[i];}//////////////////////////////////////////////////////////////////////if (BRAIN_EEG_DEBUG) {// Serial.print("Size of Data: "); Serial.println(dataLength);// Serial.print("Left Ear: "); Serial.print(leftEar);// Serial.print("\t\t\tRight Ear: "); Serial.println(rightEar);Serial.print("Left Frontal Lobe (FP1): "); Serial.print(leftFrontalLobeFP1);Serial.print("\tRight Frontal Lobe (FP2): "); Serial.println(rightFrontalLobeFP2);Serial.print("Left Motor Cortex (C3): "); Serial.print(leftMotorCortexC3);Serial.print("\tRight Motor Cortex (C4): "); Serial.println(rightMotorCortexC4);Serial.print("Left Occipital Lobe (O1): "); Serial.print(leftOccipitalLobeO1);Serial.print("\tRight Occipital Lobe (O2): "); Serial.println(rightOccipitalLobeO2);Serial.print("Left Temporal Lobe (T3): "); Serial.print(leftTemporalLobeT3);Serial.print("\tRight Temporal Lobe (T4): "); Serial.println(rightTemporalLobeT4);Serial.print("\n");}if (BRAIN_EEG_SERIAL_PLOTTER_DEBUG) {// Serial.print(leftEar); Serial.print(" ");// Serial.print(rightEar); Serial.print(" ");Serial.print(leftFrontalLobeFP1); Serial.print(" ");Serial.print(rightFrontalLobeFP2); Serial.print(" ");Serial.print(leftMotorCortexC3); Serial.print(" ");Serial.print(rightMotorCortexC4); Serial.print(" ");Serial.print(leftOccipitalLobeO1); Serial.print(" ");Serial.print(rightOccipitalLobeO2); Serial.print(" ");Serial.print(leftTemporalLobeT3); Serial.print(" ");Serial.print(rightTemporalLobeT4); Serial.print(" ");Serial.println();}// Send data over WiFiclient.print("TX2,"); // Identifier to let the server know which device it's receiving from//client.print(leftEar); client.print(",");//client.print(rightEar); client.print(",");client.print(leftFrontalLobeFP1); client.print(",");client.print(rightFrontalLobeFP2); client.print(",");client.print(leftMotorCortexC3); client.print(",");client.print(rightMotorCortexC4); client.print(",");client.print(leftOccipitalLobeO1); client.print(",");client.print(rightOccipitalLobeO2); client.print(",");client.print(leftTemporalLobeT3); client.print(",");client.print(rightTemporalLobeT4);client.println();// Brain Electroencephalography EEG Filter Timing Debug// If time cost of the loop is less than brainEEGFilterTimeBudget, then you still have (brainEEGFilterTimeBudget - brainEEGFilterTimeStamp) for code execution.// If time cost of the loop more than brainEEGFilterTimeBudget, then the sample rate needs to be reduced to SAMPLE_FREQ_500HZbrainEEGFilterTimeStamp = micros() - brainEEGFilterTimeStamp;brainEEGFilterTimeLeft = brainEEGFilterTimeBudget - brainEEGFilterTimeStamp;if (BRAIN_EEG_FILTER_DEBUG) {Serial.print("Brain Electroencephalography EEG Filters Time Cost: "); Serial.println(brainEEGFilterTimeStamp); // The filter costs an average of around 520 usSerial.print("Time Left from EEG Filter Time Budget: "); Serial.println(brainEEGFilterTimeLeft);Serial.print("\n");} else {//Serial.print("\n\n");}}}}sampleCount = 0; // Reset the index after sending data}}delay(40);}void sendCommand(byte command) {SPI.transfer(command);}void writeByte(byte registers, byte data) {char spi_data = 0x40 | registers;charspi_data_array[3];spi_data_array[0] = spi_data;spi_data_array[1] = 0x00;spi_data_array[2] = data;SPI.transfer(spi_data_array, 3);}// Function to round a float to a specified number of decimal placesfloat roundToDecimal(float value, int decimalPlaces) {float multiplier = pow(10.0, decimalPlaces);returnround(value * multiplier) / multiplier;}void initButterworthFilters() {for (int i = 0; i < 8; i++) {// Initialize highpass filter coefficientsbutterHighpass[i].a[0] = 1.0;butterHighpass[i].a[1] = -1.995856;butterHighpass[i].a[2] = 0.9960625;butterHighpass[i].b[0] = 0.99803125;butterHighpass[i].b[1] = -1.9960625;butterHighpass[i].b[2] = 0.99803125;// Initialize lowpass filter coefficientsbutterLowpass[i].a[0] = 1.0;butterLowpass[i].a[1] = -1.5610180758;butterLowpass[i].a[2] = 0.6413515381;butterLowpass[i].b[0] = 0.0200833656;butterLowpass[i].b[1] = 0.0401667312;butterLowpass[i].b[2] = 0.0200833656;// Initialize filter statesfor (int j = 0; j < 3; j++) {butterHighpass[i].x[j] = 0.0;butterHighpass[i].y[j] = 0.0;butterLowpass[i].x[j] = 0.0;butterLowpass[i].y[j] = 0.0;}}}float butterHighpassFilter(ButterworthFilter* filter, float input) {// Shift old samplesfilter->x[2] = filter->x[1];filter->x[1] = filter->x[0];filter->x[0] = input;filter->y[2] = filter->y[1];filter->y[1] = filter->y[0];// Calculate new outputfilter->y[0] = (filter->b[0] * filter->x[0] + filter->b[1] * filter->x[1] + filter->b[2] * filter->x[2]- filter->a[1] * filter->y[1] - filter->a[2] * filter->y[2]) / filter->a[0];returnfilter->y[0];}float butterLowpassFilter(ButterworthFilter* filter, float input) {// Shift old samplesfilter->x[2] = filter->x[1];filter->x[1] = filter->x[0];filter->x[0] = input;filter->y[2] = filter->y[1];filter->y[1] = filter->y[0];// Calculate new outputfilter->y[0] = (filter->b[0] * filter->x[0] + filter->b[1] * filter->x[1] + filter->b[2] * filter->x[2]- filter->a[1] * filter->y[1] - filter->a[2] * filter->y[2]) / filter->a[0];returnfilter->y[0];}
Quote from PiEEG on 07.08.2024, 16:20Hi Alikhodrali
about that, it is attempt create let say buffer for data
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1when we work with band pass-filter in REAL-TIME we can not just only send our current data and make processing, because we need buffer, when a signal first enters a band-pass filter, the filter undergoes a transient response before reaching a steady state. So we send actual data and data from past reading to band pass filter after band-pass filter we take only actual data from the result
Hi Alikhodrali
about that, it is attempt create let say buffer for data
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1
when we work with band pass-filter in REAL-TIME we can not just only send our current data and make processing, because we need buffer, when a signal first enters a band-pass filter, the filter undergoes a transient response before reaching a steady state. So we send actual data and data from past reading to band pass filter after band-pass filter we take only actual data from the result
Quote from PiEEG on 07.08.2024, 16:24About your video, I just yesterday received the same question by email, it is copy
"
About data after the electrodes are disconnected, it is totally OK, you know, EEG is the potential difference between the reference (in our case the ear) and the electrode on the head, the potential difference as we know is voltage (for EEG microvolts), therefore whether the electrode is connected or not, the potential difference between the reference and the electrode channels will always be, in fact in this case, when electrode disconnected it is just noise and nothing more.""
Do you have spikes during measurements ? when you don't move and have a good connection between the electrode and the skin
since in this case it may be a loss of data transmission, or the receiver does not have time to receive or the implemented script does not have time to send. To check this you can simply short-circuit the channels physically and check data, or short-circuit the channels through the registers
for the channel register, you need to send register 01. When channel in short-circuit stage you should receive stable data +- 2 µVch1set=0x05
write_byte (0x05, 0x01)
About your video, I just yesterday received the same question by email, it is copy
"
About data after the electrodes are disconnected, it is totally OK, you know, EEG is the potential difference between the reference (in our case the ear) and the electrode on the head, the potential difference as we know is voltage (for EEG microvolts), therefore whether the electrode is connected or not, the potential difference between the reference and the electrode channels will always be, in fact in this case, when electrode disconnected it is just noise and nothing more."
"
Do you have spikes during measurements ? when you don't move and have a good connection between the electrode and the skin
since in this case it may be a loss of data transmission, or the receiver does not have time to receive or the implemented script does not have time to send. To check this you can simply short-circuit the channels physically and check data, or short-circuit the channels through the registers
for the channel register, you need to send register 01. When channel in short-circuit stage you should receive stable data +- 2 µV
ch1set=0x05
write_byte (0x05, 0x01)
Quote from alikhodrali on 08.08.2024, 03:20Quote from admin on 07.08.2024, 16:20Hi Alikhodrali
about that, it is attempt create let say buffer for data
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1when we work with band pass-filter in REAL-TIME we can not just only send our current data and make processing, because we need buffer, when a signal first enters a band-pass filter, the filter undergoes a transient response before reaching a steady state. So we send actual data and data from past reading to band pass filter after band-pass filter we take only actual data from the result
I understand now thank you. So do you know what the structure of this data is? I'm assuming they're arrays but what would be their size?
Quote from admin on 07.08.2024, 16:20Hi Alikhodrali
about that, it is attempt create let say buffer for data
#ch1
data_after_1 = ch_1
dataset_1 = data_before_1 + data_before_1 + data_before_1 + data_after_1
data_before_1 = data_after_1when we work with band pass-filter in REAL-TIME we can not just only send our current data and make processing, because we need buffer, when a signal first enters a band-pass filter, the filter undergoes a transient response before reaching a steady state. So we send actual data and data from past reading to band pass filter after band-pass filter we take only actual data from the result
I understand now thank you. So do you know what the structure of this data is? I'm assuming they're arrays but what would be their size?
Quote from PiEEG on 08.08.2024, 12:46with the current setup for registers ads1299 in ardEEG allows receiving 250 samples per sec from 8 channels
so every second for every channel er receives 250 values (every value has 3 bytes)
So in my script, I collect data for 1 sec (250 values for every ch), and after that move forward
Yes, it arrays dataset_1 has the next structure = [[250 values],[250 values],[250 values],[250 values]]
with the current setup for registers ads1299 in ardEEG allows receiving 250 samples per sec from 8 channels
so every second for every channel er receives 250 values (every value has 3 bytes)
So in my script, I collect data for 1 sec (250 values for every ch), and after that move forward
Yes, it arrays dataset_1 has the next structure = [[250 values],[250 values],[250 values],[250 values]]
Quote from alikhodrali on 08.08.2024, 13:31Do you have spikes during measurements ? when you don't move and have a good connection between the electrode and the skin
Yes, I do occasionally, maybe once every second or two. But what scale should my measurements be? Are my measurements supposed to be only positive values? Currently my min value in the y-axis is 0 and value when I see big spikes is about 1,000,000 to 2,000,000. Is this correct or is something wrong with the code somewhere? When I put the cap on and clip on the ears, my values seem to go down, and once I remove the cap, the values go crazy as seen in the video here: Video. I'm just not sure about the scale. Does scale matter? Mind you the graph in the video is showing unfiltered raw data just converted to voltage.
since in this case it may be a loss of data transmission, or the receiver does not have time to receive or the implemented script does not have time to send. To check this you can simply short-circuit the channels physically and check data, or short-circuit the channels through the registers
for the channel register, you need to send register 01. When channel in short-circuit stage you should receive stable data +- 2 µV
ch1set=0x05
write_byte (0x05, 0x01)
When you say short circuit physically, do you mean put 5V to one of the electrodes? Sorry if this is a silly question. I've never done EEG before in my life.
with the current setup for registers ads1299 in ardEEG allows receiving 250 samples per sec from 8 channels
so every second for every channel er receives 250 values (every value has 3 bytes)
So in my script, I collect data for 1 sec (250 values for every ch), and after that move forward
Yes, it arrays dataset_1 has the next structure = [[250 values],[250 values],[250 values],[250 values]]
Also here are you saying that it is 250 samples per sec per channel as in 250/s * 8 = 2000 samples total? I hope I'm understanding this correctly? Which means that every second you are collecting a total of 2000*3 = 6000 bytes? So dataset_1 is an array of four arrays? I'll have to figure out how to do this in C++, I'm only familiar with this data structure in Python, Java and MATLAB.
Do you have spikes during measurements ? when you don't move and have a good connection between the electrode and the skin
Yes, I do occasionally, maybe once every second or two. But what scale should my measurements be? Are my measurements supposed to be only positive values? Currently my min value in the y-axis is 0 and value when I see big spikes is about 1,000,000 to 2,000,000. Is this correct or is something wrong with the code somewhere? When I put the cap on and clip on the ears, my values seem to go down, and once I remove the cap, the values go crazy as seen in the video here: Video. I'm just not sure about the scale. Does scale matter? Mind you the graph in the video is showing unfiltered raw data just converted to voltage.
since in this case it may be a loss of data transmission, or the receiver does not have time to receive or the implemented script does not have time to send. To check this you can simply short-circuit the channels physically and check data, or short-circuit the channels through the registers
for the channel register, you need to send register 01. When channel in short-circuit stage you should receive stable data +- 2 µV
ch1set=0x05
write_byte (0x05, 0x01)
When you say short circuit physically, do you mean put 5V to one of the electrodes? Sorry if this is a silly question. I've never done EEG before in my life.
with the current setup for registers ads1299 in ardEEG allows receiving 250 samples per sec from 8 channels
so every second for every channel er receives 250 values (every value has 3 bytes)
So in my script, I collect data for 1 sec (250 values for every ch), and after that move forward
Yes, it arrays dataset_1 has the next structure = [[250 values],[250 values],[250 values],[250 values]]
Also here are you saying that it is 250 samples per sec per channel as in 250/s * 8 = 2000 samples total? I hope I'm understanding this correctly? Which means that every second you are collecting a total of 2000*3 = 6000 bytes? So dataset_1 is an array of four arrays? I'll have to figure out how to do this in C++, I'm only familiar with this data structure in Python, Java and MATLAB.