I have always been fascinated with using nature as a medium for interaction and a source for new creation, especially in the area of music.
WaterBox is a musical loop station where depending on the user’s physical interaction with water plays different loops either individually or simultaneously. And, the track type changes depending on the roughness of the waves and ripples of the water surface. The final product is created using Kinect v2 to capture the waves of the water surface by its depth, and Touche Advanced Touch Sensor with Arduino for the capacitative sensor and interaction with water. Through the WaterBox, I wanted to share the rich feeling of interacting with water and fun of creating different music with physical motion of your hands in the water.
In terms of technical side, the project entails the use of Arduino Uno, a Kinect v2, a container to contain shallow level of water, and a stand that will hold the Kinect in place above the container pointing towards the water. The container was created with transparent acrylic with 18cm x 18cm x 15cm in dimension where the bottom was colored blue for clear detection of the Kinect v2.
The ideal instance of a user interaction would be where users would play around with the water, creating different waves and ripples on the surface. And, depending on the number of fingers (or, to be more precise, the surface area of your hand), different loops will be played on top of one another. Meanwhile, the kinect will capture the depth of the water, and depending on the roughness of the waves, it will change the track of the loops played.
Here are some of user-testing footages:
Development Stages
Initial Stage of using water with Kinect & Sound
Connecting Touche Sensor with Water & Sound
<Source Code>
Processing*
- Main Code
- Graph Class Library (Touche Advance Sensor)
- Serial Link (Touche Advanced Sensor)
import org.openkinect.processing.*; import processing.sound.*; int trackType = 6; int trackCount = 4; int currentTrackType = 0; int counter = 0; String trackName; /* ============ Touche Advanced Touch Sensor ============== Source: https://github.com/Illutron/AdvancedTouchSensing ======================================================== */ Graph MyArduinoGraph = new Graph(150, 80, 500, 300, color (200, 20, 20)); float[][] gesturePoints = new float[4][2]; float[] gestureDist = new float[4]; String[] names = {"Nothing", "One Finger", "Two Finger", "Hand In Water"}; /* ===================================================== */ /* ==== Music Loops ==== */ SoundFile[][] soundPlayers = new SoundFile[trackType][trackCount]; //array to hold the volumes/rate for each track float[] volumes = new float[trackCount]; //array to hold the volume/rate destinations, to smoothly fade in and out float[] volumeDestinations = new float[trackCount]; /* ===================== */ /* ==== Kinect Code ==== */ Kinect2 kinect2; // Min & Max Threshold for Calibration float minThresh = 570; float maxThresh = 690; boolean isSwitched; PImage img, video; /* ====================== */ void setup() { size(1000, 900); // ==== Touche Setup Code ==== // PortSelected=8; SerialPortSetup(); // ============================ // for (int j=0; j < 6; j++) { // ==== NAMING EACH TRACK IN THE SOUND PLAYER 2D ARRAY ==== // if (j==0) { trackName = "deep"; } else if (j==1) { trackName = "edm"; } else if (j==2) { trackName = "hiphop"; } else if (j==3) { trackName = "jazz"; } else if (j==4) { trackName = "latin"; } else { trackName = "slow"; } for (int i=0; i < soundPlayers[j].length; i++) { String name = trackName; name += str(i); name += ".wav"; println(name); soundPlayers[j][i] = new SoundFile(this, name); soundPlayers[j][i].loop(); soundPlayers[j][i].amp(0.001); volumes[i]=0; volumeDestinations[i]=0; } } // Kinect Initialization kinect2 = new Kinect2(this); kinect2.initRegistered(); kinect2.initDepth(); kinect2.initDevice(); img = createImage(kinect2.depthWidth, kinect2.depthHeight, RGB); isSwitched = false; } void draw() { background(255); int pixelCount = 0; float minDepthLevel = maxThresh; // Getting soundIndex for Touche Sensor int soundIndex = advancedTouch(); /* ===================================================== */ img.loadPixels(); video = kinect2.getRegisteredImage(); int[] depth = kinect2.getRawDepth(); // Detect Pixels using Kinect for (int x = 0; x < kinect2.depthWidth; x++) { for (int y = 0; y < kinect2.depthHeight; y++) { int index = x + y * kinect2.depthWidth; int d = depth[index]; if (d > minThresh && d < maxThresh && red(video.pixels[index]) < 100 && green(video.pixels[index]) > 180 && blue(video.pixels[index]) > 170 // Boundaries to capture only the box on the screen && 215 < x && 350 > x && 125 < y && 265 > y ) { pixelCount++; img.pixels[index] = color(red(video.pixels[index]), green(video.pixels[index]), blue(video.pixels[index])); if (d < minDepthLevel) { minDepthLevel = d; } } else { img.pixels[index] = color(0); } } } /* ========DEBUG CODE======== */ int mouseIndex = mouseX%kinect2.depthWidth + mouseY%kinect2.depthHeight * kinect2.depthWidth; text(red(video.pixels[mouseIndex]), 600, 600); text(green(video.pixels[mouseIndex]), 600, 650); text(blue(video.pixels[mouseIndex]), 600, 700); text(mouseX, 600, 750); text(mouseY-480, 680, 750); text(pixelCount, 600, 780); text(minDepthLevel, 680, 780); text(currentTrackType, 880, 780); /* ========================== */ img.updatePixels(); // Uncomment below if you want to see whether the Kinect is catching the water pixels //image(img, 0, 480); noStroke(); /* ========== Calibration Needed depending on space / light ========== */ // If the catched pixcelCount is in between 300 and 400 & the whole hand is in the water, // then change the track type. if ( pixelCount >= 300 && pixelCount <= 400 && minDepthLevel <= 590 &&soundIndex == 3 && !isSwitched) { counter++; if(counter > 800) { isSwitched = true; currentTrackType++; currentTrackType %= 6; } } else if (isSwitched) { isSwitched = false; counter = 0; } /* =================================================================== */ if (soundIndex > 1) { for (int i=1; i< soundIndex+1; i++) { volumeDestinations[i-1] = 1; if (soundIndex == 3) { volumeDestinations[i] = 1; } } } else if (soundIndex == 1) { volumeDestinations[0] = 1; } for (int j=0; j<soundPlayers.length; j++) { for (int i=0; i<soundPlayers[j].length; i++) { if (j != currentTrackType) { // set other tracks amplitude to zero soundPlayers[j][i].amp(0); } else { //set volume volumes[i]=smoothing(volumes[i], volumeDestinations[i]); soundPlayers[j][i].amp(volumes[i]); //continuously fade volume out volumeDestinations[i]-=.1; //constrian the fade out to 0 volumeDestinations[i] = constrain(volumeDestinations[i],0,1); } } } } //smoothing for fading in and out float smoothing(float current, float destination) { current += (destination-current)*.5; return current; } int advancedTouch() { /* =============================================================== Touche Advanced Touch Sensor Code =============================================================== */ if ( DataRecieved3 ) { pushMatrix(); pushStyle(); MyArduinoGraph.yMax=600; MyArduinoGraph.yMin=-200; MyArduinoGraph.xMax=int (max(Time3)); //MyArduinoGraph.DrawAxis(); MyArduinoGraph.smoothLine(Time3, Voltage3); popStyle(); popMatrix(); /* ==================================================================== Gesture compare ==================================================================== */ float totalDist = 0; int currentMax = 0; float currentMaxValue = -1; for (int i = 0; i < 4;i++) { //println("Index: " + i); //println(gesturePoints[i][0], gesturePoints[i][1]); // Calibration for each category if (mousePressed && mouseX > 750 && mouseX<800 && mouseY > 100*(i+1) && mouseY < 100*(i+1) + 50) { fill(255, 0, 0); gesturePoints[i][0] = Time3[MyArduinoGraph.maxI]; gesturePoints[i][1] = Voltage3[MyArduinoGraph.maxI]; } else { fill(255, 255, 255); } //calucalte individual dist gestureDist[i] = dist(Time3[MyArduinoGraph.maxI], Voltage3[MyArduinoGraph.maxI], gesturePoints[i][0], gesturePoints[i][1]); totalDist = totalDist + gestureDist[i]; if(gestureDist[i] < currentMaxValue || i == 0) { currentMax = i; currentMaxValue = gestureDist[i]; } } totalDist=totalDist/3; for (int i = 0; i < 4;i++) { float currentAmount = 0; currentAmount = 1-gestureDist[i]/totalDist; if(currentMax == i) { fill(0,0,0); //text(names[i],50,450); fill(currentAmount*255.0f, 0, 0); } else { fill(255,255,255); } stroke(0, 0, 0); rect(750, 100 * (i+1), 50, 50); fill(0,0,0); textSize(30); text(names[i],810,100 * (i+1)+25); fill(255, 0, 0); rect(800,100* (i+1), max(0,currentAmount*50),50); } return currentMax; } return 0; }
/* ================================================================================= The Graph class contains functions and variables that have been created to draw graphs. Here is a quick list of functions within the graph class: Graph(int x, int y, int w, int h,color k) DrawAxis() Bar([]) smoothLine([][]) DotGraph([][]) LineGraph([][]) =================================================================================*/ class Graph { float maxY = 0; float maxX = 0; int maxI = 0; boolean Dot=true; // Draw dots at each data point if true boolean RightAxis; // Draw the next graph using the right axis if true boolean ErrorFlag=false; // If the time array isn't in ascending order, make true boolean ShowMouseLines=true; // Draw lines and give values of the mouse position int xDiv=5, yDiv=5; // Number of sub divisions int xPos, yPos; // location of the top left corner of the graph int Width, Height; // Width and height of the graph color GraphColor; color BackgroundColor=color(255); color StrokeColor=color(180); String Title="Title"; // Default titles String xLabel="x - Label"; String yLabel="y - Label"; float yMax=1024, yMin=0; // Default axis dimensions float xMax=10, xMin=0; float yMaxRight=1024, yMinRight=0; Graph(int x, int y, int w, int h, color k) { // The main declaration function xPos = x; yPos = y; Width = w; Height = h; GraphColor = k; } void DrawAxis() { /* ========================================================================================= Main axes Lines, Graph Labels, Graph Background ========================================================================================== */ fill(BackgroundColor); color(0); stroke(StrokeColor); strokeWeight(1); int t=60; rect(xPos-t*1.6, yPos-t, Width+t*2.5, Height+t*2); // outline textAlign(CENTER); textSize(18); float c=textWidth(Title); fill(BackgroundColor); color(0); stroke(0); strokeWeight(1); rect(xPos+Width/2-c/2, yPos-35, c, 0); // Heading Rectangle fill(0); text(Title, xPos+Width/2, yPos-37); // Heading Title textAlign(CENTER); textSize(14); text(xLabel, xPos+Width/2, yPos+Height+t/1.5); // x-axis Label rotate(-PI/2); // rotate -90 degrees text(yLabel, -yPos-Height/2, xPos-t*1.6+20); // y-axis Label rotate(PI/2); // rotate back textSize(10); noFill(); stroke(0); smooth(); strokeWeight(1); //Edges line(xPos-3, yPos+Height, xPos-3, yPos); // y-axis line line(xPos-3, yPos+Height, xPos+Width+5, yPos+Height); // x-axis line stroke(200); if (yMin<0) { line(xPos-7, // zero line yPos+Height-(abs(yMin)/(yMax-yMin))*Height, // xPos+Width, yPos+Height-(abs(yMin)/(yMax-yMin))*Height ); } if (RightAxis) { // Right-axis line stroke(0); line(xPos+Width+3, yPos+Height, xPos+Width+3, yPos); } /* ========================================================================================= Sub-devisions for both axes, left and right ========================================================================================== */ stroke(0); for (int x=0; x<=xDiv; x++) { /* ========================================================================================= x-axis ========================================================================================== */ line(float(x)/xDiv*Width+xPos-3, yPos+Height, // x-axis Sub devisions float(x)/xDiv*Width+xPos-3, yPos+Height+5); textSize(10); // x-axis Labels String xAxis=str(xMin+float(x)/xDiv*(xMax-xMin)); // the only way to get a specific number of decimals String[] xAxisMS=split(xAxis, '.'); // is to split the float into strings text(xAxisMS[0]+"."+xAxisMS[1].charAt(0), // ... float(x)/xDiv*Width+xPos-3, yPos+Height+15); // x-axis Labels } /* ========================================================================================= left y-axis ========================================================================================== */ for (int y=0; y<=yDiv; y++) { line(xPos-3, float(y)/yDiv*Height+yPos, // ... xPos-7, float(y)/yDiv*Height+yPos); // y-axis lines textAlign(RIGHT); fill(20); String yAxis=str(yMin+float(y)/yDiv*(yMax-yMin)); // Make y Label a string String[] yAxisMS=split(yAxis, '.'); // Split string text(yAxisMS[0]+"."+yAxisMS[1].charAt(0), // ... xPos-15, float(yDiv-y)/yDiv*Height+yPos+3); // y-axis Labels /* ========================================================================================= right y-axis ========================================================================================== */ if (RightAxis) { color(GraphColor); stroke(GraphColor); fill(20); line(xPos+Width+3, float(y)/yDiv*Height+yPos, // ... xPos+Width+7, float(y)/yDiv*Height+yPos); // Right Y axis sub devisions textAlign(LEFT); String yAxisRight=str(yMinRight+float(y)/ // ... yDiv*(yMaxRight-yMinRight)); // convert axis values into string String[] yAxisRightMS=split(yAxisRight, '.'); // text(yAxisRightMS[0]+"."+yAxisRightMS[1].charAt(0), // Right Y axis text xPos+Width+15, float(yDiv-y)/yDiv*Height+yPos+3); // it's x,y location noFill(); } stroke(0); } } /* ========================================================================================= Bar graph ========================================================================================== */ void Bar(float[] a, int from, int to) { stroke(GraphColor); fill(GraphColor); if (from<0) { // If the From or To value is out of bounds for (int x=0; x<a.length; x++) { // of the array, adjust them rect(int(xPos+x*float(Width)/(a.length)), yPos+Height-2, Width/a.length-2, -a[x]/(yMax-yMin)*Height); } } else { for (int x=from; x<to; x++) { rect(int(xPos+(x-from)*float(Width)/(to-from)), yPos+Height-2, Width/(to-from)-2, -a[x]/(yMax-yMin)*Height); } } } void Bar(float[] a ) { stroke(GraphColor); fill(GraphColor); for (int x=0; x<a.length; x++) { // of the array, adjust them rect(int(xPos+x*float(Width)/(a.length)), yPos+Height-2, Width/a.length-2, -a[x]/(yMax-yMin)*Height); } } /* ========================================================================================= Dot graph ========================================================================================== */ void DotGraph(float[] x, float[] y) { for (int i=0; i<x.length; i++) { strokeWeight(2); stroke(GraphColor); noFill(); smooth(); ellipse( xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height, 2, 2 ); } } /* ========================================================================================= Streight line graph ========================================================================================== */ void LineGraph(float[] x, float[] y) { for (int i=0; i<(x.length-1); i++) { strokeWeight(2); stroke(GraphColor); noFill(); smooth(); line(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height, xPos+(x[i+1]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i+1]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height); } } /* ========================================================================================= smoothLine ========================================================================================== */ void smoothLine(float[] x, float[] y) { float tempyMax=yMax, tempyMin=yMin; if (RightAxis) { yMax=yMaxRight; yMin=yMinRight; } int xlocation=0, ylocation=0; // if(!ErrorFlag |true ){ // sort out later! beginShape(); strokeWeight(6); stroke(GraphColor); noFill(); smooth(); maxY = 0; //find max for (int i=0; i<x.length; i++) { if (maxY < y[i]) { maxY =y[i]; maxI = i; } } for (int i=0; i<x.length; i++) { /* =========================================================================== Check for errors-> Make sure time array doesn't decrease (go back in time) ===========================================================================*/ if (i<x.length-1) { if (x[i]>x[i+1]) { ErrorFlag=true; } } /* ================================================================================= First and last bits can't be part of the curve, no points before first bit, none after last bit. So a streight line is drawn instead ================================================================================= */ if (i==0 || i==x.length-2)line(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height, xPos+(x[i+1]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i+1]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height); /* ================================================================================= For the rest of the array a curve (spline curve) can be created making the graph smooth. ================================================================================= */ curveVertex( xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height); /* ================================================================================= If the Dot option is true, Place a dot at each data point. ================================================================================= */ if (i == maxI) { ellipse( xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height, 20, 20 ); } if (Dot)ellipse( xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width, yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height, 2, 2 ); /* ================================================================================= Highlights points closest to Mouse X position =================================================================================*/ if ( abs(mouseX-(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width))<5 ) { float yLinePosition = yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height; float xLinePosition = xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width; strokeWeight(1); stroke(240); // line(xPos,yLinePosition,xPos+Width,yLinePosition); strokeWeight(2); stroke(GraphColor); ellipse(xLinePosition, yLinePosition, 4, 4); } } endShape(); yMax=tempyMax; yMin=tempyMin; float xAxisTitleWidth=textWidth(str(map(xlocation, xPos, xPos+Width, x[0], x[x.length-1]))); if ((mouseX>xPos&mouseX<(xPos+Width))&(mouseY>yPos&mouseY<(yPos+Height))) { if (ShowMouseLines) { // if(mouseX<xPos)xlocation=xPos; if (mouseX>xPos+Width)xlocation=xPos+Width; else xlocation=mouseX; stroke(200); strokeWeight(0.5); fill(255); color(50); // Rectangle and x position line(xlocation, yPos, xlocation, yPos+Height); rect(xlocation-xAxisTitleWidth/2-10, yPos+Height-16, xAxisTitleWidth+20, 12); textAlign(CENTER); fill(160); text(map(xlocation, xPos, xPos+Width, x[0], x[x.length-1]), xlocation, yPos+Height-6); // if(mouseY<yPos)ylocation=yPos; if (mouseY>yPos+Height)ylocation=yPos+Height; else ylocation=mouseY; // Rectangle and y position stroke(200); strokeWeight(0.5); fill(255); color(50); line(xPos, ylocation, xPos+Width, ylocation); //int yAxisTitleWidth=int(textWidth(str(map(ylocation, yPos, yPos+Height, y[0], y[y.length-1]))) ); rect(xPos-15+3, ylocation-6, -60, 12); textAlign(RIGHT); fill(GraphColor);//StrokeColor // text(map(ylocation,yPos+Height,yPos,yMin,yMax),xPos+Width+3,yPos+Height+4); text(map(ylocation, yPos+Height, yPos, yMin, yMax), xPos -15, ylocation+4); if (RightAxis) { stroke(200); strokeWeight(0.5); fill(255); color(50); rect(xPos+Width+15-3, ylocation-6, 60, 12); textAlign(LEFT); fill(160); text(map(ylocation, yPos+Height, yPos, yMinRight, yMaxRight), xPos+Width+15, ylocation+4); } noStroke(); noFill(); } } } void smoothLine(float[] x, float[] y, float[] z, float[] a ) { GraphColor=color(188, 53, 53); smoothLine(x, y); GraphColor=color(193-100, 216-100, 16); smoothLine(z, a); } }
import processing.serial.*; int SerialPortNumber=2; int PortSelected=2; /* ================================================================================= Global variables =================================================================================*/ int xValue, yValue, Command; boolean Error=true; boolean UpdateGraph=true; int lineGraph; int ErrorCounter=0; int TotalRecieved=0; /* ================================================================================= Local variables =================================================================================*/ boolean DataRecieved1=false, DataRecieved2=false, DataRecieved3=false; float[] DynamicArrayTime1, DynamicArrayTime2, DynamicArrayTime3; float[] Time1, Time2, Time3; float[] Voltage1, Voltage2, Voltage3; float[] current; float[] DynamicArray1, DynamicArray2, DynamicArray3; float[] PowerArray= new float[0]; // Dynamic arrays that will use the append() float[] DynamicArrayPower = new float[0]; // function to add values float[] DynamicArrayTime= new float[0]; String portName; String[] ArrayOfPorts=new String[SerialPortNumber]; boolean DataRecieved=false, Data1Recieved=false, Data2Recieved=false; int incrament=0; int NumOfSerialBytes=8; // The size of the buffer array int[] serialInArray = new int[NumOfSerialBytes]; // Buffer array int serialCount = 0; // A count of how many bytes received int xMSB, xLSB, yMSB, yLSB; // Bytes of data Serial myPort; // The serial port object /* ================================================================================= A once off serail port setup function. In this case the selection of the speed, the serial port and clearing the serial port buffer =================================================================================*/ void SerialPortSetup() { // text(Serial.list().length,200,200); portName= Serial.list()[PortSelected]; ArrayOfPorts=Serial.list(); println(ArrayOfPorts); myPort = new Serial(this, portName, 115200); //delay(50); //myPort.clear(); //myPort.buffer(20); } /* ============================================================ serialEvent will be called when something is sent to the serial port being used. ============================================================ */ void serialEvent(Serial myPort) { while (myPort.available ()>0) { /* ============================================================ Read the next byte that's waiting in the buffer. ============================================================ */ int inByte = myPort.read(); myPort.write(0); if (inByte==0)serialCount=0; if (inByte>255) { println(" inByte = "+inByte); exit(); } // Add the latest byte from the serial port to array: serialInArray[serialCount] = inByte; serialCount++; Error=true; if (serialCount >= NumOfSerialBytes ) { serialCount = 0; TotalRecieved++; int Checksum=0; // Checksum = (Command + yMSB + yLSB + xMSB + xLSB + zeroByte)%255; for (int x=0; x<serialInArray.length-1; x++) { Checksum=Checksum+serialInArray[x]; } Checksum=Checksum%255; if (Checksum==serialInArray[serialInArray.length-1]) { Error = false; DataRecieved=true; } else { Error = true; // println("Error: "+ ErrorCounter +" / "+ TotalRecieved+" : "+float(ErrorCounter/TotalRecieved)*100+"%"); DataRecieved=false; ErrorCounter++; println("Error: "+ ErrorCounter +" / "+ TotalRecieved+" : "+float(ErrorCounter/TotalRecieved)*100+"%"); } } if (!Error) { int zeroByte = serialInArray[6]; // println (zeroByte & 2); xLSB = serialInArray[3]; if ( (zeroByte & 1) == 1) xLSB=0; xMSB = serialInArray[2]; if ( (zeroByte & 2) == 2) xMSB=0; yLSB = serialInArray[5]; if ( (zeroByte & 4) == 4) yLSB=0; yMSB = serialInArray[4]; if ( (zeroByte & 8) == 8) yMSB=0; // println( "0\tCommand\tyMSB\tyLSB\txMSB\txLSB\tzeroByte\tsChecksum"); // println(serialInArray[0]+"\t"+Command +"\t"+ yMSB +"\t"+ yLSB +"\t"+ xMSB +"\t"+ xLSB+"\t" +zeroByte+"\t"+ serialInArray[7]); // >=====< combine bytes to form large integers >==================< // Command = serialInArray[1]; xValue = xMSB << 8 | xLSB; // Get xValue from yMSB & yLSB yValue = yMSB << 8 | yLSB; // Get yValue from xMSB & xLSB // println(Command+ " "+xValue+" "+ yValue+" " ); /* How that works: if xMSB = 10001001 and xLSB = 0100 0011 xMSB << 8 = 10001001 00000000 (shift xMSB left by 8 bits) xLSB = 01000011 xLSB | xMSB = 10001001 01000011 combine the 2 bytes using the logic or | xValue = 10001001 01000011 now xValue is a 2 byte number 0 -> 65536 */ /* ================================================================== Command, xValue & yValue have now been recieved from the chip ================================================================== */ switch(Command) { /* ================================================================== Recieve array1 and array2 from chip, update oscilloscope ================================================================== */ case 1: // Data is added to dynamic arrays DynamicArrayTime3=append( DynamicArrayTime3, (xValue) ); DynamicArray3=append( DynamicArray3, (yValue) ); break; case 2: // An array of unknown size is about to be recieved, empty storage arrays DynamicArrayTime3= new float[0]; DynamicArray3= new float[0]; break; case 3: // Array has finnished being recieved, update arrays being drawn Time3=DynamicArrayTime3; Voltage3=DynamicArray3; // println(Voltage3.length); DataRecieved3=true; break; /* ================================================================== Recieve array2 and array3 from chip ================================================================== */ case 4: // Data is added to dynamic arrays DynamicArrayTime2=append( DynamicArrayTime2, xValue ); DynamicArray2=append( DynamicArray2, (yValue-16000.0)/32000.0*20.0 ); break; case 5: // An array of unknown size is about to be recieved, empty storage arrays DynamicArrayTime2= new float[0]; DynamicArray2= new float[0]; break; case 6: // Array has finnished being recieved, update arrays being drawn Time2=DynamicArrayTime2; current=DynamicArray2; DataRecieved2=true; break; /* ================================================================== Recieve a value of calculated power consumption & add it to the PowerArray. ================================================================== */ case 20: PowerArray=append( PowerArray, yValue ); break; case 21: DynamicArrayTime=append( DynamicArrayTime, xValue ); DynamicArrayPower=append( DynamicArrayPower, yValue ); break; } } } redraw(); // } }
Arduino* (Touche Advanced Sensor)
//**************************************************************************************** // Illutron take on Disney style capacitive touch sensor using only passives and Arduino // Dzl 2012 //**************************************************************************************** // 10n // PIN 9 --[10k]-+-----10mH---+--||-- OBJECT // | | // 3.3k | // | V 1N4148 diode // GND | // | //Analog 0 ---+------+--------+ // | | // 100pf 1MOmhm // | | // GND GND #define SET(x,y) (x |=(1<<y)) //-Bit set/clear macros #define CLR(x,y) (x &= (~(1<<y))) // | #define CHK(x,y) (x & (1<<y)) // | #define TOG(x,y) (x^=(1<<y)) //-+ #define N 160 //How many frequencies float results[N]; //-Filtered result buffer float freq[N]; //-Filtered result buffer int sizeOfArray = N; void setup() { TCCR1A=0b10000010; //-Set up frequency generator TCCR1B=0b00011001; //-+ ICR1=110; OCR1A=55; pinMode(9,OUTPUT); //-Signal generator pin pinMode(8,OUTPUT); //-Sync (test) pin Serial.begin(115200); for(int i=0;i<N;i++) //-Preset results results[i]=0; //-+ } void loop() { unsigned int d; int counter = 0; for(unsigned int d=0;d<N;d++) { int v=analogRead(0); //-Read response signal CLR(TCCR1B,0); //-Stop generator TCNT1=0; //-Reload new frequency ICR1=d; // | OCR1A=d/2; //-+ SET(TCCR1B,0); //-Restart generator results[d]=results[d]*0.5+(float)(v)*0.5; //Filter results freq[d] = d; } PlottArray(1,freq,results); TOG(PORTB,0); //-Toggle pin 8 after each sweep (good for scope) }
byte yMSB=0, yLSB=0, xMSB=0, xLSB=0, zeroByte=128, Checksum=0; void SendData(int Command, unsigned int yValue,unsigned int xValue){ /* >=================================================================< y = 01010100 11010100 (x & y are 2 Byte integers) yMSB yLSB send seperately -> reciever joins them >=================================================================< */ yLSB=lowByte(yValue); yMSB=highByte(yValue); xLSB=lowByte(xValue); xMSB=highByte(xValue); /* >=================================================================< Only the very first Byte may be a zero, this way allows the computer to know that if a Byte recieved is a zero it must be the start byte. If data bytes actually have a value of zero, They are given the value one and the bit in the zeroByte that represents that Byte is made high. >=================================================================< */ zeroByte = 128; // 10000000 if(yLSB==0){ yLSB=1; zeroByte=zeroByte+1;} // Make bit 1 high if(yMSB==0){ yMSB=1; zeroByte=zeroByte+2;} // make bit 2 high if(xLSB==0){ xLSB=1; zeroByte=zeroByte+4;} // make bit 3 high if(xMSB==0){ xMSB=1; zeroByte=zeroByte+8;} // make bit 4 high /* >=================================================================< Calculate the remainder of: sum of all the Bytes divided by 255 >=================================================================< */ Checksum = (Command + yMSB + yLSB + xMSB + xLSB + zeroByte)%255; if( Checksum !=0 ){ int inByte = Serial.read(); Serial.write(byte(0)); // send start bit Serial.write(byte(Command)); // command eg: Which Graph is this data for Serial.write(byte(yMSB)); // Y value's most significant byte Serial.write(byte(yLSB)); // Y value's least significant byte Serial.write(byte(xMSB)); // X value's most significant byte Serial.write(byte(xLSB)); // X value's least significant byte Serial.write(byte(zeroByte)); // Which values have a zero value Serial.write(byte(Checksum)); // Error Checking Byte } } void PlottArray(unsigned int Cmd,float Array1[],float Array2[]){ SendData(Cmd+1, 1,1); // Tell PC an array is about to be sent delay(1); for(int x=0; x < sizeOfArray; x++){ // Send the arrays SendData(Cmd, round(Array1[x]),round(Array2[x])); //delay(1); } SendData(Cmd+2, 1,1); // Confirm arrrays have been sent }