We are about to switch to a new forum software. Until then we have removed the registration on this forum.
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();
}
}
`
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