forked from G6EJD/ESP32_2D_Sun_Tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ESP_Sun_Tracking_Servo_Gimbal_01.ino
199 lines (174 loc) · 8.26 KB
/
ESP_Sun_Tracking_Servo_Gimbal_01.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
This program calculates solar positions as a function of location, date, and time. The equations are from NOAA
This software, the ideas and concepts is Copyright (c) David Bird 2014 and beyond.
All rights to this software are reserved.
It is prohibited to redistribute or reproduce of any part or all of the software contents in any form other than the following:
1. You may print or download to a local hard disk extracts for your personal and non-commercial use only.
2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material.
3. You may not, except with my express written permission, distribute or commercially exploit the content.
4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes.
5. You MUST include all of this copyright and permission notice ('as annotated') and this shall be included in all copies or substantial portions of the software and where the software use is visible to an end-user.
THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT.
FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <WiFi.h> // Built-in
#include <time.h> // Built-in
#include <Servo.h> // https://github.com/jkb-git/ESP32Servo
const char* ssid = "your-SSID";
const char* password = "your-PASSWORD";
float Lon = -2.33 * DEG_TO_RAD,
Lat = 51.37 * DEG_TO_RAD,
elevation,
azimuth;
#define elevation_servo 5
#define azimuth_servo 2
int sun_azimuth;
int sun_elevation;
String time_str, current_hour, current_minute, current_day, current_month, current_year;
Servo Azi_servo;
Servo Ele_servo;
void setup() {
Serial.begin(115200);
StartWiFi(ssid, password);
StartTime();
UpdateLocalTime();
Azi_servo.attach(azimuth_servo);
Ele_servo.attach(elevation_servo);
test_azimuth();
delay(1000);
test_elevation(); // Stop at 145 which is vertical or 0 elevation
delay(1000);
}
void loop() {
// All time values must not be in DST
UpdateLocalTime();
Serial.println(Update_DateTime());
Calculate_Sun_Position(current_hour.toInt(), current_minute.toInt(), 0, current_day.toInt(), current_month.toInt(), current_year.toInt()); // parameters are HH:MM:SS DD:MM:YY start from midnight and work out all 24 hour positions.
Azi_servo.write(map(sun_azimuth, 90, 270, 180, 0)); // Align to azimuth
if (sun_elevation < 0) sun_elevation = 0; // Point at horizon if less than horizon
Ele_servo.write(145 - sun_elevation); // map(value, fromLow, fromHigh, toLow, toHigh)
delay(1 * 60 * 1000); // Wait 1-minute then check position again
}
void Calculate_Sun_Position(int hour, int minute, int second, int day, int month, int year) {
float T, JDate_frac, L0, M, e, C, L_true, f, R, GrHrAngle, Obl, RA, Decl, HrAngle;
long JDate, JDx;
int zone = 0; //Unused variable but retained for continuity
JDate = JulianDate(year, month, day);
JDate_frac = (hour + minute / 60. + second / 3600.0) / 24.0 - 0.5;
T = JDate - 2451545; T = (T + JDate_frac) / 36525.0;
L0 = DEG_TO_RAD * fmod(280.46645 + 36000.76983 * T, 360);
M = DEG_TO_RAD * fmod(357.5291 + 35999.0503 * T, 360);
e = 0.016708617 - 0.000042037 * T;
C = DEG_TO_RAD * ((1.9146 - 0.004847 * T) * sin(M) + (0.019993 - 0.000101 * T) * sin(2 * M) + 0.00029 * sin(3 * M));
f = M + C;
Obl = DEG_TO_RAD * (23 + 26 / 60.0 + 21.448 / 3600. - 46.815 / 3600 * T);
JDx = JDate - 2451545;
GrHrAngle = 280.46061837 + (360 * JDx) % 360 + 0.98564736629 * JDx + 360.98564736629 * JDate_frac;
GrHrAngle = fmod(GrHrAngle, 360.0);
L_true = fmod(C + L0, 2 * PI);
R = 1.000001018 * (1 - e * e) / (1 + e * cos(f));
RA = atan2(sin(L_true) * cos(Obl), cos(L_true));
Decl = asin(sin(Obl) * sin(L_true));
HrAngle = DEG_TO_RAD * GrHrAngle + Lon - RA;
elevation = asin(sin(Lat) * sin(Decl) + cos(Lat) * (cos(Decl) * cos(HrAngle)));
azimuth = PI + atan2(sin(HrAngle), cos(HrAngle) * sin(Lat) - tan(Decl) * cos(Lat)); // Azimuth measured east from north, so 0 degrees is North
sun_azimuth = azimuth / DEG_TO_RAD;
sun_elevation = elevation / DEG_TO_RAD;
Serial.println("Longitude and latitude " + String(Lon / DEG_TO_RAD, 3) + " " + String(Lat / DEG_TO_RAD, 3));
Serial.println("Year\tMonth\tDay\tHour\tMinute\tSecond\tElevation\tAzimuth");
Serial.print(String(year) + "\t" + String(month) + "\t" + String(day) + "\t" + String(hour - zone) + "\t" + String(minute) + "\t" + String(second) + "\t");
Serial.println(String(elevation / DEG_TO_RAD, 0) + "\t\t" + String(azimuth / DEG_TO_RAD, 0));
}
long JulianDate(int year, int month, int day) {
long JDate;
int A, B;
if (month <= 2) {year--; month += 12;}
A = year / 100; B = 2 - A + A / 4;
JDate = (long)(365.25 * (year + 4716)) + (int)(30.6001 * (month + 1)) + day + B - 1524;
return JDate;
}
////////////// WiFi, Time and Date Functions /////////////////
int StartWiFi(const char* ssid, const char* password) {
int connAttempts = 0;
Serial.print(F("\r\nConnecting to: ")); Serial.println(String(ssid));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED ) {
delay(500); Serial.print(".");
if (connAttempts > 20) {
Serial.println("\nFailed to connect to a Wi-Fi network");
return false;
}
connAttempts++;
}
Serial.print(F("WiFi connected at: "));
Serial.println(WiFi.localIP());
return true;
}
void StartTime() {
configTime(0, 0, "0.uk.pool.ntp.org", "time.nist.gov");
setenv("TZ", "GMT0BST,M3.5.0/01,M10.5.0/02", 1); // Change for your location
UpdateLocalTime();
}
void UpdateLocalTime() {
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
}
//See http://www.cplusplus.com/reference/ctime/strftime/
Serial.println(&timeinfo, "%a %b %d %Y %H:%M:%S"); // Displays: Saturday, June 24 2017 14:05:49
char output[50];
strftime(output, 50, "%a %d-%b-%y (%H:%M:%S)", &timeinfo);
time_str = output;
}
String GetTime() {
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time - trying again");
}
//See http://www.cplusplus.com/reference/ctime/strftime/
//Serial.println(&timeinfo, "%a %b %d %Y %H:%M:%S"); // Displays: Saturday, June 24 2017 14:05:49
char output[50];
strftime(output, 50, "%d/%m/%y %H:%M:%S", &timeinfo); //Use %m/%d/%y for USA format
time_str = output;
Serial.println(time_str);
return time_str; // returns date-time formatted like this "11/12/17 22:01:00"
}
String Update_DateTime() {
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time - trying again");
}
//See http://www.cplusplus.com/reference/ctime/strftime/
char output[50];
strftime(output, 50, "%H", &timeinfo);
current_hour = output;
strftime(output, 50, "%M", &timeinfo);
current_minute = output;
strftime(output, 50, "%d", &timeinfo);
current_day = output;
strftime(output, 50, "%m", &timeinfo);
current_month = output;
strftime(output, 50, "%Y", &timeinfo);
current_year = output;
Serial.println(time_str);
return time_str; // returns date-time formatted like this "11/12/17 22:01:00"
}
void test_azimuth() {
Azi_servo.write(90); // Centre position
delay(500);
Azi_servo.write(60); // Centre position
delay(500);
Azi_servo.write(120); // Centre position
delay(500);
Azi_servo.write(90); // Centre position
delay(500);
}
void test_elevation() {
for (int a = 5; a < 145; a = a + 2) {
Ele_servo.write(a); // Centre position
delay(30);
}
Ele_servo.write(145); // Centre position
delay(1000);
}