Light Tracking Servo

Light Tracking Servo

Introduction

For this project, we will be building a control system that allows a servo to align itself to the direction of light coming from a flashlight. To do this we will use light sensitive resistors to detect the direction the light is coming from. The chipKIT™ board will then adjust the servo head to the calculated direction accordingly.

Inventory:

Qty Description Typical Image Schematic Symbol Breadboard Image
2 10 kΩ to 30 kΩ Photocells
2 10 μF capacitors
1 SG90 Servo
3 Gator Clips
1 Duct Tape
2 Small pieces of cardboard

Photocell:

In the Force Button project, we used a non-conventional resistor known as a force sensitive resistor. This resistor (as opposed to a fixed ceramic resistor), changed its value depending on the amount of force applied to it. Like the force sensitive resistor, there are many other types of resistors that can change their value dependent on external stimulus.

One of these resistors is a photocell (sometimes referred to as a photo sensitive resistor). A photocell changes its resistive value based on the amount of light received at the cell’s base (lowering its overall resistance the stronger the light is shown onto the cells base). The PDV-P9203 photocell used for this project has a range from 10 kΩ to 30 kΩ. Like in the “Force Button” project, we can use this change in resistance to measure the amount of light.

Figure 1. Photocells.

Light Sensor:

For our light detecting photo sensor, we will be using two photocells wired in series, as in Fig. 2, to form a voltage divider (if you are unfamiliar with voltage dividers follow the link to the right). When light is shining on both cells their resistance values will be equal, so in this case voltage output will be half the supplied voltage. Now if you change the proportion of light that hits each photocell, for instance Photocell 1 receives more light than Photocell 2, the resistance of Photocell 1 will be much less than Photocell 2, and thus the voltage output will be higher (and likewise, lower output voltage if more light hit Photocell 2 and not 1). This voltage output will be connected straight to an analog input of our chipKIT board.

Figure 2. Light Sensor.

Light Sensor Assembly:

There will be a few steps necessary in order to construct the light sensor for this project, mainly involving mounting the photocell components to a piece of cardboard that can attach to the servo. The following construction is a suggestion of one possible sensor orientation. Feel free to experiment with photocell placement.

  1. Poke two holes in a small piece of cardboard somewhat near the edge of the cardboard. Feed the photocell leads of one cell through a hole, like in Fig. 3. Then feed the leads of the second cell through the other hole. Now make sure that both cells are flush to the cardboard and that both cells are on opposite sides like Fig. 3.
  2. Figure 3. Light Sensor Assembly, step 1.
  3. Chose two leads of each photocell and intertwine them over the cardboard, like in Fig. 4.
  4. Figure 4. Light sensor assembly, step 2.
  5. Cut a small slit in the back end of the cardboard, like Fig. 5.
  6. Figure 5. Light sensor assembly, step 3.
  7. Now take another piece of cardboard and tape/glue the plastic servo head to the underside of the cardboard (the plastic servo head is the usually white piece of plastic that readily attach/detach from the actual servo itself). See Fig. 6 for an example.
  8. Figure 6. Light sensor assembly, step 4.
  9. Now attach this piece of cardboard to the previous piece via the slit, and tape/glue if necessary.
  10. Figure 7. Light sensor assembly, step 5.
  11. Now use gator clips to clamp onto the three leads of the photocell (the single lead from photocell 1, and 2, and the twisted pair of leads). Then connect the servo head to the servo itself. You may need to fix the servo to a surface as it will probably move while in operation (due to the connected wires).
  12. Figure 8. Light sensor assembly, step 6.

Setting up the circuit:

Figure 9. Overall Circuit.
  1. Connect the 3.3V power pin of the chipKIT board to a rail on the breadboard. That rail will be referred to as the 3.3V bus.
  2. Now connect the GND pin of the chipKIT board to a rail next to the 3.3V bus. This rail will be referred to the Ground bus.
  3. Connect the servo power pin to the 3.3V bus and servo Ground pin to the Ground bus (if you are unfamiliar with servos follow the link to the right to reference previous projects that setup basic servo circuits).
  4. Connect one gator clip from the light sensor assembly (one of the clips not connected to the twisted pair) to the 3.3V rail (you may have to insert a wire into the breadboard and then connect the gator clip to that wire).
  5. Now connect the other gator clip from the light sensor (that is not connected to the twisted pair) to the ground bus.
  6. Connect the gator clip that is connected to the light sensor twisted pair to a row in the breadboard. That row will be referred to as Node A.
  7. Now connect two 10 μF capacitors (in parallel) from node A to ground.
  8. Connect a wire from Node A to the A0 pin of the chipKIT board.
  9. Finally, connect the control line of the Servo to pin 9 of the chipKIT board.

Setting up the Software:

The software for this project will basically set up a very simple control system. Data will be captured from the light sensor voltage divider (which will range from 0 to 1024). Where values close to 0 represent light being close to one photocell, and values close to 1024 represent light being close to the other photocell.

You can see from Fig. 10 that data is being feedback and summed before going to the rest of the system. This function is accomplished in the line of code:

Figure 10. Overall Circuit.
                  y =.2*x_1 + .75*y;

By only updating “y” in this line of code, it will functionally sum the previous value of “y” with the current value of “x” (all scaled of course).

So essentially:

y(current) = .2 * x(current) + .75*y(previous)

This effectively acts like a low pass filter. The output of this equation relies more on the long term average of input values and less on short duration changes in the input. This is needed because data from the analog input can be somewhat noisy, so filtering is necessary.

After this statement, the y variable is subtracted by an offset constant (usually about 400). This basically centers the output value; if light is shown on the both photocells equally, then the value at x_2 (see Fig. 11) would be very close to 0. So light on the right side of the sensor will be positive and light on the left side will be negative.

Figure 11. Software Flow.

The last block checks if the x_2 value will be above or below a threshold value and move the servo head accordingly (i.e., if the x_2 value is above the threshold then move right, if below then move left). This is done because there will still be a slight amount of noise when light is shed on the sensor (thresholding will cause the servo to only move when there is a significant difference)

Software:

                  #include <Servo.h> 
                  
                  
                  float x_1;
                  float x_2;
                  float y;
                  
                  int count;
                  int pos;
                  int spd ;
                  
                  const int offset = 400;
                  const int threshold = 45;
                  const int inactive = 25;
                  
                  Servo myServo;
                  
                  boolean turnedoff;
                  
                  
                  void setup() {
                  
                  
                  x_1 = 0;
                  x_2 = 0;
                  spd = 4;
                  y = 0;
                  pos = 90;
                  count = 0;
                  
                  turnedoff = false;
                  myServo.attach(9);
                  myServo.write(90);
                  
                  }
                  
                  
                  
                  void TurnServo(int val){
                    
                   // current posistion minus a value to change
                   pos = pos - val;
                   
                           // threshold to keep pos between 0 and 180
                            if(pos < 0){
                            pos = 0; 
                             }
                             else if (pos > 180){
                               
                              pos = 180; 
                             }
                         
                          myServo.write(pos); 
                  }
                  void loop() {
                  
                    
                    // capture data from light sensor
                    x_1 = analogRead(0);
                  
                  
                    // Low pass filter data
                    y = .20*x_1 +.75*y;
                    // truncate it back to integer values, reduce noise
                    y = (int)y;
                    // center value around 0
                    x_2 = y - offset ;
                  
                  
                  
                  
                  if ( (x_2 <= -threshold)){
                  
                  
                    //if servo was turned off, then turn it back on and 
                    // move the servo to the right  
                    if (turnedoff == false){
                      
                      TurnServo(spd);
                    
                    }
                    else{
                      
                      myServo.attach(9);
                      TurnServo(spd);
                      turnedoff = false;
                      
                      
                    }
                      //if servo was turned off, then turn it back on and 
                    // move the servo to the left 
                  }else if (x_2 >= threshold){
                    
                      if (turnedoff == false){
                      
                      TurnServo(-spd);
                    
                    }
                    else{
                      
                      myServo.attach(9);
                      TurnServo(-spd);
                      turnedoff = false;
                      
                      
                    }
                  
                    
                    
                  }
                  else{
                   
                    
                      // if not above/below the threshold 
                      // do not move the servo
                      if (turnedoff == false){
                      count++;
                      TurnServo(0);
                      }
                      else{
                      
                      // do nothing , servo is off
                      }  
                    
                    // if the servo has not moved for a given amount of time
                    // then detach it so it is not constantly trying to move the 
                    // servo
                    if (count >= inactive){
                      
                     turnedoff = true;
                      count = 0; 
                      myServo.detach();
                    }
                    
                  }
                    
                    delay(50);  
                  }

You may have noticed that if the servo does not turn for a given number of cycles (the number of cycles is represented by the constant “inactive”), it will call the myServo.detach() method. This is done to turn the servo off while it is not in use (there is no need to continuously update the position if it has not changed).

Troubleshooting

Some points to check to tune your sketch if it is not working exactly like you want:

  • If the servo is not at 90 degrees when no light is shining on it: Try adjusting the “offset” variable (by about 10 to 20). What the sensor sees as “center” can change depending on ambient light, so adjustment may be necessary.
  • Servo wobbles excessively when light is shining straight on: If the servo is constantly moving back and forth, try increasing the threshold variable. This will mean a larger difference between the two photocells to signal the servo to move.
  • Servo still wobbles excessively after increasing the threshold: if the servo is still not stable, then try increasing the delay value at the end of the sketch. This will make the servo movement choppier but will stabilize the movement.

  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.
  • Circuit and breadboard images were created using Fritzing.