mirror of
https://github.com/k3ng/k3ng_rotator_controller.git
synced 2025-02-22 17:52:37 +00:00
2020.07.24.01
After pulling my hair out for two days, I rewrote the satellite tracking to use the P13 library from Mark VandeWettering \^ command to activate and deactive satellite tracking \~ command to view satellite tracking status
This commit is contained in:
parent
0a4113031b
commit
9cdc072cc3
File diff suppressed because it is too large
Load Diff
@ -193,10 +193,13 @@
|
||||
|
||||
#define DBG_BACKSLASH_GT_CMD 240
|
||||
#define DBG_BACKSLASH_GC_CMD 241
|
||||
|
||||
#define DBG_CHECK_BUTTONS_SATELLITE 244
|
||||
#define DBG_SERVICE_MOON_CLI_CMD 245
|
||||
#define DBG_SERVICE_SUN_CLI_CMD 246
|
||||
#define DBG_SERVICE_SATELLITE_CLI_CMD 247
|
||||
#define DBG_SERVICE_SATELLITE_TRACKING 248
|
||||
#define DBG_NEXTION_DATA_ENT_ENTER_PUSH_CALLBK 249
|
||||
#define DBG_NEXTION_BUTTON 250
|
||||
|
||||
#define DBG_CHECK_BUTTONS_SUN 251
|
||||
#define DBG_CHECK_BUTTONS_MOON 252
|
||||
#define DBG_SERVICE_SUN_TRACKING 253
|
||||
|
@ -66,4 +66,5 @@
|
||||
// #define DEBUG_NEXTION_DISPLAY_SERIAL_RECV
|
||||
// #define DEBUG_TEST_POLAR_TO_CARTESIAN
|
||||
// #define DEBUG_SATELLITE_TRACKING
|
||||
#define DEBUG_SATELLITE_TRACKING_CALC
|
||||
|
||||
|
@ -231,3 +231,9 @@
|
||||
#endif
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
||||
|
||||
|
@ -101,3 +101,8 @@
|
||||
#endif
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
@ -182,4 +182,9 @@
|
||||
#define pin_audible_alert 0
|
||||
#endif
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
@ -196,4 +196,10 @@
|
||||
#define pin_audible_alert 0
|
||||
#endif
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
||||
|
||||
|
@ -242,3 +242,8 @@
|
||||
#endif
|
||||
|
||||
#define pin_status_led A8 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
@ -214,3 +214,8 @@
|
||||
#endif
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
||||
|
@ -207,3 +207,7 @@
|
||||
|
||||
//#define pin_status_led 0 // Status LED - blinks when there is rotation in progress
|
||||
|
||||
// Added 2020.07.24.01
|
||||
#define satellite_tracking_active_pin 0
|
||||
#define satellite_tracking_activate_line 0
|
||||
#define satellite_tracking_button 0 // use with a normally open momentary switch to ground
|
||||
|
@ -354,3 +354,11 @@ You can tweak these, but read the online documentation!
|
||||
|
||||
// Added in 2020.07.22.02
|
||||
#define DEFAULT_ALTITUDE_M 50
|
||||
|
||||
// Added in 2020.07.24.01
|
||||
#define SATELLITE_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
#define SATELLITE_TRACKING_UPDATE_INTERVAL 5000
|
||||
#define SATELLITE_AOS_AZIMUTH_MIN 0
|
||||
#define SATELLITE_AOS_AZIMUTH_MAX 360
|
||||
#define SATELLITE_AOS_ELEVATION_MIN 0
|
||||
#define SATELLITE_AOS_ELEVATION_MAX 180
|
@ -350,3 +350,11 @@ You can tweak these, but read the online documentation!
|
||||
|
||||
// Added in 2020.07.22.02
|
||||
#define DEFAULT_ALTITUDE_M 50
|
||||
|
||||
// Added in 2020.07.24.01
|
||||
#define SATELLITE_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
#define SATELLITE_TRACKING_UPDATE_INTERVAL 5000
|
||||
#define SATELLITE_AOS_AZIMUTH_MIN 0
|
||||
#define SATELLITE_AOS_AZIMUTH_MAX 360
|
||||
#define SATELLITE_AOS_ELEVATION_MIN 0
|
||||
#define SATELLITE_AOS_ELEVATION_MAX 180
|
||||
|
@ -346,4 +346,12 @@ You can tweak these, but read the online documentation!
|
||||
#define MOON_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
|
||||
// Added in 2020.07.22.02
|
||||
#define DEFAULT_ALTITUDE_M 50
|
||||
#define DEFAULT_ALTITUDE_M 50
|
||||
|
||||
// Added in 2020.07.24.01
|
||||
#define SATELLITE_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
#define SATELLITE_TRACKING_UPDATE_INTERVAL 5000
|
||||
#define SATELLITE_AOS_AZIMUTH_MIN 0
|
||||
#define SATELLITE_AOS_AZIMUTH_MAX 360
|
||||
#define SATELLITE_AOS_ELEVATION_MIN 0
|
||||
#define SATELLITE_AOS_ELEVATION_MAX 180
|
@ -366,6 +366,14 @@ You can tweak these, but read the online documentation!
|
||||
// Added in 2020.07.22.02
|
||||
#define DEFAULT_ALTITUDE_M 500
|
||||
|
||||
// Added in 2020.07.24.01
|
||||
#define SATELLITE_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
#define SATELLITE_TRACKING_UPDATE_INTERVAL 5000
|
||||
#define SATELLITE_AOS_AZIMUTH_MIN 0
|
||||
#define SATELLITE_AOS_AZIMUTH_MAX 360
|
||||
#define SATELLITE_AOS_ELEVATION_MIN 0
|
||||
#define SATELLITE_AOS_ELEVATION_MAX 180
|
||||
|
||||
|
||||
|
||||
// ######## ######## ###### ########
|
||||
|
@ -349,4 +349,12 @@ You can tweak these, but read the online documentation!
|
||||
|
||||
// Added in 2020.07.22.02
|
||||
#define DEFAULT_ALTITUDE_M 50
|
||||
|
||||
// Added in 2020.07.24.01
|
||||
#define SATELLITE_UPDATE_POSITION_INTERVAL_MS 5000
|
||||
#define SATELLITE_TRACKING_UPDATE_INTERVAL 5000
|
||||
#define SATELLITE_AOS_AZIMUTH_MIN 0
|
||||
#define SATELLITE_AOS_AZIMUTH_MAX 360
|
||||
#define SATELLITE_AOS_ELEVATION_MIN 0
|
||||
#define SATELLITE_AOS_ELEVATION_MAX 180
|
||||
|
456
libraries/P13/P13.cpp
Executable file
456
libraries/P13/P13.cpp
Executable file
@ -0,0 +1,456 @@
|
||||
//
|
||||
// P13.cpp
|
||||
//
|
||||
// An implementation of Plan13 in C++ by Mark VandeWettering
|
||||
//
|
||||
// Plan13 is an algorithm for satellite orbit prediction first formulated
|
||||
// by James Miller G3RUH. I learned about it when I saw it was the basis
|
||||
// of the PIC based antenna rotator project designed by G6LVB.
|
||||
//
|
||||
// http://www.g6lvb.com/Articles/LVBTracker2/index.htm
|
||||
//
|
||||
// I ported the algorithm to Python, and it was my primary means of orbit
|
||||
// prediction for a couple of years while I operated the "Easy Sats" with
|
||||
// a dual band hand held and an Arrow antenna.
|
||||
//
|
||||
// I've long wanted to redo the work in C++ so that I could port the code
|
||||
// to smaller processors including the Atmel AVR chips. Bruce Robertson,
|
||||
// VE9QRP started the qrpTracker project to fufill many of the same goals,
|
||||
// but I thought that the code could be made more compact and more modular,
|
||||
// and could serve not just the embedded targets but could be of more
|
||||
// use for more general applications. And, I like the BSD License a bit
|
||||
// better too.
|
||||
//
|
||||
// So, here it is!
|
||||
//
|
||||
|
||||
#include "P13.h"
|
||||
|
||||
double
|
||||
RADIANS(double deg)
|
||||
{
|
||||
return deg * M_PI / 180. ;
|
||||
}
|
||||
|
||||
double
|
||||
DEGREES(double rad)
|
||||
{
|
||||
return rad * 180. / M_PI ;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// _ ___ _ _____ _
|
||||
// __| |__ _ ______ | \ __ _| |_ __|_ _(_)_ __ ___
|
||||
// / _| / _` (_-<_-< | |) / _` | _/ -_)| | | | ' \/ -_)
|
||||
// \__|_\__,_/__/__/ |___/\__,_|\__\___||_| |_|_|_|_\___|
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static long
|
||||
fnday(int y, int m, int d)
|
||||
{
|
||||
if (m < 3) {
|
||||
m += 12 ;
|
||||
y -- ;
|
||||
}
|
||||
return (long) (y * YM) + (long) ((m+1)*30.6f) + (long)d - 428L ;
|
||||
}
|
||||
|
||||
static void
|
||||
fndate(int &y, int &m, int &d, long dt)
|
||||
{
|
||||
dt += 428L ;
|
||||
y = (int) ((dt-122.1)/365.25) ;
|
||||
dt -= (long) (y*365.25) ;
|
||||
m = (int) (dt / 30.61) ;
|
||||
dt -= (long) (m*30.6) ;
|
||||
m -- ;
|
||||
if (m > 12) {
|
||||
m -= 12 ;
|
||||
y++ ;
|
||||
}
|
||||
d = dt ;
|
||||
}
|
||||
|
||||
SatDateTime::SatDateTime(int year, int month, int day, int h, int m, int s)
|
||||
{
|
||||
settime(year, month, day, h, m, s) ;
|
||||
}
|
||||
|
||||
|
||||
SatDateTime::SatDateTime(const SatDateTime &dt)
|
||||
{
|
||||
DN = dt.DN ;
|
||||
TN = dt.TN ;
|
||||
}
|
||||
|
||||
SatDateTime::SatDateTime()
|
||||
{
|
||||
DN = 0L ;
|
||||
TN = 0. ;
|
||||
}
|
||||
|
||||
void
|
||||
SatDateTime::gettime(int &year, int &month, int &day, int &h, int &m, int &s)
|
||||
{
|
||||
fndate(year, month, day, DN) ;
|
||||
double t = TN ;
|
||||
t *= 24. ;
|
||||
h = (int) t ;
|
||||
t -= h ;
|
||||
t *= 60 ;
|
||||
m = (int) t ;
|
||||
t -= m ;
|
||||
t *= 60 ;
|
||||
s = (int) t ;
|
||||
}
|
||||
|
||||
void
|
||||
SatDateTime::settime(int year, int month, int day, int h, int m, int s)
|
||||
{
|
||||
DN = fnday(year, month, day) ;
|
||||
TN = ((double) h + m / 60. + s / 3600.) / 24. ;
|
||||
}
|
||||
|
||||
void
|
||||
SatDateTime::ascii(char *buf)
|
||||
{
|
||||
int year, mon, day ;
|
||||
int h, m, s ;
|
||||
gettime(year, mon, day, h, m, s) ;
|
||||
sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", mon, day, year, h, m, s) ;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SatDateTime::add(double days)
|
||||
{
|
||||
TN += days ;
|
||||
DN += (long) TN ;
|
||||
TN -= (long) TN ;
|
||||
}
|
||||
|
||||
void
|
||||
SatDateTime::roundup(double t)
|
||||
{
|
||||
double inc = t-fmod(TN, t) ;
|
||||
TN += inc ;
|
||||
DN += (long) TN ;
|
||||
TN -= (long) TN ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// _ ___ _
|
||||
// __| |__ _ ______ / _ \| |__ ___ ___ _ ___ _____ _ _
|
||||
// / _| / _` (_-<_-< | (_) | '_ (_-</ -_) '_\ V / -_) '_|
|
||||
// \__|_\__,_/__/__/ \___/|_.__/__/\___|_| \_/\___|_|
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
Observer::Observer(const char *nm, double lat, double lng, double hgt)
|
||||
{
|
||||
this->name = nm ;
|
||||
LA = RADIANS(lat) ;
|
||||
LO = RADIANS(lng) ;
|
||||
HT = hgt / 1000 ;
|
||||
|
||||
U[0] = cos(LA)*cos(LO) ;
|
||||
U[1] = cos(LA)*sin(LO) ;
|
||||
U[2] = sin(LA) ;
|
||||
|
||||
E[0] = -sin(LO) ;
|
||||
E[1] = cos(LO) ;
|
||||
E[2] = 0. ;
|
||||
|
||||
N[0] = -sin(LA)*cos(LO) ;
|
||||
N[1] = -sin(LA)*sin(LO) ;
|
||||
N[2] = cos(LA) ;
|
||||
|
||||
double RP = RE * (1 - FL) ;
|
||||
double XX = RE * RE ;
|
||||
double ZZ = RP * RP ;
|
||||
double D = sqrt(XX*cos(LA)*cos(LA) +
|
||||
ZZ*sin(LA)*sin(LA)) ;
|
||||
double Rx = XX / D + HT ;
|
||||
double Rz = ZZ / D + HT ;
|
||||
|
||||
O[0] = Rx * U[0] ;
|
||||
O[1] = Rx * U[1] ;
|
||||
O[2] = Rz * U[2] ;
|
||||
|
||||
V[0] = -O[1] * W0 ;
|
||||
V[1] = O[0] * W0 ;
|
||||
V[2] = 0 ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// _ ___ _ _ _ _ _
|
||||
// __| |__ _ ______ / __| __ _| |_ ___| | (_) |_ ___
|
||||
// / _| / _` (_-<_-< \__ \/ _` | _/ -_) | | | _/ -_)
|
||||
// \__|_\__,_/__/__/ |___/\__,_|\__\___|_|_|_|\__\___|
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static double
|
||||
getdouble(const char *c, int i0, int i1)
|
||||
{
|
||||
char buf[20] ;
|
||||
int i ;
|
||||
for (i=0; i0+i<i1; i++)
|
||||
buf[i] = c[i0+i] ;
|
||||
buf[i] = '\0' ;
|
||||
return strtod(buf, NULL) ;
|
||||
}
|
||||
|
||||
static long
|
||||
getlong(const char *c, int i0, int i1)
|
||||
{
|
||||
char buf[20] ;
|
||||
int i ;
|
||||
for (i=0; i0+i<i1; i++)
|
||||
buf[i] = c[i0+i] ;
|
||||
buf[i] = '\0' ;
|
||||
return atol(buf) ;
|
||||
}
|
||||
|
||||
Satellite::Satellite(const char *nm, const char *l1, const char *l2)
|
||||
{
|
||||
tle(nm, l1, l2) ;
|
||||
}
|
||||
|
||||
Satellite::~Satellite()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Satellite::tle(const char *nm, const char *l1, const char *l2)
|
||||
{
|
||||
name = nm ;
|
||||
|
||||
// direct quantities from the orbital elements
|
||||
|
||||
N = getlong(l2, 2, 7) ;
|
||||
YE = getlong(l1, 18, 20) ;
|
||||
if (YE < 58)
|
||||
YE += 2000 ;
|
||||
else
|
||||
YE += 1900 ;
|
||||
|
||||
TE = getdouble(l1, 20, 32) ;
|
||||
M2 = RADIANS(getdouble(l1, 33, 43)) ;
|
||||
|
||||
IN = RADIANS(getdouble(l2, 8, 16)) ;
|
||||
RA = RADIANS(getdouble(l2, 17, 25)) ;
|
||||
EC = getdouble(l2, 26, 33)/1e7f ;
|
||||
WP = RADIANS(getdouble(l2, 34, 42)) ;
|
||||
MA = RADIANS(getdouble(l2, 43, 51)) ;
|
||||
MM = 2.0f * M_PI * getdouble(l2, 52, 63) ;
|
||||
RV = getlong(l2, 63, 68) ;
|
||||
|
||||
// derived quantities from the orbital elements
|
||||
|
||||
// convert TE to DE and TE
|
||||
DE = fnday(YE, 1, 0) + (long) TE ;
|
||||
TE -= (long) TE ;
|
||||
N0 = MM/86400 ;
|
||||
A_0 = pow(GM/(N0*N0), 1./3.) ;
|
||||
B_0 = A_0*sqrt(1.-EC*EC) ;
|
||||
PC = RE*A_0/(B_0*B_0) ;
|
||||
PC = 1.5f*J2*PC*PC*MM ;
|
||||
double CI = cos(IN) ;
|
||||
QD = -PC*CI ;
|
||||
WD = PC*(5*CI*CI-1)/2 ;
|
||||
DC = -2*M2/(3*MM) ;
|
||||
}
|
||||
void
|
||||
Satellite::predict(const SatDateTime &dt)
|
||||
{
|
||||
long DN = dt.DN ;
|
||||
double TN = dt.TN ;
|
||||
|
||||
float TEG = DE - fnday(YG, 1, 0) + TE ;
|
||||
|
||||
float GHAE = radians(G0) + TEG * WE ;
|
||||
float MRSE = radians(G0) + TEG * WW + M_PI ;
|
||||
float MASE = radians(MAS0 + TEG * MASD) ;
|
||||
|
||||
double T = (double) (DN - DE) + (TN-TE) ;
|
||||
double DT = DC * T / 2. ;
|
||||
double KD = 1. + 4. * DT ;
|
||||
double KDP = 1. - 7. * DT ;
|
||||
|
||||
double M = MA + MM * T * (1. - 3. * DT) ;
|
||||
double DR = (long) (M / (2. * M_PI)) ;
|
||||
M -= DR * 2. * M_PI ;
|
||||
double RN = RV + DR ;
|
||||
double EA = M ;
|
||||
|
||||
double DNOM, C_EA, S_EA ;
|
||||
|
||||
for (;;) {
|
||||
C_EA = cos(EA) ;
|
||||
S_EA = sin(EA) ;
|
||||
DNOM = 1. - EC * C_EA ;
|
||||
double D = (EA-EC*S_EA-M)/DNOM ;
|
||||
EA -= D ;
|
||||
if (fabs(D) < 1e-5)
|
||||
break ;
|
||||
}
|
||||
|
||||
double A = A_0 * KD ;
|
||||
double B = B_0 * KD ;
|
||||
RS = A * DNOM ;
|
||||
|
||||
double Vx, Vy ;
|
||||
double Sx, Sy ;
|
||||
Sx = A * (C_EA - EC) ;
|
||||
Sy = B * S_EA ;
|
||||
|
||||
Vx = -A * S_EA / DNOM * N0 ;
|
||||
Vy = B * C_EA / DNOM * N0 ;
|
||||
|
||||
double AP = WP + WD * T * KDP ;
|
||||
double CW = cos(AP) ;
|
||||
double SW = sin(AP) ;
|
||||
|
||||
double RAAN = RA + QD * T * KDP ;
|
||||
|
||||
double CQ = cos(RAAN) ;
|
||||
double SQ = sin(RAAN) ;
|
||||
|
||||
double CI = cos(IN) ;
|
||||
double SI = sin(IN) ;
|
||||
|
||||
// CX, CY, and CZ form a 3x3 matrix
|
||||
// that converts between orbit coordinates,
|
||||
// and celestial coordinates.
|
||||
|
||||
Vec3 CX, CY, CZ ;
|
||||
|
||||
CX[0] = CW * CQ - SW * CI * SQ ;
|
||||
CX[1] = -SW * CQ - CW * CI * SQ ;
|
||||
CX[2] = SI * SQ ;
|
||||
|
||||
CY[0] = CW * SQ + SW * CI * CQ ;
|
||||
CY[1] = -SW * SQ + CW * CI * CQ ;
|
||||
CY[2] = -SI * CQ ;
|
||||
|
||||
CZ[0] = SW * SI ;
|
||||
CZ[1] = CW * SI ;
|
||||
CZ[2] = CI ;
|
||||
|
||||
// satellite in celestial coords
|
||||
|
||||
SAT[0] = Sx * CX[0] + Sy * CX[1] ;
|
||||
SAT[1] = Sx * CY[0] + Sy * CY[1] ;
|
||||
SAT[2] = Sx * CZ[0] + Sy * CZ[1] ;
|
||||
|
||||
VEL[0] = Vx * CX[0] + Vy * CX[1] ;
|
||||
VEL[1] = Vx * CY[0] + Vy * CY[1] ;
|
||||
VEL[2] = Vx * CZ[0] + Vy * CZ[1] ;
|
||||
|
||||
// and in geocentric coordinates
|
||||
|
||||
double GHAA = (GHAE + WE * T) ;
|
||||
double CG = cos(-GHAA) ;
|
||||
double SG = sin(-GHAA) ;
|
||||
|
||||
S[0] = SAT[0] * CG - SAT[1] * SG ;
|
||||
S[1] = SAT[0] * SG + SAT[1] * CG ;
|
||||
S[2] = SAT[2] ;
|
||||
|
||||
V[0] = VEL[0] * CG - VEL[1]* SG ;
|
||||
V[1] = VEL[0] * SG + VEL[1]* CG ;
|
||||
V[2] = VEL[2] ;
|
||||
}
|
||||
|
||||
void
|
||||
Satellite::LL(double &lat, double &lng)
|
||||
{
|
||||
lat = DEGREES(asin(S[2]/RS)) ;
|
||||
lng = DEGREES(atan2(S[1], S[0])) ;
|
||||
}
|
||||
|
||||
void
|
||||
Satellite::altaz(const Observer &obs, double &alt, double &az)
|
||||
{
|
||||
Vec3 R ;
|
||||
R[0] = S[0] - obs.O[0] ;
|
||||
R[1] = S[1] - obs.O[1] ;
|
||||
R[2] = S[2] - obs.O[2] ;
|
||||
double r = sqrt(R[0]*R[0]+R[1]*R[1]+R[2]*R[2]) ;
|
||||
R[0] /= r ;
|
||||
R[1] /= r ;
|
||||
R[2] /= r ;
|
||||
|
||||
double u = R[0] * obs.U[0] + R[1] * obs.U[1] + R[2] * obs.U[2] ;
|
||||
double e = R[0] * obs.E[0] + R[1] * obs.E[1] + R[2] * obs.E[2] ;
|
||||
double n = R[0] * obs.N[0] + R[1] * obs.N[1] + R[2] * obs.N[2] ;
|
||||
|
||||
az = DEGREES(atan2(e, n)) ;
|
||||
if (az < 0.) az += 360. ;
|
||||
alt = DEGREES(asin(u)) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
Sun::Sun()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Sun::predict(const SatDateTime &dt)
|
||||
{
|
||||
long DN = dt.DN ;
|
||||
double TN = dt.TN ;
|
||||
|
||||
double T = (double) (DN - fnday(YG, 1, 0)) + TN ;
|
||||
double GHAE = RADIANS(G0) + T * WE ;
|
||||
double MRSE = RADIANS(G0) + T * WW + M_PI ;
|
||||
double MASE = RADIANS(MAS0 + T * MASD) ;
|
||||
double TAS = MRSE + EQC1*sin(MASE) + EQC2*sin(2.*MASE) ;
|
||||
double C, S ;
|
||||
|
||||
C = cos(TAS) ;
|
||||
S = sin(TAS) ;
|
||||
SUN[0]=C ;
|
||||
SUN[1]=S*CNS ;
|
||||
SUN[2]=S*SNS ;
|
||||
C = cos(-GHAE) ;
|
||||
S = sin(-GHAE) ;
|
||||
H[0]=SUN[0]*C - SUN[1]*S ;
|
||||
H[1]=SUN[0]*S + SUN[1]*C ;
|
||||
H[2]=SUN[2] ;
|
||||
}
|
||||
|
||||
void
|
||||
Sun::LL(double &lat, double &lng)
|
||||
{
|
||||
lat = DEGREES(asin(H[2])) ;
|
||||
lng = DEGREES(atan2(H[1], H[0])) ;
|
||||
}
|
||||
|
||||
// oops.... this is broken.
|
||||
|
||||
void
|
||||
Sun::altaz(const Observer &obs, double &alt, double &az)
|
||||
{
|
||||
Vec3 R ;
|
||||
|
||||
R[0] = H[0] - obs.O[0] ;
|
||||
R[1] = H[1] - obs.O[1] ;
|
||||
R[2] = H[2] - obs.O[2] ;
|
||||
double r = sqrt(R[0]*R[0]+R[1]*R[1]+R[2]*R[2]) ;
|
||||
R[0] /= r ;
|
||||
R[1] /= r ;
|
||||
R[2] /= r ;
|
||||
|
||||
double u = R[0] * obs.U[0] + R[1] * obs.U[1] + R[2] * obs.U[2] ;
|
||||
double e = R[0] * obs.E[0] + R[1] * obs.E[1] + R[2] * obs.E[2] ;
|
||||
double n = R[0] * obs.N[0] + R[1] * obs.N[1] + R[2] * obs.N[2] ;
|
||||
|
||||
az = DEGREES(atan2(e, n)) ;
|
||||
if (az < 0.) az += 360. ;
|
||||
alt = DEGREES(asin(u)) ;
|
||||
}
|
195
libraries/P13/P13.h
Executable file
195
libraries/P13/P13.h
Executable file
@ -0,0 +1,195 @@
|
||||
//
|
||||
// Plan13.cpp
|
||||
//
|
||||
// An implementation of Plan13 in C++ by Mark VandeWettering
|
||||
//
|
||||
// Plan13 is an algorithm for satellite orbit prediction first formulated
|
||||
// by James Miller G3RUH. I learned about it when I saw it was the basis
|
||||
// of the PIC based antenna rotator project designed by G6LVB.
|
||||
//
|
||||
// http://www.g6lvb.com/Articles/LVBTracker2/index.htm
|
||||
//
|
||||
// I ported the algorithm to Python, and it was my primary means of orbit
|
||||
// prediction for a couple of years while I operated the "Easy Sats" with
|
||||
// a dual band hand held and an Arrow antenna.
|
||||
//
|
||||
// I've long wanted to redo the work in C++ so that I could port the code
|
||||
// to smaller processors including the Atmel AVR chips. Bruce Robertson,
|
||||
// VE9QRP started the qrpTracker project to fufill many of the same goals,
|
||||
// but I thought that the code could be made more compact and more modular,
|
||||
// and could serve not just the embedded targets but could be of more
|
||||
// use for more general applications. And, I like the BSD License a bit
|
||||
// better too.
|
||||
//
|
||||
// So, here it is!
|
||||
//
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2011, Mark VandeWettering. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY MARK VANDEWETTERING ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of Mark VandeWettering
|
||||
|
||||
*/
|
||||
|
||||
// Modification by Anthony Good, K3NG 2020-07-24: Change DateTime to SatDateTime to avoid a conflict with an RTC library I'm using
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
// here are a bunch of constants that will be used throughout the
|
||||
// code, but which will probably not be helpful outside.
|
||||
|
||||
static const double RE = 6378.137f ;
|
||||
static const double FL = 1.f/298.257224f ;
|
||||
static const double GM = 3.986E5f ;
|
||||
static const double J2 = 1.08263E-3f ;
|
||||
static const double YM = 365.25f ;
|
||||
static const double YT = 365.2421874f ;
|
||||
static const double WW = 2.f*M_PI/YT ;
|
||||
static const double WE = 2.f*M_PI+ WW ;
|
||||
static const double W0 = WE/86400.f ;
|
||||
|
||||
|
||||
static const double YG = 2014.f;
|
||||
static const double G0 = 99.5828f;
|
||||
static const double MAS0 = 356.4105f;
|
||||
static const double MASD = 0.98560028f;
|
||||
static const double EQC1 = 0.03340;
|
||||
static const double EQC2 = 0.00035;
|
||||
static const double INS = radians(23.4375f);
|
||||
|
||||
// static const double YG = 2000.f ;
|
||||
// static const double G0 = 98.9821f ;
|
||||
// static const double MAS0 = 356.0507f ;
|
||||
// static const double MASD = 0.98560028f ;
|
||||
// static const double EQC1 = 0.03342 ;
|
||||
// static const double EQC2 = 0.00035 ;
|
||||
// static const double INS = radians(23.4393f) ;
|
||||
|
||||
static const double CNS = cos(INS) ;
|
||||
static const double SNS = sin(INS) ;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// the original BASIC code used three variables (e.g. Ox, Oy, Oz) to
|
||||
// represent a vector quantity. I think that makes for slightly more
|
||||
// obtuse code, so I going to collapse them into a single variable
|
||||
// which is an array of three elements
|
||||
|
||||
typedef double Vec3[3] ;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class SatDateTime {
|
||||
public:
|
||||
long DN ;
|
||||
double TN ;
|
||||
SatDateTime(int year, int month, int day, int h, int m, int s) ;
|
||||
SatDateTime(const SatDateTime &) ;
|
||||
SatDateTime() ;
|
||||
~SatDateTime() { }
|
||||
void add(double) ;
|
||||
void settime(int year, int month, int day, int h, int m, int s) ;
|
||||
void gettime(int& year, int& mon, int& day, int& h, int& m, int& s) ;
|
||||
void ascii(char *) ;
|
||||
void roundup(double) ;
|
||||
} ;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
const char *name ;
|
||||
double LA ;
|
||||
double LO ;
|
||||
double HT ;
|
||||
Vec3 U, E, N, O, V ;
|
||||
|
||||
Observer(const char *, double, double, double) ;
|
||||
~Observer() { } ;
|
||||
} ;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
class Satellite {
|
||||
long N ;
|
||||
long YE ;
|
||||
long DE ;
|
||||
double TE ;
|
||||
double IN ;
|
||||
double RA ;
|
||||
double EC ;
|
||||
double WP ;
|
||||
double MA ;
|
||||
double MM ;
|
||||
double M2 ;
|
||||
double RV ;
|
||||
double ALON ;
|
||||
double ALAT ;
|
||||
|
||||
|
||||
// these values are stored, but could be calculated on the fly
|
||||
// during calls to predict()
|
||||
// classic space/time tradeoff
|
||||
|
||||
double N0, A_0, B_0 ;
|
||||
double PC ;
|
||||
double QD, WD, DC ;
|
||||
double RS ;
|
||||
|
||||
public:
|
||||
const char *name ;
|
||||
Vec3 SAT, VEL ; // celestial coordinates
|
||||
Vec3 S, V ; // geocentric coordinates
|
||||
|
||||
Satellite() { } ;
|
||||
Satellite(const char *name, const char *l1, const char *l2) ;
|
||||
~Satellite() ;
|
||||
void tle(const char *name, const char *l1, const char *l2) ;
|
||||
void predict(const SatDateTime &dt) ;
|
||||
void LL(double &lat, double &lng) ;
|
||||
void altaz(const Observer &obs, double &alt, double &az) ;
|
||||
} ;
|
||||
|
||||
class Sun {
|
||||
public:
|
||||
Vec3 SUN, H ;
|
||||
Sun() ;
|
||||
~Sun() { } ;
|
||||
void predict(const SatDateTime &dt) ;
|
||||
void LL(double &lat, double &lng) ;
|
||||
void altaz(const Observer &obs, double &alt, double &az) ;
|
||||
} ;
|
108
libraries/P13/README
Executable file
108
libraries/P13/README
Executable file
@ -0,0 +1,108 @@
|
||||
_ The Arduino n' Gameduino
|
||||
__ _ _ _ __ _ __| |_ Satellite Tracker
|
||||
/ _` | ' \/ _` (_-< _|
|
||||
\__,_|_||_\__, /__/\__| Written by Mark VandeWettering, K6HX, 2011
|
||||
|___/ brainwagon@gmail.com
|
||||
|
||||
|
||||
Angst is an application that I wrote for the Arduino and Gameduino. It
|
||||
is being distributed under the so-called "2-class BSD License", which I
|
||||
think grants potential users the greatest possible freedom to integrate
|
||||
this code into their own projects. I would, however, consider it a great
|
||||
courtesy if you could email me and tell me about your project and how
|
||||
this code was used, just for my own continued personal gratification.
|
||||
|
||||
Angst includes P13, a port of the Plan 13 algorithm, originally written
|
||||
by James Miller, G3RUH and documented here:
|
||||
|
||||
http://www.amsat.org/amsat/articles/g3ruh/111.html
|
||||
|
||||
Other implementations exist, even for embedded platforms, such as
|
||||
the qrpTracker library of Bruce Robertson, VE9QRP and G6LVB's PIC
|
||||
implementation that is part of his embedded satellite tracker. My own
|
||||
code was ported from a quick and dirty Python implementation of my own,
|
||||
and retains a bit of the object orientation that I imposed in that code.
|
||||
|
||||
While the P13 library is reasonably independent and can be used in
|
||||
other applications, the remainder of the code is fairly specific to the
|
||||
particular hardware I had on hand:
|
||||
|
||||
1. The Gameduino
|
||||
|
||||
James Bowman developed the Gameduino as an Arduino shield to
|
||||
generate sound and graphics which might have been typical of
|
||||
8 bit computers of the 1980s. It consists of a Xilinx FPGA,
|
||||
programmed with a version of his J1 Forth processor, and
|
||||
generates video and sound. It is programmed from the Arduino
|
||||
using a simple set of commands sent over the I2C bus.
|
||||
|
||||
You can find more information here:
|
||||
|
||||
http://excamera.com/sphinx/gameduino/
|
||||
|
||||
2. A DS1307 RTC
|
||||
|
||||
Sparkfun has a Dallas Semiconductor DS1307 chip mounted on a
|
||||
handly little breakout board. I used this chip to keep track
|
||||
of time. It's not particularly great: it drifts by a couple
|
||||
of minutes a week in my prototype: a better and more accurate
|
||||
timepiece would enhance the usability of this prototype. I've
|
||||
considered using a GPS to keep track of time, that extension is
|
||||
left as an exercise for the motivated reader.
|
||||
|
||||
3. An AT24C1024 Serial EEPROM
|
||||
|
||||
The ATMEGA328 used in the Arduino contains a mere 512 bytes of
|
||||
EEPROM. This is enough space to store a few satellites, but I
|
||||
wanted to have greater capacitity. So, I got some 128K byte
|
||||
EEPROMS for about $4 from digikey. Each one of these can store
|
||||
the data for about 750 satellites. My prototype just uses one,
|
||||
but it's possible to chain up to four of them together.
|
||||
|
||||
4. A Rotary Encoder
|
||||
|
||||
The entire interface is driven from a single rotary encoder w/
|
||||
a built in switch, similar to this one:
|
||||
|
||||
http://www.sparkfun.com/products/9117
|
||||
|
||||
The code turns on the necessary internal pullup resistors to
|
||||
allow it to be directly wired to the Arduino input pins.
|
||||
|
||||
Currently the encoder is read in the polling main event loop.
|
||||
This means that quick motion of the encoder is not adequately
|
||||
tracked: consider this another exercise for the motivated
|
||||
reader.
|
||||
|
||||
|
||||
I hope you enjoy the code, and find it useful and/or informative!
|
||||
|
||||
Copyright 2011, Mark VandeWettering. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY MARK VANDEWETTERING ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of Mark VandeWettering
|
Loading…
x
Reference in New Issue
Block a user