Go Down

Topic: Need Help on Code involving IR Obstacle Sensor and Multiple Neopixels (Read 287 times) previous topic - next topic

rpalvrz

Hello, I am relatively a newbie on programming and just started exploring neopixels recently.

Currently, I'm working on a project involving 2 neopixels strips and an IR obstacle sensor. The first strip changes effects when the IR sensor is triggered, the second strip should be running a different effect constantly but I cant get it to do so, so I just left it on fill_solid().
[PS. The code for the effects are mainly from Tweaking4All, thus the delays(). Also, I am not so sure how to make them into millis.]

Although It seems to be running fine on my Bluno Beetle but I just want to be sure since I might be missing some points. Thanks in advance!


Code: [Select]
/* This code uses 1 IR proximity sensor, 2 Neopixels strips that produces 2 different effects, and 1 5v LED strip that is constantly on and directly connected to the power supply.
 *  The effects on Neopixel Strip A will change whenever the IR is triggered. Neopixel Strip B however is to produce the same effect throughout the program.
 * SOURCES:  https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ && IR Proximity Sensor interface code (Turns on an LED on when obstacle is detected, else off.) by blog.circuits4you.com 2016
*/

//IR SENSOR
const int ProxSensor = 4;

//FastLED Effects
#include "FastLED.h"
#define NUM_LEDS 60   //leds per strip
CRGB leds[NUM_LEDS];
CRGB SNOW[NUM_LEDS];
#define PIN 3        //Neopixels Strip A
#define PIN2 5       //Neopixels Strip B

/* === START FastLED EFFECTS: === */
// switches off all LEDs
void showProgramCleanUp(long delayTime)
{
  for (int i = 0; i < NUM_LEDS; ++i) {
    leds[i] = CRGB::Black;
    SNOW[i] = CRGB::Black;
  }
  FastLED.show();
  delay(delayTime);
}


void showStrip() {
 #ifndef ADAFRUIT_NEOPIXEL_H
   FastLED.show();
 #endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifndef ADAFRUIT_NEOPIXEL_H
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  showStrip();
}
//SNOW SPARKLE EFFECT
void SnowSparkle(byte red, byte green, byte blue, int SparkleDelay, int SpeedDelay) {
  setAll(red,green,blue);

  int Pixel = random(NUM_LEDS);
  setPixel(Pixel,0xff,0xff,0xff);
  showStrip();
  delay(SparkleDelay);
  setPixel(Pixel,red,green,blue);
  showStrip();
  delay(SpeedDelay);
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) { 
  setAll(0,0,0);

  for(int i = 0; i < NUM_LEDS+NUM_LEDS; i++) {


    // fade brightness all LEDs one step
    for(int j=0; j<NUM_LEDS; j++) {
      if( (!meteorRandomDecay) || (random(10)>5) ) {
        fadeToBlack(j, meteorTrailDecay );       
      }
    }

    // draw meteor
    for(int j = 0; j < meteorSize; j++) {
      if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
        setPixel(i-j, red, green, blue);
      }
    }

    showStrip();
    delay(SpeedDelay);
  }
}

void fadeToBlack(int ledNo, byte fadeValue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    uint32_t oldColor;
    uint8_t r, g, b;
    int value;

    oldColor = strip.getPixelColor(ledNo);
    r = (oldColor & 0x00ff0000UL) >> 16;
    g = (oldColor & 0x0000ff00UL) >> 8;
    b = (oldColor & 0x000000ffUL);

    r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
    g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
    b=(b<=10)? 0 : (int) b-(b*fadeValue/256);

    strip.setPixelColor(ledNo, r,g,b);
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   leds[ledNo].fadeToBlackBy( fadeValue );
 #endif

}

//SETUP
void setup() {

Serial.begin(9600);

  // initialize the digital pin as an output.
  pinMode(PIN, OUTPUT);     
  pinMode(PIN2, OUTPUT);
  pinMode(ProxSensor,INPUT);

  FastLED.addLeds<WS2812, PIN>(leds, NUM_LEDS);  //Neopixels Trigger ON
  FastLED.addLeds<WS2812, PIN2>(SNOW, NUM_LEDS); //pin for "SNOW"

}


//START**
void loop() {
  fill_solid(SNOW, NUM_LEDS, CRGB::White); //LED2 constantly ON

  if(digitalRead(ProxSensor)==HIGH)      //Check the sensor output
  {
  SnowSparkle(0x10, 0x10, 0x10, 20, random(100,1000));
  delay (100);
  Serial.print("LED ON");
  Serial.println();
  delay (100);
  }
  else
  {
  Serial.print("Fade off... Waiting (15 seconds duration)");
  Serial.println();
  meteorRain(0xff, 0xff, 0xff, 10, 64, true, 70);
  delay (1000);
  // delay (100);
  }

  delay(100);              // wait for a second
}

Grumpy_Mike

Quote
I am relatively a newbie on programming
Unfortunately you need another step change in your knowledge to do this. Fortunately we are here to help you get that knowledge.

Quote
The code for the effects are mainly from Tweaking4All, thus the delays(). Also, I am not so sure how to make them into millis.
You need to adapt the code to run as a state machine, to find out what a state machine is see my
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once
http://forum.arduino.cc/index.php?topic=223286.0

Basically you want to see if it is time to update the pattern, if so go and make one step in the pattern and return.

This code shows how you can change the examples in the FastLED examples into a state machine. The pattern changes when a button is pressed. You want to change this button being pressed part of the code into looking at your IR sensor and deciding on what pattern you want.

Code: [Select]
// Multiple patterns in a state machine format
// using the FastLED libiary
// by Mike Cook 2017

#include "FastLED.h"

// first set up the parameters to use in the pattern calling
unsigned long patternInterval [] = { 500, 40, 20, 200, 5 }; // how often each pattern updates
unsigned long lastUpdate [5] ;  // for millis() when last update occurred
boolean patternEnabled [] = {true,true,false,true,true}; // should the pattern be called at all
byte patternState[5]; // state machine variable for patterns - this initialises them to zero

// now set up the LEDs to use
#define NUM_LEDS 64
#define DATA_PIN 3
#define CLOCK_PIN 13


CRGB leds[NUM_LEDS];

// Constants for patterns
// for Fire2012
#define COOLING  20
#define SPARKING 50
#define COLOR_ORDER BGR

// now set up the array of pointers to each pattern
void (*patternPtrs[5])(int index,byte state); //the array of pattern pointers

void setup() {
  //initialises the array of pattern pointers
  patternPtrs[0] = blinkOne;
  patternPtrs[1] = cylon;
  patternPtrs[2] = fire;
  patternPtrs[3] = colorWipe;
  patternPtrs[4] = rainbowCycle;
  //initialises the FastLED driver you want
  //FastLED.addLeds<APA102,leds, NUM_LEDS); // 13 clock  and 11 data
  FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(leds, NUM_LEDS); // 13 clock  and 11 data
  FastLED.setBrightness(8);
}

void loop() {
  for(int i = 0; i<5; i++) { // go through all the patterns and see if it is time to call one
    if(patternEnabled[i] && millis() - lastUpdate[i] > patternInterval[i]){
      lastUpdate[i] = millis();
      callPatterns(i, patternState[i]);
    }
  }
}

void callPatterns(int index, byte state) {
  (*patternPtrs[index])(index,state); //calls the pattern at the index of `index` in the array
}

// These are the pattern functions written as a state machine
// this is the Blink program in FastLED's example folder
void blinkOne(int index,byte state) {
  if(state == 0){
    leds[3] = CRGB::Blue;
    FastLED.show();
    patternState[index] = 1; // move on the state machine for the next call
  }
  if(state == 1){
     leds[3] = CRGB::Black;
     FastLED.show();
     patternState[index] = 0;
   }
  }

// this is the Cylon program in FastLED's example folder
// we will use LEDs 8 to 15 to show this
void cylon(int index,byte state) {
  static int i = 8; // replaces the loop index
  if(state == 0){
    leds[i] = CRGB::Red;
    FastLED.show();
    patternState[index] = 1; // move on the state machine for the next call
  }
   if(state == 1){
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    i++; // increment what was the loop variable
    if(i >= 16){ // we have finished one direction
     patternState[index] = 2;
     i--;
    }
    else {
    patternState[index] = 0;
    }
   }
   // Now go in the other direction only green
   if(state == 2){
     leds[i] = CRGB::Green;
    FastLED.show();
    patternState[index] = 3; // move on the state machine for the next call
   }
  if(state == 3){
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    i--; // decrement what was the loop variable
    if(i < 8){ // we have finished the return, go back to the start
     patternState[index] = 0;
     i= 8; // ready to start again
    }
    else {
    patternState[index] = 2;
    }
    // note that this could be better implemented but it has been written like this to keep it close to the origional example
    // so you can see what changes have been made
  }
}

// this is the Fire2012 program in FastLED's example folder
void fire(int index,byte state) {
// using LEDs 16 to 32
// Array of temperature readings at each simulation cell
  const byte startLED = 16; // first LED in section
  const byte numLEDs = 16;
  static byte heat[numLEDs];

  random16_add_entropy( random());
  // Step 1.  Cool down every cell a little
    for( int i = 0; i < numLEDs; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }
  
    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= numLEDs - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }
    
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < numLEDs; j++) {
        leds[j+startLED] = HeatColor( heat[j]); // transfer heat array to LEDs
    }
    FastLED.show(); // display this frame
  }

//colorWipe  modified from Adafruit example to make it a state machine
// uses LEDs 32 to 40
void colorWipe(int index,byte state) {
  static int i =0; // used as state variable
  static byte firstLED = 32;
  static byte numLEDs = 8;
    leds[i+firstLED] = CRGB::Yellow;
    FastLED.show();
    i++;
  if(i >= numLEDs){
    i = 0;
    for(int j;j<numLEDs; j++) leds[j+firstLED] = CRGB::Black; // blank out strip
  }
}

 // rainbowCycle modified from Adafruit example to make it a state machine
 // uses LEDs 48 to 64
void rainbowCycle(int index,byte state) {
  static uint16_t j=0; // used as state variable
  static byte firstLED = 48;
  static byte numLEDs = 16;
    for(int i=0; i< numLEDs; i++) {
      leds[i+firstLED].setHSV( (((i * 256 / numLEDs) + j) & 255), 255, 255);
    }
    FastLED.show();
    j++;
    if(j >= 256*5) j=0;
}

Go Up