This program uses the "PSA" solar positioning algorithm calculating the sun position, based on longitude, latitude, and time zone. Then Mbed chip controls the two digital servos to rotate the solar panel to the correct azimuth and zenith angle.

Dependencies:   4DGL-uLCD-SE AX12 NetServices mbed spxml

Fork of AX12-HelloWorld by Chris Styles

main.cpp

Committer:
conantina
Date:
2016-04-25
Revision:
2:2a3493799f03
Parent:
1:b12b06e2fc2d

File content as of revision 2:2a3493799f03:

/*
This Mbed code is a demo code of a DIY dual-axis solar tracker
Since the solar position is different from place to place, the variables: YourLongitude and YourLatitude needs to be changed based on
user's location
The PSA solar positioning algorithm use UTC. There may be a time difference. The variable time_difference should be calibrated as well.
The calibration can be done by calculated the longitute difference between the user's loaction and Greenwich. 30 degree is 0.25 hours.
The futher calibration can be done by compare the PSA results with the solar position GUI results, for example:
http://www.esrl.noaa.gov/gmd/grad/solcalc/azel.html
The real time needs to be set manually at the beginning of main function
*/

#include "mbed.h"
#include "AX12.h"
#include "Helios.h"
#include "EthernetNetIf.h"
#include "HTTPClient.h"
#include "spdomparser.hpp"
#include "spxmlnode.hpp"
#include "spxmlhandle.hpp"
#include <string>
#include "uLCD_4DGL.h"

uLCD_4DGL lcd(p9,p10,p11); // serial tx, serial rx, reset pin;
EthernetNetIf eth; 
HTTPClient http;
 
HTTPResult result;
bool completed = false;
void request_callback(HTTPResult r)
{
  result = r;
  completed = true;
}
 

AX12 Hax12 (p13, p14, 1);
AX12 Vax12 (p28, p27, 1);
//uLCD_4DGL lcd(p28, p27, p29);
Serial pc(USBTX,USBRX);

Helios helios;

/////////// TEMPORARY TEST VARIABLES //////////////////////
int TheYear  = 2016;
int TheMonth = 4;
int TheDay   = 9;
double TheHour = 12;            /*  UTC TIME!  */
double TheMinute = 0.00;
double TheSeconds = 0.00;
double YourLongitude = 84.39;     // your longitude [e.g 151.857964];
double YourLatitude  = 33.4;     // your latitude  [e.g -33.579265];
////// LIVE VARIABLES SHOULD BE USED FROM A GPS //////////


//real_time variable
struct tm *t;
float time_difference = 6.1;       //calibrated time difference of Atlanta

//update the solar position and roate the panel accordingly with the time interval of update_period
float update_period = 0.5*60;    //10 minutes by default

//HTTP variables
int n = 0;
string delimiter = "weather";
string delimiter2 = ",";
string delimiter3 = ":";
string place;
string weather;
string condition;

void get_sun_position(){
        helios.calcSunPos(TheYear, TheMonth, TheDay, TheHour, TheMinute, TheSeconds, YourLongitude, YourLatitude);
        pc.printf("Sun Zenith Angle: %f\n",helios.dZenithAngle);    // Degrees down from vertical
        pc.printf("Sun Azimuth Angle: %f\n",helios.dAzimuth);       // Degrees from north
        pc.printf("Sun Elevation Angle: %f\n",helios.dElevation);   // Degrees up from horizontal
}


//rotate the horizontal angle to get the proper azimuth angle
void rotate_horizontal(float angle){
    Hax12.SetGoal(angle);
}

//rotate the vertical angle to get the proper zenith angle, the zero of the servo points vertical
void rotate_vertical(float angle){
    Vax12.SetGoal(angle+60); 
}


int main() {
    // setup time structure for Wed, 28 Oct 2016 3:12:00
    struct tm mytime;
    mytime.tm_sec = 00;    // 0-59
    mytime.tm_min = 50;    // 0-59
    mytime.tm_hour = 16;   // 0-23
    mytime.tm_mday = 28;   // 1-31
    mytime.tm_mon = 3;     // 0-11
    mytime.tm_year = 116;  // year since 1900

    time_t seconds = mktime(&mytime);
    set_time(seconds);
    
    lcd.cls();
    lcd.printf("Start\n");
 
    lcd.printf("Setting up...\n");
    EthernetErr ethErr = eth.setup(100000);
    if(ethErr)
    {
     lcd.printf("Error %d in setup.\n", ethErr);
     return -1;
    }
    lcd.printf("Setup OK\n");
  
    HTTPStream stream;
    SP_XmlDomParser parser;
   
    char BigBuf[512 + 1] = {0};
    stream.readNext((byte*)BigBuf, 512); //Point to buffer for the first read
    int i = 0;
    char buffer [512*5+1];
    while(true){
         HTTPResult r = http.get("http://openweathermap.org/data/2.1/find/city?lat=33.75&lon=-84.39&cnt=1&type=XML", &stream, request_callback); //Load a very large page, such as the hackaday RSS feed
         //http://openweathermap.org/data/2.1/find/city?lat=33.75&lon=-84.39&cnt=1&type=XML
         //http://wxdata.weather.com/wxdata/weather/local/USGA0028:1:US?cc=*&unit=m&dayf=1
         //HTTP://hackaday.com/feed/
         //http://openweathermap.org/data/2.1/find/city?lat=40.71&lon=-74.00&cnt=1&type=XML
         i = 0;
    
        while(!completed)
        {
            Net::poll(); //Polls the Networking stack
            if(stream.readable())
            {
                i++;
                BigBuf[stream.readLen()] = 0; //Transform this buffer in a zero-terminated char* string
                parser.append( BigBuf, strlen(BigBuf)); // stream current buffer data to the XML parser
                if (i == 1){  
                sprintf(buffer,"%s",BigBuf);
                 } else{
                printf("%s",BigBuf); //Display it while loading
                }
             //Note: some servers do not like if you throttle them too much, so printf'ing during a request is generally bad practice
                stream.readNext((byte*)BigBuf, 512); //Buffer has been read, now we can put more data in it
            }
        }
        //lcd.printf("\n--------------\n");
        n = sizeof(buffer);
        string ret(buffer, n);
  
        place = ret.substr(ret.find("name"),ret.length());
        place = place.substr(place.find(delimiter3),place.find(delimiter2)-4);
        //lcd.printf("Location:%s\n", place);
  
        weather = ret.substr(ret.find(delimiter), ret.length());
        weather.erase(0,weather.find(delimiter3)+1);
        condition = weather.substr(weather.find("main"),weather.length());
        condition = condition.substr(condition.find(delimiter3),place.find(delimiter2)-2);
        //lcd.printf("weather condition%s\n",condition);
        
        while (true) {
            time_t local_time = time(NULL); 
            lcd.cls();           
            lcd.printf("The Current Time is: %s\n", ctime(&local_time)); 
            pc.printf("The Current Time is: %s\n", ctime(&local_time)); 
            lcd.printf("\n--------------\n"); 
            lcd.printf("Location:%s\n", place);
            lcd.printf("weather condition%s\n",condition);
            pc.printf("weather condition%s\n",condition);
            t = localtime(&local_time);
            TheYear  = t->tm_year + 1900;
            TheMonth = t->tm_mon;
            //change the local time to UTC TIME according to longitude
            if(t->tm_hour - time_difference < 0){
                TheDay   = t->tm_mday -1;
                TheHour = t->tm_hour + 24 - time_difference; 
            } else{
                TheDay   = t->tm_mday;
                TheHour = t->tm_hour - time_difference; 
            }           
            TheMinute = t->tm_min;
            TheSeconds = t->tm_sec; 
            get_sun_position();
            pc.printf("%d\n",condition.find("Clear"));
            if( helios.dZenithAngle<90 && (condition.find("Clear")!=-1)){  
                rotate_horizontal(helios.dAzimuth);
                rotate_vertical(helios.dZenithAngle);
                lcd.printf("Sun Zenith Angle: %f\n",helios.dZenithAngle);    // Degrees down from vertical
                lcd.printf("Sun Azimuth Angle: %f\n",helios.dAzimuth);       // Degrees from north
            }else{
                lcd.printf("The solar tracker is not tracking the sun...");
            }            
            wait(update_period); 
            if(t->tm_hour == 6) break;                 
        }
    }
     
}