Finishing Up - Final Project Step 6

Code:

See code made in Arduino for our project. For full breakdown of code see this post.

#include "Adafruit_NeoPixel.h"
#include "Adafruit_NeoTrellis.h"
#include <math.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define LED_PIN 6
#define PIXELS_PER_STRIP 15
#define NUM_STRIPS 15
Adafruit_NeoPixel pixels(PIXELS_PER_STRIP*NUM_STRIPS, LED_PIN, NEO_GRB + NEO_KHZ800);
char data[100]; // for debugging print statements with sprintf
bool trellisKeys[NEO_TRELLIS_NUM_KEYS] = ;
int formerButton = 0;
int buttonState = 0;
Adafruit_NeoTrellis trellis;
//define a callback for key presses
TrellisCallback blink(keyEvent evt) {
  // Check is the pad pressed?
  if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {
    if (trellisKeys[evt.bit.NUM] == false) {
      trellisKeys[evt.bit.NUM] = true;
      trellis.pixels.setPixelColor(evt.bit.NUM, 255, 255, 255); //white trellis keys
    } else {
      trellis.pixels.setPixelColor(evt.bit.NUM, 0); //off falling
      trellisKeys[evt.bit.NUM] = false;
    }
  }
  trellis.pixels.show();
  return 0;
}
void setup() {
  pinMode (2, INPUT);
  //pixels
  Serial.begin(9600);
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  pixels.begin();
  // TRELLIS
  if (!trellis.begin()) {
    //Serial.println("Could not start trellis, check wiring?");
    while (1);
  } else {
    //Serial.println("NeoPixel Trellis started");
  }
  //activate all keys and set callbacks
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {
    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_RISING);
    //    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_FALLING);
    trellis.registerCallback(i, blink);
  }
  //do a little animation to show we're on
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, Wheel(map(i, 0, trellis.pixels.numPixels(), 0, 255)));
    trellis.pixels.show();
    delay(50);
  }
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0x000000);
    trellis.pixels.show();
    delay(50);
  }
  //PIXELS
  for (int i = 0; i < PIXELS_PER_STRIP * NUM_STRIPS; i++) {
    pixels.setPixelColor(i, 0x181818); //set to gray light (dimmed so it doesnt pull too much power and turn yellow at the bottom)
  }
  pixels.show();
}
void loop() {
  buttonState = digitalRead(2);
  Serial.println(buttonState);
  if ( buttonState != formerButton && buttonState == 1) { //if former button state does not equal current button state && current button equals 1
    reset();
  }
  int NEWmappedPotH = map(analogRead(A1), 0, 1023, 0, 65536); //HUE
  int NEWmappedPotS = map(analogRead(A3), 0, 1023, 0, 255); //SATURATION
  int NEWmappedPotV = map(analogRead(A7), 0, 1023, 0, 140); //VALUE
    Serial.print(NEWmappedPotH);
    Serial.print(",");
    Serial.print(NEWmappedPotS);
    Serial.print(",");
    Serial.println(NEWmappedPotV);
  //ALL TRELLIS KEYS
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { //look through array of trellis keys
    if (trellisKeys[i] == true) { //if key state is true
      // use division then modulo to map a 1d array to a 2d array
      int row = i / 4; // 4 = number of trellis rows
      int col = i % 4; // 4 = number of trellis columns
       //effecting color of LED matrix
      uint32_t rgbcolor = pixels.gamma32(pixels.ColorHSV(NEWmappedPotH, NEWmappedPotS, NEWmappedPotV));  
      setGridColor(row, col, rgbcolor);
      //        Serial.print(row);
      //        Serial.print(", ");
      //        Serial.println(col);
    }
  }
  trellis.read();  // interrupt management does all the work! :)
  pixels.show();
  delay(20); //the trellis has a resolution of around 60hz
  formerButton = buttonState;
}
// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return trellis.pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return trellis.pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return trellis.pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  return 0;
}
void setGridColor(int row, int col, uint32_t rgbcolor) {
//  unsigned 32 bit integer can represent 0 to (2^32)-1
//  signed 32 bit integer can represent -(2^16) to (2^16)-1
  float lightsPerRow = (float)NUM_STRIPS / 4.0;
  int startRow = (int)max(0, floor(lightsPerRow * row));
  int endRow = (int)min(NUM_STRIPS, ceil(lightsPerRow * (row + 1)));
  float lightsPerCol = (float)PIXELS_PER_STRIP / 4.0;
  int startCol = (int)max(0, floor(lightsPerCol * col));
  int endCol = (int)min(PIXELS_PER_STRIP, ceil(lightsPerCol * (col + 1)));
  //  sprintf(data, "Selected (%d, %d)", row, col);
  //  Serial.println(data);
  //  //  Serial.println(NUM_STRIPS / 4.0);
  //  sprintf(data, "\tRows %d - %d (%f lights per row)", startRow, endRow, lightsPerRow);
  //  Serial.println(data);
  //  sprintf(data, "\tCols %d - %d (%f lights per col)", startCol, endCol, lightsPerCol);
  //  Serial.println(data);
  //  sprintf(data, "\tSet to color %d", rgbcolor);
  //  Serial.println(data);
//Dealing with the way the pixels are assembled on the lightwall to account for the squiggle 
  for (int r = 0; r < NUM_STRIPS; r++) {
    for (int c = 0; c < PIXELS_PER_STRIP; c++) {
      if (r >= startRow && r < endRow && c >= startCol && c < endCol) {
        int pixelIndex;
        if (r % 2 == 0) {
          //math to map back from the 2d index to a 1d index
          pixelIndex = r * PIXELS_PER_STRIP + c;
        } else {
          //reverse math to accomodate the snaking of LEDs
          pixelIndex = (r + 1) * PIXELS_PER_STRIP - c - 1;
        }
        //sprintf is a serial print format
        //        sprintf(data, "\tSetting pixel %d to color %d", pixelIndex, rgbcolor);
        //        Serial.println(data);
        pixels.setPixelColor(pixelIndex, rgbcolor);
      }
    }
  }
}
void reset() {
  pixels.begin();

  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {
    trellisKeys[i] = false;
  }
for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0x000000);
    trellis.pixels.show();
    delay(50);
  }
  //PIXELS
  for (int i = 0; i < PIXELS_PER_STRIP * NUM_STRIPS; i++) {
    pixels.setPixelColor(i, 0x181818); //set to gray light (dimmed so it doesnt pull too much power and turn yellow at the bottom)
  }
  pixels.show();
}

Solder Board:

One big step was moving our solderless breadboard to a solder board. This took some spatial planning. I started out by making a list of all the connection on the solderless board and then mapping them out onto a printout of the solder board. This made it petty easy to know where all the wires needed to go.


IMG_6495.JPG
IMG_1220.JPG

I then checked each of the components in the serial monitor to make sure everything was running correctly. Everything looked ok except for the neotrellis which wouldnt turn on. I used the multimetor set to continuity to check all of the wires. At first we were having an issue were the positive and negative sides of the bus lines were connecting. I think there was a tiny piece of a stranded wire that was connecting two wires because I put all the equipment away one night and then next morning when I came in to figure out why the bus lines were connected they were no longer connected so something must have been fixed when I moved the equipment. Even with the corrected bus lines though the neotrellis was not reading when plugged in. I de-soldered the neotrellis and tried it in a solderless breadboard - it worked fine. So then I re-soldered it but moved it lower down the breadboard because the top left area was getting crowded. I plugged it in and the neotrellis still didnt work. Finally, after asking for someone else to check over the breadboard we realized that I had forgotten to connect to the vin pin and to ground the Arduino! Once those were connected everything worked perfectly!

Light Wall:

The next step was to work on filling out our 15x15 neopixel matrix. We de-soldered our neopixel strands so that we had strips of 15 pixels and then soldered them together with 2 inch wires so that we would be able to make our snaking matrix. We needed to be carful to make sure that we were always soldering 5v to 5v, ground to ground and Din to Dout. We then did a strand test to make sure all of our soldering was done correctly and that all of our pixels were working.

IMG_6189.JPG

Next Sydney used double sided tape to adhere the pixels to the foamcore in a grid.

IMG_0362.JPG

We then made some light displays to see how everything was working

One problem we ran into was that if the lights were on full brightness and saturation we would see a gradient of color starting at the pure color near the power source and then getting dimmer/warmer farther from the power source. We knew we could solve this by adding another positive and negative power line to the matrix but we ended up changing the brightness value so that it wouldnt pull as much current. The mapping used to be 0-1023 changed to 0-255, and we changed this to 0-1023 changed to 0-140.

IMG_6608.JPG

The last thing that we worked on was adding the semi-transparent plexi to diffuse the neo-pixels. We chose to mount the plexi 1” from the neopixels. And we added a wooden back and wooden sides or shields to minimize light spillover.

IMG_3925.jpg

Box Construction

For playtesting we laser cut a cardboard top for our control panel. Once we confirmed the layout for the panel top we added holes for the screws which we measured with the caliper. We screwed in our components, then made a couple adjustments to the AI file and then laser cut it on plexi. We then mounted all of our components to the plexi using screws.

IMG_0664.JPG
IMG_6733.JPG

We cut holes in the box for the connection to the neopixels and to the power source and one whole in the side for the reset button.

IMG_1328.JPG
Next
Next

Playtesting Part 2 - Final Project Step 5