New sun tracker idea?

Thanks for the insight. I thought that the Zenith was bottom up but we are all wrong sometimes

I think you’re allowed to be after all the work you’ve put into this code lol! ;D

BreaksBassBleeps

Right. After all that, there is some code guaranteed to work now.

//Sun Position Calculation by Mowcius (mowcius.co.uk)
//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() {
 Serial.begin(9600);
}

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;
            JulianDate=(float)(liAux2)-0.5+DecimalHours/24.0;
            // 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;
            Omega=2.1429-0.0010394594*ElapsedJulianDays;
            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
                  -0.0000203*sin(Omega);
            EclipticObliquity = 0.4090928 - 6.2140e-9*ElapsedJulianDays
                  +0.0000396*cos(Omega);
      
      // 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 + 
                  0.0657098283*ElapsedJulianDays 
                  + 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
            Parallax=(EarthMeanRadius/AstronomicalUnit)
                  *sin(ZenithAngle);
            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!");
  delay(10000); //Delay 10 seconds - Values aren't going to have changed anyway as they are currently static variables!
}

Let me know if you use the code for anything. I think I will connect the horizontal (Azimuth) values to a stepper motor this weekend and figure out how to use the RTC on my rDuino LEDHead!

The Finish Line (the song by Snow Patrol) just started playing from random… Seems rather appropriate. I can see the finish from here!
Hopefully this code will help other people too.

Mowcius

Mowcius,
Nice work! Thank you.
I’m sure this will have value for a lot of projects.

Well I am watching it now and it seems to be working perfectly. I am comparing it to stellarium and the sun. The sun's just about to set and it looks about right :) It doesn't take altitude into consideration but to be honest, for the kind of things people might use it for, that degree of accuracy is not required. That's also why I removed the seconds value. It made hardly any difference and you might as well have the extra RAM ;)

Mowcius

Had a bit of a play around and wrote some code to calculate the sunrise and sunset for the next week.

Put in the date and it’ll throw out the sunrise and sunset.

It runs through every minute until the elevation gets to ~0 then records the value. Takes about 1 second to calculate each day.

//Sun Position Calculation by Mowcius (mowcius.co.uk)
//Provides sunrise and sunset times for a week after a given date

#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 = 10; //hour
      float Minutes = 10; //minutes

      float Longitude = 1.5458; //enter longitude here
      float Latitude = 1.5464; //enter latitude here
//--------

    int SunRiseHour = 0;
    int SunRiseMinute = 0;
    int SunSetHour = 0;
    int SunSetMinute = 0;
    int d = 0;

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

      float ElapsedJulianDays;
      float DecimalHours;
      float EclipticLongitude;
      float EclipticObliquity;
//--------

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

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;
            JulianDate=(float)(liAux2)-0.5+DecimalHours/24.0;
            // 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;
            Omega=2.1429-0.0010394594*ElapsedJulianDays;
            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
                  -0.0000203*sin(Omega);
            EclipticObliquity = 0.4090928 - 6.2140e-9*ElapsedJulianDays
                  +0.0000396*cos(Omega);
      
      // 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 + 
                  0.0657098283*ElapsedJulianDays 
                  + 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
            Parallax=(EarthMeanRadius/AstronomicalUnit)
                  *sin(ZenithAngle);
            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(){
  Hours = 3;
  Minutes = 0;
  sunPos(); //Run sun position calculations
  int i = 0;
  while(i < 1){
  while(Minutes < 60 && ElevationAngle < -0.5){
    Minutes++;
    sunPos();
  }
  if(ElevationAngle < 0.5 && ElevationAngle > -0.5){
    SunRiseHour = Hours+1;                               //+1 for me to get UT to British Summer Time
    SunRiseMinute = Minutes;
    i = 1;
  }
  Minutes = 0;
  Hours++;
 }
 i = 0;
 Hours = 16;
 Minutes = 0;
 sunPos();
 while(i < 1){
 while(Minutes < 60 && ElevationAngle > 0.5){
    Minutes++;
    sunPos();
  }
  if(ElevationAngle < 0.5 && ElevationAngle > -0.5){
    SunSetHour = Hours+1;                                //+1 for me to get UT to British Summer Time
    SunSetMinute = Minutes;
    i = 1;
  }  
  Minutes = 0;
  Hours++;
}
Serial.print("Date: ");
Serial.print(Day);
Serial.print("/");
Serial.print(Month);
Serial.print("/");
Serial.println(Year);
Serial.print("Sunrise: ");
Serial.print(SunRiseHour);
Serial.print(":");
if(SunRiseMinute < 10)
Serial.print("0");
Serial.println(SunRiseMinute);
Serial.print("Sunset: ");
Serial.print(SunSetHour);
Serial.print(":");
if(SunSetMinute < 10)
Serial.print("0");
Serial.println(SunSetMinute);
Serial.print("Sketch Time Taken: ");
Serial.println(millis());
Day++;
d++;
if(d == 7){
while(i == 1){}
}
}

Any more updates to this code will be posted here: http://www.mowcius.co.uk/suntrackercode.html

Mowcius

Loving your work Mowcius!!

I'm planning to use this to control a self built solar tracker as I'd love to go off-grid. A solar tracker will make best use of the available light which as you know we don't get much of in the uk. I'm also planning to make a parabolic solar water heater which will also track the sun and pre-heat my hot water. I'm gonna be posting how it all goes so other people can do the same, if they want to :D

Breaksbassbleeps

I'm planning to use this to control a self built solar tracker as I'd love to go off-grid. A solar tracker will make best use of the available light which as you know we don't get much of in the uk. I'm also planning to make a parabolic solar water heater which will also track the sun and pre-heat my hot water. I'm gonna be posting how it all goes so other people can do the same, if they want to

Keep me updated. I will link it to my code page as an example when you get it finished.

Mowcius

I am working on the same project! Last night I put libelium-gps, compass and sun motion code together, it seems to work.

If I turn my arduino (by hand), a LED will flash when direction is reaching the sun's position (azimuth) :-).

Next step is to build the mechanics for the disher and the pv panel. .....I am looking for simple stepper motors.

I am working on the same project! Last night I put libelium-gps, compass and sun motion code together, it seems to work.

If I turn my arduino (by hand), a LED will flash when direction is reaching the sun's position (azimuth) Smiley.

Next step is to build the mechanics for the disher and the pv panel. .....I am looking for simple stepper motors.

Sounds good. Is this my modified code you are using?

How heavy is your panel? If you got some decent bearings so that your panel has minimal friction moving then you could use a high torque single turn stepper motor for the rotational movement. Then you don't need a home position switch/routine.

When the servo gets to its limits then I presume the sun will have set anyway (unless you are rather close to the north or south pole) so a stepper might be a suitable solution. It depends on the setup I suppose.

Mowcius

Today I am a very lucky man, I could buy a old parabolic sat antenna with 2 meter diameter!! for only 80 USD! So my project is running excellent...finding a huge parabolic antenna for less money was very difficult. I not received it yet, but I think that it will be about 15-20 kg's: http://www.ricardo.ch/kaufen/audio-tv-und-video/sat-systeme-und-paytv/sonstiges/satelliten-schuessel-gross-analog/v/an613575454/

Instead of stepper motors I planned to use gearmotors (3000:1) and sensors. So I can build the mechanics much easiler because the sensors (compass and potentiometer) will give me an exact feedback about the position of the axis and the mechanic construction must not be perfect.

Hope I can handle the wind force with such a great dish...

The sun powers wattage will be about 2 kW...

I am very happy :-)

Sounds like a nice project. Is the output power from this for something specific? Power for your house?/Electric vehicle?

Hope I can handle the wind force with such a great dish...

Yes, you are going to need a strong frame for it!

The power isn't specific for something. But I have some ideas...perhaps I'll heat up a friends swimming pool.

Other thing is to heat hot water for a house, but there are some problems to connect it to the boiler, because the sunniest place of a property is normally not nearest to the central heating room.

Nicest thing to build would be a stirling engine which generates eletric power, but I will not be able to build a stirling....

Here a little update about my solar dish project. Yesterday I worked on the dish and I sticked mirroring foil on it. I test it, but it was cloudly weather (only paper burned).

Today the weather is excellent and I could burn wood in seconds (see video): http://www.youtube.com/watch?v=GBKbLLDq-dw

Next step is to build the mechanics, then I will fine tune my arduino code.

Whoa, that is crazy!

I didn’t know you could get so much heat from such a small dish (compared to solar furnaces that is).

Looking great!

Mowcius

can someone tell me why I cant get the date/time to update like so?
Im new so be nice! Thanks Mowcius for all the work.

//Sun Position Calculation by Mowcius (mowcius.co.uk)
//Provides sun position (relative) from static variables

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

RTC_DS1307 RTC;

//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!

float Longitude = 1.4756; //enter longitude here
float Latitude = 1.5763; //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() {
Serial.begin(57600);
Wire.begin();
RTC.begin();
RTC.adjust(DateTime(DATE, TIME));

}

void sunPos() {
DateTime now = RTC.now();

int Year = (now.year(), DEC); //year
int Month = (now.month(), DEC); //month
int Day = (now.day(), DEC); //day
float Hours = (now.hour(), DEC); //hour
float Minutes = (now.minute(), DEC); //minutes

// 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-12liAux1))/12- (3((Year + 4900
  • liAux1)/100))/4+Day-32075;
    JulianDate=(float)(liAux2)-0.5+DecimalHours/24.0;
    // 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 2Pi
// (i.e., the result may be greater than 2
Pi)

float MeanLongitude;
float MeanAnomaly;
float Omega;
Omega=2.1429-0.0010394594ElapsedJulianDays;
MeanLongitude = 4.8950630+ 0.017202791698
ElapsedJulianDays; // Radians
MeanAnomaly = 6.2400600+ 0.0172019699ElapsedJulianDays;
EclipticLongitude = MeanLongitude + 0.03341607
sin( MeanAnomaly )

  • 0.00034894sin( 2MeanAnomaly )-0.0001134
    -0.0000203sin(Omega);
    EclipticObliquity = 0.4090928 - 6.2140e-9
    ElapsedJulianDays
    +0.0000396*cos(Omega);

// Calculate celestial coordinates ( right ascension and declination ) in radians
// but without limiting the angle to be less than 2Pi (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 +
0.0657098283*ElapsedJulianDays

  • 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_LatitudeCos_HourAngle;
    Azimuth = atan2( dY, dX );
    if ( Azimuth < 0.0 )
    Azimuth = Azimuth + twopi;
    Azimuth = Azimuth/rad;
    // Parallax Correction
    Parallax=(EarthMeanRadius/AstronomicalUnit)
    *sin(ZenithAngle);
    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(){
DateTime now = RTC.now();
sunPos(); //Run sun position calculations
Serial.print("Elevation Angle: ");
Serial.println(ElevationAngle); //Print Elevation (Vertical) with no decimal places as accuracy is not really great enough
Serial.print("Azimuth: ");
Serial.println(Azimuth); //Print Azimuth (Horizontal) with no decimal places
Serial.print("Seconds: ");
Serial.println(now.second(), DEC);
if(ElevationAngle < 0)
Serial.println(“The sun has set. Get some sleep!”);
delay(1000); //Delay 10 seconds - Values aren’t going to have changed anyway as they are currently static variables!
}

I will try and take a look at this later to try and see what’s up with it.

I have not yet tried to connect an RTC. I will do that soon too so I can post some code with it working.

Mowcius

Any more updates to this code will be posted here: http://www.mowcius.co.uk/suntrackercode.html

Mowcius

Looks very nice, but i get 404 Error - File not found! on both of pde files :'(

Sorry, website is kinda down :(

ftp issues... I will try and get off my arse and get it sorted soon :)

Mowcius