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:
Anthony Good 2020-07-24 21:24:34 -04:00
parent 0a4113031b
commit 9cdc072cc3
18 changed files with 1097 additions and 809 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
// ######## ######## ###### ########

View File

@ -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
View 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
View 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
View 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