-
BYOBeamer Event
05/01/2016 at 21:17 • 0 commentsI had the opportunity to setup 2 of the projectors at an art event called BYOB(beamer) and join quite a few other artists showing active and interactive projected projects. The projectors I built received a lot of attention, being the only unconventional projectors and installed in an entry point where they were able to utilize a narrow corridor with quite a bit of ambient light.
See below for some images and video from the event
-
Completed Projector Test
02/26/2016 at 05:00 • 0 commentsWith the addition of a second 12v DC to 5v DC adapter I was able to get enough power to both the LED and the Raspberry Pi.
Here's a shaky video looking into the projector. The next step is to do some keystone correction on the projected image and then test networking between 2 or more of them
And another shot through the back of the projector:
-
Assembly - Complete
02/25/2016 at 05:34 • 0 commentsHere are a couple quick shots of the completed assembly, showing the projector attached to the cymbal stand.
-
Assembly - 3 More
02/25/2016 at 05:22 • 0 commentsOnce the first projector seemed to be working well, I gathered all the parts needed to assemble 3 more projectors. Here are all the components on half of my ping-pong table:
-
Assembly - LED Carriage
02/25/2016 at 05:16 • 0 commentsWith the Flashlight cut down and wired up to a USB cable, the LED carriage could be assembled. Unfortunately, my T-Bolt assembly didn't work that well here. I ended up gluing the nuts into position before assembly so they wouldn't fall out when I loosened things.
-
Assembly - Main
02/25/2016 at 05:12 • 0 commentsAfter a lot of laser cutting, I test fit all of the outer case. The T-Bolt construction worked really well, as long as I was able to hold the nut in place.
-
Hacking the LEDs
02/25/2016 at 05:02 • 0 commentsMy test with 50 Watt LEDs purchased from Sure Electronics did not go well at all. Maybe the driver was under-powered or the LED was faulty. I looked for a plan B and found some decent options at the local hardware store. I picked up a 4 Million Candle Power searchlight (not LED), an LED work-light, and a 1200 Lumen LED Flashlight. Since the Flashlight worked really well reflecting off the flip-dot display using the adjustable focus, I decided to run with that.
The flashlight came with 9 AA batteries, so I assumed the LED had a driver that ran off 12V DC. But, when I took the flashlight apart and hooked my multi-meter up to the battery pack, it read 5V. It must have been using 3 sets of 3 batteries in series, running in parallel.
-
Processing on the Pi - Networking
02/25/2016 at 04:48 • 0 commentsDate: 2/20/2016
With the sequences all animated and timers allowing them to run one after another and looping back to the beginning, the last step was to add the networking. When I was testing the programs, even on a single machine, I got a bunch of errors from incomplete messages. I ended up needing to put in catch statements throughout the "Client" sketch to deal with them. I attempted to save the previous successful frame to be used in place of any that had an error.
Below is the "Client" sketch that works with the Combined 5 sketch. You'll need to adjust the IP address of your Server.
// Client - Panel 2 // // For LinkSprite V3 and AlfaZeta flip-dot display // by Michael Shaub 2016 import processing.serial.*; import processing.net.*; Client c; String input; String goodInput; String lastInput = "0,0,0,0,0,0,0\n"; int data[] = new int[7]; int panelID = 2; int timeout = 100; //how many frames of no signal from the server until I reboot myself //switches boolean drawPreview = true; boolean useSerialPort = false; // The serial port: Serial myPort; int dotSize = 50; //diameter of the dots - for preview int row1 = 0; //hold variable for row1 int row2 = 0; //hold variable for row2 int row3 = 0; //hold variable for row3 int row4 = 0; //hold variable for row4 int row5 = 0; //hold variable for row5 int row6 = 0; //hold variable for row6 int row7 = 0; //hold variable for row7 int dropConnectionCounter = 0; void setup() { size(350, 350); //draw a review of just this one panel background(35); noStroke(); //frameRate(5); ellipseMode(CORNER); noStroke(); // Connect to the server’s IP address and port c = new Client(this, "127.0.0.1", 12345); // Replace with your server’s IP and port // Open the port you are using at the rate you want: if(useSerialPort) myPort = new Serial(this, Serial.list()[0], 57600); } void draw() { // Receive data from server if (c.available() > 0) { dropConnectionCounter = 0; String tempInput = c.readString(); try{ input = tempInput.substring(0,tempInput.indexOf("\n")); // Only up to the newline } catch (StringIndexOutOfBoundsException e) { println("Error at step 1!"); input = null; } if(input == null) { input = lastInput.substring(0,lastInput.indexOf("\n")); // Only up to the newline }else{ lastInput = tempInput; } //println( input ); data = int(split(input, ',')); // Split values into an array // Draw line using received coords bitShiftData(); //crop the data needed for this board drawOnScreen(); //draw on screen printToFlipDots(); //send data out the the flipDot board }else{ dropConnectionCounter++; } if(dropConnectionCounter > 100){ dropConnectionCounter = 0; setup(); } } void drawOnScreen(){ background(35); for(int j=0; j<7; j++){ //String tempBinary = binary(int(data[j]),7); String tempBinary; try{ tempBinary = binary(int(data[j]),7); } catch (ArrayIndexOutOfBoundsException e) { tempBinary = binary(0,7); //just write a blank row println("Error at step 2!"); } for(int i=0; i<7; i++){ int dotValue = int( tempBinary.charAt(i) )-48; //for some reason 1=49 and 0=48 fill( dotValue*255 ); //read pixel values, set fill color to that ellipse(i*dotSize,j*dotSize,dotSize,dotSize); } } } void bitShiftData(){ for(int i=0; i<data.length; i++){ int a = data[i]; //load value of this incoming data (one row) int b = a >> (panelID-1)*7; //bitshift the value based on which panel this is //int b = a; data[i] = b; //update value of data with the shifted one //println(data[i]); } } void printToFlipDots(){ //int test_2[]= {0x80, 0x87, 0xFF, row1, row2, row3, row4, row5, row6, row7, 0x8F}; String arraySet = "set"; int test_2[] = {0x80, 0x87, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0x8F}; for(int i = 3; i < 10; i++){ try{ test_2[i] = data[0-3]; } catch (ArrayIndexOutOfBoundsException e) { println("Error at step 3!"); arraySet = null; } } if(arraySet != null){ for(int i=0; i<test_2.length; i++){ if(useSerialPort) myPort.write(test_2[i]); } } //reset row values for next frame row1 = 0; row2 = 0; row3 = 0; row4 = 0; row5 = 0; row6 = 0; row7 = 0; }
-
Processing on the Pi - Assembly
02/25/2016 at 04:28 • 0 commentsDate: 2/20/2016
The next step in Processing was to put the 3 animations together, with timers to run each for a certain amount of time and then automatically advance to the next. When I was assembling the code for the sequences, I also decided that a fourth sequence of a random dot pattern.
Below is the combined code. This also includes the first attempt to write the pixel display to the networked displays:
// Combined 5 // // For LinkSprite V3 and AlfaZeta flip-dot display // by Michael Shaub 2016 import processing.serial.*; import processing.net.*; //Server and client stuff Server s; Client c; //switches boolean drawPreview = true; boolean useSerialPort = false; // The serial port: Serial myPort; int frameDelay = 50; //variables for flipDot int rowCounter = 0; int row1 = 0; //hold variable for row1 int row2 = 0; //hold variable for row2 int row3 = 0; //hold variable for row3 int row4 = 0; //hold variable for row4 int row5 = 0; //hold variable for row5 int row6 = 0; //hold variable for row6 int row7 = 0; //hold variable for row7 //int rowArray[ ] = {0,0,0,0,0,0,0}; int rowArray[ ] = {0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0}; boolean mirrorX = true; //flip Left & Right? boolean mirrorY = false; //flip Top & Bottom? int dotSize = 50; //diameter of the dots - for preview PImage pix = createImage(28,7, RGB); //PImage to hold the actual size image int pixLength = pix.width*pix.height; //total amount of pixels //snow mode variables boolean drawRow = false; //use to alternate drawing a row of dots or skipping int snowFrameRepeat = 0; int snowFrames = 3; // repeat each snow frame 3 times int snowCounter = 0; int totalSnowFrames = 100; // how many times should we draw snow before moving on to the next mode //gradation mode variables int gradFrameRepeat = 0; int gradFrames = 2; // repeat each snow frame 3 times int gradCounter = 0; int totalGradFrames = 100; // how many times should we draw snow before moving on to the next mode //random mode variables int randCounter = 0; int randLikelyhood = 100; // how unlikely is it that a dot will be added (larger number = less likely) int randTwinkle = 600; // how unlikely is it that a dot will be added (larger number = less likely) float a = 0.0; float inc = TWO_PI/25.0; PGraphics pixOrig; //PGraphics to hold the actual size image PImage text1; PImage text2; PImage text3; int scrollCounter = 0; int textSelector = 1; int modeSelector = 4; //1=Scrolling Text, 2=snow, 3=gradation, 4=random noise //set the number of columns that are being calculated int numColumns = 28; //switch back to 7? void setup(){ size(1400,350); //Server and client stuff s = new Server(this, 12345); // Start a simple server on a port // List all the available serial ports: printArray(Serial.list()); // Open the port you are using at the rate you want: if(useSerialPort) myPort = new Serial(this, Serial.list()[0], 57600); ellipseMode(CORNER); noStroke(); //frameRate(3); text1 = loadImage("artatthemca.png"); //PImage for text image text2 = loadImage("gensler.png"); //PImage for text image text3 = loadImage("fiftyon.png"); //PImage for text image pixOrig = createGraphics(28,7); //PGraphics to hold the actual size image //preset the PImage pix.loadPixels(); for(int i=0; i<pixLength; i++){ pix.pixels[i] = color(0); //set each pixel to black } pix.updatePixels(); } void draw(){ background(35); if(modeSelector > 4) { modeSelector = 1; //reset any values that are too high //println("mode reset to: " + modeSelector); } switch(modeSelector){ case(1): textScroller(); //Draw Text //println("I'm drawing text"); break; case(2): pixelSnow(); //Draw Snow //println("I'm making snow"); break; case(3): //gradation gradation(); //modeSelector = 1; //go back to the beginning break; case(4): //gradation randomSparkle(); //modeSelector = 1; //go back to the beginning break; } if(modeSelector != 2 && modeSelector != 3){ //do dithering biz here pix.loadPixels(); pixOrig.loadPixels(); for(int y=0; y<7; y++){ for(int x=0; x<28; x++){ color oldpixel = pixOrig.get(x, y); color newpixel = findClosestColor( color(brightness(oldpixel) + random(-100,100)) ); //the wider the range of randomness the "softer" the result. Lower is harder edge pix.pixels[x+y*pix.width] = newpixel; //copy colors from one image to the other } } pix.updatePixels(); } if(drawPreview) drawOnScreen(); //draw on screen sendToClients(); //send out to clients printToFlipDots(); //call the flipDot conversion delay (frameDelay); } void drawOnScreen(){ //draw on screen pix.loadPixels(); for(int j=0; j<7; j++){ for(int i=0; i<28; i++){ if(i < numColumns) { //for now, only do for the 1st 7 columns? if(mirrorX){ rowArray[numColumns-1-i] = int( red(pix.pixels[i+j*pix.width])/255); //for now, only do for the 1st 7 columns }else{ rowArray[i] = int( red(pix.pixels[i+j*pix.width])/255); //for now, only do for the 1st 7 columns } //println( rowArray[i] ); } fill( pix.pixels[i+j*pix.width] ); //read pixel values, set fill color to that ellipse(i*dotSize,j*dotSize,dotSize,dotSize); } rowCounter = j; prepDotRow(j); //set the row through bitwise operations } } void prepDotRow(int rowNum){ int tempRowCounter = rowNum+1; if(mirrorY) tempRowCounter = 7-rowNum; //bitshift values from array for(int i=0; i<rowArray.length; i++){ int a = rowArray[i]; int b = a << i; //bitshift the value the number of positions equal to the digit switch(tempRowCounter){ case 1: row1 = row1 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 2: row2 = row2 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 3: row3 = row3 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 4: row4 = row4 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 5: row5 = row5 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 6: row6 = row6 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 7: row7 = row7 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; } } } void sendToClients(){ //send a single string that has comma deliminated values for each row and a line return at the end of the "frame" s.write(row1 + "," + row2 + "," + row3 + "," + row4 + "," + row5 + "," + row6 + "," + row7 + "\n"); } void printToFlipDots(){ int test_2[]= {0x80, 0x87, 0xFF, row1, row2, row3, row4, row5, row6, row7, 0x8F}; //int test_2[]= {0x80, 0x87, 0xFF, 0, rowCounter, scrollCounter, 0, 0, 0, 0, 0x8F}; for(int i=0; i<test_2.length; i++){ if(useSerialPort) myPort.write(test_2[i]); //println(test_2[i]); } //reset row values for next frame row1 = 0; row2 = 0; row3 = 0; row4 = 0; row5 = 0; row6 = 0; row7 = 0; } void randomSparkle() { //MODE 4 //Draw Randomly int totalBright = 0; pixOrig.beginDraw(); //pixOrig.background(0); for(int j=0; j<7; j++){ for(int i=0; i<28; i++){ totalBright += pixOrig.get(i,j)/255 ; //set the fill color to a smooth gradation if(random(randLikelyhood)<1){ //is the random number less than 1? A bigger variable = less likely if(randCounter==0) pixOrig.set(i,j, 255 ); //add a white dot if(randCounter==1) pixOrig.set(i,j, 0 ); //add a black dot } if(random(randTwinkle)<1){ //is the random number less than 1? A bigger variable = less likely pixOrig.set(i,j, 255 ); //add a white dot if(randCounter==1) totalBright++; //add } if(random(randTwinkle)<1){ //is the random number less than 1? A bigger variable = less likely pixOrig.set(i,j, 0 ); //add a black dot if(randCounter==0) totalBright--; //deduct } } } pixOrig.endDraw(); if(totalBright > 28*5.5 && randCounter == 0) randCounter = 1; //start dimming if(totalBright < 28*1.5 && randCounter == 1) { randCounter = 0; //go on to the next mode modeSelector++; } } void pixelSnow() { //MODE 2 //Draw Snow if(snowFrameRepeat > snowFrames){ snowFrameRepeat=0; pix.loadPixels(); //Copy each row of pixels down to the next row for(int j=6; j>0; j--){ //step through every row but the top one, in reverse int wind = round( random(-1,1) ); //set a value to blow the snow to the left, right, or none //println(wind); for(int i=0; i<28; i++){ if(!drawRow && j==6){ //only if this is the bottom row and on a frame when the snow isn't drawn on the top row //skip drawing over the last row this frame }else{ //draw this frame int targetPix; //test boundaries for values if( (i+j*pix.width+wind) < 0){ targetPix = 0; }else{ if( (i+j*pix.width+wind) > 7*pix.width-1){ targetPix = (i+j*pix.width); }else{ targetPix = (i+j*pix.width+wind); } } pix.pixels[targetPix] = pix.pixels[i+(j-1)*pix.width]; //read pixel values, set fill color to the row above } } } //Draw the first row of pixels with random values int lastRand = 0; for(int i=0; i<pix.width; i++){ int randValue = 0; if(drawRow){ randValue = round(random(.6))*255; //randomly black or white, decimal sets how likely it'll be a white dot if(i>0 && lastRand==255){ randValue = 0; //never have 2 white dots in a row } } pix.pixels[i] = color(randValue); //set each pixel to black or white lastRand = randValue; } drawRow = !drawRow; //toggle the variable pix.updatePixels(); snowCounter++; //count the number of snow frames so far } snowFrameRepeat++; if(snowCounter == totalSnowFrames) { modeSelector = 3; //move on to the next mode //println("mode: " + modeSelector); snowCounter = 0; //reset the counter } } void gradation(){ //MODE 3 if(gradFrameRepeat > gradFrames){ gradFrameRepeat=0; //Draw Gradation pixOrig.beginDraw(); pixOrig.background(0); for(int j=0; j<7; j++){ for(int i=0; i<28; i++){ //pixOrig.pixels[i+j*pix.width] = int(128+sin(a)*128.0); //set the fill color to a smooth gradation pixOrig.set(i,j, int(128+sin(a)*128.0) ); //set the fill color to a smooth gradation a = a + inc; } } pixOrig.endDraw(); //do dithering biz here pix.loadPixels(); pixOrig.loadPixels(); for(int y=0; y<7; y++){ for(int x=0; x<28; x++){ color oldpixel = pixOrig.get(x, y); color newpixel = findClosestColor( color(brightness(oldpixel) + random(-100,100)) ); //the wider the range of randomness the "softer" the result. Lower is harder edge pix.pixels[x+y*pix.width] = newpixel; //copy colors from one image to the other } } pix.updatePixels(); if(gradCounter == totalGradFrames) { modeSelector = 1; //move on to the next mode //println("mode: " + modeSelector); gradCounter = 0; //reset the counter }else{ gradCounter++; } } gradFrameRepeat++; } void textScroller(){ //MODE 1 /* if(textSelector > 3) { textSelector = 1; //scrollCounter = 0; modeSelector++; println("mode: " + modeSelector); }*/ //println("drawing text: " + textSelector); //println("scroll counter: " + scrollCounter); //Draw Text pixOrig.beginDraw(); pixOrig.background(0); switch(textSelector){ case(1): pixOrig.image(text1, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; case(2): pixOrig.image(text2, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; case(3): pixOrig.image(text3, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; } pixOrig.endDraw(); switch(textSelector){ case(1): if(scrollCounter > text1.width+pixOrig.width){ scrollCounter = 0; textSelector = 2; modeSelector = 2; //println("mode: " + modeSelector); } break; case(2): if(scrollCounter > text2.width+pixOrig.width){ scrollCounter = 0; textSelector = 3; modeSelector = 2; //println("mode: " + modeSelector); } break; case(3): if(scrollCounter > text3.width+pixOrig.width){ scrollCounter = 0; textSelector = 1; modeSelector = 2; //println("mode: " + modeSelector); } break; } scrollCounter++; } void keyPressed(){ if(key == 'x') mirrorX = ! mirrorX; if(key == 'y') mirrorY = ! mirrorY; } color findClosestColor(color c) { color r; // Treshold function if (brightness(c) < 128) { r = color(0); } else { r = color(255); } return r; }
-
Processing on the Pi – Scrolling Text
02/25/2016 at 04:18 • 0 commentsDate: 2/19/2016
Scrolling text looks great on even the lowest resolution displays. The persistence of vision effect is so strong that the words move by and I never notice the pixels. I remembered some really tiny pixelated typefaces including Silkscreen and thought I could easily get that working in Processing. I got the typeface loaded in Processing just fine, but when I scaled it down to just 5 pixels tall the text was very blurry.
I wasn't sure how to fix that problem so I decided to just make some high-res images with text, scale them down, and display the images. It's not ideal, doesn't allow for any adjustment or customization, but worked just fine for the moment.
Below is a video of text scrolling across the flip-dot display:
Here's a video of the reflection off the display onto the ceiling:
And, after an image of the text I used, the code for scrolling text:
// Scroll Text 2 // // For LinkSprite V3 and AlfaZeta flip-dot display // by Michael Shaub 2016 import processing.serial.*; // The serial port: Serial myPort; int frameDelay = 50; //variables for flipDot int rowCounter = 0; int row1 = 0; //hold variable for row1 int row2 = 0; //hold variable for row2 int row3 = 0; //hold variable for row3 int row4 = 0; //hold variable for row4 int row5 = 0; //hold variable for row5 int row6 = 0; //hold variable for row6 int row7 = 0; //hold variable for row7 int rowArray[ ] = {0,0,0,0,0,0,0}; boolean mirrorX = true; //flip Left & Right? boolean mirrorY = false; //flip Top & Bottom? int dotSize = 50; //diameter of the dots - for preview PImage pix = createImage(28,7, RGB); //PImage to hold the actual size image int pixLength = pix.width*pix.height; //total amount of pixels boolean drawRow = false; //use to alternate drawing a row of dots or skipping float a = 0.0; float inc = TWO_PI/25.0; PGraphics pixOrig; //PGraphics to hold the actual size image PImage text1; PImage text2; PImage text3; int scrollCounter = 0; int textSelector = 1; void setup(){ size(1400,350); // List all the available serial ports: printArray(Serial.list()); // Open the port you are using at the rate you want: myPort = new Serial(this, Serial.list()[0], 57600); ellipseMode(CORNER); noStroke(); //frameRate(3); text1 = loadImage("artatthemca.png"); //PImage for text image text2 = loadImage("2.png"); //PImage for text image text3 = loadImage("3.png"); //PImage for text image pixOrig = createGraphics(28,7); //PGraphics to hold the actual size image //preset the PImage pix.loadPixels(); for(int i=0; i<pixLength; i++){ pix.pixels[i] = color(0); //set each pixel to black } pix.updatePixels(); } void draw(){ background(35); switch(textSelector){ case(1): if(scrollCounter > text1.width+pixOrig.width){ scrollCounter = 0; textSelector++; } break; case(2): if(scrollCounter > text2.width+pixOrig.width){ scrollCounter = 0; textSelector++; } break; case(3): if(scrollCounter > text3.width+pixOrig.width){ scrollCounter = 0; textSelector++; } break; } if(textSelector > 3) textSelector = 1; //Draw Text pixOrig.beginDraw(); pixOrig.background(0); switch(textSelector){ case(1): pixOrig.image(text1, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; case(2): pixOrig.image(text2, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; case(3): pixOrig.image(text3, pixOrig.width-scrollCounter, 0); //draw text starting offscreen to the right break; } pixOrig.endDraw(); //do dithering biz here pix.loadPixels(); pixOrig.loadPixels(); for(int y=0; y<7; y++){ for(int x=0; x<28; x++){ color oldpixel = pixOrig.get(x, y); color newpixel = findClosestColor( color(brightness(oldpixel) + random(-100,100)) ); //the wider the range of randomness the "softer" the result. Lower is harder edge pix.pixels[x+y*pix.width] = newpixel; //copy colors from one image to the other } } pix.updatePixels(); //draw on screen pix.loadPixels(); for(int j=0; j<7; j++){ for(int i=0; i<28; i++){ if(i < 7) { if(mirrorX){ rowArray[6-i] = int( red(pix.pixels[i+j*pix.width])/255); //for now, only do for the 1st 7 columns }else{ rowArray[i] = int( red(pix.pixels[i+j*pix.width])/255); //for now, only do for the 1st 7 columns } println( rowArray[i] ); } fill( pix.pixels[i+j*pix.width] ); //read pixel values, set fill color to that ellipse(i*dotSize,j*dotSize,dotSize,dotSize); } rowCounter = j; prepDotRow(j); //set the row through bitwise operations } printToFlipDots(); //call the flipDot conversion scrollCounter++; delay (frameDelay); } void prepDotRow(int rowNum){ int tempRowCounter = rowNum+1; if(mirrorY) tempRowCounter = 7-rowNum; //bitshift values from array for(int i=0; i<rowArray.length; i++){ int a = rowArray[i]; int b = a << i; //bitshift the value the number of positions equal to the digit switch(tempRowCounter){ case 1: row1 = row1 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 2: row2 = row2 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 3: row3 = row3 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 4: row4 = row4 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 5: row5 = row5 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 6: row6 = row6 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; case 7: row7 = row7 | b; //bitwise OR addition of the "b" value to the existing "row3" value break; } } } void printToFlipDots(){ int test_2[]= {0x80, 0x87, 0xFF, row1, row2, row3, row4, row5, row6, row7, 0x8F}; //int test_2[]= {0x80, 0x87, 0xFF, 0, rowCounter, scrollCounter, 0, 0, 0, 0, 0x8F}; for(int i=0; i<test_2.length; i++){ myPort.write(test_2[i]); } //reset row values for next frame row1 = 0; row2 = 0; row3 = 0; row4 = 0; row5 = 0; row6 = 0; row7 = 0; } void keyPressed(){ if(key == 'x') mirrorX = ! mirrorX; if(key == 'y') mirrorY = ! mirrorY; } color findClosestColor(color c) { color r; // Treshold function if (brightness(c) < 128) { r = color(0); } else { r = color(255); } return r; }