Go Down

Topic: Arduino solar tracker (Read 37 times) previous topic - next topic


I too have been thinking of how to track the sun to gather that extra 30% of energy, but the cost of most commercial solutions has exceeded the cost of installing 30% more solar modules...
I'm very new to the world of Arduino, and from the few forum threads on the subject, the popular method seems to track light levels to determine the position of "Ol' Sol" visually.
The downside I see with this methodology is that it is difficult to allow for all the variations and possible scenarios that the solar array may face, and have to algorithmically respond to.  
For example, will the tracker (in the examples given) properly handle  if a thunderstorm blows in mid-day ?  In other words, all of a sudden there is no bright spot in the sky; what will it do ?  I suppose it will stay put, because the two or three light sensors will "see" the same light level, am I right ?
Next, what happens at sundown ?  How does it know whan to go back towards the east and wait for sunrise ?  Without a sense of time (ie, with an RTC) I'm not convinced it will find the sun in the morning, mostly because the sun will literally be behind the light sensors.

With respect to razorbud's and tkbyd's comments about using lat/long information  to determine azimuth and elevation of the sun in real time, I think this is a great idea.  It solves a lot of problems in terms of where the sun is, regardless of time or weather.  It's not the simplest (no KISS here) but

The big question is: has anyone done this, to calculate the sun's azimuth ?    

I've read and looked at ve9qrp's qrptracker project, and how he uses keplerian elements and Plan13 formulas.  I'm hoping someone has some information to share on how to do this, to save from re-inventing any wheels.

Thanks to all in advance for any assistance...


Jul 12, 2010, 09:35 pm Last Edit: Jul 12, 2010, 09:36 pm by retrolefty Reason: 1
I think the best simplest solution is to utilize a simple RTC/Calendar to drive a stepper motor gear drive at a constant sidereal rate for a single axis right ascension movement.

If you research telescope clock drives using polar mounts you will see that it's pretty simple, accurate and reliable. You may need to manual adjust the azimuth angle manually every month or so to optimize performance. The RTC/Calendar could also handle the skewing command to reposition to each sunrise from look up table in your program.


Mowcius has the answer!


Sun tracker code for you :)
Attach to a RTC and tell it your co-ordinates and it'll throw out sun position  ;)



Dec 28, 2010, 12:35 am Last Edit: Dec 28, 2010, 12:36 am by joeinbend Reason: 1
Great thread guys! Mowcius -- I read the info on your personal web site for the sun position tracking and was salivating, but only to find the links to the .pde's are broken! Are you still providing this sample code?


Yeah, annoying aint it.

Hopefully moving my website soon and sorting it out.

Anyway, here's some static code
Code: [Select]
//Sun Position Calculation
//Provides sun position (relative) from static variables

#include <math.h>
#define pi    3.14159265358979323846
#define twopi (2*pi)
#define rad   (pi/180)
#define EarthMeanRadius     6371.01      // In km
#define AstronomicalUnit    149597890      // In km

//Input Variables --------------------- TIME HAS TO BE IN UT (UNIVERSAL TIME)! NO TIME ZONES OR SUMMER TIMES --------
//My last modifications were probably at this time on this date!
     int Year = 2010; //year
     int Month = 7; //month
     int Day = 3; //day
     float Hours = 16; //hour
     float Minutes = 38; //minutes

     float Longitude = 1.2967; //enter longitude here
     float Latitude = 1.5465; //enter latitude here

//Program Variables
     float ZenithAngle;
     float Azimuth;
       float RightAscension;
     float Declination;
       float Parallax;
       float ElevationAngle;

     float ElapsedJulianDays;
     float DecimalHours;
     float EclipticLongitude;
     float EclipticObliquity;

void setup() {

void sunPos(){

     // Auxiliary variables
     float dY;
     float dX;

     // Calculate difference in days between the current Julian Day
     // and JD 2451545.0, which is noon 1 January 2000 Universal Time

           float JulianDate;
           long int liAux1;
           long int liAux2;
           // Calculate time of the day in UT decimal hours
           DecimalHours = Hours + (Minutes / 60.0);
           // Calculate current Julian Day
           liAux1 =(Month-14)/12;
           liAux2=(1461*(Year + 4800 + liAux1))/4 + (367*(Month
                 - 2-12*liAux1))/12- (3*((Year + 4900
           + liAux1)/100))/4+Day-32075;
           // Calculate difference between current Julian Day and JD 2451545.0
           ElapsedJulianDays = JulianDate-2451545.0;

     // Calculate ecliptic coordinates (ecliptic longitude and obliquity of the
     // ecliptic in radians but without limiting the angle to be less than 2*Pi
     // (i.e., the result may be greater than 2*Pi)

           float MeanLongitude;
           float MeanAnomaly;
           float Omega;
           MeanLongitude = 4.8950630+ 0.017202791698*ElapsedJulianDays; // Radians
           MeanAnomaly = 6.2400600+ 0.0172019699*ElapsedJulianDays;
           EclipticLongitude = MeanLongitude + 0.03341607*sin( MeanAnomaly )
                 + 0.00034894*sin( 2*MeanAnomaly )-0.0001134
           EclipticObliquity = 0.4090928 - 6.2140e-9*ElapsedJulianDays

     // Calculate celestial coordinates ( right ascension and declination ) in radians
     // but without limiting the angle to be less than 2*Pi (i.e., the result may be
     // greater than 2*Pi)

           float Sin_EclipticLongitude;
           Sin_EclipticLongitude= sin( EclipticLongitude );
           dY = cos( EclipticObliquity ) * Sin_EclipticLongitude;
           dX = cos( EclipticLongitude );
           RightAscension = atan2( dY,dX );
           if( RightAscension < 0.0 ) RightAscension = RightAscension + twopi;
           Declination = asin( sin( EclipticObliquity )*Sin_EclipticLongitude );

     // Calculate local coordinates ( azimuth and zenith angle ) in degrees

           float GreenwichMeanSiderealTime;
           float LocalMeanSiderealTime;
           float LatitudeInRadians;
           float HourAngle;
           float Cos_Latitude;
           float Sin_Latitude;
           float Cos_HourAngle;
           GreenwichMeanSiderealTime = 6.6974243242 +
                 + DecimalHours;
           LocalMeanSiderealTime = (GreenwichMeanSiderealTime*15
                 + Longitude)*rad;
           HourAngle = LocalMeanSiderealTime - RightAscension;
           LatitudeInRadians = Latitude*rad;
           Cos_Latitude = cos( LatitudeInRadians );
           Sin_Latitude = sin( LatitudeInRadians );
           Cos_HourAngle= cos( HourAngle );
           ZenithAngle = (acos( Cos_Latitude*Cos_HourAngle
                 *cos(Declination) + sin( Declination )*Sin_Latitude));
           dY = -sin( HourAngle );
           dX = tan( Declination )*Cos_Latitude - Sin_Latitude*Cos_HourAngle;
           Azimuth = atan2( dY, dX );
           if ( Azimuth < 0.0 )
             Azimuth = Azimuth + twopi;
           Azimuth = Azimuth/rad;
           // Parallax Correction
           ZenithAngle=(ZenithAngle //Zenith angle is from the top of the visible sky (thanks breaksbassbleeps)
                 + Parallax)/rad;
               ElevationAngle = (90-ZenithAngle); //Retrieve useful elevation angle from Zenith angle

void loop(){
 sunPos(); //Run sun position calculations
 Serial.print("Elevation Angle:  ");
 Serial.println(ElevationAngle, 0); //Print Elevation (Vertical) with no decimal places as accuracy is not really great enough
 Serial.print("Azimuth:  ");
 Serial.println(Azimuth, 0); //Print Azimuth (Horizontal) with no decimal places
 if(ElevationAngle < 0)
 Serial.println("The sun has set. Get some sleep!");
 while(1){} //Stop - Values aren't going to have changed anyway as they are currently static variables!

Should work fine.


Go Up