Dual Axis Solar Tracker

I have been working on a dual axis solar tracker.

The components I am using are:

  • (2) Servo motors (0 - 180 degree rotation)
  • (4) ldrs
  • Arduino Uno
  • Adafruit Motor shield V2
  • (4) 10K resistors

I currently have a sketch that allows the 2 servo motors to follow light. One servo for North - South movement. The other for East - West.

The problem I am having is stopping the servos from moving once the highest intensity of light is reached.

At the moment, the servos will continue to move in the direction of the most light until their physical limits are met. So they either move to 0 degrees or 180 degrees and remain in this position.

I have implemented limits in the sketch at 0 and 180 degrees so the motors don’t continue to rotate once they have reached these extremities, but I would like to stop the motors in the place where the most light is received. For example, at 70, 80, 90 degrees or wherever the most light is.

I have posted the current sketch below.

This is my first post, and first project with Arduino. I hope I did this right.

Please advise. Thank you.

   #include <Servo.h> //includes the servo library
    Servo myservo;
    int pos = 90; // initial position of the Horizontal movement controlling servo motor
    int ldr1 = A0; // set ldr 1 Analog input pin of East ldr as an integer
    int ldr2 = A1; // set ldr 2 Analog input pin of West ldr as an integer
    int tolerance = 2; // allowable tolerance setting - so solar servo motor isn't constantly in motion
   
    
    Servo myservo2;
    int pos2 = 90; // initial position of the Vertical movement controlling servo motor
    int ldr3 = A2; // set ldr 3 Analog input pin of the North ldr as an integer
    int ldr4 = A3; // set ldr 4 Analog input pin of the South ldr as an integer
    int tolerance2 = 2; //allowable tolerance setting - so solar servo motor isn't constantly in motion
    
    void setup()
    {
    myservo.attach(9); // attaches the servo on digital pin 9 to the horizontal movement servo motor 
    pinMode(ldr1, INPUT); //set East ldr pin as an input
    pinMode(ldr2, INPUT); //set West ldr pin as an input
    myservo.write(pos); // write the starting position of the horizontal movement servo motor 
    delay(2000); // 2 second delay to allow the solar panel to move to its staring position before comencing solar tracking 
    
    myservo2.attach(10); // attaches the servo on digital pin 10 to the vertical movement servo motor
    pinMode(ldr3, INPUT); //set North ldr pin as an input
    pinMode(ldr4, INPUT); //set South ldr pin as an input
    myservo2.write(pos2); // write the starting position of the vertical movement servo motor 
    delay(2000); // 2 second delay to allow the solar panel to move to its staring position before comencing solar tracking 
    }
    void loop()
    {
    int val1 = analogRead(ldr1); // read the value of ldr 1
    int val2 = analogRead(ldr2); // read the value of ldr 2
    int val3 = analogRead(ldr3); // read the value of ldr 2 
    int val4 = analogRead(ldr4); // read the value of ldr 4
     
    if((abs(val1 - val2) <= tolerance) || (abs(val2 - val1) <= tolerance)) {
    //no servo motor horizontal movement will take place if the ldr value is within the allowable tolerance
    } else {
    if(val1 > val2) // if ldr1 senses more light than ldr2 
    {
    pos = pos+1; // decrement the 90 degree poistion of the horizontal servo motor - this will move the panel position Eastward
    }
    if(val1 < val2) // if ldr2 senses more light than ldr1
    {
    pos = pos-1; // increment the 90 degree position of the horizontal motor - this will move the panel position Westward
    }
    delay(900);
    }
     
    if(pos > 180) { pos = 178; } // reset the horizontal postion of the motor to 180 if it tries to move past this point
    if(pos < 0) { pos = 0; } // reset the horizontal position of the motor to 0 if it tries to move past this point
    myservo.write(pos); // write the starting position to the horizontal motor
    delay(50);
    
      if((abs(val3 - val4) <= tolerance) || (abs(val4 - val3) <= tolerance)) {
    //no servo motor vertical movement will take place if the ldr value is within the allowable tolerance
    } else {
    if(val3 > val4) // if ldr3 senses more light than ldr4 
    {
    pos2 = pos+1; // decrement the 90 degree poistion of the vertical servo motor - this will move the panel position Northward
    }
    if(val4 > val3) // if ldr4 senses more light than ldr3
    {
    pos2 = pos-1; // increment the 90 degree position of the vertical motor - this will move the panel position Southward
    }
    delay(900);
    }
     
    if(pos2 > 180) { pos2 = 178; } // reset the vertical postion of the motor to 180 if it tries to move past this point
    if(pos2 < 0) { pos2 = 0; } // reset the vertical position of the motor to 0 if it tries to move past this point
    myservo2.write(pos2); // write the starting position to the vertical movement motor
    delay(50);
  }

I don’t see anything obviously wrong with the code, though it may be possible to simplify it a bit.

I would remove the code for one axis until I had the other one working properly.

I would move the delay() directly into loop().

Put in some Serial.println() statements so that you can be sure the LDR readings are changing in the way you expect. My suspicion is that they are not. How are the LDRs wired?

By the way these two tests give the same answer so only one is needed.

if((abs(val1 - val2) <= tolerance) || (abs(val2 - val1) <= tolerance))

…R

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png or pdf?

Thanks...Tom..... :)

I suspect that you have some of your logic associated with the wrong values.

You do realise that LDRs will have a LOWER resistance when they recieve MORE light.

I suggest you work with just one axis until you get it working properly, then add in the other.

patrickohara2:
I have posted the current sketch below.

This is my first post, and first project with Arduino. I hope I did this right.

Please advise. Thank you.

I suppose a wrong if/if-else logic.

Your code:

    if((abs(val1 - val2) <= tolerance) || (abs(val2 - val1) <= tolerance)) {
    //no servo motor horizontal movement will take place if the ldr value is within the allowable tolerance
    } else {
    if(val1 > val2) // if ldr1 senses more light than ldr2 
    {
    pos = pos+1; // decrement the 90 degree poistion of the horizontal servo motor - this will move the panel position Eastward
    }
    if(val1 < val2) // if ldr2 senses more light than ldr1
    {
    pos = pos-1; // increment the 90 degree position of the horizontal motor - this will move the panel position Westward
    }
    delay(900);

My change to the logic:

    if (abs(val1 - val2) <= tolerance) 
    {
      //no servo motor horizontal movement will take place if the ldr value is within the allowable tolerance
    } 
    else if (val1 > val2) // if ldr1 senses more light than ldr2 
    {
      pos = pos+1; // decrement the 90 degree poistion of the horizontal servo motor - this will move the panel position Eastward
    }
    else if(val1 < val2) // if ldr2 senses more light than ldr1
    {
      pos = pos-1; // increment the 90 degree position of the horizontal motor - this will move the panel position Westward
    }
    delay(900);

your speed to move 90 degrees should be set for about one hour. since it takes the sun 8 hours to move that distance, you would be 8 times faster.

or, create a very low speed section when the two sensors are withing a small range of each other so that once it gets close, the speed slows way down.

Do not worry about a small overshoot. the sun will move to eliminate that soon enough.

Hello All,

Thank you for the informative and helpful responses.

Since I am not sure at the moment how to address everyone separately I am trying to respond to everyone.

I realize I have made a few mistakes in regards to comments on various lines of the code, sorry.

I have constructed the circuit and tested the sketch. The servos do respond for the most part as I intend them to. With the main exception being the ability to remain at the angle with the highest intensity of light. Basically, on start up, I would like the servos to find the highest intensity. Maybe LDRs aren’t the best way to do so.

The idea of inserting a larger delay (and in the proper area) between movement makes a lot of sense. And adjusting the speed within a small range does as well.

I really appreciate the improvements on the code because I am new to this and know there is always a more functional and simpler way to perform.

I have attached a jpg. of the circuit as TomGeorge has requested. Sorry lol, I have done it in paint, but should be clear enough to understand.

;D

the LDR may work better so that two can never see the sun at the same time. when centered, if the sun can touch less than 1/10th of the sensor you may find the sensors more sensitive. the angle of the sensors may play a larger part in control stability than software tweaking.

also, the sensitivity of LDR's are horrible from one to the next. they could be 50% off from chip to chip, so a little testing would help and since you really only care about alignment of the device, you can move the sensor array in relation to the device you are moving.

Hi, Power the servos off a separate power supply, the arduino 5V is not rated at the current required by one let alone two servos.

Get this fixed first before attempting to fix anything else, as it causes the arduino to reset.

Tom..... :)

patrickohara2: Since I am not sure at the moment how to address everyone separately I am trying to respond to everyone.

I'm not sure that your reply has added any useful information.

You need to find out what data the Arduino is seeing - i.e. the values read by the ADC.

And I have just realized there is a fundamental problem here

int val1 = analogRead(ldr1); // read the value of ldr 1
    int val2 = analogRead(ldr2); // read the value of ldr 2
    int val3 = analogRead(ldr3); // read the value of ldr 2 
    int val4 = analogRead(ldr4); // read the value of ldr 4

The Arduino has only one ADC and when you switch pins you should take two readings and ignore the first one to allow time for the ADC to settle. (See the Atmel datasheet) Something like this

int discard = analogRead(ldr1);
    int val1 = analogRead(ldr1); // read the value of ldr 1
    int discard = analogRead(ldr2);
    int val2 = analogRead(ldr2); // read the value of ldr 2
    etc

But you also need to see what values are being used for the decisions.

Have you a shield between the LDRs so they full sun can only fall on both when they directly face it.

I presume your LDRs are attached to and moving with the solar panel?

...R

patrickohara2: Basically, on start up, I would like the servos to find the highest intensity.

As it is possible to calculate the position of the sun for each location on earth at any time, you just need an RTC providing exactly values for date and time, a sun calculation function and then set your servo to the elevation angle and hour angle accordingly to the realtime clock.

If I'd need a solar tracker I'd build a solar tracker and not a kind of "light finder".

jurs: If I'd need a solar tracker I'd build a solar tracker and not a kind of "light finder".

A "light finder" is just as effective and soooo much simpler.

...R

Sorry for the delayed response.

TomGeorge: Hi, Power the servos off a separate power supply, the arduino 5V is not rated at the current required by one let alone two servos.

Get this fixed first before attempting to fix anything else, as it causes the arduino to reset.

Tom..... :)

Thank you. I have a separate supply which I will use.

Robin2: A "light finder" is just as effective and soooo much simpler.

...R

Can you elaborate on this, please? I will have the ldrs on the system, separately encased at a 30 degree angle relative to the ground. Than you for the code fixes.

jurs: As it is possible to calculate the position of the sun for each location on earth at any time, you just need an RTC providing exactly values for date and time, a sun calculation function and then set your servo to the elevation angle and hour angle accordingly to the realtime clock.

If I'd need a solar tracker I'd build a solar tracker and not a kind of "light finder".

I see what you mean. I guess the route I am currently following is not an exact method of solar tracking. I looked at projects that used an RTC, but they seemed a lot more complicated. I would like to try this method as well, although probably after I am more experienced. I would like to implement the RTC after I have finished the more simple system.

dave-in-nj: also, the sensitivity of LDR's are horrible from one to the next. they could be 50% off from chip to chip, so a little testing would help and since you really only care about alignment of the device, you can move the sensor array in relation to the device you are moving.

Thank you. I didn't know this about ldrs. I'll have to test them.

Hi, I won't get on my soapbox.

RTC trackers need to know where on earth you are, the local time, an exact vertical/horizontal base.

A light seeker just needs to be put on the ground and switched ON. Its universal, will even work on the moon, mars. side of a hill. And I won't go into the fact that on a cloudy day the brightest part of the sky is not necessarily where you assume the sun to be.

Tom...... :)

patrickohara2:

A "light finder" is just as effective and soooo much simpler.

Can you elaborate on this, please? I will have the ldrs on the system, separately encased at a 30 degree angle relative to the ground. Than you for the code fixes.

Carry on with what you are doing. Don't bother with an RTC.

However I wonder when you say "separately encased at a 30 degree angle relative to the ground" if that means that the LDRs are mounted on the ground so they are always pointing in the same direction OR does it mean that they are mounted on the solar panel and move with the panel

In my opinion it is essential to have them move with the panel. Among other things that means that you are much less affected by variations between the LDRs and you can easily add a correction factor.

...R

Robin2: The Arduino has only one ADC and when you switch pins you should take two readings and ignore the first one to allow time for the ADC to settle. (See the Atmel datasheet)

No, analogRead() takes care of all of this detail for you. That's why it's an order of magnitude slower than the chip is capable of. The basic Arduino functions do work. You don't need to do any special readings and processing.

This comes up fairly often. Here's a response from a prior thread:

There is only one ADC, shared between the analog pins. The result is that one reading can be impacted by the last. A common workaround is to read twice, ignoring the first reading. When I posted something like this (not so recently now), Grumpy Mike added this:

Quote That is only true if the input impedance to the ADC is significantly higher than 10K. Keep it at 10K and you can sample at the maximum rate.

Robin2: In my opinion it is essential to have them move with the panel.

Yes, of course: When doing autotracking of the light, the sensors have to be moved by the motors, into one or the other direction. Until the sensors are moved into a position where they get equal lighting on each of the sensors. Then the motors stop.

If the sensors are "fixed the the ground" and not moved by the motors, the whole system is not working.

jurs: If the sensors are "fixed the the ground" and not moved by the motors, the whole system is not working.

This post prompted me to go searching through the thread again and tucked away in answer #12 I find

patrickohara2: I will have the ldrs on the system, separately encased at a 30 degree angle relative to the ground. Than you for the code fixes.

Good catch jurs. This is the problem that everyone has overlooked.

How are you ever going to know where the panels are relative to the brightest part of the sky if the sensors are mounted on the ground.

jurs: If the sensors are "fixed the the ground" and not moved by the motors, the whole system is not working.

well.... not necessarily true.....

if you place, say, 10 sensors you could know which has the highest output. if the one to the right were outputting half value and the one to the let were near zero, you could calculate approximate position.

if you place two, you could guesstimate partial values and make assumptions.

harder fraught with errors. but when you watch this list, you see, well, let's just say 'creative' ideas.