Introduction: Arduino and LDR

Light Dependent Resistor is as the name suggests a resistor that changes it's properties with the light's intensity. We generally use these resistors as "Light Sensors", meaning we can sense if the light is dim or bright.

Here we will show you how can that be used to create 2 interesting projects. The projects in the tutorial grow in difficulty as we near the end of the tutorial. I recommend following the tutorial and making the projects one by one as you go through it.

Supplies

  1. Arduino Uno (or any)
  2. 10 kOhm resistor (you can also try 5 kOhm - 20 kOhm)
  3. LDR (here GL5528, but you can use any other)
  4. Jumper Wires
  5. Breadboard
  6. 6V Gearmotor
  7. Encoder Disc with 20 Holes
  8. LED white (shown red)
  9. 3V power source (2xAA batteries, or a power supply)

Step 1: Wiring an LDR With Arduino

We are going to connect the LDR with the Arduino Uno, simply follow the images step by step, and connect in the same way as shown.

  1. First place the LDR inside a breadboard, orientation is not important, same as normal resistors, LDR don't care about the polarity. (Image 1)
  2. Place the 10 k Ohmresistor on one side of the LDR, this is our Pull Down resistor which we are going to connect with the ground. (Image 2)
  3. Connect the other end of the 10 k Ohm resistor with the GND on the Arduino, and the other side of the LDR with the 5 V pin on the Arduino. (Image 3)
  4. Now we need to insert an analog read jumper wire in parallel with the LDR. We do that by connecting the A0 with the LDR at the point before the 10 k Ohm resistor. (Image 4)

Now that we have finished with the wiring, we will connect the USB cable to the Arduino and Program the behavior of the Arduino.

Step 2: Reading on the Serial Monitor

Now we are going to program the Arduino to sense the light change near the LDR (light sensor) and show that change on the Serial Monitor.

Here is the complete code, you can either choose to copy it from here or download it down below. The code will be explained in the next step. The code in the attachment has all of the comments.

#define LDRpin A0
int LDRValue = 0;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  LDRValue = analogRead(LDRpin);
  Serial.println(LDRValue);
  delay(2);
}

Step 3: Code Explained

1. We first define a variable LDRpin and designate the A0 analog pin for it, also we will create the LDRValue variable where we will store current "light intensity".

#define LDRpin A0
int LDRValue = 0;

2. We start the serial communication, which we need if we want to see the sensor data on the serial monitor, we choose that the date rate transmitted will be 9600 bits per second, which is basically a default.

void setup()
{
  Serial.begin(9600);
}

3. We now store the value of the LDR into an LDRValue variable using the analogRead command and we display that value on a Serial Monitor with the Serial.println command.

void loop()
{
  LDRValue = analogRead(LDRpin);
  Serial.println(LDRValue);
  delay(2);
}

4. Now we have to connect the Arduino with the PC using the USB cable, upload the code to the board, and press the Serial Monitor button in the top right corner of the Arduino IDE. (Image)

5. In the serial monitor we can see the values read by the LDR to change as the light around the LDR changes. Simply cover the LDR with your hand and you will notice a big change in value, the LDR value displayed should drop a suddenly show a much lower level. (Image)

Step 4: Wiring the LDR With an LED

Here we are going to connect the LED with the previously shown circuit, and program a routine which will turn on the LED when the light is dim and turn it off when the light is bright.

  1. Connect the long "leg" of the LED with the digital pin D13 of the Arduino, and the short "leg" of the LED with the GND (ground) of the Arduino. (Image 1)

Now we are going to program the simple behavior.

Step 5: Turn OFF the Light

In this part of the tutorial we will program an automatic light. Here we have used an LED, the LED will turn OFF when the sensor senses high brightness, this represents the sunlight shining on the sensor, otherwise the LED will be ON.

Here you can copy the code or download it down below, attached code has detailed explanation.

#define LDRpin A0                     
int LDRValue = 0;                     
int LedPin = 13;   		        // NEW           

void setup()
{
  Serial.begin(9600);                 
  pinMode(13, OUTPUT);             	// NEW   
  digitalWrite(13, LOW);              	// NEW
}

void loop()
{
  LDRValue = analogRead(LDRpin);      	
  Serial.println(LDRValue);           
  delay(2);                           

  if (LDRValue > 300)			// NEW
  {
    digitalWrite(LedPin, LOW); 
  }
  else
  {
    digitalWrite(LedPin, HIGH);
  }
}

Step 6: Code Explained: Turn OFF the Light

Here I will explain only the new lines of code.
1. We have to define the variable for the LED.
int LedPin = 13; 

2. Set the mode as an output and make sure that the pin is cleared.

  pinMode(13, OUTPUT);                
  digitalWrite(13, LOW);

3. We now write a simple routine which in this case turns off the light if the "brightness" is higher than 300, otherwise the LED will be ON.

  if (LDRValue > 300)
  {
    digitalWrite(LedPin, LOW); 
  }
  else
  {
    digitalWrite(LedPin, HIGH);
  }

You can also use the serial monitor with this example, and it's recommended to use it to adjust the value (here 300) of the brightness depending on the common brightness of the room. To simulate this program you can upload the code and cover the LDR with your hand, the LED will turn ON, remove your hand from the LDR and the LED will turn OFF.

Step 7: LDR Motor Encoder Wiring

In this part of the tutorial we will build a simple encoder for a 6V gearmotor. This is a DIY encoder so we won't expect high accuracy of information received from it, but it's a really good way to see first hand how a motor encoder works in principle.

  1. To create a simple encoder we need to have an LED and LDR interacting with each other and an encoder disc in between rotating with the shaft of the gearmotor. (Image 1)
  2. To hold the LDR and LED in place, I have created and 3D printed a simple Housing. (Image 2)
  3. The wiring is the same as in previous example. We will connect the long "leg" of the LED with the D13 on the Arduino and a short "leg" of the LED with the GND on the Arduino. (Image 3)
  4. Connect the LDR with the breadboard using jumper wires. (Image 4)
  5. Place the Pull-down resistor as before. (Image 5)
  6. Connect the LDR through a pull-down resistor with the GND on the Arduino, and the other side of the LDR with the 5V on the Arduino. (Image 6)
  7. Connect the A0 with the LDR before the Pull-down resistor. (Image 7)

Step 8: Reading the Encoder Values

Here we have a bit complex problem. We want to read each hole on the encoder disc, we will notice the hole in the way that we notice on the sensor an increase of value and then again decrease. This represent a hole passing between the sensor and an active LED.

This seems simple in theory, but the values on the sensor will variant depending on the housing, the encoder disc, the LED and the LDR.

After we have all setup we need to read the current and previous values of the sensor and recognize these variations inside the read values. We take a sample of 20 changes and calculate the difference between them. The lowest value will be the calibration value which we use in the code. In my case this value was 250, you can see this value in the if loop of the encoder. Depending on the encoder you have build and the calibration value that you have estimated the value representing the motor rotation will vary, so be careful.

This example show how an encoder works in principle and gives you a real engineering issue where you can't actually provide a 100% secure solution. Of course the real encoders which we are going to discus in other tutorials will be better made, more precise and with less problems.

Just one more thing to mention before the code, we don't have a wheel attached to the motor so we will not be converting the number of rotation into distance traveled in this tutorial.

Here is the code you can either copy it and try it yourself or much better download the file below which has more explanation of the each line of the code.

#define LDRpin A0                     
int LDRValue = 0; 
int LDRBefore = 0;                    
int LDRCount = 0;                	// NEW     	
int MotorRot = 0;                     	// NEW
int LedPin = 13;                     	// NEW

void setup()
{
  Serial.begin(9600);                 
  pinMode(13, OUTPUT);                
  digitalWrite(13, HIGH);             	// NEW
}

void loop()
{
  LDRValue = analogRead(LDRpin);      
  delay(1);                        

/*  Serial.print("LDRValue: ");		// NEW
  Serial.println(LDRValue);           
  Serial.print(" LDRBefore: ");
  Serial.print(LDRBefore);            
  Serial.print(" LDRCount: ");
  Serial.print(LDRCount);             
  Serial.print(" MotorRot: ");*/      
  Serial.println(MotorRot);           

  if (LDRValue < LDRBefore)            	// NEW
  {
    LDRValue = LDRValue + 250;         
                                     
    if (LDRValue <= LDRBefore)         
    {
      LDRValue = LDRValue - 250;      
      LDRCount = ++LDRCount;          
      if (LDRCount == 20)             
      {
        LDRCount = 0;                 
        MotorRot = ++MotorRot;        
      }
    }
    else                              
    {
    LDRValue = LDRValue - 250;       
    }
  }
  LDRBefore = LDRValue;               
}

Step 9: Code Explained: Reading the Encoder Values

I will explain the parts of the code that are different from the previous examples. The code is based on them.

1. We need to define couple of variables to store additional data. We will define a LDRBefore variable to store the previous LDR value, LDRCount variable is used to store the big difference in sensor readings representing the hold in the encoder disc, and the MotorRot variable is used to store the number of rotations that the motor has made.

int LDRBefore = 0;                   
int LDRCount = 0;                    
int MotorRot = 0;

2. We need to turn the LED at the beginning at leave it turned on all the time.

  digitalWrite(13, HIGH);

3. We need to display information on the Serial Monitor which we will use to calculate the calibration number, which will be used to check if the hole was present. We need to be careful not to expect too much from the Arduino, we will display the information only when calculating the calibration value, and turn the information off when we use the encoder, because displaying information on the Serial Monitor slows down Arduino and we will be unable to read the information fast enough. Here you can see that only the MotorRot will be displayed on the monitor.

 /*  Serial.print("LDRValue: ");
  Serial.println(LDRValue);           
  Serial.print(" LDRBefore: ");
  Serial.print(LDRBefore);            
  Serial.print(" LDRCount: ");
  Serial.print(LDRCount);             
  Serial.print(" MotorRot: ");*/      
  Serial.println(MotorRot);

4. Now we need to create an algorithm for estimating the number of holes and number of turns that the motor has taken. Here is the routine, I will further explain each step below it.

  if (LDRValue < LDRBefore)           
  {
    LDRValue = LDRValue + 250;     
                                  
    if (LDRValue <= LDRBefore)   
    {
      LDRValue = LDRValue - 250;   
      LDRCount = ++LDRCount;       
      if (LDRCount == 20)     
      {
        LDRCount = 0;            
        MotorRot = ++MotorRot;    
      }
    }
    else                              
    {
    LDRValue = LDRValue - 250;   
    }
  }
  LDRBefore = LDRValue;               
}

First question we ask is: is the current value of the LDR smaller than previous?

if (LDRValue < LDRBefore)

If yes, add 250 (the number depends on the housing, encoder disc, LDR and LED, this number is used to calibrate the encoder) to the current value of the LDR.

  {
    LDRValue = LDRValue + 250;

Than we ask another question: is the current value still smaller than before?

    if (LDRValue <= LDRBefore)

If yes, return the current LDR value to it's original state and count this as a new "hole" on the encoder disc.

      LDRValue = LDRValue - 250;      
      LDRCount = ++LDRCount;

Next question is: have we counted 20 holes so far (that's the number of holes on my encoder disc).

     if (LDRCount == 20)

If yes, return the count number to 0, and count this action as a full turn of the motor.

        LDRCount = 0;                
        MotorRot = ++MotorRot;

The third if statement ends without any other option, if in the second if statement the answer is no, we will return the current LDR value to it's previous value by deducing 250.

    else                              
    {
    LDRValue = LDRValue - 250;        
    }

The first if statement ends without any other option, but after it we will store the current LDR value to the variable LDRBefore to be used next time in the loop as an previous value.

  LDRBefore = LDRValue;

Now we can run the code and see the number of rotations of the shaft. Here I recommend using 3 V on the 6 V motor, because it will rotate slowly and we can be sure that it will manage to count the number of rotations. In my case the error increases each 20 turns by 1 turn approximately. I can than choose to place the error correction in the loop and have it more accurate. But I believe this to be enough about Encoders for now.

Step 10: More!

I hope you have enjoyed reading this tutorial, we will soon make a Youtube video about LDR and later about Encoders which will show all of this in action. Keep in mind that errors are a normal thing in engineering.

To see similar tutorials, which are mostly directed towards learning Robotics, please check our YouTube channel, and the video bellow. Thank you.