Compare commits

...

25 Commits

Author SHA1 Message Date
b2576d3422 why are we ignoring usec 2024-02-23 11:33:20 +01:00
bccaf4a9ea capital 2024-02-23 11:31:11 +01:00
7d4e77843b frmt 2024-02-23 11:09:59 +01:00
90f3f8ef1f removed printout 2024-02-12 14:51:54 +01:00
9894935e99 time systems 2024-02-12 14:42:58 +01:00
a3a6c0720c fixes 2024-02-12 14:36:14 +01:00
d5a52eadbb i should have done this ages ago 2024-02-12 14:20:04 +01:00
b5e7179af1 Merge pull request 'Rotation from Quaternions' (#167) from rotation-from-quaternions into develop
Reviewed-on: #167
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-01-29 14:11:08 +01:00
5879eb7f7b rotation from quaternions 2024-01-26 11:06:05 +01:00
e64e8b274d Merge pull request 'check whether map is full on insert' (#166) from insert-full-check into develop
Reviewed-on: #166
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-12-12 17:53:14 +01:00
48bcce65b1 check whether map is full on insert 2023-12-12 11:24:35 +01:00
7105e199c6 Merge pull request 'SLERP for antiparallel Quaternions' (#165) from slerp-fix-antiparallel-quaternions into develop
Reviewed-on: #165
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-06 10:41:02 +01:00
94de483836 small fix 2023-12-06 09:26:22 +01:00
c648229c99 Merge pull request 'SLERP' (#163) from slerp into develop
Reviewed-on: #163
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-05 09:25:48 +01:00
5b661551a8 fixes 2023-12-04 17:52:24 +01:00
3978524181 Merge branch 'develop' into slerp 2023-11-29 15:19:09 +01:00
7187f2b5cd Merge pull request 'TLE turns too old after just 7 Days' (#164) from tle-too-old into develop
Reviewed-on: #164
2023-11-29 15:17:39 +01:00
8e367abb47 Merge branch 'develop' into tle-too-old 2023-11-29 15:17:19 +01:00
b28174db24 Merge pull request 'Fresh DHB pre-queue check hook' (#162) from fresh-dhb-pre-queue-hook into develop
Reviewed-on: #162
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-11-29 14:18:23 +01:00
c906acd659 tle turns too old after just 7 days 2023-11-29 09:48:11 +01:00
8dfc84c0b5 smoll fix 2023-11-27 10:52:47 +01:00
74775bb59d slerp 2023-11-27 10:38:25 +01:00
c02d9e009e docs improvements and fix 2023-11-21 17:40:06 +01:00
0021aa29f5 pre-queue hook 2023-11-21 17:37:02 +01:00
41d67bff63 Merge pull request 'New simpler DHB' (#161) from new-dhb into develop
Reviewed-on: #161
Reviewed-by: Ulrich Mohr <mohr@irs.uni-stuttgart.de>
2023-11-16 11:02:44 +01:00
12 changed files with 308 additions and 2 deletions

View File

@@ -6,6 +6,7 @@
#include "fsfw/globalfunctions/constants.h"
#include "fsfw/globalfunctions/math/MatrixOperations.h"
#include "fsfw/globalfunctions/math/VectorOperations.h"
#include "fsfw/globalfunctions/sign.h"
void CoordinateTransformations::positionEcfToEci(const double* ecfPosition, double* eciPosition,
timeval* timeUTC) {
@@ -207,3 +208,61 @@ void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC, double T
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3);
};
void CoordinateTransformations::cartesianFromLatLongAlt(const double lat, const double longi,
const double alt, double* cartesianOutput) {
/* @brief: cartesianFromLatLongAlt() - calculates cartesian coordinates in ECEF from latitude,
* longitude and altitude
* @param: lat geodetic latitude [rad]
* longi longitude [rad]
* alt altitude [m]
* cartesianOutput Cartesian Coordinates in ECEF (3x1)
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.34ff
* Landis Markley and John L. Crassidis*/
double radiusPolar = 6356752.314;
double radiusEqua = 6378137;
double eccentricity = sqrt(1 - pow(radiusPolar, 2) / pow(radiusEqua, 2));
double auxRadius = radiusEqua / sqrt(1 - pow(eccentricity, 2) * pow(sin(lat), 2));
cartesianOutput[0] = (auxRadius + alt) * cos(lat) * cos(longi);
cartesianOutput[1] = (auxRadius + alt) * cos(lat) * sin(longi);
cartesianOutput[2] = ((1 - pow(eccentricity, 2)) * auxRadius + alt) * sin(lat);
};
void CoordinateTransformations::latLongAltFromCartesian(const double* vector, double& latitude,
double& longitude, double& altitude) {
/* @brief: latLongAltFromCartesian() - calculates latitude, longitude and altitude from
* cartesian coordinates in ECEF
* @param: x x-value of position vector [m]
* y y-value of position vector [m]
* z z-value of position vector [m]
* latitude geodetic latitude [rad]
* longitude longitude [rad]
* altitude altitude [m]
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.35 f
* Landis Markley and John L. Crassidis*/
// From World Geodetic System the Earth Radii
double a = 6378137.0; // semimajor axis [m]
double b = 6356752.3142; // semiminor axis [m]
// Calculation
double e2 = 1 - pow(b, 2) / pow(a, 2);
double epsilon2 = pow(a, 2) / pow(b, 2) - 1;
double rho = sqrt(pow(vector[0], 2) + pow(vector[1], 2));
double p = std::abs(vector[2]) / epsilon2;
double s = pow(rho, 2) / (e2 * epsilon2);
double q = pow(p, 2) - pow(b, 2) + s;
double u = p / sqrt(q);
double v = pow(b, 2) * pow(u, 2) / q;
double P = 27 * v * s / q;
double Q = pow(sqrt(P + 1) + sqrt(P), 2. / 3.);
double t = (1 + Q + 1 / Q) / 6;
double c = sqrt(pow(u, 2) - 1 + 2 * t);
double w = (c - u) / 2;
double d = sign(vector[2]) * sqrt(q) * (w + sqrt(sqrt(pow(t, 2) + v) - u * w - t / 2 - 1. / 4.));
double N = a * sqrt(1 + epsilon2 * pow(d, 2) / pow(b, 2));
latitude = asin((epsilon2 + 1) * d / N);
altitude = rho * cos(latitude) + vector[2] * sin(latitude) - pow(a, 2) / N;
longitude = atan2(vector[1], vector[0]);
}

View File

@@ -23,6 +23,12 @@ class CoordinateTransformations {
static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]);
static void cartesianFromLatLongAlt(const double lat, const double longi, const double alt,
double* cartesianOutput);
static void latLongAltFromCartesian(const double* vector, double& latitude, double& longitude,
double& altitude);
private:
CoordinateTransformations();
static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates,

View File

@@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
timeval timeSinceEpoch = time - epoch;
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30;
double daysSinceEpoch = minutesSinceEpoch / 60 / 24;
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) {
if ((daysSinceEpoch > 7) || (daysSinceEpoch < -7)) {
return TLE_TOO_OLD;
}

View File

@@ -28,12 +28,17 @@ FreshDeviceHandlerBase::~FreshDeviceHandlerBase() {
}
ReturnValue_t FreshDeviceHandlerBase::performOperation(uint8_t opCode) {
performDeviceOperationPreQueueHandling(opCode);
handleQueue();
performDeviceOperation(opCode);
poolManager.performHkOperation();
return returnvalue::OK;
}
ReturnValue_t FreshDeviceHandlerBase::performDeviceOperationPreQueueHandling(uint8_t opCode) {
return returnvalue::OK;
}
void FreshDeviceHandlerBase::startTransition(Mode_t mode_, Submode_t submode_) {
triggerEvent(CHANGING_MODE, mode_, submode_);
// Complete mode transition immediately by default.

View File

@@ -82,6 +82,12 @@ class FreshDeviceHandlerBase : public SystemObject,
MessageQueueIF* messageQueue;
/**
* The default queue handler will process all messages for the interfaces implemented
* by this class. If there are special requirements, for example that action commands are
* received on a different queue, the user can override this function for those special
* requirements.
*/
virtual ReturnValue_t handleQueue();
// Mode Helpers.
@@ -153,6 +159,8 @@ class FreshDeviceHandlerBase : public SystemObject,
ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) override;
virtual ReturnValue_t performDeviceOperationPreQueueHandling(uint8_t opCode);
private:
// Executable Overrides.
void setTaskIF(PeriodicTaskIF* task) override;

View File

@@ -0,0 +1,19 @@
#ifndef FSFW_SRC_FSFW_GLOBALFUNCTIONS_TIMESYSTEMS_H_
#define FSFW_SRC_FSFW_GLOBALFUNCTIONS_TIMESYSTEMS_H_
#ifdef PLATFORM_WIN
#include <winsock2.h>
#else
#include <sys/time.h>
#endif
class TimeSystems {
public:
virtual ~TimeSystems() {}
static double convertUnixToJD2000(timeval time) {
return ((time.tv_sec + time.tv_usec * 1e-6) / 86400.0) + 2440587.5 - 2451545;
}
};
#endif /* FSFW_SRC_FSFW_GLOBALFUNCTIONS_TIMESYSTEMS_H_ */

View File

@@ -1,9 +1,12 @@
#ifndef MATRIXOPERATIONS_H_
#define MATRIXOPERATIONS_H_
#include <fsfw/retval.h>
#include <stdint.h>
#include <cmath>
#include <cstring>
#include <utility>
template <typename T1, typename T2 = T1, typename T3 = T2>
class MatrixOperations {
@@ -95,6 +98,139 @@ class MatrixOperations {
}
}
}
static bool isFinite(const T1 *inputMatrix, uint8_t rows, uint8_t cols) {
for (uint8_t col = 0; col < cols; col++) {
for (uint8_t row = 0; row < rows; row++) {
if (not std::isfinite(inputMatrix[row * cols + cols])) {
return false;
}
}
}
return true;
}
static void writeSubmatrix(T1 *mainMatrix, T1 *subMatrix, uint8_t subRows, uint8_t subCols,
uint8_t mainRows, uint8_t mainCols, uint8_t startRow,
uint8_t startCol) {
if ((startRow + subRows > mainRows) or (startCol + subCols > mainCols)) {
return;
}
for (uint8_t row = 0; row < subRows; row++) {
for (uint8_t col = 0; col < subCols; col++) {
mainMatrix[(startRow + row) * mainCols + (startCol + col)] = subMatrix[row * subCols + col];
}
}
}
static ReturnValue_t inverseMatrix(const T1 *inputMatrix, T1 *inverse, uint8_t size) {
// Stopwatch stopwatch;
T1 matrix[size][size], identity[size][size];
// reformat array to matrix
for (uint8_t row = 0; row < size; row++) {
for (uint8_t col = 0; col < size; col++) {
matrix[row][col] = inputMatrix[row * size + col];
}
}
// init identity matrix
std::memset(identity, 0.0, sizeof(identity));
for (uint8_t diag = 0; diag < size; diag++) {
identity[diag][diag] = 1;
}
// gauss-jordan algo
// sort matrix such as no diag entry shall be 0
for (uint8_t row = 0; row < size; row++) {
if (matrix[row][row] == 0.0) {
bool swaped = false;
uint8_t rowIndex = 0;
while ((rowIndex < size) && !swaped) {
if ((matrix[rowIndex][row] != 0.0) && (matrix[row][rowIndex] != 0.0)) {
for (uint8_t colIndex = 0; colIndex < size; colIndex++) {
std::swap(matrix[row][colIndex], matrix[rowIndex][colIndex]);
std::swap(identity[row][colIndex], identity[rowIndex][colIndex]);
}
swaped = true;
}
rowIndex++;
}
if (!swaped) {
return returnvalue::FAILED; // matrix not invertible
}
}
}
for (int row = 0; row < size; row++) {
if (matrix[row][row] == 0.0) {
uint8_t rowIndex;
if (row == 0) {
rowIndex = size - 1;
} else {
rowIndex = row - 1;
}
for (uint8_t colIndex = 0; colIndex < size; colIndex++) {
std::swap(matrix[row][colIndex], matrix[rowIndex][colIndex]);
std::swap(identity[row][colIndex], identity[rowIndex][colIndex]);
}
row--;
if (row < 0) {
return returnvalue::FAILED; // Matrix is not invertible
}
}
}
// remove non diag elements in matrix (jordan)
for (int row = 0; row < size; row++) {
for (int rowIndex = 0; rowIndex < size; rowIndex++) {
if (row != rowIndex) {
double ratio = matrix[rowIndex][row] / matrix[row][row];
for (int colIndex = 0; colIndex < size; colIndex++) {
matrix[rowIndex][colIndex] -= ratio * matrix[row][colIndex];
identity[rowIndex][colIndex] -= ratio * identity[row][colIndex];
}
}
}
}
// normalize rows in matrix (gauss)
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
identity[row][col] = identity[row][col] / matrix[row][row];
}
}
std::memcpy(inverse, identity, sizeof(identity));
return returnvalue::OK; // successful inversion
}
static void inverseMatrixDimThree(const T1 *matrix, T1 *output) {
int i, j;
double determinant = 0;
double mat[3][3] = {{matrix[0], matrix[1], matrix[2]},
{matrix[3], matrix[4], matrix[5]},
{matrix[6], matrix[7], matrix[8]}};
for (i = 0; i < 3; i++) {
determinant = determinant + (mat[0][i] * (mat[1][(i + 1) % 3] * mat[2][(i + 2) % 3] -
mat[1][(i + 2) % 3] * mat[2][(i + 1) % 3]));
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
output[i * 3 + j] = ((mat[(j + 1) % 3][(i + 1) % 3] * mat[(j + 2) % 3][(i + 2) % 3]) -
(mat[(j + 1) % 3][(i + 2) % 3] * mat[(j + 2) % 3][(i + 1) % 3])) /
determinant;
}
}
}
static void skewMatrix(const T1 *vector, T2 *result) {
// Input Dimension [3], Output [3][3]
result[0] = 0;
result[1] = -vector[2];
result[2] = vector[1];
result[3] = vector[2];
result[4] = 0;
result[5] = -vector[0];
result[6] = -vector[1];
result[7] = vector[0];
result[8] = 0;
}
};
#endif /* MATRIXOPERATIONS_H_ */

View File

@@ -39,6 +39,39 @@ void QuaternionOperations::inverse(const double* quaternion, double* inverseQuat
VectorOperations<double>::mulScalar(inverseQuaternion, -1, inverseQuaternion, 3);
}
void QuaternionOperations::slerp(const double q1[4], const double q2[4], const double weight,
double q[4]) {
double q1s[4] = {0, 0, 0, 0}, q2I[4] = {0, 0, 0, 0}, qD[4] = {0, 0, 0, 0}, left[4] = {0, 0, 0, 0},
right[4] = {0, 0, 0, 0}, angle = 0;
// we need to be able to invert this quaternion
std::memcpy(q1s, q1, 4 * sizeof(double));
// calculate angle between orientations
inverse(q2, q2I);
multiply(q1s, q2I, qD);
angle = std::acos(qD[3]);
if (std::cos(angle) < 0.0) {
// we need to invert one quaternion
VectorOperations<double>::mulScalar(q1s, -1, q1s, 4);
multiply(q1s, q2I, qD);
angle = std::acos(qD[3]);
}
if (std::sin(angle) == 0.0) {
// nothing to calculate here
std::memcpy(q, q1s, 4 * sizeof(double));
return;
}
VectorOperations<double>::mulScalar(q1s, std::sin((1 - weight) * angle) / std::sin(angle), left,
4);
VectorOperations<double>::mulScalar(q2, std::sin(weight * angle) / std::sin(angle), right, 4);
VectorOperations<double>::add(left, right, q, 4);
normalize(q);
}
QuaternionOperations::QuaternionOperations() {}
void QuaternionOperations::normalize(const double* quaternion, double* unitQuaternion) {
@@ -120,3 +153,25 @@ double QuaternionOperations::getAngle(const double* quaternion, bool abs) {
}
}
}
void QuaternionOperations::rotationFromQuaternions(const double qNew[4], const double qOld[4],
const double timeDelta, double rotRate[3]) {
double qOldInv[4] = {0, 0, 0, 0};
double qDelta[4] = {0, 0, 0, 0};
inverse(qOld, qOldInv);
multiply(qNew, qOldInv, qDelta);
if (VectorOperations<double>::norm(qDelta, 4) != 0.0) {
normalize(qDelta);
}
if (VectorOperations<double>::norm(qDelta, 3) == 0.0) {
rotRate[0] = 0.0;
rotRate[1] = 0.0;
rotRate[2] = 0.0;
return;
}
double rotVec[3] = {0, 0, 0};
double angle = getAngle(qDelta);
VectorOperations<double>::normalize(qDelta, rotVec, 3);
VectorOperations<double>::mulScalar(rotVec, angle / timeDelta, rotRate, 3);
}

View File

@@ -23,6 +23,11 @@ class QuaternionOperations {
static void inverse(const double *quaternion, double *inverseQuaternion);
static void slerp(const double q1[4], const double q2[4], const double weight, double q[4]);
static void rotationFromQuaternions(const double qNew[4], const double qOld[4],
const double timeDelta, double rotRate[3]);
/**
* returns angle in ]-Pi;Pi] or [0;Pi] if abs == true
*/

View File

@@ -99,6 +99,15 @@ class VectorOperations {
static void copy(const T *in, T *out, uint8_t size) { mulScalar(in, 1, out, size); }
static bool isFinite(const T *inputVector, uint8_t size) {
for (uint8_t i = 0; i < size; i++) {
if (not std::isfinite(inputVector[i])) {
return false;
}
}
return true;
}
private:
VectorOperations();
};

View File

@@ -43,6 +43,7 @@ class Service11TelecommandScheduling final : public PusServiceBase {
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
static constexpr ReturnValue_t MAP_IS_FULL = returnvalue::makeCode(CLASS_ID, 7);
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;

View File

@@ -150,6 +150,9 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleResetCom
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity(
const uint8_t *data, size_t size) {
if(telecommandMap.full()) {
return MAP_IS_FULL;
}
uint32_t timestamp = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&timestamp, &data, &size, DEF_END);
if (result != returnvalue::OK) {