// // Infinity Mirror Control Software // // by Michael Rosskopf (2014) // // www.mithotronic.de // // Thanks to Adafruit! // #include #define PIN 6 // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel strip = Adafruit_NeoPixel(116, PIN, NEO_GRB + NEO_KHZ800); // LED and buttons int controlLED = 8; int buttonProgram = 9; int buttonVariation = 10; // Stores whether buttons have been pressed boolean programButtonPressed; boolean variationButtonPressed; boolean buttonPressed; // Set on general button events. Used in some programs as a break condition. // Current running program and its variation byte program; byte variation; // Counter which counts the cycles in which the menu is visible int programChangeCounter; // Random mode byte randomMode; // 0: off, 1, ..., 7: Takes randomly variations from program 1, ..., 7, 8: Fully random int randomCounter; // Counts cycles till next random chnage of program/variation // Variables for colors int rValue; int gValue; int bValue; byte colorScheme; // Some programs use Color schemes: 0: Without red, 1: Without green, 2: Without blue, 3: All colors int randomColor; // Some programs use only main colors which are random: 0: red, 1: green, 2: blue, ..., 7: white // Variables for programs moving single pixels with indiviual colors and speed. Up to 58 pixel can be moved. double pixelVector[58]; double pixelPosition[58]; int pixelRValue[58]; int pixelGValue[58]; int pixelBValue[58]; int pixelPointer; // Pointer to the next pixel to be initialized int numberOfPixels; // Variables for programs moving blocks of pixels byte lengthOfBlock; byte startPixel; byte endPixel; int leftLimitOfBlock; int rightLimitOfBlock; double blockVector; // Direction of the moving block (>0: anti-clockwise, <0: clockwise int startOfBlock; int stopPixel; int fillUpCounter; // Other counter int i, counter; int delayOfProgram; // Influences the speed of some programs void setup() { // Initialize serial connection Serial.begin(9600); // Initialize random number generator randomSeed(analogRead(5)); // Define input and output pinMode(controlLED, OUTPUT); pinMode(buttonProgram, INPUT); pinMode(buttonVariation, INPUT); // Activate internal pull-up resistors for buttons digitalWrite(buttonProgram, HIGH); digitalWrite(buttonVariation, HIGH); // Set program and variation program = 0; variation = 0; programButtonPressed = false; variationButtonPressed = false; randomMode = 0; randomCounter = 0; // Setup strip strip.begin(); strip.show(); // Initialize all pixels to 'off' } void loop() { do { if(randomMode == 0) { // If system is not in random mode, the system starts the program change mode in which the user can select program and variation programChangeMode(); } else { // In random mode, the variation or additionally the program is changed randomly variation = random(8); if(randomMode != 8) { program = randomMode - 1; } else { program = random(7); } } // Program 1: Constant color if(program == 0) { program1(); } // Program 2: Chain of lights if(program == 1) { program2(); } // Program 3: Rainbow wheel if(program == 2) { program3(); } // Program 4: Symmetric movement if(program == 3) { program4(); } // Program 5: Moving blocks if(program == 4) { program5(); } // Program 6: Chaotic movement if(program == 5) { program6(); } // Program 7: Strobe if(program == 6) { program7(); } // Program 8: Random if(program == 7) { program8(); } programButtonPressed = true; variationButtonPressed = true; } while(true); } // Program change mode void programChangeMode() { programChangeCounter = 0; do { checkForProgramChange(); showProgram(); programChangeCounter++; } while(programChangeCounter < 50); } // Check for pressed buttons void checkForProgramChange() { // Program button if((digitalRead(buttonProgram) == LOW) && !programButtonPressed) { digitalWrite(controlLED, HIGH); programButtonPressed = true; program++; programChangeCounter = 0; if(program > 7) { program = 0; } } if(digitalRead(buttonProgram) == LOW) { // do nothing } else { programButtonPressed = false; delay(10); } // Variation button if((digitalRead(buttonVariation) == LOW) && !variationButtonPressed) { digitalWrite(controlLED, HIGH); variationButtonPressed = true; variation++; programChangeCounter = 0; if(variation > 7) { variation = 0; } } if(digitalRead(buttonVariation) == LOW) { // do nothing } else { variationButtonPressed = false; delay(10); } } // Visualizes current program and variation by white pixels in the program change mode void showProgram() { strip.show(); // Initialize all pixels to 'off' for(byte i = 0; i <= 3; i++) { strip.setPixelColor(0 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(1 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(2 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(3 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(4 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(5 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(6 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(7 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(8 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(9 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(10 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(11 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(4 + program + i * 29, strip.Color(255, 255, 255)); strip.setPixelColor(12 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(13 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(14 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(15 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(16 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(17 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(18 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(19 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(20 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(21 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(22 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(23 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(24 + i * 29, strip.Color(0, 0, 0)); strip.setPixelColor(17 + variation + i * 29, strip.Color(255, 255, 255)); strip.setPixelColor(25 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(26 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(27 + i * 29, strip.Color(0, 0, 255)); strip.setPixelColor(28 + i * 29, strip.Color(0, 0, 255)); } digitalWrite(controlLED, LOW); } // Get random RGB value according to a color scheme // colorScheme == 0 Without red // colorScheme == 1 Without green // colorScheme == 2 Without blue // colorScheme == 3 All colors void getColors(byte colorScheme, int& rValue, int& gValue, int& bValue) { if(colorScheme == 0) { rValue = 0; } else { rValue = random(256); } if(colorScheme == 1) { gValue = 0; } else { gValue = random(256); } if(colorScheme == 2) { bValue = 0; } else { bValue = random(256); } } // Fill the dots one after another with a color (code taken from Adafruit NeoPixel libraray example) void colorWipe(uint32_t c, uint8_t wait) { for(uint16_t i=0; i 1000) { rValue = 1; } if(gValue < 1 || gValue > 1000) { gValue = 1; } if(bValue < 1 || bValue > 1000) { bValue = 1; } if(rValue > 255) { rValue = 255; } if(gValue > 255) { gValue = 255; } if(bValue > 255) { bValue = 255; } if(randomMode > 0) { randomCounter++; } } while(!buttonPressed && randomCounter < 5); if(randomCounter < 5) { randomMode = 0; } } // Chain of lights (code partly taken from Adafruit NeoPixel libraray example) void program2() { randomCounter = 0; buttonPressed = false; clearAll(); i = 0; counter = 0; if(variation == 0 || variation == 4) // Runs through the main colors { if(variation == 0) { delayOfProgram = 20; } else { delayOfProgram = 0; } do { colorWipe(strip.Color(255, 0, 0), delayOfProgram); // Red if(buttonPressed) { break; } colorWipe(strip.Color(0, 255, 0), delayOfProgram); // Green if(buttonPressed) { break; } colorWipe(strip.Color(0, 0, 255), delayOfProgram); // Blue if(buttonPressed) { break; } colorWipe(strip.Color(255, 255, 0), delayOfProgram); // Yellow if(buttonPressed) { break; } colorWipe(strip.Color(255, 0, 255), delayOfProgram); // Magenta if(buttonPressed) { break; } colorWipe(strip.Color(0, 255, 255), delayOfProgram); // Turquois if(buttonPressed) { break; } colorWipe(strip.Color(255, 255, 255), delayOfProgram); // White if(randomMode > 0 && !buttonPressed) { randomCounter++; } } while(!buttonPressed && randomCounter < 1); if(randomCounter < 1) { randomMode = 0; } } else // Uses random colors { do { strip.show(); // Initialize all pixels to 'off' if(counter == 0) { rValue = random(256); gValue = random(256); bValue = random(256); } strip.setPixelColor(i, strip.Color(rValue, gValue, bValue)); if(variation < 4) { delay(50); } i++; counter++; if(i > 115) { i = 0; } if(variation == 1 || variation == 5) { if(counter > 115) { counter = 0; } } if(variation == 2 || variation == 6) { if(counter > 28) { counter = 0; } } if(variation == 3 || variation == 7) { if(counter > 0) { counter = 0; } } if(randomMode > 0) { randomCounter++; } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW) || randomCounter > 232)); if(randomCounter <= 232) { randomMode = 0; } } } // Rainbow wheel (code partly taken from Adafruit NeoPixel libraray example) void program3() { randomCounter = 0; buttonPressed = false; clearAll(); do { rainbowCycle(20); if(randomMode > 0) { randomCounter++; } } while(!buttonPressed && randomCounter < 1); if(buttonPressed) { randomMode = 0; } } // Symmetric movement // Movement of individual pixel in different directions with random color schemes void program4() { randomCounter = 0; clearAll(); pixelPointer = 0; numberOfPixels = 29; colorScheme = random(4); for(i = 0; i < numberOfPixels; i++) { pixelPosition[i] = i * 4; if(variation == 0) { pixelVector[i] = 0.5; } if(variation == 1) { pixelVector[i] = -0.5; } if(variation == 2) { if(i % 2 == 0) { pixelVector[i] = 0.5; } else { pixelVector[i] = -0.5; } } if(variation == 3) { if(i % 2 == 0) { pixelVector[i] = 0.5; } else { pixelVector[i] = 0.25; } } if(variation == 4) { if(i % 2 == 0) { pixelVector[i] = -0.5; } else { pixelVector[i] = -0.25; } } if(variation == 5) { if(i % 4 == 0) { pixelVector[i] = 0.5; } if(i % 4 == 1) { pixelVector[i] = 0.25; } if(i % 4 == 2) { pixelVector[i] = -0.5; } if(i % 4 == 3) { pixelVector[i] = -0.25; } } if(variation == 6) { pixelVector[i] = double(i % 4) + 1.0 / 4.0; } if(variation == 7) { if(i % 2 == 0) { pixelVector[i] = double(i % 8) + 1.0 / 8.0; } else { pixelVector[i] = double(i % 8) + 1.0 / 8.0; } } getColors(colorScheme, pixelRValue[i], pixelGValue[i], pixelBValue[i]); } do { strip.show(); // Initialize all pixels to 'off' for(i = 0; i < numberOfPixels; i++) { strip.setPixelColor(byte(pixelPosition[i]), strip.Color(0, 0, 0)); pixelPosition[i] = pixelPosition[i] + pixelVector[i]; if((pixelVector[i] < 0) && (int(pixelPosition[i]) < 0)) // Casting to int is important, since bytes know no negative values { pixelPosition[i] = pixelPosition[i] + 116.0; } if((pixelVector[i] > 0) && (int(pixelPosition[i]) > 115)) { pixelPosition[i] = pixelPosition[i] - 116.0; } strip.setPixelColor(byte(pixelPosition[i]), strip.Color(pixelRValue[i], pixelGValue[i], pixelBValue[i])); } delay(10); if(randomMode > 0) { randomCounter++; } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW) || (randomCounter > 200))); if(randomCounter <= 200) { randomMode = 0; } } // Moving blocks void program5() { randomCounter = 0; clearAll(); buttonPressed = false; colorScheme = random(4); fillUpCounter = 0; blockVector = (double(random(2)) - 0.5) * 2.0; // -1 or 1 <- Random start of direction if((variation % 2) == 0) { lengthOfBlock = 8; } else { lengthOfBlock = 4; } // Random start of first series of blocks if(variation == 0 || variation == 1 || variation == 4 || variation == 5) { // Movement in one random direction // Setup a new first block if(blockVector > 0) { startOfBlock = (random(4) * 29); } else { startOfBlock = (random(4) * 29) + 29 - lengthOfBlock; } leftLimitOfBlock = startOfBlock; rightLimitOfBlock = leftLimitOfBlock + lengthOfBlock - 1; if(blockVector > 0) { stopPixel = leftLimitOfBlock; } else { stopPixel = rightLimitOfBlock; } } else { // Movement in both directions // Setup a new first block startOfBlock = (random(4) * 29) + 15; stopPixel = startOfBlock + 58; if(stopPixel > 115) { stopPixel = stopPixel - 116; } } do { // Create a new block of pixels getColors(colorScheme, rValue, gValue, bValue); if(variation == 0 || variation == 1 || variation == 4 || variation == 5) { // Movement in one random direction leftLimitOfBlock = startOfBlock; rightLimitOfBlock = leftLimitOfBlock + lengthOfBlock - 1; strip.show(); // Initialize all pixels to 'off' // Draw the new block in start position for(i = leftLimitOfBlock; i <= rightLimitOfBlock; i++) { strip.setPixelColor(i, strip.Color(rValue, gValue, bValue)); } fillUpCounter = fillUpCounter + lengthOfBlock; } else { // Movement in both directions // Change direction of next block in comparison to previous block if(blockVector > 0) { blockVector = -1.0; stopPixel = stopPixel + fillUpCounter - 1; leftLimitOfBlock = startOfBlock - lengthOfBlock + 1; rightLimitOfBlock = startOfBlock; } else { blockVector = 1.0; stopPixel = stopPixel - fillUpCounter + 1; leftLimitOfBlock = startOfBlock; rightLimitOfBlock = leftLimitOfBlock + lengthOfBlock - 1; } // Make sure that the stop pixel is inside of the strip if(stopPixel < 0) { stopPixel = 116 + stopPixel; } if(stopPixel > 115) { stopPixel = stopPixel - 116; } strip.show(); // Initialize all pixels to 'off' // Draw the new block in start position for(i = leftLimitOfBlock; i <= rightLimitOfBlock; i++) { strip.setPixelColor(i, strip.Color(rValue, gValue, bValue)); } fillUpCounter = fillUpCounter + lengthOfBlock; } // Move the block do { strip.show(); // Initialize all pixels to 'off' // Slow mode for the first 4 variations if(variation < 4) { delay(20); } if(blockVector > 0) { rightLimitOfBlock++; if(rightLimitOfBlock > 115) { rightLimitOfBlock = 0; } if(rightLimitOfBlock == stopPixel) { stopPixel = leftLimitOfBlock; break; } strip.setPixelColor(rightLimitOfBlock, strip.Color(rValue, gValue, bValue)); strip.setPixelColor(leftLimitOfBlock, strip.Color(0, 0, 0)); leftLimitOfBlock++; if(leftLimitOfBlock > 115) { leftLimitOfBlock = 0; } } else { leftLimitOfBlock--; if(leftLimitOfBlock < 0) { leftLimitOfBlock = 115; } if(leftLimitOfBlock == stopPixel) { stopPixel = rightLimitOfBlock; break; } strip.setPixelColor(leftLimitOfBlock, strip.Color(rValue, gValue, bValue)); strip.setPixelColor(rightLimitOfBlock, strip.Color(0, 0, 0)); rightLimitOfBlock--; if(rightLimitOfBlock < 0) { rightLimitOfBlock = 115; } } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW))); // Restart the program after all pixels have been set if(variation == 0 || variation == 1 || variation == 4 || variation == 5) { // Movement in one direction if(fillUpCounter > (115 - lengthOfBlock)) { if(randomMode > 0) { randomCounter++; } clearAll(); fillUpCounter = 0; blockVector = (double(random(2)) - 0.5) * 2.0; // -1 or 1 <- Random start of direction // Setup a new first block if(blockVector > 0) { startOfBlock = (random(4) * 29); } else { startOfBlock = (random(4) * 29) + 29 - lengthOfBlock; } leftLimitOfBlock = startOfBlock; rightLimitOfBlock = leftLimitOfBlock + lengthOfBlock - 1; if(blockVector > 0) { stopPixel = leftLimitOfBlock; } else { stopPixel = rightLimitOfBlock; } } } else { // Movement in both directions if(fillUpCounter > (115 - lengthOfBlock)) { if(randomMode > 0) { randomCounter++; } clearAll(); fillUpCounter = 0; blockVector = (double(random(2)) - 0.5) * 2.0; // -1 or 1 <- Random start of direction // Setup a new first block startOfBlock = (random(4) * 29) + 15; stopPixel = startOfBlock + 58; if(stopPixel > 115) { stopPixel = stopPixel - 116; } } } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW) || (randomCounter > 0))); if(randomCounter < 1) { randomMode = 0; } } // Chaotic movement // Movement of individual pixel with random speed, directions, and color schemes void program6() { randomCounter = 0; clearAll(); pixelPointer = 0; if(variation < 4) { numberOfPixels = 10; } else { numberOfPixels = 20; } for(i = 0; i < numberOfPixels; i++) { do { pixelVector[i] = (random(1000) - 500.0) / 500.0; } while(pixelVector[i] > -0.2 && pixelVector[i] < 0.2); pixelPosition[i] = byte(random(116)); if(variation == 0 || variation == 4) { pixelRValue[i] = 0; } else { pixelRValue[i] = random(256); } if(variation == 1 || variation == 5) { pixelGValue[i] = 0; } else { pixelGValue[i] = random(256); } if(variation == 2 || variation == 6) { pixelBValue[i] = 0; } else { pixelBValue[i] = random(256); } } do { strip.show(); // Initialize all pixels to 'off' for(i = 0; i < numberOfPixels; i++) { strip.setPixelColor(byte(pixelPosition[i]), strip.Color(0, 0, 0)); pixelPosition[i] = pixelPosition[i] + pixelVector[i]; if((pixelVector[i] < 0) && (int(pixelPosition[i]) < 0)) // Casting to int is important, since bytes know no negative values { pixelPosition[i] = pixelPosition[i] + 116.0; } if((pixelVector[i] > 0) && (int(pixelPosition[i]) > 115)) { pixelPosition[i] = pixelPosition[i] - 116.0; } strip.setPixelColor(byte(pixelPosition[i]), strip.Color(pixelRValue[i], pixelGValue[i], pixelBValue[i])); } delay(10); if(randomMode > 0) { randomCounter++; } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW) || (randomCounter > 200))); if(randomCounter <= 200) { randomMode = 0; } } // Strobes // Variation 1: Short corners with multiple random colors // Variation 2: Long corners with multiple random colors // Variation 3: Middle parts with multiple random colors // Variation 4: Full edges with multiple random colors // Variation 5: Short corners with main colors // Variation 6: Long corners with main colors // Variation 7: Middle parts with main colors // Variation 8: Full edges with main colors void program7() { randomCounter = 0; clearAll(); buttonPressed = false; colorScheme = random(4); randomColor = random(7); if(variation == 0 || variation == 4) { lengthOfBlock = 10; } if(variation == 1 || variation == 5) { lengthOfBlock = 15; } if(variation == 2 || variation == 6) { lengthOfBlock = 15; } if(variation == 3 || variation == 7) { lengthOfBlock = 29; } do { if(variation == 0 || variation == 1 || variation == 4 || variation == 5) { if(random(100) < 50) { startPixel = (random(4) * 29); } else { startPixel = ((random(4) + 1) * 29) - lengthOfBlock; } } if(variation == 2 || variation == 6) { startPixel = (random(4) * 29) + 7; } if(variation == 3 || variation == 7) { startPixel = (random(4) * 29); } endPixel = startPixel + lengthOfBlock - 1; strip.show(); // Initialize all pixels to 'off' if(variation < 4) { // Random colors from a random color palette getColors(colorScheme, rValue, gValue, bValue); } else { // Main colors (without change) switch(randomColor) { case 0: rValue = 255; gValue = 0; bValue = 0; break; case 1: rValue = 0; gValue = 255; bValue = 0; break; case 2: rValue = 0; gValue = 0; bValue = 255; break; case 3: rValue = 255; gValue = 255; bValue = 0; break; case 4: rValue = 255; gValue = 0; bValue = 255; break; case 5: rValue = 0; gValue = 255; bValue = 255; break; case 6: rValue = 255; gValue = 255; bValue = 255; break; } } for(byte i = startPixel; i <= endPixel; i++) { strip.setPixelColor(i, strip.Color(rValue, gValue, bValue)); } delay(40); clearAll(); if(randomMode > 0) { randomCounter++; } } while(!((digitalRead(buttonProgram) == LOW) || (digitalRead(buttonVariation) == LOW) || (randomCounter > 100))); if(randomCounter <= 100) { randomMode = 0; } } // Random void program8() { randomMode = variation + 1; }