Satellite Tracker updates.

Add support for replaying of passes in the past, where current time is
determined from File Input device.
Add latitude and longitude to satellite data table.
Update ground track generation to better work with 3D map.
Add support for 3D models.
Add Cubesat image for 2D map.
Send LOS to other plugins, when no device settings are setup.
Pass TLEs to other plugins, so they can use a consistent copy for
replays.
This commit is contained in:
Jon Beniston 2022-02-04 17:14:12 +00:00
parent 635dbe4571
commit 04aed0b3b3
18 changed files with 296 additions and 53 deletions

View File

@ -81,3 +81,8 @@ if(WIN32)
include(DeployQt)
windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/aprs)
endif()
# Install debug symbols
if (WIN32)
install(FILES $<TARGET_PDB_FILE:${TARGET_NAME}> CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} )
endif()

View File

@ -103,6 +103,8 @@ On the Settings tab, you can set:
On the TLEs tab, you can provide a list of URL from which satellite Two Line Element files can be downloaded from.
TLE files contain the orbital parameters for a satellite and are required in order to be able to calculate a satellites position.
TLEs for may satellites can be obtained from https://www.celestrak.com/NORAD/elements/
To use a TLE file on a local disk, use a URL such as file:my_tle.txt
![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_settingsdialog3.png)

View File

@ -31,6 +31,8 @@
#include "dsp/dspengine.h"
#include "util/httpdownloadmanager.h"
#include "settings/serializable.h"
#include "channel/channelwebapiutils.h"
#include "feature/featurewebapiutils.h"
#include "satellitetrackerworker.h"
#include "satellitetracker.h"
@ -76,6 +78,14 @@ void SatelliteTracker::start()
{
qDebug("SatelliteTracker::start");
if (m_settings.m_replayEnabled)
{
m_startedDateTime = QDateTime::currentDateTimeUtc();
if (m_settings.m_sendTimeToMap) {
FeatureWebAPIUtils::mapSetDateTime(currentDateTime());
}
}
m_worker->reset();
m_worker->setMessageQueueToFeature(getInputMessageQueue());
m_worker->setMessageQueueToGUI(getMessageQueueToGUI());
@ -1066,18 +1076,40 @@ void SatelliteTracker::updateSatData()
qDebug() << "SatelliteTracker::updateSatData: update in progress";
}
// Redirect requests for current time via these methods, so it can be adjusted when testing
/// Redirect requests for current time via these methods, for replays
QDateTime SatelliteTracker::currentDateTimeUtc()
{
QDateTime now = QDateTime::currentDateTimeUtc();
//now = now.addSecs(26*60);
return now;
if (m_settings.m_replayEnabled)
{
if (m_settings.m_useFileInputTime)
{
QString dateTimeStr;
if (ChannelWebAPIUtils::getDeviceReportValue(0, "absoluteTime", dateTimeStr))
{
return QDateTime::fromString(dateTimeStr, Qt::ISODateWithMs);
}
else
{
return QDateTime::currentDateTimeUtc();
}
}
else
{
QDateTime now = QDateTime::currentDateTimeUtc();
return m_settings.m_replayStartDateTime.addSecs(m_startedDateTime.secsTo(now));
}
}
else
{
return QDateTime::currentDateTimeUtc();
}
}
QDateTime SatelliteTracker::currentDateTime()
{
QDateTime now = QDateTime::currentDateTime();
//now = now.addSecs(26*60);
return now;
if (m_settings.m_replayEnabled) {
return currentDateTimeUtc().toLocalTime();
} else {
return QDateTime::currentDateTime();
}
}

View File

@ -162,8 +162,8 @@ public:
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response);
static QDateTime currentDateTimeUtc();
static QDateTime currentDateTime();
QDateTime currentDateTimeUtc();
QDateTime currentDateTime();
static const char* const m_featureIdURI;
static const char* const m_featureId;
@ -186,6 +186,8 @@ private:
QHash<int, SatNogsSatellite *> m_satellitesId; // Same data as m_satellites, but hashed on id, rather than name
bool m_firstUpdateSatData;
QDateTime m_startedDateTime;
void start();
void stop();
void applySettings(const SatelliteTrackerSettings& settings, bool force = false);

View File

@ -2,5 +2,6 @@
<qresource prefix="/satellitetracker/">
<file>satellitetracker/iss-32.png</file>
<file>satellitetracker/satellite-32.png</file>
<file>satellitetracker/cubesat-32.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

View File

@ -268,7 +268,7 @@ SatelliteTrackerGUI::SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *fea
ui->passChart->setChart(&m_emptyChart);
ui->passChart->setRenderHint(QPainter::Antialiasing);
ui->dateTime->setDateTime(SatelliteTracker::currentDateTime());
ui->dateTime->setDateTime(m_satelliteTracker->currentDateTime());
// Use My Position from preferences, if none set
if ((m_settings.m_latitude == 0.0) && (m_settings.m_longitude == 0.0)) {
@ -604,7 +604,7 @@ void SatelliteTrackerGUI::updateTimeToAOS()
ui->aos->setText("Now");
else if (m_nextTargetAOS.isValid())
{
QDateTime currentTime = SatelliteTracker::currentDateTime();
QDateTime currentTime = m_satelliteTracker->currentDateTime(); // FIXME: UTC
int secondsToAOS = m_nextTargetAOS.toSecsSinceEpoch() - currentTime.toSecsSinceEpoch();
if (secondsToAOS > 0)
{
@ -833,7 +833,7 @@ void SatelliteTrackerGUI::plotPolarChart()
QDateTime currentTime;
if (m_settings.m_dateTime == "")
currentTime = SatelliteTracker::currentDateTimeUtc();
currentTime = m_satelliteTracker->currentDateTimeUtc();
else if (m_settings.m_utc)
currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
else
@ -863,7 +863,7 @@ void SatelliteTrackerGUI::plotPolarChart()
// Possibly geostationary, just plot current position
QDateTime currentTime;
if (m_settings.m_dateTime == "")
currentTime = SatelliteTracker::currentDateTimeUtc();
currentTime = m_satelliteTracker->currentDateTimeUtc();
else if (m_settings.m_utc)
currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
else
@ -1004,6 +1004,8 @@ void SatelliteTrackerGUI::resizeTable()
ui->satTable->setItem(row, SAT_COL_LOS, new QTableWidgetItem("+1 10:17"));
ui->satTable->setItem(row, SAT_COL_MAX_EL, new QTableWidgetItem("90"));
ui->satTable->setItem(row, SAT_COL_DIR, new QTableWidgetItem("^"));
ui->satTable->setItem(row, SAT_COL_LATITUDE, new QTableWidgetItem("-90.0"));
ui->satTable->setItem(row, SAT_COL_LONGITUDE, new QTableWidgetItem("-180.0"));
ui->satTable->setItem(row, SAT_COL_ALT, new QTableWidgetItem("50000"));
ui->satTable->setItem(row, SAT_COL_RANGE, new QTableWidgetItem("50000"));
ui->satTable->setItem(row, SAT_COL_RANGE_RATE, new QTableWidgetItem("10.0"));
@ -1125,7 +1127,8 @@ void SatelliteTrackerGUI::updateTable(SatelliteState *satState)
}
// Text alignment
for( int col : {SAT_COL_AZ, SAT_COL_EL, SAT_COL_TNE, SAT_COL_DUR, SAT_COL_MAX_EL,
for (int col : {SAT_COL_AZ, SAT_COL_EL, SAT_COL_TNE, SAT_COL_DUR, SAT_COL_MAX_EL,
SAT_COL_LATITUDE, SAT_COL_LONGITUDE,
SAT_COL_ALT, SAT_COL_RANGE, SAT_COL_RANGE_RATE, SAT_COL_DOPPLER,
SAT_COL_PATH_LOSS, SAT_COL_DELAY})
items[col]->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
@ -1143,7 +1146,7 @@ void SatelliteTrackerGUI::updateTable(SatelliteState *satState)
if (satState->m_passes.size() > 0)
{
// Get number of days to AOS/LOS
QDateTime currentDateTime = QDateTime::currentDateTime();
QDateTime currentDateTime = m_satelliteTracker->currentDateTime();
int daysToAOS = currentDateTime.daysTo(satState->m_passes[0]->m_aos);
int daysToLOS = currentDateTime.daysTo(satState->m_passes[0]->m_los);
if( satState->m_passes[ 0 ]->m_aos > currentDateTime )
@ -1170,6 +1173,8 @@ void SatelliteTrackerGUI::updateTable(SatelliteState *satState)
items[SAT_COL_MAX_EL]->setData(Qt::DisplayRole, QVariant());
items[SAT_COL_DIR]->setText("");
}
items[SAT_COL_LATITUDE]->setData(Qt::DisplayRole, satState->m_latitude);
items[SAT_COL_LONGITUDE]->setData(Qt::DisplayRole, satState->m_longitude);
items[SAT_COL_ALT]->setData(Qt::DisplayRole, (int)round(satState->m_altitude));
items[SAT_COL_RANGE]->setData(Qt::DisplayRole, (int)round(satState->m_range));
items[SAT_COL_RANGE_RATE]->setData(Qt::DisplayRole, QString::number(satState->m_rangeRate, 'f', 3));
@ -1184,6 +1189,7 @@ void SatelliteTrackerGUI::on_satTable_cellDoubleClicked(int row, int column)
QString sat = ui->satTable->item(row, SAT_COL_NAME)->text();
FeatureWebAPIUtils::mapFind(sat);
}
// Columns in table reordered

View File

@ -93,6 +93,8 @@ private:
SAT_COL_LOS,
SAT_COL_MAX_EL,
SAT_COL_DIR,
SAT_COL_LATITUDE,
SAT_COL_LONGITUDE,
SAT_COL_ALT,
SAT_COL_RANGE,
SAT_COL_RANGE_RATE,

View File

@ -628,6 +628,16 @@
<string>Direction of the next pass</string>
</property>
</column>
<column>
<property name="text">
<string>Latitude (°)</string>
</property>
</column>
<column>
<property name="text">
<string>Longitude (°)</string>
</property>
</column>
<column>
<property name="text">
<string>Alt (km)</string>

View File

@ -73,7 +73,9 @@ void SatelliteTrackerSettings::resetToDefaults()
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
m_chartsDarkTheme = true;
m_replayEnabled = false;
m_useFileInputTime = true;
m_sendTimeToMap = true;
for (int i = 0; i < SAT_COL_COLUMNS; i++)
{
m_columnIndexes[i] = i;
@ -121,10 +123,13 @@ QByteArray SatelliteTrackerSettings::serialize() const
s.writeU32(34, m_reverseAPIFeatureSetIndex);
s.writeU32(35, m_reverseAPIFeatureIndex);
s.writeBool(36, m_chartsDarkTheme);
if (m_rollupState) {
s.writeBlob(37, m_rollupState->serialize());
}
s.writeBool(38, m_replayEnabled);
s.writeString(39, m_replayStartDateTime.toString(Qt::ISODate));
s.writeBool(40, m_useFileInputTime);
s.writeBool(41, m_sendTimeToMap);
for (int i = 0; i < SAT_COL_COLUMNS; i++) {
s.writeS32(100 + i, m_columnIndexes[i]);
@ -204,12 +209,16 @@ bool SatelliteTrackerSettings::deserialize(const QByteArray& data)
d.readU32(35, &utmp, 0);
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
d.readBool(36, &m_chartsDarkTheme, true);
if (m_rollupState)
{
d.readBlob(37, &bytetmp);
m_rollupState->deserialize(bytetmp);
}
d.readBool(38, &m_replayEnabled, false);
d.readString(39, &strtmp);
m_replayStartDateTime = QDateTime::fromString(strtmp, Qt::ISODate);
d.readBool(40, &m_useFileInputTime, true);
d.readBool(41, &m_sendTimeToMap, true);
for (int i = 0; i < SAT_COL_COLUMNS; i++) {
d.readS32(100 + i, &m_columnIndexes[i], i);

View File

@ -27,7 +27,7 @@
class Serializable;
#define SAT_COL_COLUMNS 16
#define SAT_COL_COLUMNS 18
struct SatelliteTrackerSettings
{
@ -76,6 +76,10 @@ struct SatelliteTrackerSettings
QString m_losCommand; //!< Command/script to execute on LOS
bool m_chartsDarkTheme; //!< Set dark theme for charts (effective for GUI only)
QHash<QString, QList<SatelliteDeviceSettings *> *> m_deviceSettings; //!< Settings for each device set for each satellite
bool m_replayEnabled; //!< Replay a pass in the past, by setting date and time to m_replayStartDateTime
QDateTime m_replayStartDateTime; //!< Time to start the replay at
bool m_useFileInputTime; //!< Get time from FileInput device
bool m_sendTimeToMap; //!< Send time to map when start pressed
int m_columnIndexes[SAT_COL_COLUMNS];//!< How the columns are ordered in the table
int m_columnSizes[SAT_COL_COLUMNS]; //!< Size of the coumns in the table

View File

@ -51,6 +51,10 @@ SatelliteTrackerSettingsDialog::SatelliteTrackerSettingsDialog(SatelliteTrackerS
item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
ui->tles->addItem(item);
}
ui->replayEnabled->setChecked(settings->m_replayEnabled);
ui->replayDateTime->setDateTime(settings->m_replayStartDateTime);
ui->useFileInputTime->setChecked(settings->m_useFileInputTime);
ui->sendTimeToMap->setChecked(settings->m_sendTimeToMap);
}
SatelliteTrackerSettingsDialog::~SatelliteTrackerSettingsDialog()
@ -95,7 +99,12 @@ void SatelliteTrackerSettingsDialog::accept()
m_settings->m_utc = ui->utc->isChecked();
m_settings->m_drawOnMap = ui->drawOnMap->isChecked();
m_settings->m_tles.clear();
for (int i = 0; i < ui->tles->count(); i++)
for (int i = 0; i < ui->tles->count(); i++) {
m_settings->m_tles.append(ui->tles->item(i)->text());
}
m_settings->m_replayEnabled = ui->replayEnabled->isChecked();
m_settings->m_replayStartDateTime = ui->replayDateTime->dateTime();
m_settings->m_useFileInputTime = ui->useFileInputTime->isChecked();
m_settings->m_sendTimeToMap = ui->sendTimeToMap->isChecked();
QDialog::accept();
}

View File

@ -12,7 +12,6 @@
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
@ -495,6 +494,91 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="replayTab">
<attribute name="title">
<string>Replay</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="replaceEnabledLabel">
<property name="text">
<string>Enable replay</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="replayEnabled">
<property name="toolTip">
<string>Enable replay of a pass in the past, by starting with the chosen date and time</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="useFileInputTimeLabel">
<property name="text">
<string>Get time from FileInput device</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="useFileInputTime">
<property name="toolTip">
<string>Get the time from the FileInput device</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="replayDateTimeLabel">
<property name="text">
<string>Start date and time</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDateTimeEdit" name="replayDateTime">
<property name="toolTip">
<string>Set date and time to the displayed value when Satellite Tracker's start button is pressed</string>
</property>
<property name="date">
<date>
<year>2021</year>
<month>1</month>
<day>1</day>
</date>
</property>
<property name="displayFormat">
<string>dd/MM/yyyy HH:mm:ss</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="sendTimeToMapLabel">
<property name="text">
<string>Send time to map</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="sendTimeToMap">
<property name="toolTip">
<string>Send time to Map feature when Satellite Tracker's start button is pressed</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -40,7 +40,8 @@ static DateTime qDateTimeToDateTime(QDateTime qdt)
QDateTime utc = qdt.toUTC();
QDate date = utc.date();
QTime time = utc.time();
DateTime dt(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second());
DateTime dt;
dt.Initialise(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second(), time.msec() * 1000);
return dt;
}
@ -49,7 +50,8 @@ static DateTime qDateTimeToDateTime(QDateTime qdt)
void getGroundTrack(QDateTime dateTime,
const QString& tle0, const QString& tle1, const QString& tle2,
int steps, bool forward,
QList<QGeoCoordinate *>& coordinates)
QList<QGeoCoordinate *>& coordinates,
QList<QDateTime *>& coordinateDateTimes)
{
Tle tle = Tle(tle0.toStdString(), tle1.toStdString(), tle2.toStdString());
SGP4 sgp4(tle);
@ -57,7 +59,13 @@ void getGroundTrack(QDateTime dateTime,
double periodMins;
double timeStep;
// Note map doesn't support paths wrapping around Earth
// For 3D map, we want to quantize to minutes, so we replace previous
// position data, rather than insert additional positions alongside the old
// which can result is the camera view jumping around
dateTime = QDateTime(dateTime.date(), QTime(dateTime.time().hour(), dateTime.time().minute()));
// Note 2D map doesn't support paths wrapping around Earth several times
// So we just have a slight overlap here, with the future track being longer
DateTime currentTime = qDateTimeToDateTime(dateTime);
DateTime endTime;
if (forward)
@ -73,7 +81,16 @@ void getGroundTrack(QDateTime dateTime,
timeStep = -periodMins / (steps * 0.4);
}
coordinates.clear();
// Quantize time step to 30 seconds
timeStep *= 2.0;
if (timeStep > 0.0) {
timeStep = std::max(timeStep, 1.0);
} else if (timeStep < 0.0) {
timeStep = std::min(timeStep, -1.0);
}
timeStep = round(timeStep);
timeStep /= 2.0;
while ((forward && (currentTime < endTime)) || (!forward && (currentTime > endTime)))
{
// Calculate satellite position
@ -86,7 +103,11 @@ void getGroundTrack(QDateTime dateTime,
Units::radiansToDegrees(geo.longitude),
geo.altitude * 1000.0);
coordinates.append(coord);
// Map is stretched at poles, so use finer steps
QDateTime *coordDateTime = new QDateTime(dateTimeToQDateTime(currentTime));
coordinateDateTimes.append(coordDateTime);
// 2D map is stretched at poles, so use finer steps
if (std::abs(Units::radiansToDegrees(geo.latitude)) >= 70)
currentTime = currentTime.AddMinutes(timeStep/4);
else
@ -485,9 +506,15 @@ void getSatelliteState(QDateTime dateTime,
}
qDeleteAll(satState->m_groundTrack);
satState->m_groundTrack.clear();
qDeleteAll(satState->m_groundTrackDateTime);
satState->m_groundTrackDateTime.clear();
qDeleteAll(satState->m_predictedGroundTrack);
getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, false, satState->m_groundTrack);
getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, true, satState->m_predictedGroundTrack);
satState->m_predictedGroundTrack.clear();
qDeleteAll(satState->m_predictedGroundTrackDateTime);
satState->m_predictedGroundTrackDateTime.clear();
getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, false, satState->m_groundTrack, satState->m_groundTrackDateTime);
getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, true, satState->m_predictedGroundTrack, satState->m_predictedGroundTrackDateTime);
}
catch (SatelliteException& se)
{

View File

@ -47,7 +47,9 @@ struct SatelliteState {
double m_period;
QList<SatellitePass *> m_passes;
QList<QGeoCoordinate *> m_groundTrack;
QList<QDateTime *> m_groundTrackDateTime;
QList<QGeoCoordinate *> m_predictedGroundTrack;
QList<QDateTime *> m_predictedGroundTrackDateTime;
};
void getGroundTrack(QDateTime dateTime,

View File

@ -237,13 +237,17 @@ void SatelliteTrackerWorker::removeFromMap(QString id)
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
QList<MessageQueue*> *mapMessageQueues = messagePipes.getMessageQueues(m_satelliteTracker, "mapitems");
if (mapMessageQueues)
sendToMap(mapMessageQueues, id, "", "", 0.0, 0.0, 0.0, 0.0, nullptr, nullptr);
sendToMap(mapMessageQueues, id, "", "", "", 0.0f, 0.0, 0.0, 0.0, 0.0, nullptr, nullptr, nullptr, nullptr);
}
void SatelliteTrackerWorker::sendToMap(QList<MessageQueue*> *mapMessageQueues,
QString name, QString image, QString text,
QString name, QString image, QString model, QString text,
float labelOffset,
double lat, double lon, double altitude, double rotation,
QList<QGeoCoordinate *> *track, QList<QGeoCoordinate *> *predictedTrack)
QList<QGeoCoordinate *> *track,
QList<QDateTime *> *trackDateTime,
QList<QGeoCoordinate *> *predictedTrack,
QList<QDateTime *> *predictedTrackDateTime)
{
QList<MessageQueue*>::iterator it = mapMessageQueues->begin();
@ -257,7 +261,11 @@ void SatelliteTrackerWorker::sendToMap(QList<MessageQueue*> *mapMessageQueues,
swgMapItem->setImage(new QString(image));
swgMapItem->setImageRotation(rotation);
swgMapItem->setText(new QString(text));
swgMapItem->setImageMinZoom(0);
swgMapItem->setModel(new QString(model));
swgMapItem->setFixedPosition(false);
swgMapItem->setOrientation(0);
swgMapItem->setLabel(new QString(name));
swgMapItem->setLabelAltitudeOffset(labelOffset);
if (track != nullptr)
{
QList<SWGSDRangel::SWGMapCoordinate *> *mapTrack = new QList<SWGSDRangel::SWGMapCoordinate *>();
@ -268,6 +276,7 @@ void SatelliteTrackerWorker::sendToMap(QList<MessageQueue*> *mapMessageQueues,
p->setLatitude(c->latitude());
p->setLongitude(c->longitude());
p->setAltitude(c->altitude());
p->setDateTime(new QString(trackDateTime->at(i)->toString(Qt::ISODate)));
mapTrack->append(p);
}
swgMapItem->setTrack(mapTrack);
@ -282,6 +291,7 @@ void SatelliteTrackerWorker::sendToMap(QList<MessageQueue*> *mapMessageQueues,
p->setLatitude(c->latitude());
p->setLongitude(c->longitude());
p->setAltitude(c->altitude());
p->setDateTime(new QString(predictedTrackDateTime->at(i)->toString(Qt::ISODate)));
mapTrack->append(p);
}
swgMapItem->setPredictedTrack(mapTrack);
@ -297,7 +307,7 @@ void SatelliteTrackerWorker::update()
// Get date and time to calculate position at
QDateTime qdt;
if (m_settings.m_dateTime == "")
qdt = SatelliteTracker::currentDateTimeUtc();
qdt = m_satelliteTracker->currentDateTimeUtc();
else if (m_settings.m_utc)
qdt = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
else
@ -333,6 +343,7 @@ void SatelliteTrackerWorker::update()
// Do we have a new AOS?
if ((satWorkerState->m_aos != satWorkerState->m_satState.m_passes[0]->m_aos) || (satWorkerState->m_los != satWorkerState->m_satState.m_passes[0]->m_los))
{
qDebug() << "SatelliteTrackerWorker: Current time: " << qdt.toString(Qt::ISODateWithMs);
qDebug() << "SatelliteTrackerWorker: New AOS: " << name << " new: " << satWorkerState->m_satState.m_passes[0]->m_aos << " old: " << satWorkerState->m_aos;
qDebug() << "SatelliteTrackerWorker: New LOS: " << name << " new: " << satWorkerState->m_satState.m_passes[0]->m_los << " old: " << satWorkerState->m_los;
satWorkerState->m_aos = satWorkerState->m_satState.m_passes[0]->m_aos;
@ -356,14 +367,15 @@ void SatelliteTrackerWorker::update()
if (satWorkerState->m_losTimer.isActive()) {
qDebug() << "SatelliteTrackerWorker::update m_losTimer.remainingTime: " << satWorkerState->m_losTimer.remainingTime();
}
// We can detect a new AOS for a satellite, a little bit before the LOS has occured, presumably
// because the calculations aren't accurate to fractions of a second. Allow for 1s here
if (satWorkerState->m_losTimer.isActive() && (satWorkerState->m_losTimer.remainingTime() <= 1000))
// We can detect a new AOS for a satellite, a little bit before the LOS has occured
// Allow for 5s here (1s doesn't appear to be enough in some cases)
if (satWorkerState->m_losTimer.isActive() && (satWorkerState->m_losTimer.remainingTime() <= 5000))
{
satWorkerState->m_losTimer.stop();
// LOS hasn't been called yet - do so, before we reset timer
los(satWorkerState);
}
qDebug() << "SatelliteTrackerWorker:: Interval to LOS " << (satWorkerState->m_los.toMSecsSinceEpoch() - qdt.toMSecsSinceEpoch());
satWorkerState->m_losTimer.setInterval(satWorkerState->m_los.toMSecsSinceEpoch() - qdt.toMSecsSinceEpoch());
satWorkerState->m_losTimer.setSingleShot(true);
satWorkerState->m_losTimer.start();
@ -417,11 +429,29 @@ void SatelliteTrackerWorker::update()
QList<MessageQueue*> *mapMessageQueues = messagePipes.getMessageQueues(m_satelliteTracker, "mapitems");
if (mapMessageQueues)
{
const QStringList cubeSats({"AISAT-1", "FOX-1B", "FOX-1C", "FOX-1D", "FOX-1E", "FUNCUBE-1", "NO-84"});
QString image;
QString model;
float labelOffset;
if (sat->m_name == "ISS")
{
image = "qrc:///satellitetracker/satellitetracker/iss-32.png";
model = "iss.glb";
labelOffset = 15.0f;
}
else if (cubeSats.contains(sat->m_name))
{
image = "qrc:///satellitetracker/satellitetracker/cubesat-32.png";
model = "cubesat.glb";
labelOffset = 0.7f;
}
else
{
image = "qrc:///satellitetracker/satellitetracker/satellite-32.png";
model = "satellite.glb";
labelOffset = 2.5f;
}
QString text = QString("Name: %1\nAltitude: %2 km\nRange: %3 km\nRange rate: %4 km/s\nSpeed: %5 km/h\nPeriod: %6 mins")
.arg(sat->m_name)
@ -456,10 +486,11 @@ void SatelliteTrackerWorker::update()
.arg(QChar(0xb0));
}
sendToMap(mapMessageQueues, sat->m_name, image, text,
sendToMap(mapMessageQueues, sat->m_name, image, model, text, labelOffset,
satWorkerState->m_satState.m_latitude, satWorkerState->m_satState.m_longitude,
satWorkerState->m_satState.m_altitude * 1000.0, 0,
&satWorkerState->m_satState.m_groundTrack, &satWorkerState->m_satState.m_predictedGroundTrack);
&satWorkerState->m_satState.m_groundTrack, &satWorkerState->m_satState.m_groundTrackDateTime,
&satWorkerState->m_satState.m_predictedGroundTrack, &satWorkerState->m_satState.m_predictedGroundTrackDateTime);
}
}
@ -495,7 +526,7 @@ void SatelliteTrackerWorker::aos(SatWorkerState *satWorkerState)
SatWorkerState *targetSatWorkerState = m_workerState.value(m_settings.m_target);
int currentTargetIdx = m_settings.m_satellites.indexOf(m_settings.m_target);
int newTargetIdx = m_settings.m_satellites.indexOf(satWorkerState->m_name);
if ((newTargetIdx < currentTargetIdx) || !targetSatWorkerState->hasAOS())
if ((newTargetIdx < currentTargetIdx) || !targetSatWorkerState->hasAOS(m_satelliteTracker->currentDateTimeUtc()))
{
// Stop doppler correction for current target
if (m_workerState.contains(m_settings.m_target))
@ -646,7 +677,12 @@ void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name)
// Send AOS message to channels/features
SatWorkerState *satWorkerState = m_workerState.value(name);
ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth);
SatNogsSatellite *sat = m_satellites.value(satWorkerState->m_name);
// APT needs current time, for current position of satellite, not start of pass which may be in the past
// if the satellite was already visible when Sat Tracker was started
ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth,
sat->m_tle->toString(),
m_satelliteTracker->currentDateTimeUtc());
FeatureWebAPIUtils::satelliteAOS(name, satWorkerState->m_aos, satWorkerState->m_los);
// Start Doppler correction, if needed
@ -677,6 +713,7 @@ void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name)
}
if (requiresDoppler)
{
qDebug() << "SatelliteTrackerWorker::applyDeviceAOSSettings: requiresDoppler";
satWorkerState->m_dopplerTimer.setInterval(m_settings.m_dopplerPeriod * 1000);
satWorkerState->m_dopplerTimer.start();
connect(&satWorkerState->m_dopplerTimer, &QTimer::timeout, [this, satWorkerState]() {
@ -705,7 +742,10 @@ void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name)
{
// Send AOS message to channels/features
SatWorkerState *satWorkerState = m_workerState.value(name);
ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth);
SatNogsSatellite *sat = m_satellites.value(satWorkerState->m_name);
ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth,
sat->m_tle->toString(),
m_satelliteTracker->currentDateTimeUtc());
FeatureWebAPIUtils::satelliteAOS(name, satWorkerState->m_aos, satWorkerState->m_los);
}
@ -750,7 +790,7 @@ void SatelliteTrackerWorker::doppler(SatWorkerState *satWorkerState)
void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
{
qDebug() << "SatelliteTrackerWorker::los " << satWorkerState->m_name;
qDebug() << "SatelliteTrackerWorker::los " << satWorkerState->m_name << " target: " << m_settings.m_target;
// Indicate LOS to GUI
if (getMessageQueueToGUI())
@ -776,6 +816,10 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
QProcess::startDetached(program, allArgs);
}
// Send LOS message to channels/features
ChannelWebAPIUtils::satelliteLOS(satWorkerState->m_name);
FeatureWebAPIUtils::satelliteLOS(satWorkerState->m_name);
if (m_settings.m_deviceSettings.contains(satWorkerState->m_name))
{
QList<SatelliteTrackerSettings::SatelliteDeviceSettings *> *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
@ -791,10 +835,6 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
}
}
// Send LOS message to channels/features
ChannelWebAPIUtils::satelliteLOS(satWorkerState->m_name);
FeatureWebAPIUtils::satelliteLOS(satWorkerState->m_name);
// Stop acquisition
for (int i = 0; i < m_deviceSettingsList->size(); i++)
{
@ -834,7 +874,7 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
if (m_workerState.contains(m_settings.m_satellites[i]))
{
SatWorkerState *newSatWorkerState = m_workerState.value(m_settings.m_satellites[i]);
if (newSatWorkerState->hasAOS())
if (newSatWorkerState->hasAOS(m_satelliteTracker->currentDateTimeUtc()))
{
qDebug() << "SatelliteTrackerWorker::los - autoTarget setting " << m_settings.m_satellites[i];
m_settings.m_target = m_settings.m_satellites[i];
@ -852,8 +892,7 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
m_recalculatePasses = true;
}
bool SatWorkerState::hasAOS()
bool SatWorkerState::hasAOS(const QDateTime& currentTime)
{
QDateTime currentTime = SatelliteTracker::currentDateTimeUtc();
return (m_aos <= currentTime) && (m_los > currentTime);
}

View File

@ -48,7 +48,7 @@ public:
m_satState.m_name = name;
}
bool hasAOS();
bool hasAOS(const QDateTime& currentTime);
protected:
QString m_name; // Name of the satellite
@ -122,9 +122,13 @@ private:
void applySettings(const SatelliteTrackerSettings& settings, bool force = false);
MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
void removeFromMap(QString id);
void sendToMap(QList<MessageQueue*> *mapMessageQueues, QString id, QString image, QString text,
void sendToMap(QList<MessageQueue*> *mapMessageQueues, QString id, QString image, QString model, QString text,
float labelOffset,
double lat, double lon, double altitude, double rotation,
QList<QGeoCoordinate *> *track = nullptr, QList<QGeoCoordinate *> *predictedTrack = nullptr);
QList<QGeoCoordinate *> *track = nullptr,
QList<QDateTime *> *trackDateTime = nullptr,
QList<QGeoCoordinate *> *predictedTrack = nullptr,
QList<QDateTime *> *predictedTrackDateTime = nullptr);
void applyDeviceAOSSettings(const QString& name);
void startStopSinks(bool start);
void calculateRotation(SatWorkerState *satWorkerState);

View File

@ -115,6 +115,11 @@ struct SatNogsTLE {
m_tle2 = tle2;
}
QString toString() const
{
return m_tle0 + "\n" + m_tle1 + "\n" + m_tle2 + "\n";
}
static QList<SatNogsTLE *> createList(QJsonArray array)
{
QList<SatNogsTLE *> list;