Google Tag

Arduino Controlled dual axis Solar Tracker Code

//Υπολογισμός θέσης του ήλιου
//Δίνει την θέση του ήλιου στον ουρανό σε μοίρες όσο αφορά το ύψος και την ανατολή-δύση

#include <Timer.h>                    //Timer Library

Timer t;                              //defines t as a timer

#define pi    3.14159265358979323846 //Το π
#define rad   (pi/180)               //Για την μετατροπή ακτίνια=μοίρες*(π/180)


#define DS1307_ADDR_R       0xd1     //rtc i2c address for reading
#define DS1307_ADDR_W       0xd0     //rtc i2c address for writing
#define _sda_pin            A4       //i2c data line arduino pin
#define _scl_pin            A5       //i2c clock line arduino pin
#define REG_SEC     0x00     //rtc second register address
#define REG_MIN     0x01     //rtc minute register address
#define REG_HOUR     0x02     //rtc hour register address
#define REG_DOW     0x03     //rtc day of week register address
#define REG_DATE     0x04     //rtc date register address
#define REG_MON     0x05     //rtc month register address
#define REG_YEAR     0x06     //rtc year register address
#define ELEV_UP_POT_LIMIT   0x08     //rtc elevetion potensiometer upper limit ram register
#define ELEV_DOWN_POT_LIMIT 0x09     //rtc elevetion potensiometer down limit ram register
#define AZIM_EAST_POT_LIMIT 0x0a     //rtc elevetion potensiometer east limit ram register
#define AZIM_WEST_POT_LIMIT 0x0b     //rtc elevetion potensiometer west limit ram register
#define REG_DST             0x0c     //rtc DST winter-summer ram register (0=Winter, 1=Summer)

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

#define elev_UP 2         //output pin for relay elevation UP
#define elev_DOWN 3       //output pin for relay elevation DOWN

#define azim_EAST 4       //output pin for relay azimuth EAST
#define azim_WEST 5       //output pin for relay azimuth WEST

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

#define but_UP 6          //input pin for button elevation UP
#define but_DOWN 7        //input pin for button elevation DOWN

#define but_EAST 8        //input pin for button azimuth EAST
#define but_WEST 9        //input pin for button azimuth WEST

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

#define limit_UP 10       //input pin for limit switch elevation UP
#define limit_DOWN 11     //input pin for limit switch elevation DOWN

#define limit_EAST 12     //input pin for limit switch azimuth EAST
#define limit_WEST 13     //input pin for limit switch azimuth WEST

#define limits_LED A0     //Led for indicating that one or more limit switches in activated
#define auto_man A1       //input pin for auto/manual switch

#define elev_pot A2       //Analog input pin for elevation pontensiometer
#define azim_pot A3       //Analog input pin for azimuth pontensiometer

//----------The mechanical limits in degrees of tracker-------------------//
//-----------they depend from the tracker construction--------------------//
#define UP_LIMIT_DEG   90    //elevation up limit of tracker
#define DOWN_LIMIT_DEG 30    //elevation down limit of tracker
#define EAST_LIMIT_DEG 120   //azimuth east limit of tracker
#define WEST_LIMIT_DEG 240   //azimuth west limit of tracker
#define SOUTH_DEG      180   //degrees of south
//----------------------------------------------------------------//

//Εισαγωγή Μεταβλητών
//Η ημερομηνία και η ώρα την διαβάζει απο το RTC (Real Time Clock) μέσω I2C
//υπολογίζεται με αλγοριθμο αν είναι καλοκαιρινή ώρα DST(Daylight Saving Time)

  int date;         //Ημέρα
  int month;        //Μήνας
  int year;         //Χρονιά

  float hour;       //Ώρα
  float minute;     //Λεπτά
  byte sec;

 //-------------το timezone και οι συντεταγμένες πρέπει να οριστούν εδώ ανάλογα με την τοποθεσία εγκατάστασης----------//
  int timezone= 2;   //Η ζώνη ώρας της Ελλάδος (ουσιαστικά δεν μας ενδιαφέρει το πρόσημο αλλά η διαφορά από το μηδέν)

  float latitude=  39.549159;    //Γεωγραφικό Πλάτος σε μοίρες
  float longitude= 20.325640;    //Γεωγραφικό Μήκος σε μοίρες
//-------------------------------------------------------------------//



//Μεταβλητές Προγράμματος

  int doy;                //Day of year, θα υπολογίζεται απο αλγόριθμο
  int dow;                //Day of Week, υπολογιζεται απο αλγόριθμο.
  int dst;                //Καλοκαιρινή ώρα 1=Ναι 0=Όχι, θα υπολογίζεται απο αλγόριθμο

  float easn;             //Elevation Angle at Solar Noon (Οι μοίρες του ύψους του ήλιου κατά το ηλιακό μεσημέρι)

  float elevation;        //Οι τρέχουσες μοίρες ύψους του ήλιου
  int elevation_int;      //Το elevation σε ακεραια μορφή
  float zenith;           //η συμπληρωματική γωνία ως προς τις 90 μοίρες, η γωνία δηλαδή που πρέπει να έχουν τα φωτοβολταικά πάνελς
                          //ως προς το έδαφος την δεδομένη στιγμή

  float azimuth;          //οι μοίρες στις οποίες βρίσκεται ο ήλιος σε σχέση με την Ανατολή-Δύση, Νότος είναι 180
  int azimuth_int;        //Το azimuth σε ακέραια μορφή

 
  int motion_flag=0;      //για την αναγνώριση της κίνησης 8=UP, 4=DOWN, 2=EAST, 1=WEST, 0=STOP
 
  int auto_man_flag=0;    //για την ενδειξη της κατάστασης (mode) 0=Manual, 1=Auto, 2=Calibrating

  int elev_limits_flag=0; //για την ένδειξη των ορίων (ακραιοι δικόπτες) του elevation 2=UP, 1=DOWN, 0=NoLimit

  int azim_limits_flag=0; //για την ένδειξη των ορίων (ακραιοι δικόπτες) του azimuth 2=EAST, 1=WEST, 0=NoLimit

  int elev_pot_up_limit;    //η αναλογική τιμή του ποντενσιόμετρου για το πάνω όριο του elevation
  int elev_pot_down_limit;  //η αναλογική τιμή του ποντενσιόμετρου για το κάτω όριο του elevation
  int azim_pot_east_limit;  //η αναλογική τιμή του ποντενσιόμετρου για το east όριο του azimuth
  int azim_pot_west_limit;  //η αναλογική τιμή του ποντενσιόμετρου για το west όριο του azimuth

  int num_pot_readings=10;  //αριθμός τιμών που διαβάζει (analogread) απο τα ποντενσιόμετρα για να βγάλει το μεσο όρο (smoothing)

  int auto_move_elev_flag;//=0;//για τον έλεγχο αν πρέπει να κινηθεί αυτόματα σε νεα θέση κάθετα (elevation) 0=πρέπει να κινηθεί, 1=οχι
  int auto_move_azim_flag;//=0;//για τον έλεγχο αν πρέπει να κινηθεί αυτόματα σε νεα θέση οριζόντια (azimuth) 0=πρέπει να κινηθεί, 1=οχι

  int auto_move_elev_deg;  //μοίρες στις οποίες πρέπει να κινηθεί αυτόματα κάθετα (elevation)
  int auto_move_azim_deg;  //μοίρες στις οποίες πρέπει να κινηθεί αυτόματα οριζόντια (azimuth)

  int calibration_flag;    //ένδειξη για calibration mode 1=calibration, 0=no
  int calibration_state;   //φάση στην οποία βρίσκετε το calibration 8=up calibration, 4=down calibration, 2=east calibration, 1=west calibration

  int mins_to_next_move_count;  //αντιστροφη μέτρηση των λεπτών που απομένουν μέχρι την επόμενη κίνηση
  int mins_to_move_ahead=16;    //μεσοδιάστημα λεπτών που θα υπολογίζονται οι συντεταγμένες και θα γίνετε η κίνηση
  int just_moved_flag;          //ένδειξη ότι μόλις κινήθηκε 1=μόλις κινήθηκε, 0=οχι

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

 //--------------------- RTC DS1307 Routines-----------------//
  void sendStart(byte addr)
{
pinMode(_sda_pin, OUTPUT);
        digitalWrite(_scl_pin, HIGH);
digitalWrite(_sda_pin, HIGH);
digitalWrite(_sda_pin, LOW);
digitalWrite(_scl_pin, LOW);
shiftOut(_sda_pin, _scl_pin, MSBFIRST, addr);
}

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

void sendStop()
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_sda_pin, LOW);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_sda_pin, HIGH);
pinMode(_sda_pin, INPUT);
}

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

void sendNack()
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_scl_pin, LOW);
digitalWrite(_sda_pin, HIGH);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_scl_pin, LOW);
pinMode(_sda_pin, INPUT);
}

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

void waitForAck()
{
pinMode(_sda_pin, INPUT);
digitalWrite(_scl_pin, HIGH);
if (digitalRead(_sda_pin)==LOW)
           digitalWrite(_scl_pin, LOW);
}

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

byte readByte()
{
pinMode(_sda_pin, INPUT);

byte value = 0;
byte currentBit = 0;

for (int i = 0; i < 8; ++i)
{
digitalWrite(_scl_pin, HIGH);
currentBit = digitalRead(_sda_pin);
value |= (currentBit << 7-i);
delayMicroseconds(1);
digitalWrite(_scl_pin, LOW);
}
return value;
}

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

void writeByte(byte value)
{
pinMode(_sda_pin, OUTPUT);
shiftOut(_sda_pin, _scl_pin, MSBFIRST, value);
}

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

byte readRegister(byte reg)
{
byte readValue=0;

sendStart(DS1307_ADDR_W);
waitForAck();
writeByte(reg);
waitForAck();
sendStop();
sendStart(DS1307_ADDR_R);
waitForAck();
readValue = readByte();
sendNack();
sendStop();
return readValue;
}

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

void writeRegister(byte reg, byte value)
{
sendStart(DS1307_ADDR_W);
waitForAck();
writeByte(reg);
waitForAck();
writeByte(value);
waitForAck();
sendStop();
}

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

byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}

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

void setTime(byte hour, byte min, byte sec)
{
if (((hour>=0) && (hour<24)) && ((min>=0) && (min<60)) && ((sec>=0) && (sec<60)))
{
writeRegister(REG_HOUR, decToBcd(hour));
writeRegister(REG_MIN, decToBcd(min));
writeRegister(REG_SEC, decToBcd(sec));
}
}

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

void setDate(byte date, byte mon, uint16_t year)
{
if (((date>0) && (date<=31)) && ((mon>0) && (mon<=12)) && ((year>=2000) && (year<3000)))
{
year -= 2000;
writeRegister(REG_YEAR, decToBcd(year));
writeRegister(REG_MON, decToBcd(mon));
writeRegister(REG_DATE, decToBcd(date));
}
}

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

void setDOW(byte dow)
{
if ((dow>0) && (dow<8))
writeRegister(REG_DOW, dow);
}

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

byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}

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

void halt(bool enable)
{
  byte reg = readRegister(REG_SEC);
  reg &= ~(1 << 7);
  reg |= (enable << 7);
  writeRegister(REG_SEC, reg);
}

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

void getRTC(){

  sec=bcdToDec(readRegister(REG_SEC)&0x7f);
  minute=bcdToDec(readRegister(REG_MIN));
  hour=bcdToDec(readRegister(REG_HOUR)&0x3f);

  dow=bcdToDec(readRegister(REG_DOW));

  date=bcdToDec(readRegister(REG_DATE));
  month=bcdToDec(readRegister(REG_MON));
  year=2000+bcdToDec(readRegister(REG_YEAR));
}
//---------------------------------------------------------------------------------------------------------------------------------------------------//
//------------------ Motion Routines ------------------------------------------//

 // Elevetion UP
 void move_elev_UP(){

 digitalWrite(elev_UP,HIGH);
 digitalWrite(elev_DOWN,LOW);
 digitalWrite(azim_EAST,LOW);
 digitalWrite(azim_WEST,LOW);
 motion_flag=8;
}

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

void automove_elev(int deg){

  if (read_elev_pot()==deg) {auto_move_elev_flag=1; move_all_stop();}
  else if ((read_elev_pot()<deg) && (check_elev_limits()!=2)) move_elev_UP();
  else if ((read_elev_pot()>deg) && (check_elev_limits()!=1)) move_elev_DOWN(); 
  else  move_all_stop();
  check_elev_limits();
}

//--------------------------------------------------------//
//Elevation DOWN
void move_elev_DOWN(){

 digitalWrite(elev_UP,LOW);
 digitalWrite(elev_DOWN,HIGH);
 digitalWrite(azim_EAST,LOW);
 digitalWrite(azim_WEST,LOW);
 motion_flag=4;
}

//--------------------------------------------------------//
//Azimuth EAST
void move_azim_EAST(){

 digitalWrite(elev_UP,LOW);
 digitalWrite(elev_DOWN,LOW);
 digitalWrite(azim_EAST,HIGH);
 digitalWrite(azim_WEST,LOW);  
 motion_flag=2;
}

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

void automove_azim(int deg){

  if (read_azim_pot()==deg) {auto_move_azim_flag=1; move_all_stop();}
  else if ((read_azim_pot()<deg) && (check_azim_limits()!=1)) move_azim_WEST();
  else if ((read_azim_pot()>deg) && (check_azim_limits()!=2)) move_azim_EAST(); 
  else  move_all_stop();
  check_azim_limits();
}

//--------------------------------------------------------//
//Azimuth WEST
void move_azim_WEST(){

 digitalWrite(elev_UP,LOW);
 digitalWrite(elev_DOWN,LOW);
 digitalWrite(azim_EAST,LOW);
 digitalWrite(azim_WEST,HIGH);
 motion_flag=1;
}

//--------------------------------------------------------//
//BOTH motor STOP
void move_all_stop(){

 digitalWrite(elev_UP,LOW);
 digitalWrite(elev_DOWN,LOW);
 digitalWrite(azim_EAST,LOW);
 digitalWrite(azim_WEST,LOW);
 motion_flag=0;

}

//--------------------------------------------------------//
//Check Elevation Limits
int check_elev_limits(){

  int limits_reading;

  limits_reading=0;
  limits_reading=limits_reading + digitalRead(limit_UP);    //2 limit up
  limits_reading=limits_reading << 1;
  limits_reading=limits_reading + digitalRead(limit_DOWN);  //1 limit down

  elev_limits_flag=limits_reading;
  return limits_reading;
}

//--------------------------------------------------------//
//Check Azimuth Limits
int check_azim_limits(){

  int limits_reading;

  limits_reading=0;
  limits_reading=limits_reading + digitalRead(limit_EAST);  //2 limit EAST
  limits_reading=limits_reading << 1;
  limits_reading=limits_reading + digitalRead(limit_WEST);  //1 limit WEST

  azim_limits_flag=limits_reading;
  return limits_reading;
}

//--------------------------------------------------------//
//Check Buttons
int check_buttons(){

  int buttons_reading;

  int old_button_state=0;
  int button_state=0;
  long last_debounce_time =0;
  long debounce_delay=20;

  buttons_reading=digitalRead(but_UP);                      //8 UP
  buttons_reading=buttons_reading << 1;
  buttons_reading=buttons_reading + digitalRead(but_DOWN);  //4 DOWN
  buttons_reading=buttons_reading << 1;
  buttons_reading=buttons_reading + digitalRead(but_EAST);  //2 EAST
  buttons_reading=buttons_reading << 1;
  buttons_reading=buttons_reading + digitalRead(but_WEST);  //1 WEST

  if (buttons_reading!=old_button_state){
    last_debounce_time=millis(); 
  }

  if((millis()-last_debounce_time)>debounce_delay){ 
   button_state=buttons_reading;
  }

  old_button_state=buttons_reading;

  return buttons_reading;
}


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

//Αλγόριθμος υπολογισμού του αριθμού της ημέρας του χρόνου από 1 εώς 365 ή 366 για δύσεκτο έτος
void dayofyear() {
  int dom[11]={31,28,31,30,31,30,31,31,30,31,30};  //Πίνακας από 11 τιμές με τις μέρες των μηνών (Φεβρουάριος 28).
                                                   //Δεν χρειαζόμαστε τον Δεκέμβριο.

  boolean leapyear;                                //Για τον υπολογισμό Δύσεκτου Έτους
  int x;


  doy=0;

  if (month>1) {   
    for (x=1 ; x<month ; x=x+1) {   
      doy=doy+dom[x-1]; 
    }
  }

  doy=doy+date;

  if (year%400==0) leapyear=true;          //
  else if (year%100==0) leapyear=false;    //Υπολογισμός δύσεκτου έτους
  else if (year%4==0) leapyear=true;       //
  else leapyear=false;                     //

  if ((leapyear) && (month>2))  doy = doy+1;

}

//--------------------------------------------------------//
//Αλγοριθμος για τον υπολογισμό της μέρας της βδομαδας ώστε να χρησιμοποιηθεί στον υπολογισμό του DST
//1=Δευτέρα, 2=Τρίτη, 3=Τετάρτη, 4=Πέμπτη, 5=Παρασκευή, 6=Σάββατο, 7=Κυριακή
/*void dayofweek(){
  
  byte d;
  /*int a,y,m,d;
  
  a=(14-month)/12;
  y=year-a;
  m=month+(12*a)-2;
  d=(date+y+y/4-y/100+y/400+(31*m)/12)%7;*/


 /* d=dow-1;
  if (d==0) dow=7; else dow=d;
  
}*/

//--------------------------------------------------------//
//Αλγόριθμος για τον υπολογισμό Θερινής-Χειμερινής ώρας μιας ημερονηνίας, DST
//Γινεται θερινή την τελευταία Κυριακή του Μαρτίου
//Γίνεται χειμερινή την τελευταία Κυριακή του Οκτωβρίου

void dstcalc(){
  //dst=0 -->Winter
  //dst=1 -->Summer

 if (month>3 && month<10) dst=1;
 if (month<3 || month>10) dst=0;

 if ((month==3) && (date>=24)) {
           if ((dow==7) && (int(hour)>1)) dst=1;}
 //else if ((month==3) && (date<24)) dst=0;

 if ((month==10) && (date>=24)) {
           if ((dow==7) && (int(hour)>1)) dst=0;}
 //else if ((month==10) && (date<24)) dst=1;

        
 time_change();
}

//--------------Αλλαγή της Ώρας---------------------------//

void time_change(){
  int dst_in_ram;


 dst_in_ram=readRegister(REG_DST);

 if ((dst==1) && (dst_in_ram==0)){//αρχιζει η καλοκαιρινή ώρα
   hour=hour+1.0;
   setTime((int)hour,(int)minute,(int)sec);
   writeRegister(REG_DST,dst);
 }

 if ((dst==0) && (dst_in_ram==1)){//αρχιζει η χειμερινή ώρα
   hour=hour-1.0;
   setTime((int)hour,(int)minute,(int)sec);
   writeRegister(REG_DST,dst);
 }

}

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

//Υπολογισμοί για την θέση του ήλιου
void sunposition(int hour_to_calculate,int min_to_calculate){

 float b;                 //μια μεταβλητή χρήσιμη
 float bradians;
 float eot;
 int lstm;
 float tcf;
 float lst;
 float sha;
 float declination;
 float decimaltime;      //Μετατροπή της ώρας σε δεκαδική μορφή, είναι ίσο με hour+(minutes/60)
 int dst_in_ram;





 decimaltime=(float)hour_to_calculate+((float)min_to_calculate/60);        //Μετατροπή της ώρας σε δεκαδική μορφή

 b=(360.00*(doy-81.00))/365.00;       //Μεταβλητή για τον υπολογισμό άλλων παραμέτρων.
 bradians=b*rad;                      //το b σε ακτίνια

 //Equation of Time.
 //The equation of time (EoT) (σε λεπτά) είναι μια εμπειρική συνάρτηση
 //η οποία διορθώνει την ελλειπτική τροχιά της γής και την κλίση της γής ως προς τον άξονά της.

 eot=(9.87*sin(2*bradians))-(7.53*cos(bradians))-(1.5*sin(bradians));


 //Local Standard Time Meridian (LSTM)
 //είναι ένας μεσημβρινός αναφοράς για την συγκεκριμένη ώρα ζώνης
 //παρόμοιος με κύριο μεσημβρινό ο οποίος χρησιμοποιείται για Greenwich Mean Time.
 //μας ενδιαφέρει η διαφορά της τοπικής ζωνης ώρας από το 0 και όχι το πρόσημο.
 //εδώ πρέπει να προστεθεί και η 1 ώρα διαφορά της καλοκαιρινής ώρας.
 //15=360/24;

 dst_in_ram=readRegister(REG_DST);
 lstm=15*(timezone+dst_in_ram);

 //Time Correction Factor (TC)
 //The net Time Correction Factor (in minutes) accounts for the variation
 //of the Local Solar Time (LST) within a given time zone due to the longitude
 //variations within the time zone and also incorporates the EoT above.
 //The factor of 4 minutes comes from the fact that the Earth rotates 1° every 4 minutes.

 tcf=(4.00*(longitude-float(lstm)))+eot;


 //Local Solar Time (LST)
 //The Local Solar Time (LST) can be found by using the previous two corrections
 //to adjust the local time (LT).

 lst=decimaltime+(tcf/60);



 //Hour Angle (HRA)
 //The Hour Angle converts the local solar time (LST) into the number of degrees
 //which the sun moves across the sky. By definition, the Hour Angle is 0° at solar noon.
 //Since the Earth rotates 15° per hour, each hour away from solar noon corresponds
 //to an angular motion of the sun in the sky of 15°.
 //In the morning the hour angle is negative, in the afternoon the hour angle is positive.

 sha=15.00*(lst-12.00);



 //The declination angle,
 //denoted by δ, varies seasonally due to the tilt of the Earth on its axis of rotation
 //and the rotation of the Earth around the sun. If the Earth were not tilted on its axis
 //of rotation, the declination would always be 0°. However, the Earth is tilted by 23.45°
 //and the declination angle varies plus or minus this amount. Only at the spring and fall
 //equinoxes is the declination angle equal to 0°.The declination of the sun is the angle
 //between the equator and a line drawn from the centre of the Earth to the centre of the sun.
 //Despite the fact that the Earth revolves around the sun, it is simpler to think of the sun
 //revolving around a stationary Earth. This requires a coordinate transformation.
 //Under this alternative coordinate system, the sun moves around the Earth.
 //The declination is zero at the equinoxes (March 22 and September 22), positive during
 //the northern hemisphere summer and negative during the northern hemisphere winter.
 //The declination reaches a maximum of 23.45° on June 22 (summer solstice in the northern
 //hemisphere) and a minimum of -23.45° on December 22 (winter solstice in the northern hemisphere).

 declination=23.45*sin(bradians);


 //elevation angle at solar noon

 easn=90.00-latitude+declination;

 //Elevation & Zenith angle
 //The elevation angle (used interchangeably with altitude angle) is the angular height of
 //the sun in the sky measured from the horizontal. Confusingly, both altitude and elevation
 //are also used to describe the height in meters above sea level.
 //The elevation is 0° at sunrise and 90° when the sun is directly overhead
 //(which occurs for example at the equator on the spring and fall equinoxes).
 //The zenith angle is similar to the elevation angle but it is measured from the vertical
 //rather than from the horizontal, thus making the zenith angle = 90° - elevation.

 float decrad, latrad, sharad, elev, azi;
 decrad=declination*rad;
 latrad=latitude*rad;
 sharad=sha*rad;

 elev=asin((sin(decrad)*sin(latrad))+(cos(decrad)*cos(latrad)*cos(sharad)));
 elevation=elev/rad;

 //zenith=90.00-elevation;


 //Azimuth Angle
 //The azimuth angle is the compass direction from which the sunlight is coming.
 //At solar noon, the sun is always directly south in the northern hemisphere
 //and directly north in the southern hemisphere. The azimuth angle varies throughout the day
 //as shown in the animation below. At the equinoxes, the sun rises directly east and
 //sets directly west regardless of the latitude, thus making the azimuth angles 90° at sunrise
 //and 270° at sunset. In general however, the azimuth angle varies with the latitude and time
 //of year and the full equations to calculate the sun's position throughout the day are
 //given on the following page.
 //The azimuth angle is like a compass direction with North = 0° ,South = 180°, West = 270° and East = 90°
 //The above equation only gives the correct azimuth in the solar morning so that:
 //Azimuth = Azi, for lst <12 or sha < 0
 //Azimuth = 360° - Azi, for lst > 12 or sha >0



 azi=acos(((sin(decrad)*cos(latrad))-(cos(decrad)*sin(latrad)*cos(sharad)))/cos(elev));

 if (sha>0) azimuth=360.00-(azi/rad); else azimuth=azi/rad;

        

}


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

int read_elev_pot(){
  int elev_pot_val;
  int elev_pot_reading;

  elev_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    if (motion_flag!=0) elev_pot_reading=(analogRead(elev_pot)/3); else elev_pot_reading=analogRead(elev_pot)/3;
    elev_pot_val=elev_pot_val+elev_pot_reading;
}

  elev_pot_val=elev_pot_val/num_pot_readings;

 
  elev_pot_val=constrain(elev_pot_val,elev_pot_down_limit,elev_pot_up_limit);
  elev_pot_val=map(elev_pot_val,elev_pot_down_limit,elev_pot_up_limit,DOWN_LIMIT_DEG,UP_LIMIT_DEG);

  return elev_pot_val;
}
//------------------------------------//
int read_azim_pot(){
  int azim_pot_val;
  int azim_pot_reading;

  azim_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    if (motion_flag!=0) azim_pot_reading=(analogRead(azim_pot)/2); else azim_pot_reading=analogRead(azim_pot)/2;
    azim_pot_val=azim_pot_val+azim_pot_reading;
}

  azim_pot_val=azim_pot_val/num_pot_readings;


  azim_pot_val=constrain(azim_pot_val,azim_pot_east_limit,azim_pot_west_limit);
  azim_pot_val=map(azim_pot_val,azim_pot_east_limit,azim_pot_west_limit,EAST_LIMIT_DEG,WEST_LIMIT_DEG);

  return azim_pot_val;
}
//-----------------------------------------//
int check_auto_man(){
  int auto_man_state;

  auto_man_state=digitalRead(auto_man);

  auto_man_flag=auto_man_state;
  return auto_man_state;

}
//--------------------------------------//
void printdata(){
 int dst_in_ram;



 Serial.flush();

 Serial.println("ACK");


   delay(10);

   switch(dow){
    case 1:
    Serial.print("Mon");
    break;
    case 2:
    Serial.print("Tue");
    break;
    case 3:
    Serial.print("Wed");
    break;
    case 4:
    Serial.print("Thu");
    break;
    case 5:
    Serial.print("Fri");
    break;
    case 6:
    Serial.print("Sat");
    break;
    case 7:
    Serial.print("Sun");
    break;
   }
   Serial.print(" ");

   if (date<10){
    Serial.print("0");
   }
   Serial.print(date);
   Serial.print("/");
   if (month<10){
    Serial.print("0");
   }
   Serial.print(month);
   Serial.print("/");
   Serial.print(year);
   Serial.print(" ");
   if (hour<10){
    Serial.print("0");
   }
   Serial.print(hour,0);
   Serial.print(":");
   if (minute<10){
    Serial.print("0");
   }
   Serial.print(minute,0);
   Serial.print(":");
   if (sec<10){
    Serial.print("0");
   }
   Serial.print(sec);
   Serial.print(" Time Zone = ");
   Serial.print(timezone,DEC);
   Serial.print(" DST = ");
   dst_in_ram=readRegister(REG_DST);
   switch(dst_in_ram){
     case 1:Serial.print("Summer");
     break;
     case 0:Serial.print("Winter");
     break;
   }
   Serial.print(" Coordinates = ");
   Serial.print(latitude,6);
   Serial.print(" , ");
   Serial.println(longitude,6);

   delay(10);


  Serial.println(int(elevation));
  delay(10);

  //Serial.println(zenith,0);
  //delay(10);

  Serial.println(int(azimuth));

  delay(10);
  Serial.print(auto_move_elev_deg);
  Serial.print("-->");
  Serial.println(read_elev_pot());
  delay(10);
  Serial.print(auto_move_azim_deg);
  Serial.print("-->");
  Serial.println(read_azim_pot());
 
  delay(10);
  Serial.println(elev_limits_flag); 
  delay(10);
  Serial.println(azim_limits_flag);

  delay(10);
  Serial.println(auto_man_flag);

  delay(10);
  Serial.println(motion_flag);

  delay(10);
  Serial.println(mins_to_next_move_count);

}
//-----------------------------------------------------//
void current_sun_calculate(){

    getRTC();
    dayofyear();
    //dayofweek();
    dstcalc();
 
    sunposition(hour,minute);
 
    if (just_moved_flag==1) just_moved_flag=0;
    else mins_to_next_move_count=mins_to_next_move_count-1;
}

//-----------------------------------------------------//
void sun_calculate(){
  int future_min;
  int future_hour;

    getRTC();
    dayofyear();
    //dayofweek();
    dstcalc();
    future_min=minute+mins_to_move_ahead/2;
    future_hour=hour;
    if (future_min>59) {
      future_min=future_min-60;
      future_hour=future_hour+1;
      if (future_hour>23) future_hour=future_hour-24;
    }
    sunposition(future_hour,future_min);
 
    elevation_int=int(elevation);
    azimuth_int=int(azimuth);
 
    //elevation_int=-1;
    //elevation_int=40;
    //azimuth_int=170;
 
    if (elevation_int<=0) {auto_move_elev_deg=UP_LIMIT_DEG;auto_move_azim_deg=SOUTH_DEG;}
    if (elevation_int>0) {
            if (elevation_int<DOWN_LIMIT_DEG) auto_move_elev_deg=DOWN_LIMIT_DEG; else auto_move_elev_deg=elevation_int;
            if (azimuth_int<EAST_LIMIT_DEG) auto_move_azim_deg=EAST_LIMIT_DEG; else if (azimuth_int>WEST_LIMIT_DEG) auto_move_azim_deg=WEST_LIMIT_DEG; else auto_move_azim_deg=azimuth_int;
         }
 
    auto_move_elev_flag=0;
    auto_move_azim_flag=0;
 
    if ((mins_to_next_move_count<mins_to_move_ahead) && (just_moved_flag==0) ){
     mins_to_next_move_count=mins_to_move_ahead;
     just_moved_flag=1;
    }
}
//-----------------------------------------------------//
void calibrate_pot_UP(){
  int cal_elev_pot_val;
  int cal_elev_pot_reading;


  delay(2000);
  cal_elev_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    /*if (motion_flag!=0) elev_pot_reading=(analogRead(elev_pot)/2)+1; else */cal_elev_pot_reading=analogRead(elev_pot)/3;
    cal_elev_pot_val=cal_elev_pot_val+cal_elev_pot_reading;
  }
  cal_elev_pot_val=cal_elev_pot_val/num_pot_readings;
  writeRegister(ELEV_UP_POT_LIMIT,cal_elev_pot_val);
  delay(10);
  elev_pot_up_limit=readRegister(ELEV_UP_POT_LIMIT);
  read_elev_pot();

  calibration_state=4;

}
//-----------------------------------------------------//
void calibrate_pot_DOWN(){
  int cal_elev_pot_val;
  int cal_elev_pot_reading;


  delay(2000);
  cal_elev_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    /*if (motion_flag!=0) elev_pot_reading=(analogRead(elev_pot)/2)+1; else */cal_elev_pot_reading=analogRead(elev_pot)/3;
    cal_elev_pot_val=cal_elev_pot_val+cal_elev_pot_reading;
  }
  cal_elev_pot_val=cal_elev_pot_val/num_pot_readings;
  writeRegister(ELEV_DOWN_POT_LIMIT,cal_elev_pot_val);
  delay(10);
  elev_pot_down_limit=readRegister(ELEV_DOWN_POT_LIMIT);
  read_elev_pot();

  calibration_state=2;
}
//-----------------------------------------------------//
void calibrate_pot_EAST(){
  int cal_azim_pot_val;
  int cal_azim_pot_reading;

  delay(2000);
  cal_azim_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    /*if (motion_flag!=0) azim_pot_reading=(analogRead(azim_pot)/2)+1; else */cal_azim_pot_reading=analogRead(azim_pot)/2;
    cal_azim_pot_val=cal_azim_pot_val+cal_azim_pot_reading;
  }
  cal_azim_pot_val=cal_azim_pot_val/num_pot_readings;
  writeRegister(AZIM_EAST_POT_LIMIT,cal_azim_pot_val);
  delay(10);
  azim_pot_east_limit=readRegister(AZIM_EAST_POT_LIMIT);
  read_azim_pot();

  calibration_state=1;


}

//-----------------------------------------------------//
void calibrate_pot_WEST(){
  int cal_azim_pot_val;
  int cal_azim_pot_reading;
  //int azim_pot_EAST;
  //int azim_pot_WEST;

  delay(2000);
  cal_azim_pot_val=0;
  for(int i=0;i<num_pot_readings;i++){
    /*if (motion_flag!=0) azim_pot_reading=(analogRead(azim_pot)/2)+1; else */cal_azim_pot_reading=analogRead(azim_pot)/2;
    cal_azim_pot_val=cal_azim_pot_val+cal_azim_pot_reading;
  }
  cal_azim_pot_val=cal_azim_pot_val/num_pot_readings;
  writeRegister(AZIM_WEST_POT_LIMIT,cal_azim_pot_val);
  delay(10);
  azim_pot_west_limit=readRegister(AZIM_WEST_POT_LIMIT);
  read_azim_pot();

  //azim_pot_EAST=readRegister(AZIM_EAST_POT_LIMIT);
  //azim_pot_WEST=readRegister(AZIM_WEST_POT_LIMIT);
  //writeRegister(AZIM_SOUTH,azim_pot_EAST+((azim_pot_WEST-azim_pot_EAST)/2)-2);



  calibration_state=0;


}

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

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

// Set the clock to run-mode

  pinMode(_scl_pin, OUTPUT);
  digitalWrite(_scl_pin, LOW);
  pinMode(_sda_pin, OUTPUT);
  digitalWrite(_sda_pin, LOW);
  halt(false);

  //setTime(16,41,1);
  //setDate(5,10,2012);
  //setDOW(5);
  //writeRegister(REG_DST,1);

  dst=readRegister(REG_DST);

 pinMode(elev_UP, OUTPUT);
 pinMode(elev_DOWN, OUTPUT);
 pinMode(azim_EAST, OUTPUT);
 pinMode(azim_WEST, OUTPUT);

 pinMode(but_UP, INPUT);
 pinMode(but_DOWN, INPUT);
 pinMode(but_EAST, INPUT);
 pinMode(but_WEST, INPUT);

 pinMode(limit_UP, INPUT);
 pinMode(limit_DOWN, INPUT);
 pinMode(limit_EAST, INPUT);
 pinMode(limit_WEST, INPUT);

 digitalWrite(elev_UP,LOW);
 digitalWrite(elev_DOWN,LOW);
 digitalWrite(azim_EAST,LOW);
 digitalWrite(azim_WEST,LOW);

 pinMode(limits_LED,OUTPUT);
 pinMode(auto_man,INPUT);

 pinMode(elev_pot,INPUT);
 pinMode(azim_pot,INPUT);

 t.every(2000,printdata); //2 sec
 t.every(60000,current_sun_calculate); //1 min
 t.every((long)mins_to_move_ahead*60*1000,sun_calculate); // 16 min (16 * 60sec/min* 1000msec/sec)=960000

 //writeRegister(ELEV_UP_POT_LIMIT,250);
 //writeRegister(ELEV_DOWN_POT_LIMIT,146);
 //writeRegister(AZIM_EAST_POT_LIMIT,2);
 //writeRegister(AZIM_WEST_POT_LIMIT,251);
 //writeRegister(AZIM_SOUTH,2+((251-2)/2));

 elev_pot_up_limit=readRegister(ELEV_UP_POT_LIMIT);
 elev_pot_down_limit=readRegister(ELEV_DOWN_POT_LIMIT);
 azim_pot_east_limit=readRegister(AZIM_EAST_POT_LIMIT);
 azim_pot_west_limit=readRegister(AZIM_WEST_POT_LIMIT);
 //azim_south=readRegister(AZIM_SOUTH);

 mins_to_next_move_count=0;
 just_moved_flag=0;
 sun_calculate();
 current_sun_calculate();

}

//-----------------------------------------------------//
//Κυρίως Πρόγραμμα
void loop(){

   if (calibration_flag==HIGH){
    switch (calibration_state){
       case 8:if (check_elev_limits()==2) {move_all_stop(); calibrate_pot_UP();} else {move_elev_UP(); auto_man_flag=2;auto_move_elev_flag=0;}
       break;
       case 4:if (check_elev_limits()==1) {move_all_stop(); calibrate_pot_DOWN();} else {move_elev_DOWN(); auto_man_flag=2;auto_move_elev_flag=0;}
       break;
       case 2:if (check_azim_limits()==2) {move_all_stop();calibrate_pot_EAST();} else {move_azim_EAST(); auto_man_flag=2; auto_move_azim_flag=0;}
       break;
       case 1:if (check_azim_limits()==1) {move_all_stop();calibrate_pot_WEST();} else {move_azim_WEST(); auto_man_flag=2; auto_move_azim_flag=0;}
       break;
       case 0:{move_all_stop();auto_man_flag=LOW;calibration_flag=LOW;}
       break;
    }
  } else {

   if (check_auto_man()==LOW){
     switch(check_buttons()){
       case 8:if (check_elev_limits()==2) move_all_stop(); else {move_elev_UP(); auto_move_elev_flag=0;}
       break;
       case 4:if (check_elev_limits()==1) move_all_stop(); else {move_elev_DOWN(); auto_move_elev_flag=0;}
       break;
       case 2:if (check_azim_limits()==2) move_all_stop(); else {move_azim_EAST();  auto_move_azim_flag=0;}
       break;
       case 1:if (check_azim_limits()==1) move_all_stop(); else {move_azim_WEST();  auto_move_azim_flag=0;}
       break;
       case 10:{calibration_flag=HIGH; calibration_state=8;}
       break;
       case 0:move_all_stop();
       break;
      }
   }



   if (check_auto_man()==HIGH){
     if (elevation_int<=0) auto_man_flag=3;
     if (auto_move_elev_flag==0) automove_elev(auto_move_elev_deg);
     else if (auto_move_azim_flag==0) automove_azim(auto_move_azim_deg);
   }
  }

    if ((check_elev_limits()>0) || (check_azim_limits()>0)) digitalWrite(limits_LED,HIGH); else digitalWrite(limits_LED,LOW);


  
    t.update();
}
  

No comments:

Post a Comment