LDR/Servo Project Help

If the LDR cannot move to search for the light, then you will need a circular array of LDRs with each in adjacent "cones" of view. You could run the LDR outputs thru a multiplex chip to a single analog input if necessary. Photo transistors might be more sensitive than LDRs.

Hi, you can use the adruino to generate your error and response, then all you need is the terminal monitoring function in the IDE to monitor the outputs.

Tom...... :slight_smile:

So, here are my calibration equations. "x" is the LDR reading (lumen, I believe?) and "y" is the output for the function "myservo.write(y)."

LDR 1:

For 138.6 < x < 262.2: y = -7E-08x5 + 7E-05x4 - 0.0286x3 + 5.8433x2 - 591.49x + 23798
For 138.6 < x < 160.4: y = 0.0979x2 - 27.475x + 2033.6
For 150.2 < x < 160.4: y = -0.1442x2 + 42.82x - 3012

LDR 2:

For 371.4 < x < 376: y = -2.1739x + 824.39
For 371.4 < x < 375: y = 2.7778x - 1014.7
For 353.8 < x < 375: y = -0.4717x + 203.89
For 353.8 < x < 357: y = 3.125x - 1068.6
For 197 < x < 357: y = -5E-09x5 + 8E-06x4 - 0.005x3 + 1.5431x2 - 234.67x + 14128
For 197 < x < 226.8: y = 0.0011x3 - 0.7179x2 + 158.03x - 11476

LDR 3:

For 277 < x < 415.8: y = 6E-05x3 - 0.0567x2 + 18.97x - 2102.3
For 215.8 < x < 415.8: y = -2E-05x3 + 0.0148x2 - 4.5545x + 628.98

LDR 4:

For 171 < x < 173.2: y = -4.5455x + 794.27
For 171 < x < 172.6: y = 6.25x - 1051.8
For 172 < x < 172.6: y = -16.667x + 2903.7
For 172 < x < 375.2: y = -2E-11x6 + 4E-08x5 - 3E-05x4 + 0.0092x3 - 1.8726x2 + 199.89x - 8746.9
For 342.2 < x < 375.2: y = 5E-05x4 - 0.0779x3 + 42.681x2 - 10377x + 945014

LDR 5:

For 163.2 < x < 208.6: y = -5E-06x5 + 0.0043x4 - 1.5863x3 + 291.32x2 - 26722x + 979713
For 163.2 < x < 342.8: y = -1E-12x6 + 6E-09x5 - 6E-06x4 + 0.0029x3 - 0.6965x2 + 84.823x - 4051.8

LDR 6:

For 118.6 < x < 121.6: y = -3.3333x + 412.33
For 118.6 < x < 150.4: y = 0.0019x3 - 0.7627x2 + 103.43x - 4663.2
For 108.2 < x < 150.4: y = 3E-05x4 - 0.0178x3 + 3.5439x2 - 314.85x + 10668
For 108.2 < x < 170.4: y = -0.0097x2 + 3.2293x - 102.84

As you can see, on certain LDR's, for a certain "x" input, we can have multiple "y" outputs. So we need to compare them to the LDR's next door in order to determine a proper "y" output. If the output between the angles aren't the same, we need to compute a finite angle within the code. Also, this code is only valid for the current room I'm in. We need some free time in the lab to make a new calibration curve for the lab we'll be testing in.

Now, we're working on a code to assign zones (i.e. Zone1 = LDR between 1 and 2, Zone2 = LDR between 2 and 3, Zone3 = LDR between 3 and 4, etc.)

zoomkat:
If the LDR cannot move to search for the light, then you will need a circular array of LDRs with each in adjacent "cones" of view. You could run the LDR outputs thru a multiplex chip to a single analog input if necessary. Photo transistors might be more sensitive than LDRs.

Can you give a brief explanation on how Multiplexers work and how you could run the outputs to a single analog input?

Below is a 16 channel multiplex chip. In use your LDR outputs would go to the Y pins, the Z pin would be connected to the arduino analog input pin, E and chip VSS ground go to arduino ground, chip VDD goes to arduino +5v. Chip S pins are controlled by four arduino digital output pins that control the chip. The data sheet has the details. An eight channel 4051 chip could also be used if eight or less LDRs are used. check the data sheet.

Hi, have you got a sample of the lamp you are trying to target?

Do you have the specification of the playing field, such as ambient light level and range that the targets will be .

To get any performance you will have to have the laser point at an angle bisecting the angle of two LDR's so you can use two LDRs to get your precision needed.

(Sounds like a solar tracker)
Tom..... :slight_smile:
What course / subject are you doing, what educational level, secondary, college, uni?

MuuMuu101:
We're not allowed to use that 10-15 lines of code. That's what our old code was like. What makes it challenging is that he doesn't want the servo to move till Arduino figures out what angle the light source is at.

That's the new eddication for you !

I'm content with something that works reliably with the minimum investment by me.

it will reference a linear error curve with a PID and tell the servo, "you need to move in this direction, this quickly."

I can't see how you can relate this to a servo. All the PID stuff for a servo is INSIDE the servo when you buy it - unless part of your plan is to remove the servo electronics and replace it with the Arduino.

And what has the speed of the servo got to do with an error curve. Either you want to point at the light as quickly as possible, or you don't.

...R

i have one quistion , this system , do you want it to go to a reset position , and when light go on , it wil react and point ?
or do you want a sweeping system ?
i made some trackers , bassed on one signal also ,
when it is no problem to make a sweep before finding a light bulb , then make use of the eeprom
this is how do it , i know the steps of the servo 180 ,, every step i check incoming signal ,
this can be done real fast , when signal is find above the signal before ,, it wil store the servo pos and writes the signal strenght to eeprom , then when it goes further it wil check if signal wil be stronger , if so it wil write this tho eeprom again ,it wil do the full 180 sweep ,then returns fast to saved position with strongest signal ,,
you can also say when signal goes bellow saved point it is passing by the signal , and stops and wil go to saved position , then when you done this sweep , it is on saved point , and then it wil do the same on the second servo to see wat heihgt it is , en then wil go there ,, when done sweep it stays there ,,
this wil be looped til signal drops bellow found and stored < with a smal treshold > and goes to start position ,,
looks like a missile defends system then ,,

TomGeorge:
Hi, have you got a sample of the lamp you are trying to target?

Do you have the specification of the playing field, such as ambient light level and range that the targets will be .

To get any performance you will have to have the laser point at an angle bisecting the angle of two LDR's so you can use two LDRs to get your precision needed.

(Sounds like a solar tracker)
Tom..... :slight_smile:
What course / subject are you doing, what educational level, secondary, college, uni?

The test will be conducted in a lab. We need to provide the light source and it will be mounted on the same plane as the tracker. Distance is totally up to our discretion. We already have the laser mounted so that it's bisecting the two LDRs and every LDR is equally spaced out. Unfortunately I don't have a picture of our revised tracker.

This is a Senior level Controls class at a University. The reason why he wants a linear error function is so that we can write out a Transfer function at the end of it. He also wants a Bode Plot. Unfortunately, the only previous coding class we've had was in VBA and most professors teach it poorly. We do have one class on electrical engineering, but essentially they take a whole year of work for the electrical engineering department and shove it all into 1 quarter (10 weeks) so it makes it very difficult for us to learn and retain the information. Our University is not on the semester system.

Robin2:
And what has the speed of the servo got to do with an error curve. Either you want to point at the light as quickly as possible, or you don't.

...R

Maybe I explained this poorly. The further the servo is away from our light source the quicker it needs to move towards the light so that our error signal is linear. I'm not sure how that works, but that's what he explained to us. The error signal needs to be linear so that we can write a Transfer function for the system (a detail I left out earlier).

MuuMuu101:
The further the servo is away from our light source the quicker it needs to move towards the light so that our error signal is linear.

Is it a continuous rotation servo?

...R

Dexterbot:
i have one quistion , this system , do you want it to go to a reset position , and when light go on , it wil react and point ?
or do you want a sweeping system ?
i made some trackers , bassed on one signal also ,
when it is no problem to make a sweep before finding a light bulb , then make use of the eeprom
this is how do it , i know the steps of the servo 180 ,, every step i check incoming signal ,
this can be done real fast , when signal is find above the signal before ,, it wil store the servo pos and writes the signal strenght to eeprom , then when it goes further it wil check if signal wil be stronger , if so it wil write this tho eeprom again ,it wil do the full 180 sweep ,then returns fast to saved position with strongest signal ,,
you can also say when signal goes bellow saved point it is passing by the signal , and stops and wil go to saved position , then when you done this sweep , it is on saved point , and then it wil do the same on the second servo to see wat heihgt it is , en then wil go there ,, when done sweep it stays there ,,
this wil be looped til signal drops bellow found and stored < with a smal treshold > and goes to start position ,,
looks like a missile defends system then ,,
https://www.youtube.com/watch?v=ogqtlKjm_gI&list=UUnrsFghXI-H--uOdov_Fe1Q&index=3

So, ideally, we'd want the system to find a light source, rotate to the light source, then once that light source is turned off and another 135 or so degrees from it is turned on, to go to that light source. Essentially, this is what you first described without the reset. However, in doing this, we realized that we're going to need some sort of transformation equation (a difference between two angles) as the LDR's are recording relative to the disc and not relative to the servo. Our professor does not want a sweeping system. We're only utilizing one servo as the light source is on the same plane as our satellite.

Robin2:
Is it a continuous rotation servo?

...R

It's a standard servo. I believe this is the part: http://www.radioshack.com/radioshack-standard-servo/2730766.html#.VHIv9cnDX3Y

MuuMuu101:
It's a standard servo.

Then the PID system is inside the little black box. And it is sophisticated enough to have flown countless model aircraft successfully over many years.

You don't need to worry about servo speed as far as pointing to a given angle is concerned. Just say myServo.Write(myAngle); and stuff happens.

If the servo moves too fast you could use the technique in the servo sweep example to "pseudo slow it down" by moving a small angle with each step and having a waiting period between movements.

...R

So, we were able to write a code that identified the position and tell the motor to go to the light under a void setup. However, when we threw it under void loop, the system goes crazy and it just hops randomly between 0 and 180. It slows when it's near the target but then it dramatically overshoots once it gets close to zero. We're trying to write a code that will stop the servo once it gets within a tolerance of the target. We're also thinking we may need to write a PID into the Arduino code as we're pretty sure that's what the professor wants. Unfortunately, he doesn't cover how to calculate PID's till 2 days before the project is due (this Wed). Does anybody have any feedback or advice on what we could do. We have an idea of PID's work, but some extra knowledge would be greatly appreciated.

Also, for my calculations, I need to know what the angular acceleration of the servo motor is to find the torque (I*alpha) for my Transfer function. I know it's variable, but is there a way to find out what it is? Even if it's just the maximum angular acceleration.

MuuMuu101:
So, we were able to write a code that identified

Did you forget to post the latest code?

...R

Robin2:
Did you forget to post the latest code?

...R

It was too many characters for a post. -_-

However, we modified it a bit and now it's able to track the light decently. The angle is just off a little (LED isn't completely mounted and we can tune it a bit in the code). I still feel like he wants a PID. We still need to output an error signal to show our system is linear.

First half of the code...

#include <Servo.h> 
 
Servo myservo; 
int pos = 90;   // initial position
int sens1 = A0; // LRD 1 pin
int sens2 = A1; // LDR 2 pin
int sens3 = A2; // LDR 3 pin
int sens4 = A3; // LDR 4 pin
int sens5 = A4; // LDR 5 pin
int sens6 = A5; // LDR 6 pin

int tolerance = 5; // adjusts sensitivity at nuetral position 
 
void setup() 

{ 
  
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  pinMode(sens1, INPUT);
  pinMode(sens2, INPUT);
  pinMode(sens3, INPUT);
  pinMode(sens4, INPUT);
  pinMode(sens5, INPUT);
  pinMode(sens6, INPUT);
  myservo.write(pos);
  delay(3000); // a 3 seconds delay 
    
  Serial.begin(57600);
  
  int currentpos = myservo.read();
 

  int val1 = analogRead(sens1); // read the value of sensor 1
  int val2 = analogRead(sens2); // read the value of sensor 2
  int val3 = analogRead(sens3); // read the value of sensor 3
  int val4 = analogRead(sens4); // read the value of sensor 4
  int val5 = analogRead(sens5); // read the value of sensor 5
  int val6 = analogRead(sens6); // read the value of sensor 6 
  
  //start of plugging sens1 into an equation 
  
  double y=0.00000000000;
  double x=0.00000000000;
  double theta2=0;
  double z=0.00;
  int LightVal[6]; 
  int max1=0;
  int max2=0;
  LightVal[1]=val1;
  LightVal[2]=val2;
  LightVal[3]=val3;
  LightVal[4]=val4;
  LightVal[5]=val5;
  LightVal[6]=val6;
  
 
  
  
//Serial.print(" Val1: ");
//Serial.print(val1);
 
 //Serial.print(" val2: ");
//Serial.print(val2);
 
 //Serial.print(" val3: ");
  //Serial.print(val3);
 
 //Serial.print(" val4: ");
 //Serial.print(val4);
 
//Serial.print(" val5: ");
// Serial.print(val5);
 
// Serial.print(" val6: ");
// Serial.print(val6);
 
 

 
 
  
 
 
 }
  
  void loop()
    {
      
 
  int currentpos = myservo.read();
 

  int val1 = analogRead(sens1); // read the value of sensor 1
  int val2 = analogRead(sens2); // read the value of sensor 2
  int val3 = analogRead(sens3); // read the value of sensor 3
  int val4 = analogRead(sens4); // read the value of sensor 4
  int val5 = analogRead(sens5); // read the value of sensor 5
  int val6 = analogRead(sens6); // read the value of sensor 6 
  
  //start of plugging sens1 into an equation 
  
  double y=0.00000000000;
  double x=0.00000000000;
  double theta2=0;
  double z=0.00;
  int LightVal[6]; 
  int max1=0;
  int max2=0;
  LightVal[1]=val1;
  LightVal[2]=val2;
  LightVal[3]=val3;
  LightVal[4]=val4;
  LightVal[5]=val5;
  LightVal[6]=val6;
  
      
      
     //Finding the largest value--------------------------------------- 

      for (int i=1; i<6; i++) 
      {
          if (max1<LightVal[i])
            {
              max1=LightVal[i];
              
            }
     
      }
// Serial.print(" Largest Value is: ");  
// Serial.print(max1);
 
//Finding second largest value ------------------------------------   
for (int i=1; i<6; i++)
    if (max1==LightVal[i])
     { 
       LightVal[i]=0;
       
       break;
     }
  
  
     for (int i=1; i<6; i++) 
      {
          if (max2<LightVal[i])
            {
              max2=LightVal[i];
            }
        
  //Serial.print(" Second Highest Value is: ");
  //Serial.print(max2);
  
//-----------------------------Locating the zone---------------------------------------------

//------ If the two highest values are in zone A---------------------------------------------

    if ((val1==max1) && (val2==max2))
    {
      
      Serial.print("    We are in Zone A    ");
                   x=(float)(val1)/(val2); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1        
                 
                 Serial.print("      x is       ");
                 Serial.print(x); 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
                 
                 theta2=-135+y;  //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 //z=theta2;
                 Serial.print("   light angle is:    ");
                 Serial.print(z);
                 
                 Serial.print("   servo move to pos:   ");
                 Serial.print(currentpos+z);
                         //Servo movement
                       myservo.write(currentpos+z);
                        
                                                     
                         
                         
                                      
                                               
    }
    else if (val2==max1 && val1==max2)   
   { 
     Serial.print("    We are in Zone A  ");
     
                   x=(float)(val1)/(val2); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1       
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=-135+y;  //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 //z=theta2;
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                 
                 Serial.print("   servo move to pos:   ");
                 Serial.print(currentpos+z);
                        //Servo movement 
                        Serial.print(currentpos+z);
   }

Second half...

//-----If the two highest values are in zone B----------------------------------------------
  
    else if (val2==max1 && val3==max2)
    {
      Serial.print(" We are in Zone B");
    
                   x=(float)(val2)/(val3); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=-81+y;  //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 //z=theta2;
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to:   ");
                 Serial.print(currentpos+z);

    }          
    
    else if (val3==max1 && val2==max2)
    {
      Serial.print("    We are in Zone B    ");
      
                   x=(float)(val2)/(val3); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1       
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=-81+y;  //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                
                 Serial.print("   servo move to:   ");
                 Serial.print(currentpos+z);
                 
                     myservo.write(currentpos+z);
                          
    }
    
//---If the two highest values are in Zone C------------------------
    
    else if (val3==max1 && val4==max2)
    {
      Serial.print("     We are in Zone C    ");
                   x=(float)(val3)/(val4); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=-27+y;  //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to: ") ;
                 Serial.print(currentpos+z);

                 
               if (((currentpos+z)-currentpos)>1 )
                     {
                           myservo.write(currentpos+z);
                   }
                         else
                         {
                          myservo.write(currentpos);
                         }
                        
                        
                        
    }
    
    else if (val4==max1 && val3==max2)
    {
      Serial.print("   We are in Zone C ");
                   x=(float)(val3)/(val4); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=-27+y;   //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to:   ");
                 Serial.print(currentpos-z);
                 
                    if (((currentpos-z)-currentpos)>1 )
                     {
                            myservo.write(currentpos-z);
                     }
                        else
                         {
                          myservo.write(currentpos);
                         }
    }
//-----If the two highest values in Zone D-------------------------
     
     
      else if (val4==max1 && val5==max2)
    {
      Serial.print("     We are in Zone D    ");
                   x=(float)(val4)/(val5); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=27+y;          //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to:   ");
                 Serial.print(currentpos-z);

                  myservo.write(currentpos-z);
                  
                  
    }
    
    else if (val5==max1 && val4==max2)
    {
      Serial.print("   We are in Zone D ");
                   x=(float)(val4)/(val5); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=27+y;   //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to: ");
                 Serial.print(currentpos-z);

                   
                          myservo.write(currentpos-z);
                    
    }
 
//-----If the two highest values Zone E-----------------------------
   else if (val5==max1 && val6==max2)
    {
      Serial.print("     We are in Zone E    ");
                   x=(float)(val5)/(val6); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=81+y;          //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo move to:   ");
                 Serial.print(currentpos-z);

                  
                        myservo.write(currentpos-z);
                   
    }
    
    else if (val6==max1 && val5==max2)
    {
      Serial.print("   We are in Zone E ");
                   x=(float)(val5)/(val6); //ratio of ldr 1 to ldr 2 
                   y=(float)1438.103724*pow(x,3)-3660.351098*pow(x,2)+2884.894604*x-657.756777; // deg theta 1    
            
                 Serial.print("      x is      ");
                 Serial.print(x);                 
                 Serial.print("      y is:    ");           
                 Serial.print(y);
    
                 theta2=81+y;   //this is the angle of the left hand side of the zone
                 z=abs(theta2);
                 Serial.print("   the light angle is:    ");
                 Serial.print(z);
                           
                 Serial.print("   servo position move to:   ");
                 Serial.print(currentpos-z);

                  
                          myservo.write(currentpos-z);
                          
    }
    

    
//---------------------------------------------------------

 }   
      
      delay(1000);
    }

I think it better to use map function and constrain function to constrain and map your L.D.R values for your servo motor either 180/360