final _ the code — three concepts for chimes + plus a bonus

I chose to work with the headset’s “Meditation” values — the idea of meditation, or relaxation,  seemed to fit nicely with wind chimes. I  experimented with three different scenarios. Here they are, along with the code.

1) meditation by quintiles.

Meditation values are delivered to the Arduino on a scale of 0-100. There are 6 chimes. I decided to attached EEG to 5 of them, and leave one as the “observer” — a concept I picked up from reading about Mindfullness meditation. So, I divided the meditation values into quintiles and deliverd them to the wind chime via five independent muscle wires (all powered by the same 12V external power supply, but each attached to a separate pin on the UNO and passing through individuals MOSFETs.

FYI Also, using PWM, I drove Meditation (and sometimes Attention) values to an LED as a visual cue that the headset was delivering data.

SEE CODE at bottom of post (1/2)

Here is a basic schematic I have drawn to illustrate the wiring of the wind chime.

 

2) Bandwave values

One of the most exciting moments for me during this project was the decision to tap into the bandwave values and tie them to the Arduino.

EEG bandwaves (as they relate to the Mindwave headset are as follows:

delta // 0.5 – 2.75Hz

theta  // 3.5 – 6.75Hz

lowAlpha // 7.5 – 9.25Hz

highAlpha // 10 – 11.75Hz

lowBeta // 13 – 16.75Hz

highBeta  // 18 – 29.75Hz

lowGamma // 31 – 39.75Hz

highGamma // 41 – 49.75Hz

I had to do a little research: basically find the the Neursosky literature that explained how I could access the bandwaves. It didn’t take too long. Inside the original code provided by Neurosky, there is the “case 0x83”. That’s where you access the bandwaves — however, what is the specific code used to do it? I experimented with writing my own, but got only one value output for all of the bands. I looked around. Finally, I discovered a Processing sketch that had accomplished what I wanted to do. So I adapted that code to Arduino – and it worked!

see the code below (2/2).

Here is a pic of the output.

PROBLEM: all that extra work seemed to really slow down the Arduino. I saw lots of chugging going on in the serial monitor – and so I  decided not to work with the bandwave data.

3) pwm meditation

Lastly, I drove all of the Meditation data through a single pin, using PWM. So that the higher the M-values, the more current passed through to the muscle wires, causing(in theory) more activity.

OUTCOME:

I experimented with all of these scenarios, hoping that one might actually trigger some chimes. But ultimately, the mechanics of making the wind chime “chime” was the problem.  I should have consulted Jim, as he had mentioned to me that he had worked with muscle wire. I had run out of time. But I am very excited about what I did accomplish:

— a Nitinol PWM circuit

— the Mindwave hack

— accessing the EEG bandwave values via some reseacrh and tweaking code

— powering muscle wire with EEG input!

–> I will keep experimenting with EEG, muscle wire and … wind chimes. I am still excited by the project.

 

4) BONUS!

…earlier on in the project, I used PWM to power an analog meter I found at Active Surplus — this was for kicks. But I thought it could be used to illustrate Attention values that were active during Meditation sessions on the chimes.

–> I was helped by a nice fellow at the Integrated Media wing to figure out how much voltage would power the meter. It turned out that the range for the meter was 0 – 0.3 DC. After consulting with Jim, the first step was to try PWM, and map the headset values  to “0 and (0.3/5)*255 = 15”.

I found that I had to go much lower, and map between 0 and 4.

But it worked! (the first time – the next few times the meter only tracked about 1/3 of the entire spectrum?!?)

What became obvious here was that the headset data was being transmitted 1/s. I already knew this, but you really see it with the meter.

I mocked up a new graphic for the meter – a sort of spoofy Design Fiction meter that reads when and what kind of memory is being formed by the headset user.

HERE IS THE CODE FOR WINDCHIMES

/*

Project Title: MindChimes
Group Member: Mark Thoburn

Course Code & Title: Creation and Computation DIGF6B02
OCAD University

Created: November, 2011

Based on:
Arduino Bluetooth Interface with Mindwave (example code provided by NeuroSky, Inc.)
NeuroSky MindSet packet parser for Processing, by Rory Nugent, Last updated October 27th, 2009

 

*/

//START analogWrite code
int MusclePin = 3;
int MuscleValue;
int MinWaveValue;

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
//END analogWrite code

#define LED 13
#define BAUDRATE 115200
#define DEBUGOUTPUT 0
//#define BLUESMIRFON 2

#define MEDITATION0 5
#define MEDITATION1 6
#define MEDITATION2 7
#define MEDITATION3 8
#define MEDITATION4 9
//#define MEDITATION5 10
#define MINDWAVE A0

// checksum variables
byte generatedChecksum = 0;
byte checksum = 0;
int payloadLength = 0;
byte payloadData[64] = {
0};
byte poorQuality = 0;
byte attention = 0;
byte meditation = 0;

// system variables
long lastReceivedPacket = 0;
boolean bigPacket = false;

void setup() {

//START analoWrite code
pinMode(MusclePin, OUTPUT);

// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
//    END analogWrite code

pinMode(MINDWAVE, OUTPUT);
pinMode(MEDITATION0, OUTPUT);
pinMode(MEDITATION1, OUTPUT);
pinMode(MEDITATION2, OUTPUT);
pinMode(MEDITATION3, OUTPUT);
pinMode(MEDITATION4, OUTPUT);
//pinMode(MEDITATION5, OUTPUT);
pinMode(LED, OUTPUT);
//pinMode(BLUESMIRFON, OUTPUT);
//digitalWrite(BLUESMIRFON, HIGH);
Serial.begin(BAUDRATE);           // USB
delay(3000) ;
Serial.print(194,BYTE) ;

}

// Read data from Serial UART //

byte ReadOneByte() {
int ByteRead;
while(!Serial.available());
ByteRead = Serial.read();
#if DEBUGOUTPUT
Serial.print((char)ByteRead);   // echo the same byte out the USB serial (for debug purposes)
#endif

return ByteRead;
}

void loop() {

// Look for sync bytes
if(ReadOneByte() == 170) {
if(ReadOneByte() == 170) {

payloadLength = ReadOneByte();
if(payloadLength > 169)                      //Payload length can not be greater than 169
return;

generatedChecksum = 0;
for(int i = 0; i < payloadLength; i++) {
payloadData[i] = ReadOneByte();            //Read payload into memory
generatedChecksum += payloadData[i];
}

checksum = ReadOneByte();                      //Read checksum byte from stream
generatedChecksum = 255 – generatedChecksum;   //Take one’s compliment of generated checksum

if(checksum == generatedChecksum) {

poorQuality = 200;
attention = 0;
meditation = 0;

for(int i = 0; i < payloadLength; i++) {    // Parse the payload
switch (payloadData[i]) {
case 2:
i++;
poorQuality = payloadData[i];
bigPacket = true;
break;
case 4:
i++;
attention = payloadData[i];
break;
case 5:
i++;
meditation = payloadData[i];
break;
case 0x80:
i = i + 3;
break;

case 0x83:
i = i + 25;
break;
default:
break;
} // switch
} // for loop

#if !DEBUGOUTPUT

// *** Add your code here ***

if(bigPacket) {
if(poorQuality == 0)
digitalWrite(LED, HIGH);
else
digitalWrite(LED, LOW);
Serial.print(“PoorQuality: “);
Serial.print(poorQuality, DEC);
Serial.print(” Attention: “);
Serial.print(attention, DEC);

Serial.print(” Meditation: “);
Serial.print(meditation, DEC);

if(meditation > 40)
digitalWrite(MEDITATION1, HIGH);
else
digitalWrite(MEDITATION1, LOW);

Serial.print(” Time since last packet: “);
Serial.print(millis() – lastReceivedPacket, DEC);
lastReceivedPacket = millis();
Serial.print(“n”);

// START analoREAD code
//MinWaveValue = analogRead(MinWavePin);
MinWaveValue = analogRead(attention);
MuscleValue = map(MinWaveValue, 0, 100, 0, 4);
analogWrite(MusclePin, MuscleValue);
Serial.println(MinWaveValue);

// subtract the last reading:
total= total – readings[index];
// read from the sensor:
readings[index] = analogRead(attention);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;

// if we’re at the end of the array…
if (index >= numReadings)
// …wrap around to the beginning:
index = 0;

// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println(average);

//  END analogWrite code

switch(meditation / 6) {

case 0:
digitalWrite(MEDITATION0, HIGH);
digitalWrite(MEDITATION1, LOW);
digitalWrite(MEDITATION2, LOW);
digitalWrite(MEDITATION3, LOW);
digitalWrite(MEDITATION4, LOW);
//digitalWrite(MEDITATION5, LOW);
break;

case 1:
digitalWrite(MEDITATION0, LOW);
digitalWrite(MEDITATION1, HIGH);
digitalWrite(MEDITATION2, LOW);
digitalWrite(MEDITATION3, LOW);
digitalWrite(MEDITATION4, LOW);
//digitalWrite(MEDITATION5, LOW);

break;
case 2:
digitalWrite(MEDITATION0, LOW);
digitalWrite(MEDITATION1, LOW);
digitalWrite(MEDITATION2, HIGH);
digitalWrite(MEDITATION3, LOW);
digitalWrite(MEDITATION4, LOW);
//digitalWrite(MEDITATION5, LOW);

break;
case 3:
digitalWrite(MEDITATION0, LOW);
digitalWrite(MEDITATION1, LOW);
digitalWrite(MEDITATION2, LOW);
digitalWrite(MEDITATION3, HIGH);
digitalWrite(MEDITATION4, LOW);
//digitalWrite(MEDITATION5, LOW);

break;
case 4:
digitalWrite(MEDITATION0, LOW);
digitalWrite(MEDITATION1, LOW);
digitalWrite(MEDITATION2, LOW);
digitalWrite(MEDITATION3, LOW);
digitalWrite(MEDITATION4, HIGH);
digitalWrite(MEDITATION5, LOW);

break;
case 5:
digitalWrite(MEDITATION0, LOW);
digitalWrite(MEDITATION1, LOW);
digitalWrite(MEDITATION2, LOW);
digitalWrite(MEDITATION3, LOW);
digitalWrite(MEDITATION4, LOW);
//digitalWrite(MEDITATION5, HIGH);
break;

}
}

#endif
bigPacket = false;
}

else {
// Checksum Error
}  // end if else for checksum
} // end if read 0xAA byte
} // end if read 0xAA byte
}

HERE IS THE CODE FOR *BANDWAVES AND *MEMORY METER.

/*

THIS CODE CONTAINS TWO EXPERIMENTS THAT WORKED OUT WELL:
1) I accessed EEG bandwave data by adapting an existing Processing sketch
2) I powered a $5 analog meter bought at Active Surplus,
using PWM and mapping headset values (0-100) to the meter’s voltage input (0-0.3 volts).

<>

Project Title: MindChimes
Group Member: Mark Thoburn

Course Code & Title: Creation and Computation DIGF6B02
OCAD University

Created: November, 2011

Based on:
Arduino Bluetooth Interface with Mindwave (example code provided by NeuroSky, Inc.)
NeuroSky MindSet packet parser for Processing, by Rory Nugent, Last updated October 27th, 2009

Wiring:
Inputs:
Outputs:

*/

//START analogWrite code
int MusclePin = 3;
int MuscleValue;
int MinWaveValue;

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average

//END analogWrite code
#define LED 13
#define BAUDRATE 115200
#define DEBUGOUTPUT 0
//#define BLUESMIRFON 2

#define MEDITATION1 6
#define MEDITATION2 7
#define MEDITATION3 8
#define MEDITATION4 9
#define MEDITATION5 10

#define MINDWAVE A0

// checksum variables
byte generatedChecksum = 0;
byte checksum = 0;
int payloadLength = 0;
byte payloadData[64] = {
0};
byte poorQuality = 0;
byte attention = 0;
byte meditation = 0;

//byte payloadData[24] = {
//  0};

byte delta = 0;// 0.5 – 2.75Hz
byte theta = 0;// 3.5 – 6.75Hz
byte lowAlpha = 0;// 7.5 – 9.25Hz
byte highAlpha = 0;// 10 – 11.75Hz
byte lowBeta = 0;// 13 – 16.75Hz
byte highBeta = 0; // 18 – 29.75Hz
byte lowGamma = 0; // 31 – 39.75Hz
byte highGamma = 0;// 41 – 49.75Hz

// system variables
long lastReceivedPacket = 0;
boolean bigPacket = false;

void setup() {

//START analoWrite code

pinMode(MusclePin, OUTPUT);

// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
//    END analogWrite code

pinMode(MINDWAVE, OUTPUT);
pinMode(MEDITATION1, OUTPUT);
pinMode(MEDITATION2, OUTPUT);
pinMode(MEDITATION3, OUTPUT);
pinMode(MEDITATION4, OUTPUT);
pinMode(MEDITATION5, OUTPUT);
pinMode(LED, OUTPUT);
//pinMode(BLUESMIRFON, OUTPUT);
//digitalWrite(BLUESMIRFON, HIGH);
Serial.begin(BAUDRATE);           // USB
delay(3000) ;
Serial.print(194,BYTE) ;

}

// Read data from Serial UART //

byte ReadOneByte() {
int ByteRead;
while(!Serial.available());
ByteRead = Serial.read();
#if DEBUGOUTPUT
Serial.print((char)ByteRead);   // echo the same byte out the USB serial (for debug purposes)
#endif

return ByteRead;
}

//MAIN LOOP//

void loop() {

// Look for sync bytes
if(ReadOneByte() == 170) {
if(ReadOneByte() == 170) {

payloadLength = ReadOneByte();
if(payloadLength > 169)                      //Payload length can not be greater than 169
return;

generatedChecksum = 0;
for(int i = 0; i < payloadLength; i++) {
payloadData[i] = ReadOneByte();            //Read payload into memory
generatedChecksum += payloadData[i];
}

checksum = ReadOneByte();                      //Read checksum byte from stream
generatedChecksum = 255 – generatedChecksum;   //Take one’s compliment of generated checksum

if(checksum == generatedChecksum) {

poorQuality = 200;
attention = 0;
meditation = 0;

lowAlpha = 0;
highAlpha = 0;
lowBeta = 0;
highBeta = 0;
lowGamma = 0;
highGamma = 0;
theta = 0;

for(int i = 0; i < payloadLength; i++) {    // Parse the payload
switch (payloadData[i]) {

case 2:
i++;
poorQuality = payloadData[i];
bigPacket = true;
break;

case 4:
i++;
attention = payloadData[i];
break;

case 5:
i++;
meditation = payloadData[i];
break;

case 0x80:
i = i + 3;
break;

case 0x83:  // EEG DATA EEG DATA _ adapted from a Processing sketch _ see above
{
int eegData [24];
int bytesParsed = 0;
//i = i +25;

for(int i = 0; i < payloadLength; i++){

eegData[i] = (int)payloadData[bytesParsed + i];
}

delta = ((eegData[0] << 16) | (eegData[1] << 8)) | eegData[2];
theta = ((eegData[3] << 16) | (eegData[4] << 8)) | eegData[5];
lowAlpha = ((eegData[6] << 16) | (eegData[7] << 8)) | eegData[8];
highAlpha = ((eegData[9] << 16) | (eegData[10] << 8)) | eegData[11];
lowBeta = ((eegData[12] << 16) | (eegData[13] << 8)) | eegData[14];
highBeta = ((eegData[15] << 16) | (eegData[16] << 8)) | eegData[17];
lowGamma = ((eegData[18] << 16) | (eegData[19] << 8)) | eegData[20];
highGamma = ((eegData[21] << 16) | (eegData[22] << 8)) | eegData[23];
}
break;

default:
break;

} // switch
} // for loop

#if !DEBUGOUTPUT

// *** Add your code here ***

if(bigPacket) {
if(poorQuality == 0)
digitalWrite(LED, HIGH);
else
digitalWrite(LED, LOW);
Serial.print(“PoorQuality: “);
Serial.print(poorQuality, DEC);

Serial.print(” Attention: “);
Serial.print(attention, DEC);
Serial.print(” Meditation: “);
Serial.print(meditation, DEC);

Serial.print(” lowAlpha: “);
Serial.print(lowAlpha, DEC);
Serial.print(” highAlpha: “);
Serial.print(highAlpha, DEC);

Serial.print(” lowBeta: “);
Serial.print(lowBeta, DEC);
Serial.print(” highbeta: “);
Serial.print(highBeta, DEC);

Serial.print(” lowGamma: “);
Serial.print(lowGamma, DEC);

Serial.print(” highGamma: “);
Serial.print(highGamma, DEC);

Serial.print(” Theta: “);
Serial.print(theta, DEC);

Serial.print(” Delta: “);
Serial.print(delta, DEC);

Serial.print(” Time since last packet: “);
Serial.print(millis() – lastReceivedPacket, DEC);
lastReceivedPacket = millis();
Serial.print(“n”);

// START analoREAD code
//MinWaveValue = analogRead(MinWavePin);
MinWaveValue = analogRead(attention);
MuscleValue = map(MinWaveValue, 0, 100, 0, 4);
analogWrite(MusclePin, MuscleValue);
Serial.println(MinWaveValue);

// subtract the last reading:
total= total – readings[index];
// read from the sensor:
readings[index] = analogRead(attention);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;

// if we’re at the end of the array…
if (index >= numReadings)
// …wrap around to the beginning:
index = 0;

// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println(average);

//  END analogWrite code

/*switch(attention / 10) {

case 0:
digitalWrite(GREENLED1, LOW);
digitalWrite(GREENLED2, LOW);
digitalWrite(GREENLED3, LOW);
digitalWrite(YELLOWLED1, LOW);
digitalWrite(YELLOWLED2, LOW);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;

case 1:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, LOW);
digitalWrite(GREENLED3, LOW);
digitalWrite(YELLOWLED1, LOW);
digitalWrite(YELLOWLED2, LOW);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 2:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, LOW);
digitalWrite(YELLOWLED1, LOW);
digitalWrite(YELLOWLED2, LOW);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 3:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, LOW);
digitalWrite(YELLOWLED2, LOW);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 4:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, LOW);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 5:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, LOW);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 6:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, HIGH);
digitalWrite(YELLOWLED4, LOW);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 7:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, HIGH);
digitalWrite(YELLOWLED4, HIGH);
digitalWrite(REDLED1, LOW);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 8:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, HIGH);
digitalWrite(YELLOWLED4, HIGH);
digitalWrite(REDLED1, HIGH);
digitalWrite(REDLED2, LOW);
digitalWrite(REDLED3, LOW);
break;
case 9:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, HIGH);
digitalWrite(YELLOWLED4, HIGH);
digitalWrite(REDLED1, HIGH);
digitalWrite(REDLED2, HIGH);
digitalWrite(REDLED3, LOW);
break;
case 10:
digitalWrite(GREENLED1, HIGH);
digitalWrite(GREENLED2, HIGH);
digitalWrite(GREENLED3, HIGH);
digitalWrite(YELLOWLED1, HIGH);
digitalWrite(YELLOWLED2, HIGH);
digitalWrite(YELLOWLED3, HIGH);
digitalWrite(YELLOWLED4, HIGH);
digitalWrite(REDLED1, HIGH);
digitalWrite(REDLED2, HIGH);
digitalWrite(REDLED3, HIGH);
break;

*/

if(meditation > 40){
digitalWrite(MEDITATION1, HIGH);
}
else
{
digitalWrite(MEDITATION1, LOW);
}

if (highAlpha > 30 && < 60) {
digitalWrite (MEDITATION1, HIGH);
} else {
digitalWrite(MEDITATION1, LOW);
}

if (lowBeta =>20 && =< 50) {
digitalWrite (MEDITATION2, HIGH);
} else {
digitalWrite(MEDITATION2, LOW);
}

theta 20-60
highGamma 10-35
delta -20-60

}
}

#endif
bigPacket = false;
}

else {
// Checksum Error
}  // end if else for checksum
} // end if read 0xAA byte
} // end if read 0xAA byte
}

 

 

 

Comments are closed.