Luis Rodil-Fernandez
2 years ago
commit
6fd89c7ee1
7 changed files with 588 additions and 0 deletions
-
5README.md
-
46lib/README
-
3lib/wmm/README.md
-
302lib/wmm/wmm.cpp
-
44lib/wmm/wmm.h
-
26platformio.ini
-
162src/main.cpp
@ -0,0 +1,5 @@ |
|||
## Heliograph prototype |
|||
|
|||
ESP32 with a GPS module calculates sun position and magnetic declination. |
|||
|
|||
- Is this enough for an earth bound object to know where to find the sun? |
@ -0,0 +1,46 @@ |
|||
|
|||
This directory is intended for project specific (private) libraries. |
|||
PlatformIO will compile them to static libraries and link into executable file. |
|||
|
|||
The source code of each library should be placed in a an own separate directory |
|||
("lib/your_library_name/[here are source files]"). |
|||
|
|||
For example, see a structure of the following two libraries `Foo` and `Bar`: |
|||
|
|||
|--lib |
|||
| | |
|||
| |--Bar |
|||
| | |--docs |
|||
| | |--examples |
|||
| | |--src |
|||
| | |- Bar.c |
|||
| | |- Bar.h |
|||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html |
|||
| | |
|||
| |--Foo |
|||
| | |- Foo.c |
|||
| | |- Foo.h |
|||
| | |
|||
| |- README --> THIS FILE |
|||
| |
|||
|- platformio.ini |
|||
|--src |
|||
|- main.c |
|||
|
|||
and a contents of `src/main.c`: |
|||
``` |
|||
#include <Foo.h> |
|||
#include <Bar.h> |
|||
|
|||
int main (void) |
|||
{ |
|||
... |
|||
} |
|||
|
|||
``` |
|||
|
|||
PlatformIO Library Dependency Finder will find automatically dependent |
|||
libraries scanning project source files. |
|||
|
|||
More information about PlatformIO Library Dependency Finder |
|||
- https://docs.platformio.org/page/librarymanager/ldf.html |
@ -0,0 +1,3 @@ |
|||
World Magnetic Model library slightly modified |
|||
from original written by Rene Herrero Gomez |
|||
https://github.com/sevenseas-io/wmm |
@ -0,0 +1,302 @@ |
|||
#include <stdint.h>
|
|||
#include <stdbool.h>
|
|||
#include <string.h>
|
|||
#include <math.h>
|
|||
#include "wmm.h"
|
|||
|
|||
#define PI_CONST 3.14159265359f
|
|||
#define RADIANS_TO_DEGREES 0.017453292f
|
|||
#define DEGREES_TO_RADIANS (PI_CONST / 180.0f)
|
|||
#define A_CONST 6378.137f
|
|||
#define A2_CONST (A_CONST * A_CONST)
|
|||
#define B_CONST 6356.7523142f
|
|||
#define B2_CONST (B_CONST * B_CONST)
|
|||
#define RE_CONST 6371.2f
|
|||
#define A4_CONST (A2_CONST * A2_CONST)
|
|||
#define B4_CONST (B2_CONST * B2_CONST)
|
|||
#define C2_CONST (A2_CONST - B2_CONST)
|
|||
#define C4_CONST (A4_CONST - B4_CONST)
|
|||
#define COEFFICIENTS_COUNT 90U
|
|||
|
|||
static float c[13][13]; |
|||
static float cd[13][13]; |
|||
static float k[13][13]; |
|||
static float snorm[169]; |
|||
static float fn[13]; |
|||
static float fm[13]; |
|||
|
|||
const uint8_t wmm_cof_entries_encoded[] = |
|||
{0xDD, 0xF2, 0x23, 0x00, 0x83, 0x01, 0x00, 0xEB, 0xE2, 0x01, 0x81, 0xD7, 0x05, 0x8D, 0x01, 0xFB, 0x03, 0xE8, 0x86, 0x03, 0x00, 0xF3, 0x01, 0x00, 0xBC, 0xD1, 0x03, 0xDC, 0xD3, 0x03, 0xC7, 0x01, 0xEE, 0x04, 0x80, 0x86, 0x02, 0xF4, 0x72, 0x56, 0xEF, 0x03, 0x87, 0xD5, 0x01, 0x00, 0x1C, 0x00, 0xC2, 0xF4, 0x02, 0xF6, 0x0C, 0x7E, 0x39, 0x8A, 0xC1, 0x01, 0xB2, 0x25, 0x22, 0x4A, 0x89, 0x52, 0xF5, 0x54, 0xFA, 0x01, 0x0B, 0x87, 0x8D, 0x01, 0x00, 0x4B, 0x00, 0x9E, 0x7E, 0x84, 0x2C, 0x50, 0x02, 0x9E, 0x0D, 0xF0, 0x18, 0x7C, 0x85, 0x01, 0xD6, 0x30, 0x8E, 0x1F, 0x36, 0x25, 0x9F, 0x07, 0xED, 0x36, 0x77, 0x78, 0xE8, 0x24, 0x00, 0x43, 0x00, 0xAF, 0x38, 0x9D, 0x07, 0x06, 0x01, 0x96, 0x1D, 0xA4, 0x20, 0x47, 0x19, 0xFF, 0x15, 0xFD, 0x12, 0x01, 0x49, 0xE8, 0x17, 0x82, 0x05, 0x0C, 0x1E, 0x89, 0x02, 0x9F, 0x0F, 0x0A, 0x05, 0x93, 0x0A, 0x00, 0x46, 0x00, 0x90, 0x0A, 0xFF, 0x02, 0x44, 0x01, 0x9A, 0x0B, 0xBA, 0x03, 0x05, 0x52, 0xFF, 0x12, 0x8F, 0x08, 0x0E, 0x4E, 0xEA, 0x05, 0xC4, 0x0A, 0x4E, 0x09, 0x87, 0x02, 0x9A, 0x01, 0x00, 0x01, 0xC7, 0x0A, 0xA9, 0x0A, 0x08, 0x0A, 0xA6, 0x0C, 0x00, 0x41, 0x00, 0xC0, 0x0C, 0xC2, 0x08, 0x43, 0x05, 0xD3, 0x01, 0xE8, 0x02, 0x41, 0x06, 0xB5, 0x08, 0x17, 0x07, 0x47, 0x9E, 0x02, 0xAB, 0x03, 0x02, 0x42, 0x80, 0x01, 0x56, 0x45, 0x4C, 0xC8, 0x01, 0xD0, 0x04, 0x48, 0x02, 0xA2, 0x01, 0x53, 0x0A, 0x03, 0xAC, 0x03, 0x00, 0x41, 0x00, 0xA2, 0x01, 0x94, 0x01, 0x01, 0x43, 0xEF, 0x02, 0xD9, 0x02, 0x41, 0x07, 0x44, 0x80, 0x02, 0x05, 0x42, 0xD3, 0x03, 0xF6, 0x01, 0x41, 0x05, 0x99, 0x02, 0x95, 0x02, 0x04, 0x43, 0x89, 0x02, 0x24, 0x05, 0x45, 0xE5, 0x02, 0xC5, 0x01, 0x00, 0x04, 0x43, 0x1C, 0x04, 0x01, 0x32, 0x00, 0x41, 0x00, 0x92, 0x01, 0xE9, 0x03, 0x42, 0x43, 0x1D, 0xAF, 0x01, 0x00, 0x02, 0x4E, 0xA2, 0x01, 0x04, 0x44, 0x4B, 0x73, 0x43, 0x04, 0xC5, 0x02, 0x7E, 0x00, 0x01, 0x0B, 0x8E, 0x01, 0x03, 0x00, 0x99, 0x01, 0x04, 0x00, 0x42, 0xDD, 0x01, 0x4F, 0x00, 0x05, 0xF7, 0x01, 0xA1, 0x01, 0x44, 0x02, 0x53, 0x00, 0x00, 0x00, 0x7E, 0x22, 0x00, 0x00, 0x41, 0x42, 0x00, 0x01, 0x11, 0x23, 0x02, 0x43, 0x49, 0x30, 0x41, 0x01, 0x06, 0xD6, 0x01, 0x42, 0x42, 0x49, 0x41, 0x00, 0x01, 0x13, 0x6A, 0x41, 0x00, 0x0E, 0x62, 0x42, 0x41, 0x58, 0x41, 0x41, 0x02, 0x67, 0xD8, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x41, 0x00, 0x59, 0x1A, 0x00, 0x01, 0x18, 0x45, 0x00, 0x00, 0x49, 0x44, 0x00, 0x02, 0x03, 0x06, 0x41, 0x00, 0x47, 0x42, 0x00, 0x00, 0x41, 0x51, 0x00, 0x01, 0x0E, 0x50, 0x41, 0x00, 0x46, 0x5E, 0x41, 0x41, 0x02, 0x54, 0x41, 0x00, 0x1F, 0x5A, 0x41, 0x00, 0x54, 0x00, 0x00, 0x00, 0x41, 0x4C, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x41, 0x4C, 0x52, 0x00, 0x01, 0x07, 0x01, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x05, 0x41, 0x00, 0x00, 0x42, 0x06, 0x00, 0x01, 0x45, 0x02, 0x00, 0x00, 0x01, 0x49, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x43, 0x05, 0x41, 0x41}; |
|||
|
|||
static wmm_cof_record_t wmm_cof_entries[COEFFICIENTS_COUNT]; |
|||
|
|||
static float convert_varint_to_float(char **bytes); |
|||
|
|||
float wmm_get_date(uint8_t year, uint8_t month, uint8_t date) |
|||
{ |
|||
return (float)year + 2000.0f + (float)(month - 1U) / 12.0f + (float)(date - 1U) / (365.0f); |
|||
} |
|||
|
|||
static float convert_varint_to_float(char **bytes) |
|||
{ |
|||
float result; |
|||
int32_t result_int; |
|||
bool negative = false; |
|||
bool first_byte = true; |
|||
uint8_t shift; |
|||
|
|||
do |
|||
{ |
|||
if (first_byte) |
|||
{ |
|||
if (**bytes & 0x40) |
|||
{ |
|||
negative = true; |
|||
} |
|||
|
|||
result_int = **bytes & 0x3f; |
|||
shift = 6U; |
|||
first_byte = false; |
|||
} |
|||
else |
|||
{ |
|||
result_int += (uint32_t)(**bytes & 0x7f) << shift; |
|||
shift += 7U; |
|||
} |
|||
|
|||
if ((**bytes & 0x80) == 0U) |
|||
{ |
|||
(*bytes)++; |
|||
break; |
|||
} |
|||
|
|||
(*bytes)++; |
|||
|
|||
} while (true); |
|||
|
|||
|
|||
result = ((float)result_int) / 10.0f; |
|||
if (negative) |
|||
{ |
|||
result = -result; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void wmm_init(void) |
|||
{ |
|||
uint8_t j; |
|||
uint8_t m; |
|||
uint8_t n; |
|||
uint8_t D2; |
|||
float gnm; |
|||
float hnm; |
|||
float dgnm; |
|||
float dhnm; |
|||
float flnmj; |
|||
uint8_t i; |
|||
char *bytes = (char *)&wmm_cof_entries_encoded[0]; |
|||
|
|||
// unpack coefficients
|
|||
for (i = 0U; i < COEFFICIENTS_COUNT; i++) |
|||
{ |
|||
wmm_cof_entries[i].gnm = convert_varint_to_float(&bytes); |
|||
wmm_cof_entries[i].hnm = convert_varint_to_float(&bytes); |
|||
wmm_cof_entries[i].dgnm = convert_varint_to_float(&bytes); |
|||
wmm_cof_entries[i].dhnm = convert_varint_to_float(&bytes); |
|||
} |
|||
|
|||
c[0][0] = 0.0f; |
|||
cd[0][0] = 0.0f; |
|||
|
|||
j = 0U; |
|||
for (n = 1U; n <= 12U; n++) |
|||
{ |
|||
for (m = 0U; m <= n; m++) |
|||
{ |
|||
gnm = wmm_cof_entries[j].gnm; |
|||
hnm = wmm_cof_entries[j].hnm; |
|||
dgnm = wmm_cof_entries[j].dgnm; |
|||
dhnm = wmm_cof_entries[j].dhnm; |
|||
j++; |
|||
|
|||
if (m <= n) |
|||
{ |
|||
c[m][n] = gnm; |
|||
cd[m][n] = dgnm; |
|||
if (m != 0U) |
|||
{ |
|||
c[n][m - 1U] = hnm; |
|||
cd[n][m - 1U] = dhnm; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// CONVERT SCHMIDT NORMALIZED GAUSS COEFFICIENTS TO UNNORMALIZED
|
|||
*snorm = 1.0f; |
|||
for (n = 1U; n <= 12U; n++) |
|||
{ |
|||
*(snorm + n) = *(snorm + n - 1U) * (float)(2U * n - 1U) / (float)n; |
|||
j = 2U; |
|||
m = 0U; |
|||
for (D2 = n - m + 1U; D2 > 0U; D2--) |
|||
{ |
|||
k[m][n] = (float)(((n - 1U) * (n - 1U)) - (m * m)) / (float)((2U * n - 1U) * (2U * n - 3U)); |
|||
if (m > 0U) |
|||
{ |
|||
flnmj = (float)((n - m + 1U) * j) / (float)(n + m); |
|||
*(snorm + n + m * 13U) = *(snorm + n + (m - 1U) * 13U) * sqrt(flnmj); |
|||
j = 1U; |
|||
c[n][m - 1U] = *(snorm + n + m * 13U) * c[n][m - 1U]; |
|||
cd[n][m - 1U] = *(snorm + n + m * 13U) * cd[n][m - 1U]; |
|||
} |
|||
c[m][n] = *(snorm + n + m * 13U) * c[m][n]; |
|||
cd[m][n] = *(snorm + n + m *13U) * cd[m][n]; |
|||
m += 1U; |
|||
} |
|||
fn[n] = (float)(n + 1U); |
|||
fm[n] = (float)n; |
|||
} |
|||
k[1][1] = 0.0f; |
|||
} |
|||
|
|||
void E0000(float glat, float glon, float time_years, float *dec) |
|||
{ |
|||
static float tc[13][13]; |
|||
static float sp[13]; |
|||
static float cp[13]; |
|||
static float dp[13][13]; |
|||
static float pp[13]; |
|||
float dt = time_years - WMM_EPOCH; |
|||
float rlon = glon * DEGREES_TO_RADIANS; |
|||
float rlat = glat * DEGREES_TO_RADIANS; |
|||
float srlon = sinf(rlon); |
|||
float srlat = sinf(rlat); |
|||
float crlon = cosf(rlon); |
|||
float crlat = cosf(rlat); |
|||
float srlat2 = srlat * srlat; |
|||
float crlat2 = crlat * crlat; |
|||
sp[0] = 0.0f; |
|||
sp[1] = srlon; |
|||
cp[0] = 1.0f; |
|||
cp[1] = crlon; |
|||
dp[0][0] = 0.0f; |
|||
pp[0] = 1.0f; |
|||
|
|||
// CONVERT FROM GEODETIC COORDS. TO SPHERICAL COORDS
|
|||
float q = sqrtf(A2_CONST - C2_CONST * srlat2); |
|||
float q2 = (A2_CONST / (B2_CONST)) * (A2_CONST / B2_CONST); |
|||
float ct = srlat / sqrtf(q2 * crlat2 + srlat2); |
|||
float st = sqrtf(1.0f - (ct * ct)); |
|||
float r2 = (A4_CONST - C4_CONST * srlat2) / (q * q); |
|||
float r = sqrtf(r2); |
|||
float d = sqrtf(A2_CONST * crlat2 + B2_CONST * srlat2); |
|||
float ca = d / r; |
|||
float sa = C2_CONST * crlat * srlat / (r * d); |
|||
for (uint8_t m = 2U; m <= 12U; m++) |
|||
{ |
|||
sp[m] = sp[1] * cp[m - 1U] + cp[1] * sp[m - 1U]; |
|||
cp[m] = cp[1] * cp[m - 1U] - sp[1] * sp[m - 1U]; |
|||
} |
|||
float aor = RE_CONST / r; |
|||
float ar = aor * aor; |
|||
float br = 0.0f; |
|||
float bt = 0.0f; |
|||
float bp = 0.0f; |
|||
float bpp = 0.0f; |
|||
|
|||
for (uint16_t n = 1U; n <= 12U; n++) |
|||
{ |
|||
ar = ar * aor; |
|||
uint8_t m = 0U; |
|||
for (uint8_t D4 = n + 1U; D4 > 0U; D4--) |
|||
{ |
|||
// COMPUTE UNNORMALIZED ASSOCIATED LEGENDRE POLYNOMIALS AND DERIVATIVES VIA RECURSION RELATIONS
|
|||
if (n == m) |
|||
{ |
|||
*(snorm + n + m * 13U) = st * *(snorm + n - 1U + (m - 1U) * 13U); |
|||
dp[m][n] = st * dp[m - 1U][n - 1U] + ct * *(snorm + n - 1U + (m - 1U) * 13U); |
|||
goto S50; |
|||
} |
|||
if (n == 1U && m == 0U) |
|||
{ |
|||
*(snorm + n + m * 13U) = ct * *(snorm + n - 1U + m * 13U); |
|||
dp[m][n] = ct * dp[m][n - 1U] - st * *(snorm + n - 1U + m * 13U); |
|||
goto S50; |
|||
} |
|||
if (n > 1U && n != m) |
|||
{ |
|||
if (m > n - 2U) |
|||
{ |
|||
*(snorm + n - 2U + m * 13U) = 0.0f; |
|||
} |
|||
if (m > n - 2U) |
|||
{ |
|||
dp[m][n - 2U] = 0.0f; |
|||
} |
|||
*(snorm + n + m * 13U) = ct * *(snorm + n - 1U + m * 13U) - k[m][n] * *(snorm + n - 2U + m * 13U); |
|||
dp[m][n] = ct * dp[m][n - 1U] - st * *(snorm + n - 1U + m * 13U) - k[m][n] * dp[m][n - 2U]; |
|||
} |
|||
S50: |
|||
|
|||
// TIME ADJUST THE GAUSS COEFFICIENTS
|
|||
tc[m][n] = c[m][n] + dt * cd[m][n]; |
|||
if (m != 0U) |
|||
{ |
|||
tc[n][m - 1U] = c[n][m - 1U] + dt * cd[n][m - 1U]; |
|||
} |
|||
|
|||
// ACCUMULATE TERMS OF THE SPHERICAL HARMONIC EXPANSIONS
|
|||
float par = ar * *(snorm + n + m * 13U); |
|||
float temp1; |
|||
float temp2; |
|||
|
|||
if (m == 0) |
|||
{ |
|||
temp1 = tc[m][n] * cp[m]; |
|||
temp2 = tc[m][n] * sp[m]; |
|||
} |
|||
else |
|||
{ |
|||
temp1 = tc[m][n] * cp[m] + tc[n][m - 1U] * sp[m]; |
|||
temp2 = tc[m][n] * sp[m] - tc[n][m - 1U] * cp[m]; |
|||
} |
|||
|
|||
bt = bt - ar * temp1 * dp[m][n]; |
|||
bp += (fm[m] * temp2 * par); |
|||
br += (fn[n] * temp1 * par); |
|||
|
|||
// SPECIAL CASE: NORTH/SOUTH GEOGRAPHIC POLES
|
|||
if (st == 0.0f && m == 1U) |
|||
{ |
|||
if (n == 1U) |
|||
{ |
|||
pp[n] = pp[n - 1U]; |
|||
} |
|||
else |
|||
{ |
|||
pp[n] = ct * pp[n - 1U] - k[m][n] * pp[n - 2U]; |
|||
} |
|||
bpp += (fm[m] * temp2 * ar * pp[n]); |
|||
} |
|||
m += 1U; |
|||
} |
|||
} |
|||
if (st == 0.0f) |
|||
{ |
|||
bp = bpp; |
|||
} |
|||
else |
|||
{ |
|||
bp /= st; |
|||
} |
|||
|
|||
// ROTATE MAGNETIC VECTOR COMPONENTS FROM SPHERICAL TO GEODETIC COORDINATES
|
|||
float bx = -bt * ca - br * sa; |
|||
float by = bp; |
|||
|
|||
// COMPUTE DECLINATION
|
|||
*dec = atan2f(by, bx) / DEGREES_TO_RADIANS; |
|||
} |
@ -0,0 +1,44 @@ |
|||
#ifndef WMM_H |
|||
#define WMM_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#define WMM_EPOCH 2020.0f |
|||
|
|||
typedef struct |
|||
{ |
|||
float gnm; |
|||
float hnm; |
|||
float dgnm; |
|||
float dhnm; |
|||
} wmm_cof_record_t; |
|||
|
|||
/** |
|||
* Initialize the WMM. Needs calling only once. |
|||
*/ |
|||
void wmm_init(void); |
|||
|
|||
/** |
|||
* Get the date in WMM format |
|||
* |
|||
* @param year Year in 2 digit format of 21st centuary, i.e. 20 represents 2020 |
|||
* @param month Month, 1 to 12 |
|||
* @param date Date of month, 1 to 31 |
|||
* @return Date in WMM format |
|||
* @note No checking of illegal dates is done |
|||
*/ |
|||
float wmm_get_date(uint8_t year, uint8_t month, uint8_t date); |
|||
|
|||
/** |
|||
* Get the magnetic variation at a point on the earth's surface |
|||
* |
|||
* @param glat Latitude in degrees and fractional degrees, negative west |
|||
* @param glon Longitude in degrees and fractional degrees, negative west |
|||
* @param time_years The date as returned from wmm_get_date |
|||
* @param dec Pointer to float holding calculated magnetic variation (also known as declination). Negative is west. |
|||
* @note The altitude used is the ellipsoid at the supplied latitude/longitude, not the earth's surface. This will |
|||
* give very small errors in some parts of the world comapred to sea level. |
|||
*/ |
|||
void E0000(float glat, float glon, float time_years, float *dec); |
|||
|
|||
#endif |
@ -0,0 +1,26 @@ |
|||
; PlatformIO Project Configuration File |
|||
; |
|||
; Build options: build flags, source filter |
|||
; Upload options: custom upload port, speed and extra flags |
|||
; Library options: dependencies, extra library storages |
|||
; Advanced options: extra scripting |
|||
; |
|||
; Please visit documentation for the other options and examples |
|||
; https://docs.platformio.org/page/projectconf.html |
|||
|
|||
[env:lolin32] |
|||
platform = espressif32 |
|||
board = lolin32 |
|||
framework = arduino |
|||
|
|||
|
|||
monitor_speed = 115200 |
|||
|
|||
lib_deps = |
|||
SSD1306=adafruit/Adafruit SSD1306@^2.5.6 |
|||
Adafruit_GPS=https://github.com/adafruit/Adafruit_GPS/archive/refs/tags/1.7.0.zip |
|||
SoftwareSerial=https://github.com/plerup/espsoftwareserial/archive/refs/tags/6.16.1.zip |
|||
Time=paulstoffregen/Time@^1.6.1 |
|||
SolarPosition=https://github.com/KenWillmott/SolarPosition.git |
|||
; NeoGPS=slashdevin/NeoGPS@^4.2.9 |
|||
|
@ -0,0 +1,162 @@ |
|||
#include <Arduino.h>
|
|||
|
|||
#include <SPI.h>
|
|||
#include <Wire.h>
|
|||
#include <Adafruit_GFX.h>
|
|||
#include <Adafruit_SSD1306.h>
|
|||
|
|||
#include <Adafruit_GPS.h>
|
|||
#include <SoftwareSerial.h>
|
|||
|
|||
#include <wmm.h>
|
|||
#include <SolarPosition.h>
|
|||
|
|||
#define SCREEN_WIDTH 128
|
|||
#define SCREEN_HEIGHT 64
|
|||
|
|||
#define OLED_RESET -1
|
|||
#define SCREEN_ADDRESS 0x3C
|
|||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
|||
|
|||
SoftwareSerial altserial(14, 12); |
|||
Adafruit_GPS GPS(&altserial); |
|||
|
|||
uint32_t tstamp = millis(); |
|||
|
|||
typedef struct { |
|||
time_t epoch; |
|||
float latitude; |
|||
float longitude; |
|||
float declination; |
|||
float elevation; |
|||
float azimuth; |
|||
} tSolar; |
|||
|
|||
tSolar sun; |
|||
|
|||
void init_display() { |
|||
Wire.begin(5, 4); |
|||
|
|||
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS, false, false)) { |
|||
Serial.println(F("SSD1306 allocation failed")); |
|||
while(true) ; // do not proceed
|
|||
} |
|||
|
|||
display.clearDisplay(); |
|||
} |
|||
|
|||
void init_gps() { |
|||
altserial.begin(9600); |
|||
delay(2000); |
|||
|
|||
// Serial.println("Software Serial GPS Test Echo Test");
|
|||
// you can send various commands to get it started
|
|||
//mySerial.println(PMTK_SET_NMEA_OUTPUT_RMCGGA);
|
|||
altserial.println(PMTK_SET_NMEA_OUTPUT_ALLDATA); |
|||
altserial.println(PMTK_SET_NMEA_UPDATE_1HZ); |
|||
// Serial.println("Get version!");
|
|||
altserial.println(PMTK_Q_RELEASE); |
|||
} |
|||
|
|||
// ///////////////////////////////////////////////////////////////////////////////////////
|
|||
// ///////////////////////////////////////////////////////////////////////////////////////
|
|||
// ///////////////////////////////////////////////////////////////////////////////////////
|
|||
void setup() { |
|||
Serial.begin(115200); |
|||
init_display(); |
|||
init_gps(); |
|||
wmm_init(); |
|||
} |
|||
|
|||
void draw_sunpos() { |
|||
display.clearDisplay(); |
|||
|
|||
display.setTextSize(1); |
|||
display.setTextColor(SSD1306_WHITE); |
|||
display.setCursor(0, 0); |
|||
//display.print(F("lat ------> "));
|
|||
display.print(F("lat ....... ")); |
|||
display.print((double)sun.latitude, 2); |
|||
display.println(); |
|||
display.print(F("lon ....... ")); |
|||
display.print((double)sun.longitude, 2); |
|||
display.println(); |
|||
display.print(F("WMM ....... ")); |
|||
display.print((double)sun.declination, 2); |
|||
display.println(); |
|||
display.print(F("elevation .. ")); |
|||
display.print((double)sun.elevation, 4); |
|||
display.println(); |
|||
display.print(F("azimuth .... ")); |
|||
display.print((double)sun.azimuth, 4); |
|||
display.println(); |
|||
|
|||
// refresh
|
|||
display.display(); |
|||
} |
|||
|
|||
void debug_solar() { |
|||
Serial.print("Location: "); |
|||
Serial.print(sun.latitude, 4); //Serial.print(GPS.lat);
|
|||
Serial.print(", "); |
|||
Serial.print(sun.longitude, 4); //Serial.println(GPS.lon);
|
|||
|
|||
Serial.println(); |
|||
|
|||
Serial.print("WMM declination "); Serial.print(sun.declination, 4); |
|||
|
|||
Serial.println(); |
|||
|
|||
Serial.print(F("elevation: ")); |
|||
Serial.print(sun.elevation, 4); |
|||
Serial.print(F(" azimuth: ")); |
|||
Serial.println(sun.azimuth, 4); |
|||
|
|||
Serial.println(); |
|||
|
|||
// Serial.print("Speed (knots): "); Serial.println(GPS.speed);
|
|||
// Serial.print("Angle: "); Serial.println(GPS.angle);
|
|||
// Serial.print("Altitude: "); Serial.println(GPS.altitude);
|
|||
// Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
|
|||
// Serial.print("Antenna status: "); Serial.println((int)GPS.antenna);
|
|||
} |
|||
|
|||
void loop() { |
|||
char c = GPS.read(); |
|||
// // if you want to debug, this is a good time to do it!
|
|||
//if (c) Serial.write(c);
|
|||
|
|||
// if a sentence is received, we can check the checksum, parse it...
|
|||
if (GPS.newNMEAreceived()) { |
|||
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
|
|||
return; // we can fail to parse a sentence in which case we should just wait for another
|
|||
} |
|||
|
|||
// approximately every 2 seconds or so, print out the current stats
|
|||
if (millis() - tstamp > 2000) { |
|||
tstamp = millis(); // reset the timer
|
|||
float wmmtime = wmm_get_date(GPS.year, GPS.month, GPS.day); |
|||
|
|||
sun.latitude = GPS.latitudeDegrees; |
|||
sun.longitude = GPS.longitudeDegrees; |
|||
|
|||
// create a fixed UNIX time to test fixed time method
|
|||
tmElements_t someTime = {GPS.seconds, GPS.minute, GPS.hour, 0, GPS.day, GPS.month, CalendarYrToTm(GPS.year) }; |
|||
sun.epoch = makeTime(someTime); |
|||
|
|||
if (GPS.fix) { |
|||
SolarPosition location(GPS.latitudeDegrees, GPS.longitudeDegrees); |
|||
|
|||
// calculate magnetic declination
|
|||
E0000(GPS.latitudeDegrees, GPS.longitudeDegrees, wmmtime, &sun.declination); |
|||
|
|||
sun.elevation = location.getSolarPosition(sun.epoch).elevation; |
|||
sun.azimuth = location.getSolarPosition(sun.epoch).azimuth; |
|||
|
|||
debug_solar(); |
|||
draw_sunpos(); |
|||
} |
|||
} |
|||
|
|||
// draw_sunpos();
|
|||
} // loop()
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue