I have made a mind map with MindMeister, which shows how to connect the Emotiv EPOC to Arduino and/or Processing for developing your own mind-controlled applications including interactive art, music, data visualizations, games, neurofeedback, and robot controllers. Link to map (in case embedded map does not work for you): http://www.mindmeister.com/214762396/emotiv-epoc-processing-arduino
Generative Sigils
Related articles: TAD2011.06 Lorenz Attractor | Processing + EPOC via OSC
In his book, Chaos in Wonderland: Visual Adventures in a Fractal World, Clifford Pickover describes methods for generating beautiful, complex images from certain chaotic equations. In the context of the book’s narrative, these images are the dreams of a species of inorganic, computer-like entities called the Latööcarfians — the “dream-weavers of Ganymede.” Here I consider using these images as algorithmically generated magical sigils (cf., generative art).
The images are generated by recursively plotting:
xt + 1 = sin(ytb) + c sin(xtb)
yt + 1 = sin(xta) + d sin(yta)
(There are variant equations that produce “mutations” — see “Appendix A: Mutations of Equations”, pp. 209–210.) Here is a sketch that will draw the following image in Processing:
/** Generative Sigil 1 * Joshua Madara, hyperRitual.com * Based on code on pg. 26 of _Chaos in Wonderland_ * by Clifford A. Pickover * Good ranges for a, b, c, and d: * (-3 < a, b < 3) * (0.5 < c, d < 1.5) */ float a = 1.5641136; float b = 2.7102947; float c = 0.9680385; float d = 0.995141; float x, y = 0.1; int counter = 0; int iterations = 500000; void setup() { size(700,700,P2D); // remove P2D for Processing v2.0 background(0); // black stroke(255,255,255,90); // white, semi-transparent } void draw() { println(counter); translate(width/2, height/2); // draw from center of window float xNew = sin(y*b) + c * (sin(x*b)); float yNew = sin(x*a) + d * (sin(y*a)); x = xNew; y = yNew; point(x*100, y*100); counter++; if(counter >= iterations) { println("done!"); noLoop(); } }
I hypothesize that the key to using such images successfully as magical sigils is to assign non-trivial values to the inputs, a, b, c, and d. E.g., one could randomly generate the values at an auspicious moment, or acquire values from some act or object, and map those to the optimal ranges for the algorithm’s inputs. The magician could wear the Emotiv EPOC during a magical ritual and at the ritual’s apex a Processing sketch could map data from the EPOC to the a, b, c, and d values for generating the image. The images could subsequently be used for divination or evocation.
N.b., even while keeping the input values within optimal ranges, not all sets of values produce interesting images. Here is a Processing function to calculate the set’s Lyapunov exponent (based on the code on p. 62 of Chaos in Wonderland) — values >= 0.5 tend to be more interesting:
float calcLyapunovExponent(float a, float b, float c, float d) { float Lsum = 0; float n = 0; float x = 0.1; float y = 0.1; float xe = x + 0.000001; float ye = y; float xx, yy, xsave, ysave, dLx, dLy, dL2, df, rs, L = 0; float bigNumber = 2139095039; /* Pickover's algorithm calls for a long int (1000000000000) here, but I often get NaN returned when using it in Processing, and I have found that using a large float returns a value close enough to Pickover's to be useful. */ for(int i=0; i<10000000; i++) { xx = sin(y*b) + c*sin(x*b); yy = sin(x*a) + d*sin(y*a); xsave = xx; ysave = yy; x = xe; y = ye; n++; xx = sin(y*b) + c*sin(x*b); yy = sin(x*a) + d*sin(y*a); dLx = xx - xsave; dLy = yy - ysave; dL2 = dLx*dLx + dLy*dLy; df = bigNumber*dL2; rs = 1/sqrt(df); xe = xsave + rs*(xx - xsave); ye = ysave + rs*(yy - ysave); xx = xsave; yy = ysave; Lsum = Lsum + log(df); L = 0.721347*Lsum/n; x = xx; y = yy; } return L; }
Mind-Controlled Robots @ Seattle Mini Maker Faire
For those who attended mine and my daughter Chloe’s presentation on mind-controlled robots, today, here are some details about the tech we used.
Magabot Arduino+laptop-based robot: http://magabot.cc/
Emotiv EPOC neuroheadset: http://emotiv.com/
Mind Your OSCs: http://sourceforge.net/projects/mindyouroscs/
oscP5 library for Processing: http://www.sojamo.de/libraries/oscP5/
Here is the Processing code I used to read the OSC data from the EPOC and send serial signals to the Arduino:
/** * NeuroMagabot * by Joshua Madara, hyperritual.com * * Transforms data from the Emotiv EPOC neuroheadset * to control data for the Magabot, via OSC. */ import processing.serial.*; import oscP5.*; import netP5.*; Serial port; OscP5 oscP5; float thresh = 0.25; // one threshold for all Cognitiv values void setup() { size(200, 200); println(Serial.list()); port = new Serial(this, Serial.list()[0], 9600); //start oscP5, listening for incoming messages at port 7400 //make sure this matches the port in Mind Your OSCs oscP5 = new OscP5(this, 7400); // plug the messages for the Cognitiv values oscP5.plug(this,"sendW","/COG/PUSH"); oscP5.plug(this,"sendS","/COG/PULL"); oscP5.plug(this,"sendA","/COG/LEFT"); oscP5.plug(this,"sendD","/COG/RIGHT"); } void draw() { // here you could graph the EPOC data, draw an animated face on the laptop screen, etc. } public void sendW(float val) { if (val >= thresh) { port.write('w'); // send move-forward command to Arduino } else { port.write('p'); // send stop command } } public void sendS(float val) { if (val >= thresh) { port.write('s'); // send move-reverse command to Arduino } else { port.write('p'); } } public void sendA(float val) { if (val >= thresh) { port.write('a'); // send turn-left command to Arduino } else { port.write('p'); } } public void sendD(float val) { if (val >= thresh) { port.write('d'); // send turn-right command to Arduino } else { port.write('p'); } }
The Arduino code is the Magabot_SerialControl sketch for Magabot (protocol = ‘H’).
Arcana Manor: A Ceremonial Magick Simulator
Jeff Howard, author of Quests: Design, Theory, and History in Games and Narratives, has been developing a ceremonial magic simulator with EPOC and Kinect interfaces. Check it out.
TAD2011.02 Emotiv EPOC Video Recorder
Second TAD project (with video). [2013.12.09: the TAD website has been offline for a while now]
Here is the source code:
/** * EPOC Recorder 1 * by Joshua Madara, hyperRitual.com * This sketch records graphical data from the Emotiv * EPOC via OSC messages, as a .mov video file. */ import oscP5.*; import processing.video.*; // declare objects OscP5 oscP5; MovieMaker mm; Format formatter; PFont miniMono; Date time; int barColor = (color(255,0,0)); void setup() { size(320, 240); background(0); rectMode(CORNERS); // listen for OSC messages on port 7400 oscP5 = new OscP5(this, 7400); // plug the messages from COG/PUSH to function makeFrame() oscP5.plug(this,"makeFrame","/COG/PUSH"); // load MiniMono font miniMono = loadFont("MiniMono.vlw"); textFont(miniMono); // format timestamp formatter = new SimpleDateFormat("HH:mm:ss:SSS"); // Create MovieMaker object with size, filename, // framerate, compression codec and quality mm = new MovieMaker(this, width, height, "epoc_record.mov", 30, MovieMaker.H263, MovieMaker.LOSSLESS); } void draw() { // not used } // for each new event, add a frame to the video void makeFrame(float pushValue) { background(0); // clear screen // update and draw timestamp and COG/PUSH value /* note that the time here is the local time when the event is recorded, not a count-up timer that initiates when recording begins, although that could be implemented */ time = new Date(); String timestamp = formatter.format(time); fill(255); text("Time: "+timestamp+" Value: "+pushValue, 5, 10); // draw horizontal lines for (int i = 0; i <= 10; i++) { stroke(map(i, 0, 10, 255, 0)); float yPos = map(i, 0, 10, 20, 220); line(100, yPos, 220, yPos); } // draw bar float barHeight = map(pushValue, 0, 1, 220, 20); noStroke(); fill(barColor, 100); rect(width/2 - 20, 220, width/2 + 20, barHeight); // write pixels to video frame mm.addFrame(); } // press space bar to finish the video void keyPressed() { if (key == ' ') { mm.finish(); } }