Fading HELP

And also one important notes: the incoming useful data from the sensor are in range 160-700.
Please do you know how to convert (lineary) these data to range 0-255?
Thanks a lot!

Sorry I don't have tome to look at your code problem, but I can help with this.

The range 160 -> 700 is 540. You need this ranged to 256. 540 / 256 = 2.11

To do the ranging, first subtract 160 then multiply by 2.11 -> (x-160) * 2.11

That will put you into using floating point numbers (not necessarily a problem), but if you can stand 5% inaccuracy you could just multiply by 2 instead of 2.11 and stay in integer territory.

Regards,

Mike

#define NUMREADINGS 10 // nastavuje pocet prumerovanych cteni na 10

int sensPin = 0; // sensor zapojeny na analog pin 0
int ledPin1 = 11; // led zapojena na digital pin pwm 11
int ledPin2 = 10; // led zapojena na digital pin pwm 10
int ledPin3 = 9; // led zapojena na digital pin pwm 9
int ledPin4 = 6; // led zapojena na digital pin pwm 6
int ledPin5 = 5; // led zapojena na digital pin pwm 5
int ledPin6 = 3; // led zapojena na digital pin pwm 3
int ledPin7 = 13; // led zapojena na digital pin klasik 13
int sensval = 0; // variable na signal ze senzoru
int ledval = 0; // variable na signal do LED

int readings[NUMREADINGS]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // vysledny prumer

void setup()
{
pinMode (ledPin1, OUTPUT); // deklaruje ledpin jako výstup
pinMode (ledPin2, OUTPUT);
pinMode (ledPin3, OUTPUT);
pinMode (ledPin4, OUTPUT);
pinMode (ledPin5, OUTPUT);
pinMode (ledPin6, OUTPUT);
pinMode (ledPin7, OUTPUT);
Serial.begin(115200); // initialize serial communication with computer - LZE TIM ZRYCHLIT ODEZVU
for (int i = 0; i < NUMREADINGS; i++)
readings = 0; // initialize all the readings to 0
}
[/color]
[/quote]
The first thing I notice is that your variable "i" in the for loop: for(int i = 0; i < NUMREADINGS; i++) is not defined at the beginning of the program. Add int i = 0 to the definitions.
> void loop() {
*> *
> total -= readings[index]; // subtract the last reading
> readings[index] = analogRead(sensPin); // read from the sensor
> total += readings[index]; // add the reading to the total
> index = (index + 1); // advance to the next index
>
> if (index >= NUMREADINGS) // if we're at the end of the array...
> index = 0; // ...wrap around to the beginning
>
> average = total / NUMREADINGS; // calculate the average
> }
The next thing I notice is that the way you have your averaging code setup it's not subtracting the last reading taken. It's subtracting the next reading before it's taken. This could be causing your total to be higher than it should after you've taken the first 10 readings. Try rearranging it like this:
total -= readings[index]; // subtract the last reading

  • index += 1; // advance to the next index*
  • if (index >= NUMREADINGS) // if we're at the end of the array...*
  • index = 0; // ...wrap around to the beginning*
  • readings[index] = analogRead(sensPin); // read from the sensor*
  • total += readings[index]; // add the reading to the total*
  • average = total / NUMREADINGS; // calculate the average*
    Let us know what this does for you. After that we can talk about making the LEDs fade in and out (which can be as simple as using variables for the analog out values). Also, which LEDs were the only "two" fading with your original code? You might also want to double check your LEDs to make sure none of them are backwards.

The first thing I notice is that your variable "i" in the for loop: for(int i = 0; i < NUMREADINGS; i++) is not defined at the beginning of the program. Add int i = 0 to the definitions.

Not necessary. Declaring int i=0 as the first expression to the for loop is sufficient. The counter used here does not need to be global--it may be local to the block, and still be totally kosher.

Err...that's all I have to add. Carry on!

Didn't know the declaration wasn't required. Thanks ccarlson

Hmm, it just occurred to me that the averaging routine as you originally wrote it, JURA, would properly average all the readings in the readings[] array, so my correction to your code is wrong. My incorrection would merely track the current reading. In otherwords, ignore the code I posted. Sorry :(. I'll have to analyze your code further and see what I can come up with.

Can you give a more detailed description of what happens with the hardware. How exactly does each LED light in response to what your IR sensor reads? Do the numbers you read from the serial port agree with what you're testing? Are you using an IR LED at different ranges to test the sensor?

Thanks for all replies!
BigMike: I´ll try it. Thanks a lot in way how to thing about the problem!
I think I will have to divide (not multiple) it by 2.11 to get the result on range 0-255. Isnt it true?

Floating points... Is there some problem with them using as a value for a PWM output?

Quijonsith: thanks for your deep interest. The part of the code with smoothing the signal with averaging the readings is taken from the tutorial on arduino learning web page... This was working ok - I tried to change the number of readings and I saw visible result... So this part of the code is OK I think - but to be honest I dont understand it at all. :-[
The working code works that IRsensor detects the distance. When distance value is in condition, then specified LED is turn on. It is working very well. .... maybe the latnecy could be smaller to faster interactivity....

WHat I want to do now is to FADE OUT the led when the condition is not true anymore.

The totaly problematic is the RED part. Its probably all wrong....

Please how to program this ( I say it in somehow normal language...]:

If condition is true do something just once - even if condition is still valid. You can do it once again only after the condition is not true.

That will solve probably the problem.
I realize that I dont know how to say do it just once. It is doing onceagain and anceagain if the condition is still valid....

and also how to program fade after the if condition...

Sorry for my beginers problems / but I tried it alone and it was quiet difficult and timewasting in this moment...
Thanks a lot!

If all you need is to fade the LEDs out once they shouldn't be on, that's not very hard. I'm at work right now, but when I get home tonight I'll work up a couple algorithms for you to try and see which you like better.

As far as the beginner questions, quite frankly I would consider this to be slightly above beginner and into the realm of intermediate atleast. Beginner would be simply getting the LEDs to light :wink:

long time; // pocita cas millis od spusteni programu
long LED1ON = 0; // will store last time LED1 was used
int interval = 1; // interval rozdilu mezi ON/OFF

void loop() {
if (average >= 600)
{ ledval = 255;
analogWrite (ledPin1, ledval);
LED1ON = millis ();}

So far you defined your time tracking variables (though I didn't see the time variable used in your code). Then you check if your reading is over 600.
If it is, you set your ledval = 255 (max analog output), then set the analog pin "ledPin1" to ledval, in other words turn on the led at full brightness.
Then you're recording the time, in milliseconds, that the led was turned on by setting LED1ON = millis().

else
{analogWrite (ledPin1, 250); }
if (millis () - LED1ON == interval);
ledval -= 25;
{analogWrite (ledPin1, ledval);}
if (ledval=0);
{return;}
}

Then you have what happens if the average is not >=600.
First you have it set the ledPin1 output to 250, which is almost full on and not enough really difference to see it being dimmer than full on. So no matter what, you're turning that LED on and full brightness.
Next you're checking if the current time - LED1ON = interval. Interval is set to 1, so you're checking if the current time is 1 millisecond greater than when LED1ON was set. The problem there is the timing. It would be very hard to have the interval actually = 1 millisecond. This should be checking to see if millis() - LED1ON >= interval.
Next you're trying to gradually lower ledval by 25 and write that to ledPin1.
Finally, if ledval is 0, leave the routine.

Thanks a lot for any idea and suggestion!
P.S.: Sorry of my english - I am not native speaker....

Personally I think your english is excellent for not speaking it natively. Sometimes the hardest thing to do is try :wink:
Now on to some code suggestions:

If I understand you correctly, you want the LED to turn on only when the value first gets to that range, then fade out, even if it's still in that range, and the problem is that your LED is staying on as long as the range is true. If that's the case, here's how I would solve that problem aswell as making the LED fade reliably:

long LED1ON = 0; // will store last time LED1 was used
int interval = 1; // interval rozdilu mezi ON/OFF
int LED1Trigger = 0; //stores if LED1 is already on
int led1val = 0; //analog output for led1
int ledDecay = 25; //how fast the leds fade to off
...
void loop() {
if (average >= 600 & LED1Trigger == 0) //if the average is high enough and LED1 is not already on
{ led1val = 250; //set the brightness of LED1
LED1Trigger = 1; //store the fact that LED1 is now on and average has not gone out of range
LED1ON = millis ();} //store what time LED1 was turned on
if (average < 600 & LED1Trigger == 1) //if the average has gone below this range and LED1 was already on
{LED1Trigger = 0;} //store the fact that average has gone out of this range
if (millis () - LED1ON >= interval & led1val > 0); //if it has been more than "interval" milliseconds since LED1 was turned on and LED1 has not dropped to 0 brightness
{led1val -= ledDecay;} //start fading out LED1's brightness
analogWrite (ledPin1, led1val); //set LED1 to it's brightness
}

A couple of notes:
ledDecay can be used the same for all ranges and LEDS. Making it higher will of course make them fade faster.
The way this is setup, if you were to remake the code for all of your ranges this way (seperate variables for each range such as LED2Trigger, led2val, LED3Trigger, etc.) then you could have one led turn on while another one is still fading out, but none of them "should" stay on with this code unless you are rapidly moving in and out of the same range.

There are other modifications I could do to this code, such as making the LEDs fade out on a logarithmic scale instead of a linear one, but for now this should get you going unless I've missed something or messed up any of the syntax. Please look over my code when you test it to make sure I didn't misspell any variables (ledDecay does not need to be made led1Decay, led2Decay, etc) and I haven't missed any symbols like {} or anything.

As far as maping your data from 170-700 to 0-255, you could use the map () function like this:
average = map(average, 170, 700, 0, 255);

This function works with integers. See http://www.arduino.cc/en/Reference/Map

Hope this is what you are looking for. I'd love to see some video of your LEDs in action if possible :wink:

Have fun with your project,
-Jon

PS: Is this just something to experiment with or do you have a larger project/goal you're planning?
This actually gives me ideas to use this technique with audio as the source like you're using IR. I like the idea of only turning on the first time the value is in range.

Quijonsith thanks a lot!

I´ve tried your notes and here is the result:

1.)GOOD NEWS: map function is mostly working. I´ve made simple code to test it:

average=map(average, 170, 700, 0, 255);
analogWrite (ledPin1, average);

it is working, but only when IR is detcting something.
BUT when the space infront of the IR is empty ( so the measured data is about 160 -- so this might be remaped to 0) the LED is fully shining. Thats the first problem... :stuck_out_tongue:

2.)
I ve put your improved code into arduino (and check the syntax ;}{ etc..) and the result is, that the led was very little blinking all the times and it does not react to average data....

so I have deleted all the parts with the millis, because logicaly I though it could also work in very simple way
(also I ve put && instead & in if condition - as I understand when used && then both conditions must be true.
But what happens when just & is written - is it the same or not???):

if (average >= 600 && LED1Trigger == 0) //if the average is high enough and LED1 is not already on
{
led1val = 255; //set the brightness of LED1
LED1Trigger = 1; //store the fact that LED1 is now on and average has not gone out of range
}
if (average < 600 && LED1Trigger == 1) //if the average has gone below this range and LED1 was already on
{ LED1Trigger = 0; //store the fact that average has gone out of this range
led1val -= ledDecay; //start fading out LED1's brightness
analogWrite (ledPin1, led1val); //set LED1 to it's brightness
}

The result was that when I was in range, the LED lights on}OK thats GOOD!) and stay shining even when I moved out of the range... (thats BAD...)

So I ve tried simple test of the fading code:

if (average >= 600 ) //if the average is high enough and LED1 is not already on
{ led1val=255; // set the starting value to max
led1val -= ledDecay; // start fading out LED1's brightness
analogWrite (ledPin1, led1val); //set LED1 to it's brightness
}

But the result was , the same - LED starts shinig and stay shining all the time and didnt react on anything....

3.) I ve noted that when LED puted on PWM+ (just pin6) and no specified data is send there, the LED is shining.
(i ve just declard it as output - nothing more...). Is it normal? But the PWM+ in pin 5 doesn´t do this....

4.)

LED1ON = millis ();} //store what time LED1 was turned on

How does this work? Is it storing just the time the led is shining (for example 300ms) or is it giving to LED1ON the value from the central clock?
Does the millis work as the central clock of the program running all the time from the starting program?
So when i say LED1ON = millis and the millis in this moment is for example 32512345, then the LED1ON is 32512345??
Or it starts counting the time in millis from this moment? (so it will be 0 and rising up...)

Thanks a lot!

I am really beginer - I´ve bought the arduino one year ago, but when I looked at programming enviroment I said UFFF! :o and put arduino back to the box...
I opened it again 5 days ago. Fisrt day I pathed through Geting started. Next day I read mostly the all Reference. The third day I tried some learning programs and check what the hell these numbers and signs are doing... Then I tried to changing some values and check what it is doing.... As I simply understand it I ve tried to create my first program. So and here it is...

Thanks alot with helping! :slight_smile:

P.S.:
Now it is experimenting - learning the code and hardware, but yes I want to make a small interactive project - thats the reason why I am learning and putting effort in it. I will put video on youtube, when it will be working.
Anyway I live in the Czech republic and making music and video, but now interactivity is intersting me very much!
The idea of audio as input source is great! This could be some LED music like an old chinesse cassete players... :smiley:

Cheers JIRI

And one more question:
when this code is runnig:

ledval -= 25;
analogWrite (ledPin1, ledval);

  • what is the speed of the substracting?
    (when nothing about it is more specified... would be this even working???)
    Is not important to set up some delay function there?
    Sorry for the lot of questions - if there is some other step by step tutorial with showing different (basic) coding situations to solve I will check it.
    I ve checked the arduino.cc web but now I have still some questions....

Thanks for all replies!
BigMike: I´ll try it. Thanks a lot in way how to thing about the problem!
I think I will have to divide (not multiple) it by 2.11 to get the result on range 0-255. Isnt it true?

You are correct, it should be a divide. Or you could calculate 256 / 540 and multiply by that.

I haven't tried it on an arduino, but intuitively I guess is a floating point divide will take longer than a floating point multiply. It feels safer at least.

Floating points... Is there some problem with them using as a value for a PWM output?

No problem - its just integer sums are quicker than floating point sums.

Regards,

Mike

Quijonsith thanks a lot!

I´ve tried your notes and here is the result:

1.)GOOD NEWS: map function is mostly working. I´ve made simple code to test it:

average=map(average, 170, 700, 0, 255);
analogWrite (ledPin1, average);

it is working, but only when IR is detcting something.
BUT when the space infront of the IR is empty ( so the measured data is about 160 -- so this might be remaped to 0) the LED is fully shining. Thats the first problem... :stuck_out_tongue:

The result was that when I was in range, the LED lights on}OK thats GOOD!) and stay shining even when I moved out of the range... (thats BAD...)

So I ve tried simple test of the fading code:

if (average >= 600 ) //if the average is high enough and LED1 is not already on
{ led1val=255; // set the starting value to max
led1val -= ledDecay; // start fading out LED1's brightness
analogWrite (ledPin1, led1val); //set LED1 to it's brightness
}

But the result was , the same - LED starts shinig and stay shining all the time and didnt react on anything....

3.) I ve noted that when LED puted on PWM+ (just pin6) and no specified data is send there, the LED is shining.
(i ve just declard it as output - nothing more...). Is it normal? But the PWM+ in pin 5 doesn´t do this....

To fix the new problem you could reverse all of your code, changing 255's to 0's and 0's to 255's aswell as changing to ledval-= to ledval+=, or you could do it the easy way and reverse your LED as it sounds to me like it's in backwards. :wink:

The millis() function returns the number of milliseconds since the program started, so it's like an internal clock. So when it says LED1ON = millis(), if the program has been running for 7298319 milliseconds, that's what is stored in LED1ON. Then later when you have if(millis() - LED1ON >= interval) it's comparing the current number of milliseconds since program start to LED1ON. So "interval" is how many milliseconds the LED will stay on until it starts to fade out.

Using millis() instead of delay() allows the program to do other things (like compare the other ranges) while it waits to fade the LED, instead of sitting and doing nothing until it's time to fade the LED. So using:
LED1ON = millis();
if(millis() - LED1ON >= interval);

is the same as:
delay(interval);

Only it lets your program keep running. If the LED isn't fading out smoothly/slowly enough for you then you can decrease the subtraction, such as led1val-=1. If it starts fading too soon, increase interval.

You could also hook a potentiometer up to another analog input and read it's value as interval, or do the same for the subtraction value, or both, and you would be able to adjust them while the program is running without having to rewrite your program every time.

Also:
if (average >= 600 ) //if the average is high enough and LED1 is not already on
{ led1val=255; // set the starting value to max
led1val -= ledDecay; // start fading out LED1's brightness
analogWrite (ledPin1, led1val); //set LED1 to it's brightness
}

The problem with this test fade code is every time it runs it sets led1val to 255, so even though it subtracts afterwards, as long as you're >=600, led1val gets set to 255 again. The subtraction and analogwrite should be outside the if statement.

Try my code again, but with the LED reversed from how it is now and try simply adjusting ledDecay and interval as I described.

Also, you are correct about using && in the if statement. That's why I asked you to look it over ;). I haven't programmed in a long time so I'm still remembering the syntax.

[edit]Also, here's the reference for millis():
http://www.arduino.cc/en/Reference/Millis[/edit]

thanks for your suggestions!

I ve tested something and when I think the code could be working its telling me " expected ) befor { token "

here is the new ON/OFF fading code:

if (average >= 600 ) //if the average is high enough
{ led1val = 250; //set the brightness of LED1 - its normal FULL SHINE without fade
LED1ON = millis (); //store what time LED1 was turned on
}
if (average < 600 && (millis () - LED1ON <= 25 ) // if the average has gone below this range and the time elapsed from the
// change of the condition is less or equal 25ms
{ do { led1val -= ledDecay; // start with fading out
analogWrite (ledPin1, led1val); // write the fading value
}
while (led1val > 0); // untill the LED is completly OFF
}

I really didnt think that the fading could be so dificult.... :stuck_out_tongue:
Nothing worked well yet... nonstop looped fading, or just little bit blinking.....

But thanks to your comments I slowly start to understand the data flow :slight_smile:

thanks for your suggestions!

I ve tested something and when I think the code could be working its telling me " expected ) befor { token "

here is the new ON/OFF fading code:

if (average >= 600 ) //if the average is high enough
{ led1val = 250; //set the brightness of LED1 - its normal FULL SHINE without fade
LED1ON = millis (); //store what time LED1 was turned on
}
if (average < 600 && (millis () - LED1ON <= 25 ) // if the average has gone below this range and the time elapsed from the
// change of the condition is less or equal 25ms
{ do { led1val -= ledDecay; // start with fading out
analogWrite (ledPin1, led1val); // write the fading value
}
while (led1val > 0); // untill the LED is completly OFF
}

I really didnt think that the fading could be so dificult.... :stuck_out_tongue:
Nothing worked well yet... nonstop looped fading, or just little bit blinking.....

But thanks to your comments I slowly start to understand the data flow :slight_smile:

if (average >= 600 ) //if the average is high enough
{ led1val = 250; //set the brightness of LED1 - its normal FULL SHINE without fade
LED1ON = millis (); //store what time LED1 was turned on
}
if (average < 600 && (millis () - LED1ON <= 25 )) // if the average has gone below this range and the time elapsed from the
// change of the condition is less or equal 25ms
{ do { led1val -= ledDecay; // start with fading out
analogWrite (ledPin1, led1val); // write the fading value
}
while (led1val > 0); // untill the LED is completly OFF
}

You missed a ) in the if second if statement (see where I put the red one).

ups ::slight_smile: (I ll never again make post like this....)

But the led is still fading onceagain and onceagain :-/

I just want to fade out once

Somewhere here is the problem / please look at my RED interpretation of the code:

if (average >= 600 ) //if the average is high enough
{ led1val = 250; //set the brightness of LED1 - its normal FULL SHINE without fade
LED1ON = millis (); /store what time LED1 was turned on - does it stop writing millis() to LED1ON
when the if condition is not valid???
/
}
if (average < 600 && (millis () - LED1ON <= 25 ) /* if the average has gone below this range and the time
elapsed from the change of the condition is less or equal 25ms /
{ do { led1val -= ledDecay; // start with fading out
analogWrite (ledPin1, led1val); // write the fading value
}
while (led1val > 0); /
untill the LED is completly OFF - when the led1val will be 0 then the
do loop will stop and than program will check the if statement: the result might be false,
because millis() - LED1ON might be bigger than 25ms - is it right??? */
}

Finally I ve found simple soulution. Thanks for any support :wink:

But I have another begginers problem:

Please how to write in code three conditions for if?

I used multiplied &&:

if (condition1 && condition2 && condition 3 )
{ //do something }

but only first two conditions were checked.
Do you know how to test all three conditions?

Thanks a lot!

In a compound logical and statement like that, the compiler produces code that will stop checking as soon as any condition is false. So if condition1 is false, conditions 2 & 3 aren't checked. If condition2 is false then condition3 is not checked.

If this doesn't explain what is happening then post the smallest working sketch that illustrates what you are observing.

:)Thanks. I understand. Now works well.

So it si possible to set even unlimited more conditions with &&, isn´t it right? ::slight_smile:
Then the code is checking from the first condition on left to the last on the right and when the first is false the loop stops.

Exactly. So if you have a condition that is more likely than the others to be false, its most efficient to have that one first so no time is wasted evaluating expressions that don't matter.