Massive LED Installation - Need Help w/ Programming

Hello,

New to these forums. I'm working on a huge project with over 600m of digital LED strips from Adafruit. I'm using an ultrasonic sensor to make an initial lighting state change and then capacitive touch sensor to trigger subsequent state changes.

See below for my current code. Here are my issues with the behavior:

  • When passing in front of ultrasonic sensor - Strip1 lights up then Strip2 with brighter light as expected - but in sequence [need these to happen simultaneously]
  • When moving away from the ultrasonic sensor - strip1 dims immediately then Strip2 [need these to happen simultaneously]
  • Strip1 (connected to pins 2,3) - lights up as expected when touching capacitive button
  • Strip2 (connected to pins 4,5) - lights up as expected when touching capacitive button
  • Both touch sensors are really slow to respond (you have to hold them for 2-3secs) - sometimes they are instant - but often it takes way too long for the color change state

My biggest issues are the staged lighting as a result of the ultrasonic sensor & the slow button responses.

Side question - what if I need to monitor multiple (say 4) ultrasonic sensor simultaneously so that if there is motion on any side of the installation.

Thanks for any help anyone can offer!

#include "LPD8806.h"
#include "SPI.h"

// Program to control LPD8806-based RGB LED Modules in multiple strips - multi-tasking button demo


/*****************************************************************************/

// Number of RGB LEDs in strand:
int nLEDs = 160;    //assumes both strands have same number of LEDs

// Chose 2 pins for output; can be any valid output pins:
int dataPin1  = 2;
int clockPin1 = 3;
int dataPin2  = 4;
int clockPin2 = 5;

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip1 = LPD8806(nLEDs, dataPin1, clockPin1);
LPD8806 strip2 = LPD8806(nLEDs, dataPin2, clockPin2);

//Setup Sonar variables

int sonarPin = 0; //pin connected to analog out on maxsonar sensor
int inchesAway; //setup holder variable for the sonar reading

//Setup Capacitive Touch Sensor variables

int touchpin1 = 8; //pin connected to capacitive touch sensor 1
int touchstate1 = 0; //setup initial state of touch sensor to off/low

int touchpin2 = 9; //pin connected to capacitive touch sensor 2
int touchstate2 = 0; //setup initial state of touch sensor to off/low


long strip1Start; //setup timing variables
long strip2Start;
boolean strip1On = false; //setup strip state variables
boolean strip2On = false;


void setup() {
  // Start up the LED strip
  strip1.begin();
  strip2.begin();
  
  // Update the strip, to start they are all 'off'
  strip1.show();
  strip2.show();
  
  //setup the LED strip as the output - DO WE NEED THIS??
  //pinMode(LEDpin, OUTPUT);
  
  pinMode(touchpin1, INPUT);
  pinMode(touchpin2, INPUT);
    
}

void loop()
{
  //*****Strip1 ON & timing routine*****
  if (strip1On)  // strip is on now - check if it is time to turn it off
  {
    if (millis() - strip1Start > 10000) // if 10000 milliseconds has passed, it is time to turn off
    {
      strip1On = false;
    }
  }
  else if (digitalRead(touchpin1) == HIGH)  // strip is not on yet, check the touch sensor
  {
     strip1On = true;
     strip1Start = millis(); // set a timer to remember when we turned it on
     colorWipeFULL(strip1.Color(  0, 127, 127), 1);  // Fill full strip1 with Cyan
  }
  else if (analogRead(sonarPin) /2 < 60) // if no touch sensor, check the sonar
  { 
    colorWipe1st(strip1.Color(  127,   80, 50), 1);  // fill with white
    colorWipe2nd(strip1.Color(  0,   0, 0), 1);  // turn off second half pixels
  }
  else     //By default - display dim white light
  {
    colorWipe1st(strip1.Color(  32,   20, 13), 1);  // White - quarter brightness
    colorWipe2nd(strip1.Color(  0,   0, 0), 1);  // fill with white
  }
  
  //*****Strip2 ON & timing routine*****
  
  if (strip2On)  // strip is on now - check if it is time to turn it off
  {
    if (millis() - strip2Start > 10000) // if 10000 milliseconds has passed, it is time to turn off
    {
      strip2On = false;
    }
  }
  else if (digitalRead(touchpin2) == HIGH)  // strip is not on yet, check the touch sensor
  {
     strip2On = true;
     strip2Start = millis(); // set a timer to remember when we turned it on
     colorWipeFULL2(strip2.Color(  127, 30, 0), 1);  // Fill full strip2 with Orange
  }
  else if (analogRead(sonarPin) /2 < 60) // if no touch sensor, check the sonar
  { 
    colorWipe1st2(strip2.Color(  127,   80, 50), 1);  // fill with white
    colorWipe2nd2(strip2.Color(  0,   0, 0), 1);  // turn off second half pixels
  }
  else     //By default - display dim white light
  {
    colorWipe1st2(strip2.Color(  32,   20, 13), 1);  // White - quarter brightness
    colorWipe2nd2(strip2.Color(  0,   0, 0), 1);  // turn off second half pixels
  }
}


///////////////////////Fill Functions - Strip1///////////////

// Fill the dots progressively along a 1st half of the strip.
void colorWipe1st(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=0; i < 80; i++) {
      strip1.setPixelColor(i, c);
      strip1.show();
      delay(wait);
  }
  
}

// Fill the dots progressively along a 2nd half of the strip.
void colorWipe2nd(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=80; i < 160; i++) {
      strip1.setPixelColor(i, c);
      strip1.show();
      delay(wait);
  }
  
}

// Fill the dots progressively along the ENTIRE strip.
void colorWipeFULL(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=0; i < strip1.numPixels(); i++) {
      strip1.setPixelColor(i, c);
      strip1.show();
      delay(wait);
  }
  
}

///////////////////////STRIP 2 CODE////////////////////////////////

// Fill the dots progressively along a 1st half of the strip.
void colorWipe1st2(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=0; i < 80; i++) {
      strip2.setPixelColor(i, c);
      strip2.show();
      delay(wait);
  }
  
}

// Fill the dots progressively along a 2nd half of the strip.
void colorWipe2nd2(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=80; i < 160; i++) {
      strip2.setPixelColor(i, c);
      strip2.show();
      delay(wait);
  }
  
}

// Fill the dots progressively along the ENTIRE strip.
void colorWipeFULL2(uint32_t c, uint8_t wait) {
  int i;
//strip.numPixels()  -  use this command below - replace 80 - to have entire strip fill
  for (i=0; i < strip2.numPixels(); i++) {
      strip2.setPixelColor(i, c);
      strip2.show();
      delay(wait);
  }
  
}

I guess the slow responce is due to the loops containing delays.
Instant reaction may be obtained with an interrupt for the touchbuttons

knut_ny:
Instant reaction may be obtained with an interrupt for the touchbuttons

Can you please give me an example of what you mean by the interrupt for the touch buttons?

knut_ny:
I guess the slow responce is due to the loops containing delays.
Instant reaction may be obtained with an interrupt for the touchbuttons

I actually tried commenting out all of the delays - even the ones in the fill functions - so I would have no delays anywhere in the code and there is still a big lag in the button sensing.

You might try a different driver library.
The datasheet shows it supports data clock rates of up to 20 MHz.
With SPI & divisor set to 2, you can achieve 8 MHz, the best a 16 MHz Arduino can do.
Add a couple of high speed AND gates and you can fake having a slave select for 2 lines - whichever AND gate gets a High for its 2nd output is allowed to have SCK go thru for a clock line.

This thread has some more info also.
http://forums.adafruit.com/viewtopic.php?f=47&t=23519

Each chip in the string needs 6 bytes of data (for two RGB LEDs), you can output that at nearly 1uS/byte with good coding, pulling data to go out from an array and not using for:loops.
How many LEDs in each string?

CrossRoads:
You might try a different driver library.
The datasheet shows it supports data clock rates of up to 20 MHz.
With SPI & divisor set to 2, you can achieve 8 MHz, the best a 16 MHz Arduino can do.
Add a couple of high speed AND gates and you can fake having a slave select for 2 lines - whichever AND gate gets a High for its 2nd output is allowed to have SCK go thru for a clock line.
http://www.adafruit.com/datasheets/lpd8806%20english.pdf
This thread has some more info also.
http://forums.adafruit.com/viewtopic.php?f=47&t=23519

Each chip in the string needs 6 bytes of data (for two RGB LEDs), you can output that at nearly 1uS/byte with good coding, pulling data to go out from an array and not using for:loops.
How many LEDs in each string?

I gotta be honest, I'm pretty much a noob trying to repurpose snippets of code where I can find something applicable and you left me in the dust with most of what you're suggesting above. The strips have 32 LEDs per meter and I will have runs as long as 10m.

One person suggested trying interrupts. I'm checking out the documentation here:

It looks like I can only have one interrupt running at a time. I will need to monitor at least 3 capacitive buttons while the system is running.

3 buttons, but you will not be pressing them simultaneously will you? So they can each be addressed as they are pressed.

A 10m strip will have 320 LEDs, so 960 bytes of data need to go out. So with high speed SPI transfers that will take 960uS , or nearly 1mS to send all the data out. If you have an interrupt in the middle of that transfer that takes "too long" and I can't tell from the data sheet how long that is, the outputs will change to reflect the data that was shifted in.
I think you will be better off checking the button inputs in between strings of data going out, 1mS delay I don't think will be noticeable to responsiveness.

How might you go about addressing them between strings? I've been attempting to monitor them concurrently while the sketch is running using the millis() function, but there is still a lag. The buttons are part of an interactive installation and attached to a structure, so it is very likely that we will have people pressing buttons at the same time. It would be ok if the delay was 1ms, but right now I'm seeing delays of 2-3secs at a time.

Put them all on one port and use direct port manipulation to read them all on once then act on any that were pressed.
Say they were D4,5,6,7:

buttons = (PIND & 0b11110000) >> 4; // pins with internal pullups, buttons to Gnd, D7-6-5-4
switch (buttons){
case 0b00001111:
// no buttons pressed
break;
case  0b00001110:
// button D4 pressed
break;
case 0b00001101:
// button D5 pressed
break;
case 0b00001011:
// button D6 pressed
break;
case 0b00000111:
// button D7 pressed
break;
case 0b00001100:
// buttons D4, D5 pressed
break;
// for the other combinations, address all 15 if desired
} // end switch