Noisey Analog photoresistor read

I have a project. The project comprises an RGB LED, a light tight tube, and a photo resistor at the other end. There is a slot in the tube, into which I can put Photographers filters

Here is the filter book

each filter comes with a graph, showing the transmission of light (100% to 0%) over a range of wavelengths, (300 to 800 nm, which can be considered blue through to red to all intense purposes)

here is the setup (there is a hole vertically though the wooden block)

Upon button press, the LED scrolls through its colour range. I did this by starting fully blue, fade green up, then once green is 100%, fade blue down, and once blue is at 0%, fade red up, followed lastly by fading green back down again.

the sketch fades "5" of the "255" per cycle of the processor.
on each cycle it prints the PR resistance to the serial port.
there is a 20ms delay on each cycle to let the LED and PR settle (and so one can observe the colour change)

Now on this here graph, (Y axis Analog read from the PR, X axis is sketch cycle).
No filter, is self explanatory, no filter. I kind of expected it to be a bit rough, as the PR has limitations in detection, and the LED certainly wont output pure light

OP (Opaque) is the dark line at the bottom, and involved placing black card in slot, effectively darkening the PR completely.

Now the colour graphs are "OK" upon comparison to the provided filter graphs, but in the loosest sense. The basic form is there, but little more.

Can some one please provide a suggestion as to where the spikes on the OP line are coming from please ?

I think if i can eliminate this "noise" i will get much better results.

FYI, The PR is set up with one side wired to the A2, and Ground, and the other to +5V via a 10k ohm resistor

Maybe i can eliminate the spikes with some mods to the sketch, or is it more likely to be a physical thing?

Also, i have no idea what the flat table in the middle of the green line is, but i ran the sketch twice, and got the same flat table...

I would guess that the photoresistor is fast enough to be affected by the PWM of the LEDs. Try increasing the PWM rates.

http://www.arduino.cc/playground/Main/TimerPWMCheatsheet

The hardware solution would be to add a capacitor between the anode of the LED and GND to smooth out the current.

Now on this here graph,

I am not sure if I follow the chart and those lines.

photoresistors are very slow reacting to sudden light increases: on the tune of 100ms or so. So you may want to slow down your fading on / off to actually measure light intensity.

As to the plateau, show your hardware set-up may help people help you.

The sketch outputs the reading taken from the PR, once per "fade unit" on the LED.

this results in a column of data pasted into excel
The sketch is re run for each coloured filter, and the column pasted into the file

the x Axis, represents the cycling from Blue (Left most) through to Red (Right most). The units are currently only "line numbers"

The Y axis represents the reading from the PR. as the colour changes on the LED, the filter allows only a certain percentage of light through to teh PR.

for each colour, there is a separate column in the data set, and therefore a separate line on the graph.
The Dark grey represents an opaque filter, and in theory should sit at or close to 1023 and be stable...
the Light grey represents no filter, and is expected to be "high" on the graph (low resistance) but how high is not known, as it this will depend on the sensitivity of the PR and the quality of light out put by the LED.

ideally the coloured graphs will be adjusted so that the 100% light transmission is defined by the light grey coloured line, as 100% on the Y axis, and 0% is defined by the Dark Grey line.

Concentrate on getting a steady reading with the opaque filter. Things to check:

  1. Is the filter really opaque? If you hold it in front of a light in an otherwise dark room, can you really not see any light at all through it?

  2. Are you sure that artificial room lighting isn't reaching the LDR? Room lighting is modulated at 50 or 60Hz, so it will make the reading vary. Try with the lights off.

  3. What value pullup resistor do you have connected between the analog input pin and +5V?

  4. Is there mains wiring anywhere near the LDR or Arduino, which could be causing interference?

  5. If you modify the software so that the LEDs are always off, does the amount of variation decrease?

Once you have a steady black level, you can work on the response when you use filters. I agree with Chagrin that you may have to increase the PWM frequency. LDRs react slowly at low light levels, but much faster with high light levels.

Hi dc42. That was my thoughts, the opaque SHOULD be super predictable and stable, so thats the one to concentrate on.
so your suggestions in order:

  • The filter is very opaque. held directly over a Halogen Desk lamp, you can JUST see a glow through it, but it gets very hot very quickly. The LED has nothing on the power of this lamp.
  • I am pretty certain no exterior light is getting in. the setup has a slot barely big enough to fit the filter into, and is encased on all sides by ply or natural timber (modified further than the picture above). Running the test in the dark makes no difference. I have also blacked out the onboard LEDs on the duino on the off chance they were shining through the shield
  • the pull up resistor is 10k ohm.
  • i moved the USB to a front mounted port on the PC, rather than in the back. I dont THINK it made any difference. It is still very spiky.
  • i have run the program without the "write to LED" line in it, so it still carries out all the calculation. It still creates the spikes just the same

Maybe a change of resistor would help, the spikes are effectively the voltage returning to LOW?, but what would you suggest on that front?
I will have a fiddle with the PWM,if i can work it out...

Thank you kindly.

more graphs.

The Blue line is with "//" before the "write to LED" line. The duino still carries out the calcs.
the red line is with a "//" before EVERYTHING other than "write PR value to serial port"
less spikeyness, but the spikeyness is still there.
the LED isnt doing anything either, its off, so it cant be PWM sensitivity?

suggestion as to resistor change perhaps?
i wouldnt know where to start there :blush:

Can you post your code? (or did I miss it)

The flat green line can be both a short circuit or a SW artefact.

If I were you, I would fix one color and vary the other two colors, and then plot out the PR readings (assuming sufficient delay) two dimensionally. You will see smoother pattern or your setup is wrong.

Code is below. Sorry, i could have done something daft in there.

whats an "SW artefact"??
it did occour to me that it could be a short, but i started off with the circuit on a breadboard, and have subsequently put it onto a veroboard. both builds have the same issues.
Also, the spikes back on the colours graph nr the top, all line up, which suggests to me it could be an arduino issue, rather than the hardware.
i dont suppose i can clean up the power supply recieved from the usb, but obviously i need it to read the serial port.

I am trying to sort the PR values, with no colours involved. on the lastest tests, the LED has been off (write 255 to all pins as it is common anode, rather than cathode)

const int LEDR = 6;
const int LEDG = 5;
const int LEDB = 3;
int PR1 = A2;

const int button = 4;
//int Scale = 0;


void setup(){

  Serial.begin(9600);

  pinMode (LEDR, OUTPUT);
  pinMode (LEDG, OUTPUT);
  pinMode (LEDB, OUTPUT);
  pinMode (PR1, INPUT);

  pinMode (button, INPUT);

  analogWrite(LEDR, 255);
  analogWrite(LEDG, 255);
  analogWrite(LEDB, 0); // Program Starts Blue
 

}

void loop()  { 

  analogWrite(LEDR, 255);
  analogWrite(LEDG, 255);
  analogWrite(LEDB, 0); // Program Starts Blue

  while (digitalRead (button) == HIGH){
    // stops script. Its waiting for a button press (LOW on "button")
  }

Serial.println("************************Break*********************");  
  //Scale = 0;

  //Green Up
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    analogWrite(LEDG, fadeValue);
    delay(20);  
    PR1 = analogRead(PR1);
    Serial.println(PR1);
  
                           
  } 

  //Blue Down
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    analogWrite(LEDB, fadeValue);   
  delay(20);      
    PR1 = analogRead(PR1);
    Serial.println(PR1);
                      
  } 

  //Red Up
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    analogWrite(LEDR, fadeValue);  
    delay(20);    
    PR1 = analogRead(PR1);
    Serial.println(PR1);
                         
  } 

  //Green Down
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    analogWrite(LEDG, fadeValue);      
   delay(20);     
    PR1 = analogRead(PR1);
    Serial.println(PR1);
                            
  } 



}
PR1 = analogRead(PR1);

That's the problem. You are overwriting variable PR1 with the reading, and then using that as the pin number in the next iteration. So you are reading the values from random analog input pins.

Change the type of PR1 to 'const int' (so that you can't make this mistake), and store the return value from the analogRead() call in a local variable instead of in PR1.

Woah. Thats the Badger. Sorry i didnt put the code up earlier.

Im a bit of a noob, so tend to take "example" codes, and then mash them together. I think i see what i did wrong there. I also think i see why on the sample code I was referencing it wasnt causing any problems. :blush:

Though there are anomalies which still confuse me.

prime example, some codes specify that pins are either input or outputs.
others, they dont bother.
does it matter which way around you do these things?

every day is a school day, still learning. I will try and regraph this data now...

Thank you kindly.

OllyR:
prime example, some codes specify that pins are either input or outputs.
others, they dont bother.
does it matter which way around you do these things?

All pins default to being inputs, so using a pinMode call to specify that a pin is an input (without pullup) is optional.