Inseguitore Solare Astronomico

L’inseguitore solare astronomico è un progetto pensato per orientare un pannello solare nella direzione del sole in qualsiasi punto del nostro pianeta esso sia installato, attraverso calcoli astronomici che, utilizzando i valori dei Latitudine e Longitudine oltre che Data e Ora, possano determinare la sua posizione relativa rispetto ai pannelli, in modo tale da garantire una produzione elevata.

La fase iniziale si è basata sulla ricerca in quanto è necessario effettuare calcoli astronomici di precisione per ottenere i valori di Altezza Solare ed Azimut di interesse. Per determinare la posizione
del sole analiticamente, infatti, occorre stabilire il numero di gradi di elevazione rispetto alla superficie terrestre (Altezza Solare) e l’angolo tra il piano verticale passante per l’astro e quello orizzontale passante per il punto di osservazione, con riferimento a nord (Azimut).

L’inseguitore solare non presenta un solo Pannello Solare, ma 2, di identico tipo.
Uno rivolto direttamente verso il sole ed un secondo che raccoglie la luce solare concentrata da una parabola riflettente. In questo modo oltre ad una maggiore produzione di energia ci è possibile anche valutare la differenza tra produzione diretta ed a concentrazione.

L’APPROCCIO ASTRONOMICO

Il funzionamento dell’Inseguitore Solare Astronomico si basa sugli studi astronomici che permettono, in un preciso momento ed in un punto geografico preciso della Terra, di calcolare l’altezza del Sole all’orizzonte (Altezza Solare) ed il suo angolo con il Nord sul piano equatoriale (Azimut).

Le coordinate del luogo (Latitudine e Longitudine) in cui l’inseguitore è installato, oltre a data e ora, sono determinati dal modulo GPS GY-NEO6MV2, e passati all’Arduino Mega 2560 che esguirà i calcoli e controllerà i motori.

La parte di programma sviluppato in C++ con Arduino IDE che realizza questi calcoli è il seguente:

// Calcoli Astronomici per determinare l'Azimut e Altezza Solare

//GPS Virtuale
// -------------------------
String Latitudine = "44.4359"; // Latitudine Castelnovo Monti
String Longitudine = "10.4026";// Longitudine Castelnovo Monti
String Dir_Lat = "N"; 
String Dir_Lon = "E"; 
String Altitudine = "700.5"; 
String Hour = "6"; // ORA SOLARE
String Minute = "13"; 
String Second = "27"; 
String Day = "31"; 
String Month = "1"; 
String Year = "2023";
String Data, Ora;

// AltezzaSolare e Azimut
// -------------------------
//float Lon_meridiano = 15.0; //0.26179939 meridiano di riferimento 15°0'0" (Etna) || DA INDIVIDUARE per l località considerata
int Lon_meridiano;
float tempo = 0.0;
float tempo_luogo = 0.0;
float mezzogiorno_luogo;
float EqT = 0.0;
float angoloOrario = 0.0; //angolo orario Rad
float declinazione = 0.0; //declinazione Rad
float altezzaSolare = 0.0; //altezza solare Rad
float azimut = 0.0; //azimut solare Rad
int pro;
float inRad;
float Y;
// Offset hours from gps time (UTC)
int ora_legale = 1; // da settare!!!!

// il GPS considera già l'offset!
const int offset = 1;   // Central European Time (rispetto a Greenweck)

// -----------------------------------------------
// Funzioni --------------------------------------
// -----------------------------------------------

//GPS
//-------------------------------------------------
void lettura_GPS() {
  Serial.print("Data = ");Serial.print(Day);Serial.print("/");Serial.print(Month);Serial.print("/");Serial.println(Year);
  Serial.print("Orario = ");Serial.print(Hour);Serial.print(":");Serial.print(Minute);Serial.print(":");Serial.println(Second);
  Serial.print("Latitudine = ");Serial.print(Latitudine);
  Serial.print(" ");Serial.println(Dir_Lat);
  // correggo Longitudine
  float LonF = Longitudine.toFloat();
  if(Dir_Lon == "W") Longitudine = "-" + Longitudine;
  if(Dir_Lon == "E" && Longitudine.toFloat() > 180) Longitudine = "-" + String(360 - LonF);
  Serial.print("Longitudine = ");Serial.print(Longitudine);
  Serial.print(" ");Serial.println(Dir_Lon);
  Serial.print("Altitudine = ");Serial.println(Altitudine);Serial.println("");
}
int longitudineMeridianoFuso(String Longitudine){
  float deltaLongitudine = Longitudine.toFloat() - int(Longitudine.toFloat()/15)*15;
  if(deltaLongitudine < 7.5 && deltaLongitudine > -7.5) Lon_meridiano = int(Longitudine.toFloat()/15)*15;
  else if(deltaLongitudine > 7.5) Lon_meridiano = int(Longitudine.toFloat()/15)*15 + 15;
  else if(deltaLongitudine < -7.5) Lon_meridiano = int(Longitudine.toFloat()/15)*15 - 15;
  else Lon_meridiano = 0;
  return Lon_meridiano;
}
// Calcolo Altezza Solare e Azimut
//-------------------------------------------------
int progressivo(){
  //calcolo del numero progressivo corrispondente al giorno dell’anno
  pro = 0;
  int anno = 1900 + Year.toInt();
  int mese = Month.toInt();
  int giorno = Day.toInt();
  int bise = bisestile(anno);
  if (mese==1){pro=giorno;}
  if (mese==2){pro=0*30+1*31+giorno;}
  if (mese==3){pro=0*30+1*31+giorno+bise;}
  if (mese==4){pro=0*30+2*31+giorno+bise;}
  if (mese==5){pro=1*30+2*31+giorno+bise;}
  if (mese==6){pro=1*30+3*31+giorno+bise;}
  if (mese==7){pro=2*30+3*31+giorno+bise;}
  if (mese==8){pro=2*30+4*31+giorno+bise;}
  if (mese==9){pro=2*30+5*31+giorno+bise;}
  if (mese==10){pro=3*30+5*31+giorno+bise;}
  if (mese==11){pro=3*30+6*31+giorno+bise;}
  if (mese==12){pro=4*30+6*31+giorno+bise;}
  return pro;
}
int bisestile(int a){
  //funzione per scoprire se l’anno in corso è bisestile
  int bis = 28;
  if(a%4==0){
    if(a%100==0){
      if(a%400==0) bis = 29;
      else bis = 28;
    }
    else bis = 29;
  }
  else bis = 28;
  return bis;
}
void posizione_Sole(){
  /*
   * 24 Fusi orari, ognuno composto da 15 Meridiani a distanza di 1° tra uno e l'altro
   * 
   * Equazione del tempo: EqT = 229,18(0,000075+0,001868cos@-0,032077sin@-0,014615cos2@-0,040849sin2@)
   * dove @ = (2PI/365)*(N-1)
   * 
   * Latitudine: LAT
   * Longitudine: LON
   * Angolo Orario: AO  = 15*(h_conv + ((EqT-4*(longitudineMeridianoFuso-LON))/60))-180
   * Declinazione Solare: DS = 0.006918-0.399912cos(@)+0.070257sin(@)-0.006758cos(2@)-0.002697cos(3@)+0.00148sin(3@) 
   * 
   * sin(AS) = sin(LAT)sin(DS)+cos(LAT)cos(DS)cos(AO)
   * cos(Az) = (cos(AO)cos(DS)sin(LAT)-sin(DS)cos(LAT))/cos(AS)
   * 
   * dove:
   * g = 360°/365 con angoli espressi in ° o 2pi/365 con angoli espressi in Rad
   * N = giorno progressivo dell'anno
   * @ = (2PI/365)*(N-1)
  */
  float Hour_f;
  if(Month.toInt() >= 4 && Month.toInt() <=10) Hour_f = Hour.toFloat() + ora_legale; //-----------SOLO QUANDO C'E' L'ORA LEGALE!!!!
  else Hour_f = Hour.toFloat();
  
  tempo = Hour_f + (Minute.toFloat()/60) + (Second.toFloat()/3600);
  inRad = (2*PI/360); 
  Y = (2*PI/365)*(progressivo()-1);
  EqT = 229.18*(0.000075+0.001868*cos(Y)-0.032077*sin(Y)-0.014615*cos(2*Y)-0.040849*sin(2*Y));
  tempo_luogo = tempo -((EqT-4*(longitudineMeridianoFuso(Longitudine)-Longitudine.toFloat()))/60);
  mezzogiorno_luogo = 12.00 -((EqT-4*(longitudineMeridianoFuso(Longitudine)-Longitudine.toFloat()))/60);
  angoloOrario = 15*(tempo + ((EqT-4*(longitudineMeridianoFuso(Longitudine)-Longitudine.toFloat()))/60))-180; //angolo orario °
  declinazione = (0.006918-0.399912*cos(Y)+0.070257*sin(Y)-0.006758*cos(2*Y)-0.002697*cos(3*Y)+0.00148*sin(3*Y))*(365/(2*PI)); //declinazione Deg
  altezzaSolare = asin((sin(Latitudine.toFloat()*inRad)*sin(declinazione*inRad))+(cos(Latitudine.toFloat()*inRad)*cos(declinazione*inRad)*cos(angoloOrario*inRad)))/inRad; //altezza solare
  azimut = (acos(((cos(angoloOrario*inRad)*cos(declinazione*inRad)*sin(Latitudine.toFloat()*inRad))-(sin(declinazione*inRad)*cos(Latitudine.toFloat()*inRad)))/cos(altezzaSolare*inRad))/inRad); //azimut Rad
  if(tempo < mezzogiorno_luogo) azimut = 180 - azimut;
  else azimut = 180 + azimut;
  
  Serial.println("Posizione Sole:"); Serial.println("----------------------------------------"); 
  Serial.print("Ora = "); Serial.print(tempo); Serial.println(" (Hd)");
  Serial.print("Ora_luogo = "); Serial.print(tempo_luogo); Serial.println(" (Hd)");
  Serial.print("Mezzogiorno_luogo = "); Serial.print(mezzogiorno_luogo); Serial.println(" (Hd)");
  Serial.print("Longitudine_meridiano_fuso = "); Serial.print(longitudineMeridianoFuso(Longitudine)); Serial.println(" Gradi");
  Serial.print("Equazione_Tempo = "); Serial.print(EqT); Serial.println(" (Md)");
  Serial.print("Angolo_Orario = "); Serial.print(angoloOrario); Serial.println(" Gradi");
  Serial.print("Declinazione = "); Serial.print(declinazione); Serial.println(" Gradi");
  
  Serial.print("Altezza_Solare = "); Serial.print(altezzaSolare); Serial.println(" Gradi");
  Serial.print("Azimut = "); Serial.print(azimut); Serial.println(" Gradi");
  Serial.println("----------------------------------------");Serial.println("");
}

void setup() {
  
  //init seriale hardware
  Serial.begin(9600);

  Serial.println("INSEGUITORE SOLARE ASTRONOMICO SIM");
  Serial.println("----------------------------------");
  Serial.println("");
}

void loop() {
  // Calcolo Coord Solari
  posizione_Sole();
  
  while(1);
}

Una volta determinate le coordinate solari il sistema le confronta con i valori di Inclinazione determinata con l’Accelerometro ADXL335 utilizzato come inclinometro, e l’Azimut misurato con la Bussola Elettronica CMP12. Se questi valori non coincidono, i motori dei 2 assi X e Y lungo i quali l’inseguitore può muoversi si movimentano riportando il sistema ai valori determinati, cioè rivolto verso il sole.

Raspberry e MODULO IoT

Una volta determinate Altezza Solare e Azimut, e posizionato i pannelli solari nella direzione del sole, il sistema memorizza i propri dati inviandoli attraverso la comunicazione Seriale al Raspberry, il quale realizza una HTTP Request ad applicazioni PHP che fungono da API (), ad un Database posizionato su un server web.

Questi dati sono quindi visualizzati da una pagina internet che funge da monitoraggio dei valori Geografici, Ambientali e di produzione Energetica.

E’ stata anche realizzata una App sviluppata in C# che permette di visualizzare l’andamento della produzione nelle 24 ore, sia in forma di dati che graficamente, e di fare impostazioni manuali sul sistema.

Potrebbero interessarti anche...