Arduino Brain Interface

Some time ago I decided that I wanted to attempt a DIY human brain to Arduino interface.  With the dawn of cheap and easy micro-controllers I figured this is now within easy reach of hobbyists and I should give it a try…

diy 3d prosthetic arm

 

In late 2013 I set about interfacing a hacked Mind-Flex headset (a Mattel game) to control an output via an Arduino.  It turned out this was not as difficult as I originally expected!

All information here is documented via videos in the playlist below.  If you have any trouble- just watch the related video for that stage of the build/testing and you should be all set reproducing my results.

I purchased the Mind Flex Duel game manufactured by Mattel which you can purchase Here.

MindFlex hacked DIY EEG

 

The headset is a quite simple unit with a battery compartment and a sensor compartment connected via a head-band.

MindFlex hacked headset DIY EEG

 

From here you simply disassemble the sensor/transmitter compartment with 4 screws to locate the serial data transmit terminal (TX) As well, you will need to locate a suitable ground terminal (I chose battery ground).  I’m sure you could also tap directly into the 2.4 GHz wireless signal but I did not attempt that yet.

Mind Flex Hacked serial data pins

 

From here I simply soldered on a wire to the TX pin and the ground pin, cut a hole in the case, and ran the wires out for connection to Arduino.

Mind Flex hacked serial pins soldered wires

 

A quick check on the oscilloscope shows that we are getting serial data.  Fantastic!

Mind Flex serial data on Rigol oscilloscope

 

From here the TX connection from the headset is hooked to the Arduino RX pin (remember to unhook this when you upload code to the Arduino).  The Ground from the headset is hooked to Arduino ground.

You can download the Processing sketch for the “brain grapher” and you can view the signals live and in real time.  This is actually not necessary for control of my DIY prosthetic arm- but nice for troubleshooting.

The serial data from the Mind-Flex headset is simply read by the Arduino board and a servo output can be controlled.  As well the data is printed to serial so the PC can display the live values in graphic format.

I have since taken this setup and modified the code to directly control my InMoov 3D printed robotic arm.   My intent is to demo this with my InMoov 3D printed robot arm (prosthetic) to show how simple it would be for anyone, anywhere to produce a cheap rudimentary mind controlled prosthetic.  Perhaps it could be useful during physiotherapy or rehabilitation such as with stroke victims, paralysis etc. *EDIT* This has since been done via video 8 in the build series.

The cost would easily be below $200 USD to reproduce my results (if you have a 3D printer).

This entire project could be reproduced anywhere in the world at a fraction of the cost for a medical grade unit.

Inmoov, arm, prosthetic

Inmoov, arm, prosthetic

You can open the below videos in YouTube to view the entire playlist of how I developed and tested the DIY Brain-computer-interface.  At the end you will see videos of me directly controlling the robotic arm using just my brainwaves.  Pretty neat for a budget DIY Arduino project 🙂

Below is the really basic  Arduino code. Updated versions will be posted here.  Copy and paste this into your Arduino IDE and modify to suit your needs.

At the end of the project I proved to myself I could fully 3D print a DIY prosthetic arm and control it via my brainwaves with a cheap hacked interface and an open-source Arduino.  Overall it was a huge success.

Take the design, code and instructions.  Make it better and make it free for the world!

Eric

*UPDATE!* Here is new code from April 2014 whereby I have changed the output on the arm to a proportional reaction in the arm.  The fingers will perform a “pinch” movement proportional to the attention level from the DIY EEG headset.  Enjoy!

/*
This is my development of a DIY prosthetic arm interfaced via a hacked MindFlex headset
The output controls my InMoov robot hand/arm which is also open source and can be printed on any 3D printer
You can find the details of this project on the website or forum at:
http://www.mkme.org/
Please register and comment in the Forum for any help needed.

You can find lots of related videos om my YouTube channel:
Youtube : http://www.youtube.com/user/Shadow5549

Some of the code below is not applicable unless you would like to control the entire robot- I am only currently using the hand
The code can be adapted to use any variations of the different brainwave values. The information for which can be found on the github link.
You can find all the information on the InMoov robot project at http://www.inmoov.fr
Arduino MindFlex Brain Library and Instruction https://github.com/kitschpatrol/Arduino-Brain-Library
-------------------------------------------------------------------------

V2 April 27 2014- Added varSpeed and proportional Output for pinch motion only as a test 
Should allow pinch motion to be directly proportional to attention value
*/


//#include <Servo.h>
#include <Brain.h>
// Set up the brain parser, pass it the hardware serial object you want to listen on.
#include <VarSpeedServo.h>
Brain brain(Serial);

VarSpeedServo servothumb;          // Define thumb servo
VarSpeedServo servoindex;          // Define index servo
VarSpeedServo servomajeure;
VarSpeedServo servoringfinger;
VarSpeedServo servopinky;
VarSpeedServo servowrist;
VarSpeedServo servobiceps;
VarSpeedServo servorotate;
VarSpeedServo servoshoulder;
VarSpeedServo servoomoplat;
VarSpeedServo servoneck;
VarSpeedServo servorothead;

long attention; // Attention value read
 long val;
  long val2;

void setup() { 
  // Start the hardware serial.
  Serial.begin(9600);
  servothumb.attach(2);  // Set thumb servo to digital pin 2
  servoindex.attach(3);  // Set index servo to digital pin 3
  servomajeure.attach(4);
  servoringfinger.attach(5);
  servopinky.attach(6);
  servowrist.attach(7);
  servobiceps.attach(8);
  servorotate.attach(9);
  servoshoulder.attach(10);
  servoomoplat.attach(11);
  servoneck.attach(12);
  servorothead.attach(13);
  
  long val;
  long val2;
} 

void loop() {     

 // Expect packets about once per second.
        // The .readCSV() function returns a string (well, char*) listing the most recent brain data, in the following format:
        // "signal strength, attention, meditation, delta, theta, low alpha, high alpha, low beta, high beta, low gamma, high gamma"   
        if (brain.update()) {
        //Commented out the serial output for hraphing untill troubleshooting complete
        Serial.println(brain.readCSV());
                
                
	attention = brain.readAttention();// Retrieve Attention Value 0 - 100
        }

// Make sure we have a signal.
	//if(brain.readSignalQuality() == 0) {

// Close hand if attention value high enough
	  if (attention > 1) {
          pinch();
//} 
	  }	
	else {
        alltorest();
	}

// Loop through motion tests
//alltovirtual();        // Example: alltovirtual
//delay(4000);           // Wait 4000 milliseconds (4 seconds)
//delay(8000); 
//alltorest();           // Uncomment to use this
//delay(1500);           // Uncomment to use this
//alltomax();            // Uncomment to use this
//delay(1500);           // Uncomment to use this
//peace();           // Uncomment to use this
//delay(1500);
//alltorest();
//delay(2000);// Uncomment to use this
//rock();           // Uncomment to use this
//delay(1500); 
//alltorest();
//delay(1000);// Uncomment to use this
//point();           // Uncomment to use this
//delay(1500);  
//alltorest();
//delay(1500);// Uncomment to use this
//pinch();           // Uncomment to use this
//delay(1500);// Uncomment to use this 
}
// Motion to set the servo into "virtual" 0 position: alltovirtual
void alltovirtual() {         
  servothumb.slowmove(0,75);
  servoindex.slowmove(0,75);
  servomajeure.slowmove(0,60);
  servoringfinger.slowmove(0,75);
  servopinky.slowmove(0,75);
  servowrist.slowmove(0,75);
  servobiceps.slowmove(0,75);  
  servorotate.slowmove(20,75);    //Never less then (20 degree)
  servoshoulder.slowmove(30,75);  //Never less then (30 degree)
  servoomoplat.slowmove(10,75);   //Never less then (10 degree)
  servoneck.slowmove(0,75);
  servorothead.slowmove(0,75);
}
// Motion to set the servo into "rest" position: alltorest
void alltorest() {         
  servothumb.slowmove(15,80);//Thumb binds dont go to zero
  servoindex.slowmove(0,75);
  servomajeure.slowmove(0,75);
  servoringfinger.slowmove(0,75);
  servopinky.slowmove(0,75);
  servowrist.slowmove(0,75);
  servobiceps.slowmove(0,75);     
  servorotate.slowmove(90,75);    //Never less then (20 degree)
  servoshoulder.slowmove(30,75);  //Never less then (30 degree)
  servoomoplat.slowmove(10,75);   //Never less then (10 degree)
  servoneck.slowmove(90,75);
  servorothead.slowmove(90,75);
}



// Motion to set the servo into "max" position: alltomax
void alltomax() {
  servothumb.slowmove(95,50);
  servoindex.slowmove(90,75);
  servomajeure.slowmove(90,75);
  servoringfinger.slowmove(90,75);
  servopinky.slowmove(90,75);
  servowrist.slowmove(120,75);
  servobiceps.slowmove(85,75);      //Never more then (85 or 90degree)
  servorotate.slowmove(110,75);     //Never more then (110 degree)
  servoshoulder.slowmove(130,75);   //Never more then (130 degree)
  servoomoplat.slowmove(70,75);     //Never more then (70 degree)
  servoneck.slowmove(180,75);
  servorothead.slowmove(180,75);
 
}
void peace() {
  servothumb.slowmove(95,50);
  servoindex.slowmove(0,75);
  servomajeure.slowmove(0,60);
  servoringfinger.slowmove(90,75);
  servopinky.slowmove(90,75);
  servowrist.slowmove(120,75);
  servobiceps.slowmove(85,75);      //Never more then (85 or 90degree)
  servorotate.slowmove(110,75);     //Never more then (110 degree)
  servoshoulder.slowmove(130,75);   //Never more then (130 degree)
  servoomoplat.slowmove(70,75);     //Never more then (70 degree)
  servoneck.slowmove(180,75);
  servorothead.slowmove(180,75);
 
}

void rock() {
  servothumb.slowmove(95,50);
  servoindex.slowmove(0,75);
  servomajeure.slowmove(80,75);
  servoringfinger.slowmove(90,75);
  servopinky.slowmove(0,75);
  servowrist.slowmove(120,75);
  servobiceps.slowmove(85,75);      //Never more then (85 or 90degree)
  servorotate.slowmove(110,75);     //Never more then (110 degree)
  servoshoulder.slowmove(130,75);   //Never more then (130 degree)
  servoomoplat.slowmove(70,75);     //Never more then (70 degree)
  servoneck.slowmove(180,75);
  servorothead.slowmove(180,75);
 
}

void point() {
  servothumb.slowmove(95,75);
  servoindex.slowmove(0,75);
  servomajeure.slowmove(80,75);
  servoringfinger.slowmove(90,75);
  servopinky.slowmove(90,75);
  servowrist.slowmove(120,75);
  servobiceps.slowmove(85,75);      //Never more then (85 or 90degree)
  servorotate.slowmove(110,75);     //Never more then (110 degree)
  servoshoulder.slowmove(130,75);   //Never more then (130 degree)
  servoomoplat.slowmove(70,75);     //Never more then (70 degree)
  servoneck.slowmove(180,75);
  servorothead.slowmove(180,75);
 
}
//Slowed down pinch a bit compared to others for testing
void pinch() {
  val=attention;
  val2=attention;
  val = map(val, 0, 65, 0, 95);
  servothumb.slowmove(val,50);
  //servothumb.slowmove(95,50);
  val2 = map(val2, 0, 65, 0, 90);
  servoindex.slowmove(val2,70);
  //servoindex.slowmove(90,70);
  servomajeure.slowmove(0,70);
  servoringfinger.slowmove(0,70);
  servopinky.slowmove(0,70);
  servowrist.slowmove(120,70);
  servobiceps.slowmove(85,70);      //Never more then (85 or 90degree)
  servorotate.slowmove(110,70);     //Never more then (110 degree)
  servoshoulder.slowmove(130,70);   //Never more then (130 degree)
  servoomoplat.slowmove(70,70);     //Never more then (70 degree)
  servoneck.slowmove(180,70);
  servorothead.slowmove(180,70);
 
}

Leave a Reply

Your email address will not be published. Required fields are marked *