Community /

A toy helicopter throttle controlled by alpha waves

What is more facinating than a brain-controlled helicopter that can be flown using nothing more than your brainwaves? When wearing your OpenBCI headset, you’ll be able to control s toy helicopter through focused concentration or by closing your eyes.

Get the hardware

We need to indispensable things to “hack” the helicopter tottle:

  • DS1803 DigiPot from Maxim. This test uses a 50K dual version. You can check the Adressable Dual Digital Potentiometer documentation file here. The digiPot ranges from 0 to 50K, so plan to use only 1/10th of the digiPot wiper range.
  • Helicopter from Amazon. Actually, it’s a kids toys gift, but it works perfectly for what we want to do. You can even choose the color, and buy it here. The analog pot from the toy ranges from 0 to 5K.

61BP6OytyaL._SL1500_
616Z47fjpWL._SL1500_
61huW680IjL._SL1500_
71HWGGo8kRL._SL1500_
71sCDBAEQVL._SL1500_

Once we got the helicopter and the potentiometer, we de-soldered the throttle control potentiometer, and wired in some jumpers.

Set Up the software

The throttle control code is in the Processing sketch tabs ‘EEG_Processing‘ and ‘Helicopter‘. The GUI already has a peak detection, so we look to see if the peak is in the alpha range. If it is, and if it’s strong enough against the background noise, then a character is sent out to the Arduino that controls the helicopter. The strength of the alpha wave is encoded in the characters ‘A’ to ‘Z’. Then Processing sends the prefix ‘$’ followed by the character code. Arduino gets the prefix, and then applys the next value it gets to the potentiometer. It all took about half a day of hacking on the original OpenBCI_GUI, so I’m sure there’s room for improvement. You can download both the Arduino code and the OpenBCI GUI here.

Take the entire OpenBCI_GUI folder and put it in your

Documents/Processing

folder. If you already have an OpenBCI_GUI and don’t want to over-write it, create a subfolder in the Processing folder called ‘copter control’ for this one to live in.

Take the entire ‘CopterControl‘ folder and put it in your Arduino folder:

Documents/Arduino

Upload Arduino code

For this setup, you need an Arduino connected to a digi pot connected to the hacked throttle control of a toy helicopter.

Helicopter Control

The code below controls the toy helicopter:

#include <Wire.h>
// digitPot defines
#define DS_0 0x28 // address for DS1803 is 0101000 pull all address pins down
#define WRITE_P0 0xA9 // 10101001
#define WRITE_P1 0xAA // 10101010
#define WRITE_BOTH 0xAF // 10101111 

boolean testingPot = false; // used to test initial pot function
boolean expectingValue = false;

unsigned long throttleTimer;
int throttleDuration = 2000;
byte throttleSetting = 0x00;
byte lastThrottleSetting;

void setup() {
 Serial.begin(115200);
 Wire.begin();
 Serial.println("Copter Control 02");
 throttleSetting = lastThrottleSetting = 0x00;
 setBothWipers(DS_0,throttleSetting);
 Serial.print("trottle: ");Serial.println(throttleSetting);
}

void loop() {
 if(millis() - throttleTimer > throttleDuration){ throttleSetting = 0; }
 if(throttleSetting != lastThrottleSetting){
 setWiper0(DS_0,throttleSetting);
 Serial.print("trottle: ");Serial.println(throttleSetting,DEC);
 lastThrottleSetting = throttleSetting;
 }
 
 eventSerial();
}

void eventSerial(){
 while (Serial.available()) {
 char inChar = (char)Serial.read();
// Serial.print("Received "); Serial.println(inChar);
 if(expectingValue){
 throttleSetting = byte(inChar - 'A'); // variable is ascii encoded 0=A, 1=B, etc
// Serial.print("trottle: ");Serial.println(throttleSetting);
 throttleTimer = millis();
 expectingValue = false;
 return; // get outa here
 }
 
 Serial.print("Received "); Serial.println(inChar);
 switch (inChar) {
 case '$': // Processing must send the $ to tell Arduino the next value is special
 if(expectingValue){return;}
 expectingValue = true;
 break;
 
 default:
 break;
 }}
}

The Potentiometer (DigiPot_Stuph)

The following code is for the digi potenciometer:

void setWiper0(byte address, byte val){
 Wire.beginTransmission(address); // start transmission to slave 0x
 Wire.write(WRITE_P0); // sends instruction byte
 Wire.write(val); // sends potentiometer value byte
 Wire.endTransmission(); // stop transmitting
}

void readWipers(byte address){
// address ++;
 Wire.requestFrom(address,2); // 
 while (Wire.available()) { // slave may send less than requested 
  byte x = Wire.read(); // receive a byte as character
  Serial.print(x,DEC); // print the character
  Serial.print(" ");
 }
 Serial.println();
}

void setWiper1(byte address, byte val){
 Wire.beginTransmission(address); // start transmission to slave 0x
 Wire.write(WRITE_P1); // sends instruction byte
 Wire.write(val); // sends potentiometer value byte
 Wire.endTransmission(); // stop transmitting
}

void setBothWipers(byte address, byte val){
 Wire.beginTransmission(address); // start transmission to slave 0x
 Wire.write(WRITE_BOTH); // sends instruction byte
 Wire.write(val); // sends potentiometer value byte
 Wire.endTransmission(); // stop transmitting
}

void digiPotTest(){
 for(int i=0; i<25; i++){ // scroll up
  eventSerial();
  if(testingPot){
   setBothWipers(DS_0,i);
   readWipers(DS_0);
   delay(500);
 } else{return;}
 }
 for(int i=25; i>0; i--){ // scroll down
  eventSerial();
  if(testingPot){
   setBothWipers(DS_0,i);
   readWipers(DS_0);
   delay(500);
 } else{return;}
 }
}

Upload GUI

This is a variant of OpenBCI GUI that uses strength of alpha wave to control the helicopter throttle. So, if you have the original version of OpenBCI GUI you only have to add the helicopter class in it, and you should be fine.

class Helicopter {
 
 private int wait_millis = 5;
 private boolean fireBetweenMoves = false;
 
 //create inner class to wrap up a "command"
 class Command {
 private String command_str;
 private String variable_str;
 private String name;
 // private String mappedValue; // variable to control throttle
 private int counter;
 private Serial serial_h;
 public boolean printReceivedCommand = true;
 public int ID;
 
 Command(Serial _serial_h, String _str, String _var, String _name, int _ID) {
 serial_h = _serial_h;
 command_str = _str;
 variable_str = _var;
 name =_name;
 counter = 0;
 ID = _ID;
 }
 
 public int issue() {
 counter++;
 if (printReceivedCommand) {
 println("Helicopter: Command: " + name + " (" + counter + ")");
 }
 if (serial_h != null) serial_h.write(command_str);
 return ID;
 }} //close definition of class Command

 private Command command_forward, command_climb, command_dive, command_left, command_right,
 command_throttle; 
 private int prev_command = -1;
 private String mappedValue; // variable to control throttle
 private int counter = 0;
 //Constructor, pass in an already-opened serial port
 Helicopter(Serial serialPort) {
 int ID = 0;// display comands
 command_forward = new Command(serialPort,"O","Swim!",ID++);
 command_right = new Command(serialPort,"|","Right",ID++);
 command_left = new Command(serialPort,"{","Left",ID++);
 command_climb = new Command(serialPort,"}","Climb",ID++);
 command_dive = new Command(serialPort,"P","Dive",ID++);
 }
 
 public void climb() {
 prev_command = command_climb.issue();
 }
 public void dive() {
 prev_command = command_dive.issue();
 }
 public void forward() {
 //if (fireBetweenMoves & (prev_command != command_forward.ID)) {
 prev_command = command_fire.issue(); //issue a FIRE command on a transition
 waitMilliseconds(wait_millis);
 prev_command = command_forward.issue();
 }
 public void left() {
 //if (fireBetweenMoves & (prev_command != command_left.ID)) {
 prev_command = command_fire.issue(); //issue a FIRE command on a transition
 waitMilliseconds(wait_millis);
 prev_command = command_left.issue();
 }
 public void right() {
 //if (fireBetweenMoves & (prev_command != command_right.ID)) {
 prev_command = command_fire.issue(); //issue a FIRE command on a transition
 waitMilliseconds(wait_millis);
 prev_command = command_right.issue();
 }

 public void throttle(String V) {
 counter++;
 println("Helicopter: Command: Throttle $" + V + " (" + counter + ")");
 helicopter_serial.write("$" + V);
 while(helicopter_serial.available() > 0){
 print(char(helicopter_serial.read()));
 }}
 
 public void waitMilliseconds(int dt_millis) {
 int start_time = millis();
 int t = millis();
 while (t-start_time < dt_millis) {
 t = millis();
 }}
}

Let’s hack it!

We’ve got the helicopter and the potentiometer, we’ve uploded the new Arduino code to the OpenBCI 32bit board, and we have the OpenBCI headset in our heads. So, we are more than ready to hack the brains and control the toy helicopter!

alphawaves3.png
Figure 1. By closing your eyes, the alpha waves increases.

It is known that if you close your eyes, your alfa waves increase instantly. That’s what I’m trying to the in the figure above. Besides, I discovered that you can also get alpha waves if you only stare at one specific point.

helicopter4.png
Figure 2. Me staring at an specific point to get alpha waves.

If you don’t believe me, the guys from Futurism did a live stream video at OpenBCI HQ and you can watch it or downloaded here. Enjoy it!

Leave a Reply