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

Committer:
conantina
Date:
Mon Apr 25 17:28:13 2016 +0000
Revision:
2:2a3493799f03
Parent:
1:b12b06e2fc2d
n

Who changed what in which revision?

UserRevisionLine numberNew contents of line
conantina 2:2a3493799f03 1 /*
conantina 2:2a3493799f03 2 This Mbed code is a demo code of a DIY dual-axis solar tracker
conantina 2:2a3493799f03 3 Since the solar position is different from place to place, the variables: YourLongitude and YourLatitude needs to be changed based on
conantina 2:2a3493799f03 4 user's location
conantina 2:2a3493799f03 5 The PSA solar positioning algorithm use UTC. There may be a time difference. The variable time_difference should be calibrated as well.
conantina 2:2a3493799f03 6 The calibration can be done by calculated the longitute difference between the user's loaction and Greenwich. 30 degree is 0.25 hours.
conantina 2:2a3493799f03 7 The futher calibration can be done by compare the PSA results with the solar position GUI results, for example:
conantina 2:2a3493799f03 8 http://www.esrl.noaa.gov/gmd/grad/solcalc/azel.html
conantina 2:2a3493799f03 9 The real time needs to be set manually at the beginning of main function
conantina 2:2a3493799f03 10 */
conantina 2:2a3493799f03 11
chris 0:f6f8cf11779f 12 #include "mbed.h"
chris 0:f6f8cf11779f 13 #include "AX12.h"
conantina 2:2a3493799f03 14 #include "Helios.h"
conantina 2:2a3493799f03 15 #include "EthernetNetIf.h"
conantina 2:2a3493799f03 16 #include "HTTPClient.h"
conantina 2:2a3493799f03 17 #include "spdomparser.hpp"
conantina 2:2a3493799f03 18 #include "spxmlnode.hpp"
conantina 2:2a3493799f03 19 #include "spxmlhandle.hpp"
conantina 2:2a3493799f03 20 #include <string>
conantina 2:2a3493799f03 21 #include "uLCD_4DGL.h"
conantina 2:2a3493799f03 22
conantina 2:2a3493799f03 23 uLCD_4DGL lcd(p9,p10,p11); // serial tx, serial rx, reset pin;
conantina 2:2a3493799f03 24 EthernetNetIf eth;
conantina 2:2a3493799f03 25 HTTPClient http;
conantina 2:2a3493799f03 26
conantina 2:2a3493799f03 27 HTTPResult result;
conantina 2:2a3493799f03 28 bool completed = false;
conantina 2:2a3493799f03 29 void request_callback(HTTPResult r)
conantina 2:2a3493799f03 30 {
conantina 2:2a3493799f03 31 result = r;
conantina 2:2a3493799f03 32 completed = true;
conantina 2:2a3493799f03 33 }
conantina 2:2a3493799f03 34
conantina 2:2a3493799f03 35
conantina 2:2a3493799f03 36 AX12 Hax12 (p13, p14, 1);
conantina 2:2a3493799f03 37 AX12 Vax12 (p28, p27, 1);
conantina 2:2a3493799f03 38 //uLCD_4DGL lcd(p28, p27, p29);
conantina 2:2a3493799f03 39 Serial pc(USBTX,USBRX);
conantina 2:2a3493799f03 40
conantina 2:2a3493799f03 41 Helios helios;
conantina 2:2a3493799f03 42
conantina 2:2a3493799f03 43 /////////// TEMPORARY TEST VARIABLES //////////////////////
conantina 2:2a3493799f03 44 int TheYear = 2016;
conantina 2:2a3493799f03 45 int TheMonth = 4;
conantina 2:2a3493799f03 46 int TheDay = 9;
conantina 2:2a3493799f03 47 double TheHour = 12; /* UTC TIME! */
conantina 2:2a3493799f03 48 double TheMinute = 0.00;
conantina 2:2a3493799f03 49 double TheSeconds = 0.00;
conantina 2:2a3493799f03 50 double YourLongitude = 84.39; // your longitude [e.g 151.857964];
conantina 2:2a3493799f03 51 double YourLatitude = 33.4; // your latitude [e.g -33.579265];
conantina 2:2a3493799f03 52 ////// LIVE VARIABLES SHOULD BE USED FROM A GPS //////////
conantina 2:2a3493799f03 53
conantina 2:2a3493799f03 54
conantina 2:2a3493799f03 55 //real_time variable
conantina 2:2a3493799f03 56 struct tm *t;
conantina 2:2a3493799f03 57 float time_difference = 6.1; //calibrated time difference of Atlanta
conantina 2:2a3493799f03 58
conantina 2:2a3493799f03 59 //update the solar position and roate the panel accordingly with the time interval of update_period
conantina 2:2a3493799f03 60 float update_period = 0.5*60; //10 minutes by default
conantina 2:2a3493799f03 61
conantina 2:2a3493799f03 62 //HTTP variables
conantina 2:2a3493799f03 63 int n = 0;
conantina 2:2a3493799f03 64 string delimiter = "weather";
conantina 2:2a3493799f03 65 string delimiter2 = ",";
conantina 2:2a3493799f03 66 string delimiter3 = ":";
conantina 2:2a3493799f03 67 string place;
conantina 2:2a3493799f03 68 string weather;
conantina 2:2a3493799f03 69 string condition;
conantina 2:2a3493799f03 70
conantina 2:2a3493799f03 71 void get_sun_position(){
conantina 2:2a3493799f03 72 helios.calcSunPos(TheYear, TheMonth, TheDay, TheHour, TheMinute, TheSeconds, YourLongitude, YourLatitude);
conantina 2:2a3493799f03 73 pc.printf("Sun Zenith Angle: %f\n",helios.dZenithAngle); // Degrees down from vertical
conantina 2:2a3493799f03 74 pc.printf("Sun Azimuth Angle: %f\n",helios.dAzimuth); // Degrees from north
conantina 2:2a3493799f03 75 pc.printf("Sun Elevation Angle: %f\n",helios.dElevation); // Degrees up from horizontal
conantina 2:2a3493799f03 76 }
conantina 2:2a3493799f03 77
conantina 2:2a3493799f03 78
conantina 2:2a3493799f03 79 //rotate the horizontal angle to get the proper azimuth angle
conantina 2:2a3493799f03 80 void rotate_horizontal(float angle){
conantina 2:2a3493799f03 81 Hax12.SetGoal(angle);
conantina 2:2a3493799f03 82 }
conantina 2:2a3493799f03 83
conantina 2:2a3493799f03 84 //rotate the vertical angle to get the proper zenith angle, the zero of the servo points vertical
conantina 2:2a3493799f03 85 void rotate_vertical(float angle){
conantina 2:2a3493799f03 86 Vax12.SetGoal(angle+60);
conantina 2:2a3493799f03 87 }
conantina 2:2a3493799f03 88
chris 0:f6f8cf11779f 89
chris 0:f6f8cf11779f 90 int main() {
conantina 2:2a3493799f03 91 // setup time structure for Wed, 28 Oct 2016 3:12:00
conantina 2:2a3493799f03 92 struct tm mytime;
conantina 2:2a3493799f03 93 mytime.tm_sec = 00; // 0-59
conantina 2:2a3493799f03 94 mytime.tm_min = 50; // 0-59
conantina 2:2a3493799f03 95 mytime.tm_hour = 16; // 0-23
conantina 2:2a3493799f03 96 mytime.tm_mday = 28; // 1-31
conantina 2:2a3493799f03 97 mytime.tm_mon = 3; // 0-11
conantina 2:2a3493799f03 98 mytime.tm_year = 116; // year since 1900
chris 1:b12b06e2fc2d 99
conantina 2:2a3493799f03 100 time_t seconds = mktime(&mytime);
conantina 2:2a3493799f03 101 set_time(seconds);
conantina 2:2a3493799f03 102
conantina 2:2a3493799f03 103 lcd.cls();
conantina 2:2a3493799f03 104 lcd.printf("Start\n");
conantina 2:2a3493799f03 105
conantina 2:2a3493799f03 106 lcd.printf("Setting up...\n");
conantina 2:2a3493799f03 107 EthernetErr ethErr = eth.setup(100000);
conantina 2:2a3493799f03 108 if(ethErr)
conantina 2:2a3493799f03 109 {
conantina 2:2a3493799f03 110 lcd.printf("Error %d in setup.\n", ethErr);
conantina 2:2a3493799f03 111 return -1;
chris 0:f6f8cf11779f 112 }
conantina 2:2a3493799f03 113 lcd.printf("Setup OK\n");
conantina 2:2a3493799f03 114
conantina 2:2a3493799f03 115 HTTPStream stream;
conantina 2:2a3493799f03 116 SP_XmlDomParser parser;
conantina 2:2a3493799f03 117
conantina 2:2a3493799f03 118 char BigBuf[512 + 1] = {0};
conantina 2:2a3493799f03 119 stream.readNext((byte*)BigBuf, 512); //Point to buffer for the first read
conantina 2:2a3493799f03 120 int i = 0;
conantina 2:2a3493799f03 121 char buffer [512*5+1];
conantina 2:2a3493799f03 122 while(true){
conantina 2:2a3493799f03 123 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
conantina 2:2a3493799f03 124 //http://openweathermap.org/data/2.1/find/city?lat=33.75&lon=-84.39&cnt=1&type=XML
conantina 2:2a3493799f03 125 //http://wxdata.weather.com/wxdata/weather/local/USGA0028:1:US?cc=*&unit=m&dayf=1
conantina 2:2a3493799f03 126 //HTTP://hackaday.com/feed/
conantina 2:2a3493799f03 127 //http://openweathermap.org/data/2.1/find/city?lat=40.71&lon=-74.00&cnt=1&type=XML
conantina 2:2a3493799f03 128 i = 0;
conantina 2:2a3493799f03 129
conantina 2:2a3493799f03 130 while(!completed)
conantina 2:2a3493799f03 131 {
conantina 2:2a3493799f03 132 Net::poll(); //Polls the Networking stack
conantina 2:2a3493799f03 133 if(stream.readable())
conantina 2:2a3493799f03 134 {
conantina 2:2a3493799f03 135 i++;
conantina 2:2a3493799f03 136 BigBuf[stream.readLen()] = 0; //Transform this buffer in a zero-terminated char* string
conantina 2:2a3493799f03 137 parser.append( BigBuf, strlen(BigBuf)); // stream current buffer data to the XML parser
conantina 2:2a3493799f03 138 if (i == 1){
conantina 2:2a3493799f03 139 sprintf(buffer,"%s",BigBuf);
conantina 2:2a3493799f03 140 } else{
conantina 2:2a3493799f03 141 printf("%s",BigBuf); //Display it while loading
conantina 2:2a3493799f03 142 }
conantina 2:2a3493799f03 143 //Note: some servers do not like if you throttle them too much, so printf'ing during a request is generally bad practice
conantina 2:2a3493799f03 144 stream.readNext((byte*)BigBuf, 512); //Buffer has been read, now we can put more data in it
conantina 2:2a3493799f03 145 }
conantina 2:2a3493799f03 146 }
conantina 2:2a3493799f03 147 //lcd.printf("\n--------------\n");
conantina 2:2a3493799f03 148 n = sizeof(buffer);
conantina 2:2a3493799f03 149 string ret(buffer, n);
conantina 2:2a3493799f03 150
conantina 2:2a3493799f03 151 place = ret.substr(ret.find("name"),ret.length());
conantina 2:2a3493799f03 152 place = place.substr(place.find(delimiter3),place.find(delimiter2)-4);
conantina 2:2a3493799f03 153 //lcd.printf("Location:%s\n", place);
conantina 2:2a3493799f03 154
conantina 2:2a3493799f03 155 weather = ret.substr(ret.find(delimiter), ret.length());
conantina 2:2a3493799f03 156 weather.erase(0,weather.find(delimiter3)+1);
conantina 2:2a3493799f03 157 condition = weather.substr(weather.find("main"),weather.length());
conantina 2:2a3493799f03 158 condition = condition.substr(condition.find(delimiter3),place.find(delimiter2)-2);
conantina 2:2a3493799f03 159 //lcd.printf("weather condition%s\n",condition);
conantina 2:2a3493799f03 160
conantina 2:2a3493799f03 161 while (true) {
conantina 2:2a3493799f03 162 time_t local_time = time(NULL);
conantina 2:2a3493799f03 163 lcd.cls();
conantina 2:2a3493799f03 164 lcd.printf("The Current Time is: %s\n", ctime(&local_time));
conantina 2:2a3493799f03 165 pc.printf("The Current Time is: %s\n", ctime(&local_time));
conantina 2:2a3493799f03 166 lcd.printf("\n--------------\n");
conantina 2:2a3493799f03 167 lcd.printf("Location:%s\n", place);
conantina 2:2a3493799f03 168 lcd.printf("weather condition%s\n",condition);
conantina 2:2a3493799f03 169 pc.printf("weather condition%s\n",condition);
conantina 2:2a3493799f03 170 t = localtime(&local_time);
conantina 2:2a3493799f03 171 TheYear = t->tm_year + 1900;
conantina 2:2a3493799f03 172 TheMonth = t->tm_mon;
conantina 2:2a3493799f03 173 //change the local time to UTC TIME according to longitude
conantina 2:2a3493799f03 174 if(t->tm_hour - time_difference < 0){
conantina 2:2a3493799f03 175 TheDay = t->tm_mday -1;
conantina 2:2a3493799f03 176 TheHour = t->tm_hour + 24 - time_difference;
conantina 2:2a3493799f03 177 } else{
conantina 2:2a3493799f03 178 TheDay = t->tm_mday;
conantina 2:2a3493799f03 179 TheHour = t->tm_hour - time_difference;
conantina 2:2a3493799f03 180 }
conantina 2:2a3493799f03 181 TheMinute = t->tm_min;
conantina 2:2a3493799f03 182 TheSeconds = t->tm_sec;
conantina 2:2a3493799f03 183 get_sun_position();
conantina 2:2a3493799f03 184 pc.printf("%d\n",condition.find("Clear"));
conantina 2:2a3493799f03 185 if( helios.dZenithAngle<90 && (condition.find("Clear")!=-1)){
conantina 2:2a3493799f03 186 rotate_horizontal(helios.dAzimuth);
conantina 2:2a3493799f03 187 rotate_vertical(helios.dZenithAngle);
conantina 2:2a3493799f03 188 lcd.printf("Sun Zenith Angle: %f\n",helios.dZenithAngle); // Degrees down from vertical
conantina 2:2a3493799f03 189 lcd.printf("Sun Azimuth Angle: %f\n",helios.dAzimuth); // Degrees from north
conantina 2:2a3493799f03 190 }else{
conantina 2:2a3493799f03 191 lcd.printf("The solar tracker is not tracking the sun...");
conantina 2:2a3493799f03 192 }
conantina 2:2a3493799f03 193 wait(update_period);
conantina 2:2a3493799f03 194 if(t->tm_hour == 6) break;
conantina 2:2a3493799f03 195 }
conantina 2:2a3493799f03 196 }
conantina 2:2a3493799f03 197
conantina 2:2a3493799f03 198 }