PID led control

Using the excellent PID library from Brett Beauregard.
Using a LDR to control a LED
when the light levels are high it works fine as shown

the set point is 600 and as the natural day light level falls it goes haywire as shown below

Ive tried messing around with the PID manual tuning settings Kp, Ki, Kd but without success. It seems to me as if the LDR can't read a constant light level as the light falls.
Any help would be much appreciated

What are your Kp, Ki, and Kd settings with the screenshots above?

Correct. As the light level falls, the LDR reading will fall. It would be useless otherwise.

Please post your code (use code tags).

Control it how? Could the light from the led be affecting the LDR? Perhaps some feedback is causing the oscillation. I think you are using a PWM pin to drive the led? Do you understand how PWM controls the brightness of a led?

Kp= 0.1 Ki =10 Kd=0.12. I have got those values from someone who carried out the same experiment on youtube. However I have tried manually tuning it. Putting Ki= 10 , leaving Kd=0 and then slowly increasing Kp. But I find that the output controlling led slightly flickers. I would have expected a more constant light output.
Thanks for your help

Can you be more clear on the objective of your design:

  • Or you are using a PID to control the actual level of light => Then the LED's need to shine on the LDR because a PID regulator does not make sense if you have no feedback.

  • Or you are using the PID as an 'amplifier' amplifying the signal from the LDR, where the LDR its intensity is determined by the light outside. Then PID is overkill and adding complexity that is not necessary.

  • In order to see where the variations come from: measure the output of the LDR with a static source of light, if this is stable, the problem is not there.

  • Offer a constant value to the output of the PWM (no PID), if this is stable, then the cause is not there.

  • Continue as you are doing with the PID, stable input (disabling I, should give stable output).

Hence you can narrow down on the culprit of the problem.

I would also try to run without the Serial.print() statements as they slow down the main loop as they can cause dead time delays in the loop (depending on the implementation of the PID). Dead times are killers for stability.

thanks for helping me. I went back to the project the next day and with a Kp=0.1, Ki=10 and Kd=0 I got the following perfect result
with the ambient light high and a setpoint of 600 I got this

the red graph is the ambient light level falling on the LDR. Its just above 600 and the blue line representing the led output is clearly at zero as expected.
Now with the ambient light level below 600 we get

this is clearly what i'm after a constant output. I wasn't getting that yesterday.
however the ldr is supposed to pick up the some light from the LED which it isn't doing because the led is ultrabright and its angle of light very small. When the light from the led shines some of its light onto the ldr it goes haywire with the led oscillating between on and off wildly

#include <PID_v1.h>

double Setpoint; // pidsetpoint.desired level of brightness
double photocellReading; //input
double ledBrightness; // output

double kp =0.1, ki =10, kd = 0; // tuning values

const int photocellPin = 0; // the analog pin A0
const int ledPin = 5; // the digital pin output 5

//setup the PID

PID myPID(&photocellReading, &ledBrightness, &Setpoint, kp, ki, kd, DIRECT);

void setup() {

  Setpoint = 600;


void loop() {
  photocellReading = analogRead(photocellPin);
  analogWrite(ledPin, ledBrightness);




the problem is when the amplitude of the ldr signal varies either side of the 600 setpoint as shown in the graph below. The led then oscillates. is it possible a piece of code could fix that ?

Have you tried making small adjustments to the PID parameters, for example increasing Kd a little above zero?

Yes you are right. because the LED is not shining on the LDR it is not being used in the feedback loop and this is wrong.
I have included the serial plotter graph below

As you can see the led (blue line) is flickering on and off. It should dim up or down. Do you think this is where I need to tweak the PID tuning parameters until it stops flickering and is a constant dimmed level?

The blue line is the led output. It is too choppy. I need that to be more joined together to look more like a wave than a series of pulses

I read somewhere unless you are needing very accurate control Kp and Ki should be enough to get what you are looking for

I am no expert on PID control. It appears to me that choosing the optimal values for Kp, Ki, Kd is a black art!

As mentioned earlier, perhaps if we understood your application better, we could suggest a simpler algorithm which would be equally effective but not require the parameter tuning that PID involves.

Finding optimal PID parameters depends on the type of system that you are trying to manage.

There are many ways to do one of them is Ziegler-Nichols;

The math behind is uses Laplace transforms to describe the system in algebra.

But the system needs to be LTI Linear and time invariant or you have to linearize in a working point.

Other methods also exist: pole-zero is one of them.

But indeed, it requires a combination of math, simulation and experience.

Essential in this splitting up the reading of the light, the regulator and the actuator (LED) and making sure all of them work in a stable way before connecting all objects together.

It might be necessary to put a filter after the LDR measurement to make sure fluctuations in the LDR measurement do not trigger unwanted outputs.

With integral action, the change in controller output is proportional to the amount of time the error is present.

The proportional gain responds to the setpoint change, and then as time passes, the integral action works to eliminate the offset and bring the process variable back to setpoint.

The proper amount of integral action must be used. If there is too little integral action the system
will be sluggish and takes too long to get to setpoint. If there is too much integral action the system could end up oscillating and never settling down.

Start with all your gains at zero. Set your Proportional Gain much higher - I would guess anywhere from 8 - 15. What you want is your output to overshoot your setpoint from the LDR. Once you find a Kp that overshoots, start adding a little bit of Integral Gain. Not much, maybe 0.1 - 2.5 I would guess, but it's a process and it takes time and may be more. If you decide to use Derivative Gain, you do not need much at all, it will help with overshoot, but can again cause your output to oscillate and make it "jittery".

Thanks for your help and advice ,very much appreciated. It was your point that if the light from the led is not adding to the light at the ldr there is no feedback control at all. However I am using ultrabright leds and at the moment the ldr is shining on the ldt from a distance of 30mm. Increasing the distance between them might help.
also you mention in your comment ' what you want is your output to overshoot your setpoint from the LDR'. The output from the LED will never reach the setpoint (600) because the output is an analogWrite pwm with maximum 255.
I will increase the distance between the LDR and the led and carry out your tuning procedure as mentioned above,

thanks again

I think it's a timing issue. You currently have ...

  • LDR rise time (light, 1000 lux) : 3 ms
  • LDR rise time (dark, 10 lux) : 20 ms
  • PWM period: 1-2 ms
  • Loop speed: 7 ms (9600 baud print speed)
  • PID sample time: 100 ms (default)
  1. Try changing the print baudrate to 115200.
  2. In setup, try including: myPID.SetSampleTime(5); //5ms
  3. Could optionally slow and smooth the LDR response by adding i.e. 4.7µF capacitor from analog input to GND
  4. If the oscillation matches the PWM frequency, its possible to greatly increase the PWM frequency (say 25kHz with some direct register setup code.

I am afraid that at first you will need to determine the properties of your system because it is very well possible it is unsuited for PID control. But anyway, proving that something is not possible is also a result.
Therfor, before getting started with the PID itself it is essential to do some experiments to see if the system is fit. As said in my previous post, if a system is not Linear and time invariant or can be linearized around a certain working point, it can be difficult to manage, but first things first:
Would it be possible to scale your in put and output in a range 0-100%. PID control is easier to manage if you only have to take % into account.
Then: let the output increase in steps 5% a range 0-100% and measure what is coming out of your LDR sensor ADC => this way we can see if there is real feedback or not. I read in your previous post, that you assume that as the angle of attack between LED and LDR is what it its, you think there is no feedback in some cases.
As said before: if there is no feedback, PID is not applicable because it relies on feedback (or you have to build a feed forward controller but that is another topic).

There is software (I wrote it), that you can use to change the values of the PID parameters and of the outputs without stopping your PID loop. The software is called WawiLib and it comes in quite handy if you want to experiment. You can look at the inputs, see the outputs, manipulate PID parameters while the whole thing is working. You can even record the values of the parameters to a file.

Looks like the LED/LDR system + code responds in say 10-20ms, but the PID rate is 100ms. The PID rate should be at least 2.5 times faster than the system its controlling. If the PID rate is slower than the system's response, oscillations are guaranteed.

Just 2 lines of code will make a huge difference ...


this is the schematic of the circuit.