Monochrome Fading with RGB LED strip

Hi everyone,

This is only my second thread on the Arduino Forum, I'm still very new to this.

I have the following LED strip:

I was wondering if it's possible to use Arduino to program a fading "sequence" that only goes through a single color. In other words, what would be called "breathing" or "pulsing" in a single LED.

I realize this can be accomplished using one of these remotes:

http://www.amazon.com/Lighting-EVER-Remote-Controller-Features/dp/B00AQUYK3M/ref=sr_1_1?s=hi&ie=UTF8&qid=1366291393&sr=1-1&keywords=Controller+44+Keys+for+RGB+LED

However, I may eventually add a proximity sensor which responds with brightness to darkness of the LEDs.

I was also wondering if it's necessary to keep the Arduino connected to the strip once it's programmed.

Any code, hints, guidance would be much appreciated!

togethernessnyc:
I was wondering if it's possible to use Arduino to program a fading "sequence" that only goes through a single color. In other words, what would be called "breathing" or "pulsing" in a single LED.

Yes.

togethernessnyc:
I was also wondering if it's necessary to keep the Arduino connected to the strip once it's programmed.

Yes.

togethernessnyc:
Any code, hints, guidance would be much appreciated!

There's about 100000000 threads on how to do this. Please try using the search box.

@Fungus, thanks!

I did do a search, but the problem with being new is, you don't always know how to refine your search to get the results you're looking for.

If you could guide me in a more specific direction, it would be very helpful!

Alternatives, if you don't know what is a solder iron , than you follow your path buying controller + IR remote and using arduino as remotes replica. There is a library somewhere, that allows arduino to intercept / decipher and than reproduce practically any device protocol, TV, DVD, etc.

Thanks @Magician.

I found this example, which is more or less exactly what I want to do:

However, rather than have it in the "off" position, before the viewer approaches, I wanted to have it "breathing", fading in and out.

When the viewer approaches, I wanted the bright peak of the "breath" to grow much brighter. The dark peak should remain the same.

Any suggestions?

Any suggestions?

Don't expect someone will write code for you. There are hundreds examples posted on-line, start to put pieces together and see what you get. If there is a question, than you come back, post your code and explain what you want and what is not working. Humble person like me, could spare a few minutes trying to solve your problem, but not much

@Magician, thanks! Yes, I don't expect anyone to do the work for me. But, to reiterate, as a newbie, the necessary search terms to get to the solution aren't always obvious.

For example, for this particular problem, there's certain libraries that I never would've anticipated needing, much less knew they existed to look for. You would think this is a fairly simple code, but it's not.

Below, you can see what I've been working with. I started with the basic Arduino fade example, and then started adding variables:

#include <SPI.h>


/*
 Fade
 
 This example shows how to fade an LED on pin 9
 using the analogWrite() function.
 
 This example code is in the public domain.
 */

int sensorPin = A3;        // the pin that the sensor is attached to 
int ledPin = 9;           // the pin that the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 1;    // how many points to fade the LED by
int proximity;
int maxBrightness;
int pwmActual[] = {
  0, 1, 2, 3, 4, 5, 7, 9,
  12, 15, 18, 22, 27, 32, 37, 44,
  50, 58, 66, 75, 85, 96, 107, 120,
  133, 147, 163, 179, 196, 215, 234, 255
};
 

// the setup routine runs once when you press reset:
void setup()  { 
  // declare pin 9 to be an output:
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
} 

// the loop routine runs over and over again forever:
void loop()  { 

  proximity = analogRead(sensorPin);   // returns 0 to 1023 in theory (0-5V), but TEST SENSOR
  Serial.println(proximity);

  maxBrightness  = map(proximity, 0,1023, 0,255);


  // set the brightness of pin 9:
  analogWrite(ledPin, brightness);    // 0 = 0% = 0V, 255 = 100% = 5V

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (brightness <= 0) {     
    fadeAmount = +1; 
  }     
  
  if (brightness >= maxBrightness) {
    fadeAmount = -1; 
  }  
  
  // wait for 30 milliseconds to see the dimming effect    
  delay(80);                            
}

The problems I'm currently encountering are this:

  • before the IR sensor is more closely engaged, it is blinking too quickly. I've tried to insert delays in two places: between the gradations of the fade, as well as on either side of the full fade "cycle". Between gradations, it creates the "blinking" effect that poorly written Arduino fades have. Between full fade cycles, it creates and awkward split-second pause.
  • when the IR sensor is closely engaged, the fade performs well, but the blink slows down, presumably because there are a greater amount of steps necessary to return back to it's zero (0) initial state. There must be some elegant variable I could insert to control that.
  • I've also been looking at these two links, but am having a hard time incorporating them:
    http://neuroelec.com/2011/04/led-brightness-to-your-eye-gamma-correction-no/
    http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
    (you can see the first of the two at the start of the code)

So, in a nutshell, I need to find a way to slow down the blink before proximity is engaged, and speed it up after it's enaged.

Secondly:

I've been testing this with a single LED, but I will eventually be using an LED strip, attached to the following:

I will use 8 AA's in series, interfacing the Arduino with a transistor. The Arduino will be interfacing the LED strip with tip120s, per the Adafruit tutorial.

Can anyone see any unanticipated issues from this?

I would say the most obvious things you need to look at are what sort of pattern you consider 'breathing' to be, and how you control rate.

Currently you are setting a maximum value based on proximity, counting up to it and counting down when you get there, which is the problem with your pattern. It is not how you breath (unless you are ill). You start breathing slowly, ramp up to full speed and then slow down when you are nearly full, then repeat, ie, much like a sine wave, you don't start breathing in at full speed then stop at a certain point and breath out.

The timing issue you have is that if you dont have much of a value for proximity, you have (say) a value of 25. It takes 25 steps to get there. If you have close proximity, you have 255. You are still counting it the same rate so you have 255 steps to get there, or 10 times as long. If you want the period of the breath to stay the same, you need the same number of steps, but going up at a much faster rate.

I would have something more like (and note, I haven't tried this):

double currentAngle = 0;

double offset = 

void loop()  { 

  currentAngle += 0.01; // add some small part to the current angle, adjust for breathing rate
  double intensity = cos(currentAngle)  / 2.0 + 0.5;	// gives a cosine wave from 0 - 1.0

  proximity = analogRead(sensorPin);   // returns 0 to 1023 in theory (0-5V), but TEST SENSOR
  Serial.println(proximity);

  // come up with some scale here, so max proximity (1024) 
  // at max intensity (1.0) is full brighness, min proximity 
  // at max intensity is still showing something, say 200?

  double proximityRange = ((double)proximity + 200.0) / 1224 * 255;

  int brightness = (int)proximityRange;

  // set the brightness of pin 9:
  analogWrite(ledPin, brightness);    // 0 = 0% = 0V, 255 = 100% = 5V

  // wait for 30 milliseconds to see the dimming effect    
  delay(80);                            
}

so there is one big sine wave that is always going the same speed, but the max voltage is based on the proximity

@woodinblack, thanks for your input! for a newbie, your code is impressively complex! i'm not quite sure how i can revise it, given my skill level.

in the meantime, i've adjusted my code to include a sine wave, which has brought me much closer to my end goal. here's what i have so far . . . please disregard the artifacts from the earlier version, i'll be editing them out soon.

#include <SPI.h>


/*
 Fade
 
 This example shows how to fade an LED on pin 9
 using the analogWrite() function.
 
 This example code is in the public domain.
 */

int sensorPin = A3;        // the pin that the sensor is attached to 
int LEDpin = 9;           // the pin that the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 1;    // how many points to fade the LED by
int proximity;
int maxBrightness;
int pwmActual[] = {
  0, 1, 2, 3, 4, 5, 7, 9,
  12, 15, 18, 22, 27, 32, 37, 44,
  50, 58, 66, 75, 85, 96, 107, 120,
  133, 147, 163, 179, 196, 215, 234, 255
};
float counter;
float val;
int minMap, maxMap;

// the setup routine runs once when you press reset:
void setup()  { 
  // declare pin 9 to be an output:
  pinMode(LEDpin, OUTPUT);
  Serial.begin(9600);
} 

// the loop routine runs over and over again forever:
void loop()  { 

  proximity = analogRead(sensorPin);   // returns 0 to 1023 in theory (0-5V), but TEST SENSOR
//  Serial.println(proximity);

  minMap  = map(proximity, 0,1023, 0,45);
  
  maxMap = minMap + 128;

counter += .1;
val = sin(counter) * 1000;


val = map(val, -1025,1025, minMap, maxMap);
analogWrite(LEDpin, val);

//Serial.println(sin(counter));
Serial.println(maxMap);
  
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}

i suppose my remaining issue is this:

i'd like to lower the peak brightness value when the viewer is not in close range of the IR proximity sensor. i tried to revise the value here:

minMap  = map(proximity, 0,1023, 0,45);

i experimented with bringing 45 down to various other values, but i didn't see any perceptible difference.

i feel like the answer is really obvious, yet i just can't fix this.

I made some changes to try to bring down the max brightness before close proximity is engaged. seems a little closer now, but the LED is flickering . . . the transition is not smooth.

int sensorPin = A3;        // the pin that the sensor is attached to 
int LEDpin = 9;           // the pin that the LED is attached to
int proximity;
int pwmActual[] = {
  0, 1, 2, 3, 4, 5, 7, 9,
  12, 15, 18, 22, 27, 32, 37, 44,
  50, 58, 66, 75, 85, 96, 107, 120,
  133, 147, 163, 179, 196, 215, 234, 255
};
float counter;
float val;
int minMap, maxMap;

// the setup routine runs once when you press reset:
void setup()  { 
  // declare pin 9 to be an output:
  pinMode(LEDpin, OUTPUT);
  Serial.begin(9600);
} 

// the loop routine runs over and over again forever:
void loop()  { 

  proximity = analogRead(sensorPin);   // returns 0 to 1023 in theory (0-5V), but TEST SENSOR
//  Serial.println(proximity);

  minMap  = 0;
  
  maxMap = map(proximity, 0,715, 0,31);

counter += .1;
val = sin(counter) * 1000;


val = map(val, -1025,1025, minMap, maxMap);
analogWrite(LEDpin, val);

maxMap = constrain(maxMap,0,31);

//Serial.println(sin(counter));
Serial.println(maxMap);
  
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}

togethernessnyc:
@woodinblack, thanks for your input! for a newbie, your code is impressively complex!

Oh I am sorry about that, complexity is not impressive, it is a fault! I must admit I did it in a hurry while doing something else so maybe I could have described it better.

As a brief look it seems you have the right ideas though. So you have a sine wave and the angle is updated at a constant rate, so regarless of anything else, it is 'breathing' in and out.

Producing a sine (cos) wave gives you a number between -1 and 1, so I added 1 (0 - 2) and halved it (0 - 1) which gives you a 'off' to 'on' scale which you can adjust for the speed you want.

Now I don't know what these LEDs you are using are like and how linear they are. One of those other links showed how to do a look up table between those values and the LED values, but that maybe for later.

Now you need the difference between something close and nothing close. There is some level which is the full brightness you want when the proximity is off (I am guessing 0 on the sensor), and there is some level which is the full brightness when someone is touching the device (I assume is 1024 on the sensor), so the rest of the maths there is to make the max value on the sine wave = that brightness.

so convert the 1024 to a double (as if you divide an int by a large number, and then remultiply you will start losing d values), divide it by 1024 (which gives you 0 - 1), then the value for your brightness is:

proximity (as a 0-1) * brightness (as a 0-1 sine) * (255 - 40) + 40;

It may well be that you want the proximity to not be linear between 40 and 255, as I would imagine that wouldn't look right, but until you try it you won't know.

alright!

basic code required some significant revision, but with some help, it's finally nailed. there may be some residual artifacts in there, but this is pretty much the final version.

int sensorPin = A0;        // the pin that the sensor is attached to 
int LEDpin = 9;           // the pin that the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 1;    // how many points to fade the LED by
int proximity;
int maxBrightness;
float counter;
float val;
int minMap, maxMap;

// the setup routine runs once when you press reset:
void setup()  { 
  // declare pin 9 to be an output:
  pinMode(LEDpin, OUTPUT);
  Serial.begin(9600);
  
  counter = 3*PI/2.0;
} 

// the loop routine runs over and over again forever:
void loop()  { 

  counter += .08;
  if(counter >= (7*PI/2.0)) {
    // Change third parameter here to change far range
    proximity = map(analogRead(sensorPin), 0, 250, 255, 0);
    proximity = pow(proximity, 3.0) / 65536.0;
    counter = 3*PI/2.0;
  }
    
  val = (sin(counter) + 1) * (proximity / 2.0);
  if(val > 255)
    val = 255;

  analogWrite(LEDpin, val);

  delay(30);                            
}

the NEXT STEP is to switch from my single LED to a RGB LED strip, and program it to a monochrome blue.

i may be using this great little device, not sure if I mentioned this earlier:

Little dude can take 12 v of power on the VIN pin. I was originally going to use a 5v regulator, but the VIN pin goes to the onboard 5V regulator.

I'm following the Adafruit RGB LED tutorial for making the connection.

I'm revisiting this code, but trying to slow down the fade rate.

naturally, as you slow down the PWM on arduino, the LEDs begin to flicker more.

I've been told I can smooth that out using capacitors.

This raises two questions:

  1. Won't the pulses from the Arduino code be so quick that the LEDs will appear continuously "ON" if the code passes through a capacitor? And if so, how can I change that?

  2. I'm working off of a combination of the following two circuits:


taken from: UP/DOWN FADING LED Circuit

taken from: Usage | RGB LED Strips | Adafruit Learning System

To be more specific, I've been using a Digispark instead of an actual Arduino controller. They have a great community and I've got some good feedback here:

Below are some photos of my current circuit (please ignore the TIP120 in the background, it's not doing anything).

I'm still learning this, so please forgive my newbie questions. I was wondering:

  1. The power should go through the capacitor first before going into the RGB LED strip. The question is, how do I do that? Based on the above 555 schematic, I'm not entirely clear on how the power gets into the capacitor.

  2. The digispark should technically be the "brain" that replaces the 555 Timer . . . so does anyone have any suggestions as to where I can place it in the circuit?

Any schematics welcome!