PID Control - Photocell

example code

1. Introduction

A proportional–integral–derivative controller (PID controller or three-term controller) is a control loop mechanism employing feedback that is widely used in industrial control systems and a variety of other applications requiring continuously modulated control. A PID controller continuously calculates an error value e(t) as the difference between a desired setpoint (SP) and a measured process variable (PV) and applies a correction based on proportional, integral, and derivative terms (denoted P, I, and D respectively), hence the name.

2. The simplest PID control setup - the photocell and the LED.

Connect the Arduino board, the photocell, the LED, and the resistors as shown in the following schematic:

The photocell shows very large resistance in dark. The stronger the light it receives, the lower the internal resistance it has. By sensing the voltage at the bottom pin of the photocell in the schematic above, the voltage at A0 increases as the light gets more intense and vice versa.

Test the ambient light intensity. Keep in mind that the circuit setup doesn't have an 'Ambient Light Dimmer'. You cannot make your ambient light intensity weaker than what you have (it is from the sun!). At a different time point (it receives different amount of light during different time of the day) you are testing your circuit, you must test the ambient light first before you move forward.

If the ambient ligh intensity is very strong and easily saturates your photocell, you may use a box to cover your photocell to block some of the light.

In the following example, I did this experiment at noon, it was very bright in the room, the ambient light intensity received by the photocell is 677 (0-1023).

In my PID controller, the setpoint must be larger than this value because I can not make it dimmer, the only thing the external LED can do is add more light.

Now, I will turn on the LED to the brightest level and see what is the maximum value being receied by the photocell:

Is this correct?

Remember the Arduino board is running at 16M Hz, from 'digitalWrite(3,255)' to 'int ambientLight=analogRead(A0)' may only take several microseconds. Before the LED is being turned on to the full brightness, the 'ananlogRead' function has been executed and the light intensity being read to the CPU is smaller than the real value.

So, we need a time delay after the 'digitalWrite()' function:

After the delay function is added, the intensity is a lot higher than the previous one, and it reflects the real light being received by the photocell.

Now I know my current ambient light intensity is 677 and the brightest light my LED can provide plus the ambient light is 924. I'll set the SP (set point) to the middle of these two values: 800.

Now let's look at the the following code to implement the PID controller.

(Note that I did not use the Ki*I so I've to integrate the PID_value to make it work, which is PID_value=PID_value+Kp*p+Ki*I+Kd*D. If you have a non-zero Ki value, you can directlly use PID_value=Kp*P+Ki*I+Kd*D)

The set point is 400 but the ambient light is already way above the setpoint. The system will never be able to reach the set point!

Task 1: Fix the code above to make the sensed light oscillate around the setpoint (use an appropriate setpoint). Complete the blocked line for the 'PID_value'.


3. Add an extra LED to change the ambient light

We can add an extra LED light beside the photocell to see the respose of the PID controller:

Connect the following circuit. Use a pushbutton to turn on/off the LED.

Now, change Kp to 0.001. Run the program, turn on/off the LED and observe what the real-time plot looks like:

At 0:03, I turned on the extra LED (hold the push buton) so the signal being received the photocell is more than the SP. The PID controller generates a negative error to reduce the light from the original LED to bring the intensity back to the set point. At 0:20, I release the push button to turn off the extra LED. The PID controller must send more power to the original LED to bring the light intensity back to the set point.

Aparently the 'P' gain is too low. I changed it to 'Kp=0.1', it looks like this:
At 0:03, I pressed the pushbutton to turn on the LED and held it. At 0:06, I released the pushbutton to turn off the LED.

Task 2: Repeat the work in this section. Save the data in a local drive and plot your data use Python and present your data in your report. Show clear X/Y axis, labels, and titles.
Record and plot data using Python can be found in this link:
Refer to the lectures on Aprial 12th for how to save your data to your local drive. Refer to the lectures on March 1st and March 11th for plotting/presenting your data using Python.

4. Setpoint tracking

The set point can be a variable and your system must be adjusted to follow the set point in real-time.

Add an extra pushbutton to your system, every time you push the button to trigger activate a new setpoint, the board will detect a signal and the PID system will adjust the setpoint to a new value.

A function 'setPointChange()' was added to the script. I was trying to add 10 to the LED intensity every time I push the button. However, this code won't make it.

** Correction: I=+error should be I+=error

An exmaple sketch of the pushbutton detection

Keep in mind that the CPU runs at 16M Hz, the mechanical pushbutton won't give you a clear step function but a lot of bounces. Also, how can you make your code only detect one 'push' when you push it? You finger definitely cannot push it at the similar rate (16M Hz), which means when you push it even though you think you did it fast, the loop() function has been executed for thousands of times.

Task 3: Fix the setPointChange() function to enable the desired PID function as follows. Plot both the SP and the sensor data in a same figure using Python. Present your result in your report.

Complete Task 1 - Task 3, upload your report to the website.