Mindflex EEG

I've been following this Tutorial and have since got everything to work. The code is rather complicated tho and I want to write a simple sketch that can change the color of the screen using based on the values I'm getting from the arduino. I however do not know what variable I need to get the serial data. I need help please!

// Main controller / model file for the the Processing Brain Grapher.

// See README.markdown for more info.
// See http://frontiernerds.com/brain-hack for a tutorial on getting started with the Arduino Brain Library and this Processing Brain Grapher.

// Latest source code is on https://github.com/kitschpatrol/Processing-Brain-Grapher
// Created by Eric Mika in Fall 2010, updates Spring 2012, early 2014, and Spring 2016.

import processing.serial.*;
import controlP5.*;

ControlP5 controlP5;

Serial serial;

Channel[] channels = new Channel[11];
Monitor[] monitors = new Monitor[10];
Graph graph;
ConnectionLight connectionLight;

int packetCount = 0;
int globalMax = 0;
String scaleMode;

void setup() {
  // Set up window
  size(1024, 768);
  frameRate(60);
  smooth();
  surface.setTitle("Processing Brain Grapher");  

  // Set up serial connection
  println("Find your Arduino in the list below, note its [index]:\n");

  for (int i = 0; i < Serial.list().length; i++) {
    println("[" + i + "] " + Serial.list()[i]);
  }

  // Put the index found above here:
  serial = new Serial(this, Serial.list()[3], 9600);

  serial.bufferUntil(10);

  // Set up the ControlP5 knobs and dials
  controlP5 = new ControlP5(this);

  controlP5.setColorValueLabel(color(0));
  controlP5.setColorCaptionLabel(color(0)); 
  controlP5.setColorBackground(color(0));
  controlP5.disableShortcuts(); 
  controlP5.setMouseWheelRotation(0);
  controlP5.setMoveable(false);

  // Create the channel objects
  channels[0] = new Channel("Signal Quality", color(0), "");
  channels[1] = new Channel("Attention", color(100), "");
  channels[2] = new Channel("Meditation", color(50), "");
  channels[3] = new Channel("Delta", color(219, 211, 42), "Dreamless Sleep");
  channels[4] = new Channel("Theta", color(245, 80, 71), "Drowsy");
  channels[5] = new Channel("Low Alpha", color(237, 0, 119), "Relaxed");
  channels[6] = new Channel("High Alpha", color(212, 0, 149), "Relaxed");
  channels[7] = new Channel("Low Beta", color(158, 18, 188), "Alert");
  channels[8] = new Channel("High Beta", color(116, 23, 190), "Alert");
  channels[9] = new Channel("Low Gamma", color(39, 25, 159), "Multi-sensory processing");
  channels[10] = new Channel("High Gamma", color(23, 26, 153), "???");

  // Manual override for a couple of limits.
  channels[0].minValue = 0;
  channels[0].maxValue = 200;
  channels[1].minValue = 0;
  channels[1].maxValue = 100;
  channels[2].minValue = 0;
  channels[2].maxValue = 100;
  channels[0].allowGlobal = false;
  channels[1].allowGlobal = false;
  channels[2].allowGlobal = false;

  // Set up the monitors, skip the signal quality
  for (int i = 0; i < monitors.length; i++) {
    monitors[i] = new Monitor(channels[i + 1], i * (width / 10), height / 2, width / 10, height / 2);
  }

  monitors[monitors.length - 1].w += width % monitors.length;

  // Set up the graph
  graph = new Graph(0, 0, width, height / 2);

  // Set yup the connection light
  connectionLight = new ConnectionLight(width - 140, 10, 20);
}

void draw() {
  // Keep track of global maxima
  if (scaleMode == "Global" && (channels.length > 3)) {
    for (int i = 3; i < channels.length; i++) {
      if (channels[i].maxValue > globalMax) globalMax = channels[i].maxValue;
    }
  }

  // Clear the background
  background(255);

  // Update and draw the main graph
  graph.update();
  graph.draw();

  // Update and draw the connection light
  connectionLight.update();
  connectionLight.draw();

  // Update and draw the monitors
  for (int i = 0; i < monitors.length; i++) {
    monitors[i].update();
    monitors[i].draw();
  }
}

void serialEvent(Serial p) {
  // Split incoming packet on commas
  // See https://github.com/kitschpatrol/Arduino-Brain-Library/blob/master/README for information on the CSV packet format

  String incomingString = p.readString().trim();
  print("Received string over serial: ");
  println(incomingString);  

  String[] incomingValues = split(incomingString, ',');

  // Verify that the packet looks legit
  if (incomingValues.length > 1) {
    packetCount++;

    // Wait till the third packet or so to start recording to avoid initialization garbage.
    if (packetCount > 3) {

      for (int i = 0; i < incomingValues.length; i++) {
        String stringValue = incomingValues[i].trim();

      int newValue = Integer.parseInt(stringValue);

        // Zero the EEG power values if we don't have a signal.
        // Can be useful to leave them in for development.
        if ((Integer.parseInt(incomingValues[0]) == 200) && (i > 2)) {
          newValue = 0;
        }

        channels[i].addDataPoint(newValue);
      }
    }
  } 
}


// Utilities

// Extend Processing's built-in map() function to support the Long datatype
long mapLong(long x, long in_min, long in_max, long out_min, long out_max) { 
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// Extend Processing's built-in constrain() function to support the Long datatype
long constrainLong(long value, long min_value, long max_value) {
  if (value > max_value) return max_value;
  if (value < min_value) return min_value;
  return value;
}
class Channel {
  // Value object class to store EEG power information for each channel.
  // One instance per EEG channel.

  String name;
  int drawColor;
  String description;
  boolean graphMe;
  boolean relative;
  int maxValue;
  int minValue;
  ArrayList points;
  boolean allowGlobal;

  Channel(String _name, int _drawColor, String _description) {
    name = _name;
    drawColor = _drawColor;
    description = _description;
    allowGlobal = true;
    points = new ArrayList();
  }

  void addDataPoint(int value) {
    long time = System.currentTimeMillis();

    if (value > maxValue) maxValue = value;
    if (value < minValue) minValue = value;

    points.add(new Point(time, value));
  }

  Point getLatestPoint() {
    if (points.size() > 0) {
      return (Point)points.get(points.size() - 1);
    }
    else {
      return new Point(0, 0);
    }
  }
}
class Monitor {
  // View class showing a bar-graph of each channel's 
  // One instance per EEG channel.

  int x, y, w, h, currentValue, targetValue, backgroundColor;
  Channel sourceChannel;
  CheckBox showGraph;   
  Textlabel label;
  Toggle toggle;

  Monitor(Channel _sourceChannel, int _x, int _y, int _w, int _h) {
    sourceChannel = _sourceChannel;
    x = _x;
    y = _y;
    w = _w;
    h = _h;
    currentValue = 0;
    backgroundColor = color(255);

    // Create GUI
    showGraph = controlP5.addCheckBox("showGraph" + sourceChannel.name, x + 16, y + 32);
    showGraph.addItem("GRAPH" + sourceChannel.name, 0);
    showGraph.activate(1);
    showGraph.setColorForeground(sourceChannel.drawColor);
    showGraph.setColorActive(color(180));
    showGraph.setColorBackground(color(0));

    toggle = showGraph.getItem(0);
    toggle.setLabel("GRAPH"); 

    label = new Textlabel(controlP5, sourceChannel.name.toUpperCase(), x + 12, y + 15);
    label.setColorValue(0);
  }

  void update() {
    sourceChannel.graphMe = (showGraph.getItem(0).getValue() == 0);
  }

  void draw() {
    pushMatrix();
    translate(x, y);

    // Background
    noStroke();
    fill(backgroundColor);
    rect(0, 0, w, h);

    // Border line
    strokeWeight(1);
    stroke(220);
    line(w - 1, 0, w - 1, h);

    // Bar graph
    if (sourceChannel.points.size() > 0) {
      Point targetPoint = (Point)sourceChannel.points.get(sourceChannel.points.size() - 1);
      targetValue = round(map(targetPoint.value, sourceChannel.minValue, sourceChannel.maxValue, 0, h));

      if ((scaleMode == "Global") && sourceChannel.allowGlobal) {                   
        targetValue = (int)map(targetPoint.value, 0, globalMax, 0, h);
        background (0);
      } 

      // Calculate the new position on the way to the target with easing
      currentValue = currentValue + round(((float)(targetValue - currentValue) * .08));

      // Bar
      noStroke();
      fill(sourceChannel.drawColor);
      rect(0, h - currentValue, w, h);
    }

    // Draw the checkbox matte
    noStroke();
    fill(240, 150);     
    rect(10, 10, w - 20, 40);

    popMatrix();
    label.draw();
  }
}
class Point {
  // Value object class to store time / value tuple. 
  // One instance per data point per channel.
  long time;
  int value;

  Point(long _time, int _value) {
    time = _time;
    value = _value;
  }
}
class Graph {
  // View class to draw a graph of the channel model's values over time.
  // Used as a singleton.

  int x, y, w, h, pixelsPerSecond, gridColor, gridX, originalW, originalX;
  long leftTime, rightTime, gridTime;
  boolean scrollGrid;
  String renderMode;
  float gridSeconds;
  Slider pixelSecondsSlider;
  RadioButton renderModeRadio;
  RadioButton scaleRadio;

  Graph(int _x, int _y, int _w, int _h) {
    x = _x;
    y = _y;
    w = _w;
    h = _h;

    pixelsPerSecond = 50;
    gridColor = color(0);
    gridSeconds = 1; // seconds per grid line
    scrollGrid = false;

    originalW = w;
    originalX = x;    

    // Set up GUI controls
    pixelSecondsSlider = controlP5.addSlider("PIXELS PER SECOND", 10, width, 50, 16, 16, 100, 10);
    pixelSecondsSlider.setColorForeground(color(180));
    pixelSecondsSlider.setColorActive(color(180));
    pixelSecondsSlider.setColorValueLabel(color(255));

    renderModeRadio = controlP5.addRadioButton("RENDER MODE", 16, 36);
    renderModeRadio.setColorForeground(color(255));
    renderModeRadio.setColorActive(color(0));
    renderModeRadio.setColorBackground(color(180));
    renderModeRadio.setSpacingRow(4);    
    renderModeRadio.addItem("Lines", 1);
    renderModeRadio.addItem("Curves", 2);
    renderModeRadio.addItem("Shaded", 3);
    renderModeRadio.addItem("Triangles", 4);

    renderModeRadio.activate(0);

    scaleRadio = controlP5.addRadioButton("SCALE MODE", 104, 36);
    scaleRadio.setColorForeground(color(255));
    scaleRadio.setColorActive(color(0));
    scaleRadio.setColorBackground(color(180));
    scaleRadio.setSpacingRow(4);    
    scaleRadio.addItem("Local Maximum", 1);
    scaleRadio.addItem("Global Maximum", 2);        
    scaleRadio.activate(0);
  }

  void update() {
    // Set pixels per second from GUI slider
    pixelsPerSecond = round(pixelSecondsSlider.getValue());

    // Set render mode from GUI radio buttons
    switch (round(renderModeRadio.getValue())) {
    case 1:
      renderMode = "Lines";
      break;
    case 2:
      renderMode = "Curves";
      break;
    case 3:
      renderMode = "Shaded";
      break;
    case 4:
      renderMode = "Triangles";
      break;
    }

    // Set scale mode from GUI radio buttons
    switch(round(scaleRadio.getValue())) {
    case 1:
      scaleMode = "Local";
      break;
    case 2:
      scaleMode = "Global";
      break;
    }

    // Smooth drawing kludge
    w = originalW;
    x = originalX;    

    w += (pixelsPerSecond * 2);
    x -= pixelsPerSecond;

    // Figure out the left and right time bounds of the graph, based on
    // the pixels per second value
    rightTime = System.currentTimeMillis();
    leftTime = rightTime - ((w / pixelsPerSecond) * 1000);
  }

  void draw() {
    pushMatrix();
    translate(x, y);

    // Background



    fill(220);
    rect(0, 0, w, h);

    // Draw the background graph paper grid
    strokeWeight(1);
    stroke(255);

    if (scrollGrid) {
      // Start from the first whole second and work right           
      gridTime = (rightTime / (long)(1000 * gridSeconds)) * (long)(1000 * gridSeconds);
    }
    else {
      gridTime = rightTime;
    }

    while (gridTime >= leftTime) {
      int gridX = (int)mapLong(gridTime, leftTime, rightTime, 0L, (long)w);
      line(gridX, 0, gridX, h);
      gridTime -= (long)(1000 * gridSeconds);
    }

    // Draw square horizontal grid for now
    int gridY = h;
    while (gridY >= 0) {
      gridY -= pixelsPerSecond * gridSeconds; 
      line(0, gridY, w, gridY);
    }

    // Draw each channel
    noFill();               
    if (renderMode == "Shaded" || renderMode == "Triangles") noStroke();        
    if (renderMode == "Curves" || renderMode == "Lines") strokeWeight(2);

    for (int i = 0; i < channels.length; i++) {
      Channel thisChannel = channels[i];

      if (thisChannel.graphMe) {
        // Draw the graph line
        if (renderMode == "Lines" || renderMode == "Curves") stroke(thisChannel.drawColor);

        if (renderMode == "Shaded" || renderMode == "Triangles") {
          noStroke();
          fill(thisChannel.drawColor, 120);
        }

        if (renderMode == "Triangles") {
          beginShape(TRIANGLES);
        } 
        else {
          beginShape();
        }

        if (renderMode == "Curves" || renderMode == "Shaded") vertex(0, h);

        for (int j = 0; j < thisChannel.points.size(); j++) {
          Point thisPoint = (Point)thisChannel.points.get(j);

          // check bounds
          if ((thisPoint.time >= leftTime) && (thisPoint.time <= rightTime)) {

            int pointX = (int)mapLong(thisPoint.time, leftTime, rightTime, 0L, (long)w);
            int pointY = 0;

            if ((scaleMode == "Global") && (i > 2)) {
              // Global scale                   
              pointY = (int)map(thisPoint.value, 0, globalMax, h, 0);
            }
            else {
              // Local scale
              pointY = (int)map(thisPoint.value, thisChannel.minValue, thisChannel.maxValue, h, 0);
            }

            if (renderMode == "Curves") {
              curveVertex(pointX, pointY);
            }
            else {
              vertex(pointX, pointY);
            }
          }
        }
      }

      if (renderMode == "Curves" || renderMode == "Shaded") vertex(w, h);
      if (renderMode == "Lines" || renderMode == "Curves" || renderMode == "Triangles") endShape();
      if (renderMode == "Shaded") endShape(CLOSE);
    }

    popMatrix();

    // GUI background matte
    noStroke();
    fill(255, 150);
    rect(10, 10, 195, 81);
  }
}
class ConnectionLight {
  // View class to display EEG connection strength.
  // Used as a singleton.

  int x, y, diameter, latestConnectionValue;
  int currentColor = 0;
  int goodColor = color(0, 255, 0);
  int badColor = color(255, 255, 0);
  int noColor = color(255, 0, 0);
  Textlabel label;
  Textlabel packetsRecievedLabel;

  ConnectionLight(int _x, int _y, int _diameter) {
    x = _x;
    y = _y;
    diameter = _diameter;

    // Set up the text label
    label = new Textlabel(controlP5, "CONNECTION QUALITY", 32, 11, 200, 30);
    label.setMultiline(true);   
    label.setColorValue(color(0));

    packetsRecievedLabel = new Textlabel(controlP5, "PACKETS RECEIVED: 0", 5, 35, 200, 30);
    packetsRecievedLabel.setMultiline(false);  
    packetsRecievedLabel.setColorValue(color(0));    
  }

  void update() {
    // Show red if no packets yet
    if (channels[0].points.size() == 0) {
      latestConnectionValue = 200;
    }
    else {
      latestConnectionValue = channels[0].getLatestPoint().value;
    }

    if (latestConnectionValue == 200) currentColor = noColor;
    if (latestConnectionValue < 200) currentColor = badColor;
    if (latestConnectionValue == 00) currentColor = goodColor;

    packetsRecievedLabel.setText("PACKETS RECIEVED: " + packetCount);

  }

  void draw() {
    pushMatrix();
    translate(x, y);

    noStroke();
    fill(255, 150);
    rect(0, 0, 132, 50);

    noStroke();
    fill(currentColor);
    ellipseMode(CORNER);
    ellipse(5, 4, diameter, diameter);

    label.draw();
   packetsRecievedLabel.draw();         
    popMatrix();
  }
}

`

Tagged:

Answers

  • Edit post, highlight code, press ctrl-o to format.

  • Okay Thanks, I was wondering about the formating. All I want to do is use the data to change the tint() of a video ...which isnt in the code yet but first I need to find what the hell makes this thing tick! THanks

Sign In or Register to comment.