Project showcase
BrainForce

BrainForce © CC BY-NC-ND

A wireless headset which allows you to control devices through cerebral waves. It works with two sensors and a Bluetooth shield.

  • 4,484 views
  • 2 comments
  • 23 respects

Components and supplies

Ads1292r ecgrespiration shield v2
ProtoCentral ADS1292R ECG/Respiration Shield for Arduino- v2
this shield allows to perform signals via hardware and pick up them from the cerebral cortex, splitting out them in two different channels.
×1
A000066 iso both
Arduino UNO & Genuino UNO
×2
Texas instruments l293dne image
Texas Instruments Dual H-Bridge motor drivers L293D
×1
DC motor (generic)
×1
61pby065esl  sx679  tnr8syww5d
HC-05 Bluetooth Module
×2
g.sahara
×1
E switch eg1218 image 75px
Slide Switch
×1
Tens70
9V battery (generic)
×3
Openbuilds wire cable by foot
OpenBuilds Wire Cable - By the Foot
×1
elastic
×1

Necessary tools and machines

3drag
3D Printer (generic)
welder

Apps and online services

About this project

First of all we would like to thank Davide Valeriani for his support at BrainForce project in giving us lessons and information about BCIs. He has been very willing to us and the knowledge that we acquired for realising this project comes from what he taught us.

The idea

The idea of realizing a BCI came out with the purpose of building a device which allows people with physical disease to move. In particular they can control for example a wheelchair with only using their cerebral status changes.

How does it work?

BrainForce would pick up the signal from the scalp, over the visual cortex, perform it, and evaluate if the power of the signal is major than a threshold: this would mean that the brain of the patient has changed his status, from relaxing to an activity one. This would generate an output which let us control a toy car as an application of the project.

Headset construction

The headset was built using pieces made from the case of an old computer. Each piece has been manually molded to make the headset comfortable to wear and make it wearable by different users. An elastic was attached in such a way that it adapted to different dimensions of the head. The headset's front box contains the heart of the project. It is where the Arduino and the shield reside, protected by a metal casing and an insulating rubber sheath. For economic unavailability, a jumble was used to create a sensor that could stick to the lobe. We added a battery on the headset to make it stand-alone from the pc. Then Arduino's power is handled via a switch.

The ordinary cables supplied with the shield have been replaced with shielded cables (coaxial cables) to minimize direct signal disturbances.

(*This part is not definitive*)

Signal analysis

The signals picked up by the BCI are electrical impulses triggered at the extremities of the neurons, when they fire. The signal is composed of many waves, but we analyse the ones between 8 and 12 Hertz, or rather Alpha waves. The BCI calculates the spectral density of these frequencies, which is major during a brain activity (mental math calculation as an example).

The application

The application of our project is moving a toy car through the visualization of an optical effects video by the patient. With a deep concentration on the video, BrainForce would generate many outputs which will make move the car.

Support us

We are also the creator of ProjecTo which is a StartUp with the objective of sharing information through video-tutorials about about arduino. In particular we make tutorials about single components, arduino projects, latest arduino tools, etc.

Subscribe on our Patreon page for supporting our activity!

Thank you very much!

Reference & contacts

Daniel Rossi

My YouTube Channel

https://www.youtube.com/channel/OfficialProjecto

Code

BrainForce car codeC/C++
//Realizzato da Daniel Rossi
//5C Blaise Pascal - informatico
//Reggio Emilia 06-04-2017
#include <ads1292r.h>
#include <SPI.h>
#include <arduinoFFT.h>
#include <SoftwareSerial.h>
//bluetooth settings
#define PinRx 10
#define PinTx 9
SoftwareSerial BT(PinRx,PinTx);

ads1292r ADS1292 ;
arduinoFFT FFT = arduinoFFT();

const uint16_t samples = 32;//This value MUST ALWAYS be a power of 2
const int I_SottoCamp = 32, I_Camp = 128;


char *SPI_RX_Buff_Ptr;
byte Campioni_Rosso[I_Camp], Campioni_Nero[I_Camp], Campioni_Blu[I_Camp],  SPI_RX_Buff[9];
double *DATA, *IMAG, *ALPHA, media, somma, soglia, mediatot, sommatot;
double SottoCamp_Rosso[I_SottoCamp], SottoCamp_Nero[I_SottoCamp], SottoCamp_Blu[I_SottoCamp], filtrato[I_SottoCamp], vImag[I_SottoCamp], Alpha[9], Power[9];
int i, k, conta, contamedie;

unsigned long utemp;
signed long stemp;

void ResetImag() {
  for (i = 0; i < I_SottoCamp; i++) {
    vImag[i] = 0;
  }
}

void setup() {

  // initalize the  data ready and chip select pins:
  pinMode(ADS1292_DRDY_PIN, INPUT);  //6
  pinMode(ADS1292_CS_PIN, OUTPUT);    //7
  pinMode(ADS1292_START_PIN, OUTPUT);  //5
  pinMode(ADS1292_PWDN_PIN, OUTPUT);  //4

  pinMode(PinRx, INPUT);
  pinMode(PinTx, OUTPUT);
  BT.begin(38400);
  Serial.begin(56700);  // Baudrate for serial communica
  //initalize ADS1292 slave
  ADS1292.ads1292_Init();
  //ADS1292.ads1292_Reset();

  soglia = 0 ;
  mediatot = 0;
  contamedie = 0;
  sommatot = 0;
  ResetImag();
}

signed long shifting(volatile byte val1, volatile byte val2, volatile byte val3) {
  utemp = (unsigned long) ((val1 << 16) | (val2 << 8) | val3);
  utemp = (unsigned long) (utemp << 8);
  stemp = (signed long) (utemp);
  stemp = (signed long) (stemp >> 8);
  return stemp;
}


void loop() {
  /* creo 3 vettori contenenti 32 campioni ognuno
      campioni_Ref è il vettore che contiene i valori di riferimento per poi filtrare i segnali
      Campioni_Rosso è il vettore che contiene i valori del sensore rosso
      Campioni_Blu è il vettore che contiene i valori del sensore blu
  */

  for (i = 0; i < I_Camp; i++) {

    if ((digitalRead(ADS1292_DRDY_PIN)) == LOW)
    {
      SPI_RX_Buff_Ptr = ADS1292.ads1292_Read_Data();
      for (k = 0; k < 9; k++) {
        SPI_RX_Buff[k] =  *(SPI_RX_Buff_Ptr + k);
      }
    }
    //nero
    Campioni_Nero[i] = shifting(SPI_RX_Buff[0], SPI_RX_Buff[1], SPI_RX_Buff[2]);
    //blu
    Campioni_Blu[i] = shifting(SPI_RX_Buff[3], SPI_RX_Buff[4], SPI_RX_Buff[5]);
    //rosso
    Campioni_Rosso[i] = shifting(SPI_RX_Buff[6], SPI_RX_Buff[7] , SPI_RX_Buff[8]);

  }
  //sottocampiono il vettore della media del segnale

  k = 0;
  for (i = 0; i < I_Camp; i += 4) {
    SottoCamp_Rosso[k] = ((double)(Campioni_Rosso[i] )) * 1.0;
    SottoCamp_Blu[k] = ((double)(Campioni_Blu[i] )) * 1.0;
    SottoCamp_Nero[k] = ((double)(Campioni_Nero[i] )) * 1.0;
    filtrato[k] = SottoCamp_Rosso[k]  - SottoCamp_Blu[k];
    k++;
  }

  DATA = filtrato;
  IMAG = vImag;

  /*
     svolgo la trasformata di fourier per il vettore finale ottenuto
     in modo da passare il segnale dal dominio del tempo al dominio delle frequenze
  */

  FFT.Windowing(DATA, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(DATA, IMAG, samples, FFT_FORWARD);


  k = 0;
  for (i = 0; i < I_SottoCamp; i++) {
    if ((vImag[i] > 150) || (vImag[i] < -150)) ResetImag();
    if ((i >= 16) && (i <= 24)) {
      Alpha[k] = filtrato[i];
      k++;
    }
  }
  conta = 0;
  somma = 0;

  for (i = 0; i < 9; i++) {
    Power[i] = (double) pow(Alpha[i], 2)  ;
    if (Power[i] > 400000)
      Power[i] = 0;
    else {
      somma += Power[i];
    }
  }
  media = somma / 9;
  contamedie++;
  sommatot += media;
  mediatot = sommatot / contamedie;
  if (contamedie >= 50) {
    contamedie = 1;
    sommatot = mediatot;
  }
  if (mediatot >= soglia) {
    BT.write('1');

  }
  else {
    BT.write('0');
  }
  Serial.println(BT.available());



}   //chiusura void loop
BrainForce analysis codeC/C++
//Realizzato da Daniel Rossi
//5C Blaise Pascal - informatico
//Reggio Emilia 06-04-2017
#include <ads1292r.h>
#include <SPI.h>
#include <arduinoFFT.h>

ads1292r ADS1292 ;
arduinoFFT FFT = arduinoFFT();

const uint16_t samples = 32;//This value MUST ALWAYS be a power of 2
const int I_SottoCamp = 32, I_Camp = 128;

//imposta pacchetto da inviare via seriale
uint8_t DataPacketHeader[15], *PACKET;
volatile char DataPacketFooter[2];
volatile int datalen = 135;
uint8_t data_len = 8;

//Packet format
#define  CES_CMDIF_PKT_START_1   0x0A
#define CES_CMDIF_PKT_START_2   0xFA
#define CES_CMDIF_TYPE_DATA   0x02
#define CES_CMDIF_PKT_STOP    0x0B

char *SPI_RX_Buff_Ptr;
byte Campioni_Rosso[I_Camp], Campioni_Nero[I_Camp], Campioni_Blu[I_Camp],  SPI_RX_Buff[9];
double *DATA, *IMAG, *ALPHA, media, somma, soglia, mediatot, sommatot;
double SottoCamp_Rosso[I_SottoCamp], SottoCamp_Nero[I_SottoCamp], SottoCamp_Blu[I_SottoCamp], filtrato[I_SottoCamp], vImag[I_SottoCamp], Alpha[9], Power[9];
int i, k, conta, contamedie;

unsigned long utemp;
signed long stemp;

void ResetImag() {
  for (i = 0; i < I_SottoCamp; i++) {
    vImag[i] = 0;
  }
}

void setup() {

  // initalize the  data ready and chip select pins:
  pinMode(ADS1292_DRDY_PIN, INPUT);  //6
  pinMode(ADS1292_CS_PIN, OUTPUT);    //7
  pinMode(ADS1292_START_PIN, OUTPUT);  //5
  pinMode(ADS1292_PWDN_PIN, OUTPUT);  //4

  Serial.begin(56700);  // Baudrate for serial communica
  //initalize ADS1292 slave
  ADS1292.ads1292_Init();
  //ADS1292.ads1292_Reset();

  DataPacketHeader[0] = CES_CMDIF_PKT_START_1;
  DataPacketHeader[1] = CES_CMDIF_PKT_START_2;
  DataPacketHeader[2] = (datalen);
  DataPacketHeader[3] = (datalen >> 8);
  DataPacketHeader[4] = CES_CMDIF_TYPE_DATA;

  DataPacketFooter[0] = 0x00;
  DataPacketFooter[1] = CES_CMDIF_PKT_STOP;

  ResetImag();
}

signed long shifting(volatile byte val1, volatile byte val2, volatile byte val3) {
  utemp = (unsigned long) ((val1 << 16) | (val2 << 8) | val3);
  utemp = (unsigned long) (utemp << 8);
  stemp = (signed long) (utemp);
  stemp = (signed long) (stemp >> 8);
  return stemp;
}

void feedBodyPacchetto(uint8_t pacchetto[15], volatile double dato[9]) {
  for (i = 5; i < 15; i++) {
    pacchetto[i] = dato[i - 5];
  }
}




void loop() {
  /* creo 3 vettori contenenti 32 campioni ognuno
      campioni_Ref è il vettore che contiene i valori di riferimento per poi filtrare i segnali
      Campioni_Rosso è il vettore che contiene i valori del sensore rosso
      Campioni_Blu è il vettore che contiene i valori del sensore blu
  */

  for (i = 0; i < I_Camp; i++) {

    if ((digitalRead(ADS1292_DRDY_PIN)) == LOW)
    {
      SPI_RX_Buff_Ptr = ADS1292.ads1292_Read_Data();
      for (k = 0; k < 9; k++) {
        SPI_RX_Buff[k] =  *(SPI_RX_Buff_Ptr + k);
      }
    }
    //nero
    Campioni_Nero[i] = shifting(SPI_RX_Buff[0], SPI_RX_Buff[1], SPI_RX_Buff[2]);
    //blu
    Campioni_Blu[i] = shifting(SPI_RX_Buff[3], SPI_RX_Buff[4], SPI_RX_Buff[5]);
    //rosso
    Campioni_Rosso[i] = shifting(SPI_RX_Buff[6], SPI_RX_Buff[7] , SPI_RX_Buff[8]);

  }
  //sottocampiono il vettore della media del segnale

  k = 0;
  for (i = 0; i < I_Camp; i += 4) {
    SottoCamp_Rosso[k] = ((double)(Campioni_Rosso[i] )) ;
    SottoCamp_Blu[k] = ((double)(Campioni_Blu[i] )) ;
    SottoCamp_Nero[k] = ((double)(Campioni_Nero[i] )) ;
    filtrato[k] = SottoCamp_Rosso[k]  - SottoCamp_Blu[k];
    k++;
  }

  DATA = filtrato;
  IMAG = vImag;

  /*
     svolgo la trasformata di fourier per il vettore finale ottenuto
     in modo da passare il segnale dal dominio del tempo al dominio delle frequenze
  */

  FFT.Windowing(DATA, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(DATA, IMAG, samples, FFT_FORWARD);


  k = 0;
  for (i = 0; i < I_SottoCamp; i++) {
    if ((vImag[i] > 150) || (vImag[i] < -150)) ResetImag();
    if ((i >= 16) && (i <= 24)) {
      Alpha[k] = filtrato[i];
      k++;
    }
  }

  for (i = 0; i < 9; i++) {
    Power[i] = (double) pow(Alpha[i], 2)  ;
  }
   ALPHA = Alpha;

     PACKET = DataPacketHeader;
     DataPacketHeader[0] = 0x0A;
     DataPacketHeader[1] = 0xFA;
     DataPacketHeader[2] = (uint8_t) (data_len);
     DataPacketHeader[3] = (uint8_t) (data_len >> 8);
     DataPacketHeader[4] = 0x02;

     feedBodyPacchetto(PACKET, ALPHA);

     DataPacketHeader[13] = 0x00;
     DataPacketHeader[14] = 0x0b;

     for (i = 0; i < 15; i++) // transmit the data
     {
      Serial.write(DataPacketHeader[i]);
     }



}   //chiusura void loop

Schematics

Brainforce headset circuit
Senza titolo 1 6hidbfhd8y
BrainForce car circuit
Untitled sketch 2 bb ipgp6avt1m
Documentazione sulle BCI
During tests
brainforce_YaKSEFclQF.mp4

Comments

Author

Pp mjdqwydnq3
Daniel Rossi
  • 2 projects
  • 10 followers

Additional contributors

  • Processing gui for visualization by Alberto Lusuardi
  • Teaching bci's theory by Davide Valeriani
  • Main software programmation; construction of the headset; construction of the sensors by Daniel Rossi

Published on

June 6, 2017

Members who respect this project

18556253 1863512647306811 7958973213698853415 nOpenbuildslogo blueboxRsz abc zizu0nacga1896914 750255351652331 2051847972 nDefaultDefaultDefaultDefault

and 16 others

See similar projects
you might like

Similar projects you might like

3D Printed R2-D2 with an Arduino Core

Project showcase by Raul Antonio

  • 3,245 views
  • 1 comment
  • 4 respects

Voice-Controlled Pick-and-Place Robot

by Sagar pawar

  • 2,254 views
  • 0 comments
  • 8 respects

DIY 3-Axis CNC VMC

Project tutorial by Amit Nandi (BigWiz)

  • 12,165 views
  • 9 comments
  • 46 respects

Bluetooth-Controlled Arduino Robot

Project showcase by jayesh_nawani

  • 1,657 views
  • 1 comment
  • 8 respects

WW2 Tank Laser Tag Sherman & Panther

Project tutorial by Arduino “having11” Guy

  • 15,446 views
  • 1 comment
  • 57 respects

Android controlled robot car

Project showcase by Isara Naranirattisai

  • 6,235 views
  • 2 comments
  • 12 respects
Add projectSign up / Login