You are on page 1of 14

//Solar Tracker //Tracks Azimuth and Elevation for use with active tracking solar panels #include <Time.

h> #include <Wire.h> #include <LiquidCrystal.h> #include <DS1307RTC.h> #include <enc28j60.h> #include <etherShield.h> #include <ip_arp_udp_tcp.h> #include <ip_config.h> #include <net.h> #include <websrv_help_functions.h> #include <Client.h> #include <SPI.h>

#include <math.h> #include <AFMotor.h> #define pi //AdaFruit Stepper motor library

3.14159265358979323846

#define twopi (2*pi) #define rad (pi/180) #define EarthMeanRadius #define AstronomicalUnit 6371.01 // In km 149597890 // In km

//----- Ethernet Shield define ---// static uint8_t mymac[6] = { 0x54,0x55,0x58,0x10,0x00,0x24};

static uint8_t myip[4] = { 192,168,4,202};

#define MYWWWPORT 80 #define BUFFER_SIZE 550 static uint8_t buf[BUFFER_SIZE+1];

// The ethernet shield EtherShield es=EtherShield();

uint8_t serverport = 80; uint8_t serverip[4] = {192, 168, 4, 45};

Client client(serverip, serverport);

//----- end ethernet shield ---//

LiquidCrystal lcd(4, 9, 7, 8, 5, 6); AF_Stepper ElevStepper(200,1); AF_Stepper AziStepper(200,2);

boolean nightTime; int AziStep = 0; int ElevStep = 0; int AziPrevious = 0;

int ElevPrevious = 0; int AziOneDegree = 10; // Enter number of steps to physically move your rig 1 degree Azimuth. int ElevOneDegree = 20; // Enter number of steps to physically move your rig 1 degree Elevation.

float Longitude = -121.23486042022705; //enter longitude here float Latitude = 44.224928297647466; //enter latitude here

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); lcd.begin (19,3); Wire.begin();

pinMode (17, OUTPUT); // +5v for DS1307 RTC on analog 4 (digital 17)

pinMode (16, OUTPUT); // Ground for DS1307 on analog 3 (digital 16) pinMode (2, OUTPUT); // Backlight for LCD

digitalWrite (17, HIGH); // tell pin 17 to be +5v digitalWrite (16, LOW); digitalWrite (2, HIGH); // tell pin 16 to be Ground // tell pin 2 to be +5v (for backlight)

setSyncProvider(RTC.get); // Get time from RTC setSyncInterval(86400); ElevStepper.setSpeed(120); AziStepper.setSpeed(120); // re-sync time with the RTC every ( ) seconds.

//--- Ethernet shield setup ----// // initialize enc28j60 // es.ES_enc28j60Init(mymac);

// init the ethernet/ip layer: // es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);

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

void RealTimeClock() {

lcd.setCursor(0,1); if(hour() <10)

lcd.print("0"); lcd.print(hour()); lcd.print(":"); if(minute() <10) lcd.print("0"); lcd.print(minute()); lcd.print(":"); if(second() <10) lcd.print("0"); lcd.print(second()); lcd.print(" "); lcd.print(month()); lcd.print("/"); lcd.print(day()); lcd.print("/"); lcd.print(year()); lcd.print(" "); }

void sunPos(){

RealTimeClock();

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 = (hour() + minute() / 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 RealTimeClock(); //Call time function

lcd.setCursor(0,0); lcd.print("Sun Position Tracker");

lcd.setCursor(0,2); lcd.print("E: "); lcd.print(ElevationAngle); lcd.print(" A: "); lcd.print(Azimuth);

// Convert Azimuth and ElevationAngle to output to stepper motors // NOTE!!! For the code below, you must manually calculate how many steps it takes // to mechanically move your rig exactly 1 degree of physical motion. This is in variables above, // as ElevOneDegree and AziOneDegree.

ElevStep = (ElevationAngle * ElevOneDegree); //Elevation is 0 - 90 degrees, so this adds up perfect. AziStep = ((Azimuth / 2) * AziOneDegree); //devide Azimuth by 2 to give us 180 degrees of range.

if (ElevationAngle < 0){ nightTime = true; lcd.setCursor(0,3); lcd.print (" Parking All Panels "); ElevStepper.step(((90-ElevationAngle)*ElevOneDegree),BACKWARD, DOUBLE); // Park the panel flat at night. This is the safest position in AziStepper.step(((Azimuth/4)*AziOneDegree),BACKWARD, DOUBLE); // case of high winds. }

while(nightTime){ ElevPrevious = 0; AziPrevious = 0; lcd.setCursor(0,3); lcd.print(" Night Time "); // Clear "previous" values

sunPos(); //Run sun position calculations to see when Elevation is above zero. if (ElevationAngle > 0) nightTime = false;

lcd.setCursor(0,2); lcd.print("E: "); lcd.print(ElevationAngle); lcd.print(" A: "); lcd.print(Azimuth); delay(1000); }

if ((ElevStep - ElevPrevious)<0) noon, Elevation will be declining, so we have

// After the solar

ElevStepper.step(((ElevStep - ElevPrevious)*-1),BACKWARD, DOUBLE); // to invert the negative number to positive (* -1), and tell else BACKWARD. // the stepper to run // For //

ElevStepper.step((ElevStep - ElevPrevious),FORWARD, DOUBLE); the steppers, we want to only have motion if there has been AziStepper.step((AziStep - AziPrevious),FORWARD, DOUBLE); change. By subtracting the previous values from the current values, unless there is change. // lcd.setCursor(0,3); // lcd.print(ElevStep); // lcd.print(" "); // lcd.print(AziStep); // lcd.print(" "); // lcd.print(ElevStep - ElevPrevious); // lcd.print(" "); // lcd.print(AziStep - AziPrevious); // lcd.print(" ");

// it will result in a 0 value,

lcd.setCursor(0,3); lcd.print(" Day Time ");

ElevPrevious = ElevStep; AziPrevious = AziStep;

//--- output to MySQL ---//

while (client.connected() && client.available()) { bool connected; client.print("GET /writeDBTrackingData.php?elevation="); client.print(ElevationAngle); client.print("&azimuth="); client.println(Azimuth); client.stop(); connected = false; } //delay (10000);

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h> #include "RTClib.h" #include <LiquidCrystal.h>

LiquidCrystal lcd(4, 9, 7, 8, 5, 6);

RTC_DS1307 RTC;

void setup () {

Serial.begin(57600); Wire.begin(); RTC.begin(); lcd.begin(19,3); pinMode (17, OUTPUT); // +5v for DS1307 RTC on analog 4 (digital 17) pinMode (16, OUTPUT); // Ground for DS1307 on analog 3 (digital 16) pinMode (2, OUTPUT); // Backlight for LCD

digitalWrite (17, HIGH); // tell pin 17 to be +5v digitalWrite (16, LOW); digitalWrite (2, HIGH); // tell pin 16 to be Ground // tell pin 2 to be +5v (for backlight)

// following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); }

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

lcd.setCursor(0,0); lcd.print("RTC Clock set to:"); lcd.setCursor(0,1); lcd.print(now.hour(), DEC); lcd.print(':'); if(now.minute() <10)

lcd.print("0"); lcd.print(now.minute(), DEC); lcd.print(':'); if(now.second() <10) lcd.print("0"); lcd.print(now.second(), DEC); lcd.print(" "); lcd.print(now.month(), DEC); lcd.print('/'); lcd.print(now.day(), DEC); lcd.print('/'); lcd.print(now.year(), DEC);

delay(1000);