2022-09-19 15:17:39 +02:00
|
|
|
#include "Guidance.h"
|
2022-10-12 15:06:24 +02:00
|
|
|
|
2022-11-03 10:43:27 +01:00
|
|
|
#include <fsfw/datapool/PoolReadGuard.h>
|
2022-09-27 11:06:11 +02:00
|
|
|
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
|
|
|
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
2022-10-12 15:06:24 +02:00
|
|
|
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
|
|
|
#include <math.h>
|
2022-09-19 15:17:39 +02:00
|
|
|
|
2023-01-12 14:49:37 +01:00
|
|
|
#include <filesystem>
|
|
|
|
|
2022-10-12 15:06:24 +02:00
|
|
|
#include "string.h"
|
|
|
|
#include "util/CholeskyDecomposition.h"
|
|
|
|
#include "util/MathOperations.h"
|
2022-09-19 15:17:39 +02:00
|
|
|
|
2022-10-12 15:06:24 +02:00
|
|
|
Guidance::Guidance(AcsParameters *acsParameters_) { acsParameters = *acsParameters_; }
|
2022-09-19 15:17:39 +02:00
|
|
|
|
2022-10-12 15:06:24 +02:00
|
|
|
Guidance::~Guidance() {}
|
2022-09-19 15:17:39 +02:00
|
|
|
|
|
|
|
void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3]) {
|
2023-01-12 14:49:37 +01:00
|
|
|
if (not std::filesystem::exists(SD_0_SKEWED_PTG_FILE) or
|
|
|
|
not std::filesystem::exists(SD_1_SKEWED_PTG_FILE)) { // ToDo: if file does not exist anymore
|
|
|
|
std::memcpy(sunTargetSafe, acsParameters.safeModeControllerParameters.sunTargetDir,
|
|
|
|
3 * sizeof(double));
|
|
|
|
} else {
|
|
|
|
std::memcpy(sunTargetSafe, acsParameters.safeModeControllerParameters.sunTargetDirLeop,
|
|
|
|
3 * sizeof(double));
|
2022-10-12 15:06:24 +02:00
|
|
|
}
|
2023-01-12 14:49:37 +01:00
|
|
|
std::memcpy(satRateSafe, acsParameters.safeModeControllerParameters.satRateRef,
|
|
|
|
3 * sizeof(double));
|
2022-09-19 15:17:39 +02:00
|
|
|
}
|
|
|
|
|
2023-02-17 13:44:44 +01:00
|
|
|
void Guidance::targetQuatPtgSingleAxis(acsctrl::MekfData *mekfData,
|
2022-12-14 11:46:58 +01:00
|
|
|
acsctrl::SusDataProcessed *susDataProcessed,
|
2023-02-17 13:44:44 +01:00
|
|
|
timeval now,
|
2022-12-14 11:46:58 +01:00
|
|
|
double targetQuat[4], double refSatRate[3]) {
|
2022-10-12 15:06:24 +02:00
|
|
|
//-------------------------------------------------------------------------------------
|
2022-11-14 17:16:47 +01:00
|
|
|
// Calculation of target quaternion to groundstation or given latitude, longitude and altitude
|
2022-10-12 15:06:24 +02:00
|
|
|
//-------------------------------------------------------------------------------------
|
2022-11-14 17:16:47 +01:00
|
|
|
// Transform longitude, latitude and altitude to cartesian coordiantes (earth
|
2022-10-12 15:06:24 +02:00
|
|
|
// fixed/centered frame)
|
2023-01-10 11:20:28 +01:00
|
|
|
double targetCart[3] = {0, 0, 0};
|
2022-10-12 15:06:24 +02:00
|
|
|
|
2023-01-10 11:20:28 +01:00
|
|
|
MathOperations<double>::cartesianFromLatLongAlt(
|
2023-01-23 16:34:52 +01:00
|
|
|
acsParameters.targetModeControllerParameters.latitudeTgt,
|
|
|
|
acsParameters.targetModeControllerParameters.longitudeTgt,
|
2023-01-12 15:19:21 +01:00
|
|
|
acsParameters.targetModeControllerParameters.altitudeTgt, targetCart);
|
2022-10-12 15:06:24 +02:00
|
|
|
|
|
|
|
// Target direction in the ECEF frame
|
|
|
|
double targetDirE[3] = {0, 0, 0};
|
2023-01-10 11:20:28 +01:00
|
|
|
VectorOperations<double>::subtract(targetCart, posSatE, targetDirE, 3);
|
2022-10-12 15:06:24 +02:00
|
|
|
|
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
2022-11-04 17:21:17 +01:00
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
2022-10-12 15:06:24 +02:00
|
|
|
|
2022-11-04 17:21:17 +01:00
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
2022-10-12 15:06:24 +02:00
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// Transformation between ECEF and Body frame
|
|
|
|
double dcmBJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmBE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
2022-11-03 10:43:27 +01:00
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
|
|
|
|
2022-10-12 15:06:24 +02:00
|
|
|
QuaternionOperations::toDcm(quatBJ, dcmBJ);
|
|
|
|
MatrixOperations<double>::multiply(*dcmBJ, *dcmJE, *dcmBE, 3, 3, 3);
|
|
|
|
|
|
|
|
// Target Direction in the body frame
|
|
|
|
double targetDirB[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmBE, targetDirE, targetDirB, 3, 3, 1);
|
|
|
|
|
|
|
|
// rotation quaternion from two vectors
|
|
|
|
double refDir[3] = {0, 0, 0};
|
|
|
|
refDir[0] = acsParameters.targetModeControllerParameters.refDirection[0];
|
|
|
|
refDir[1] = acsParameters.targetModeControllerParameters.refDirection[1];
|
|
|
|
refDir[2] = acsParameters.targetModeControllerParameters.refDirection[2];
|
|
|
|
double noramlizedTargetDirB[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::normalize(targetDirB, noramlizedTargetDirB, 3);
|
|
|
|
VectorOperations<double>::normalize(refDir, refDir, 3);
|
|
|
|
double normTargetDirB = VectorOperations<double>::norm(noramlizedTargetDirB, 3);
|
|
|
|
double normRefDir = VectorOperations<double>::norm(refDir, 3);
|
|
|
|
double crossDir[3] = {0, 0, 0};
|
|
|
|
double dotDirections = VectorOperations<double>::dot(noramlizedTargetDirB, refDir);
|
|
|
|
VectorOperations<double>::cross(noramlizedTargetDirB, refDir, crossDir);
|
|
|
|
targetQuat[0] = crossDir[0];
|
|
|
|
targetQuat[1] = crossDir[1];
|
|
|
|
targetQuat[2] = crossDir[2];
|
|
|
|
targetQuat[3] = sqrt(pow(normTargetDirB, 2) * pow(normRefDir, 2) + dotDirections);
|
|
|
|
VectorOperations<double>::normalize(targetQuat, targetQuat, 4);
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of reference rotation rate
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
double velSatB[3] = {0, 0, 0}, velSatBPart1[3] = {0, 0, 0}, velSatBPart2[3] = {0, 0, 0};
|
|
|
|
// Velocity: v_B = dcm_BI * dcmIE * v_E + dcm_BI * DotDcm_IE * v_E
|
|
|
|
MatrixOperations<double>::multiply(*dcmBE, velSatE, velSatBPart1, 3, 3, 1);
|
|
|
|
double dcmBEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MatrixOperations<double>::multiply(*dcmBJ, *dcmJEDot, *dcmBEDot, 3, 3, 3);
|
|
|
|
MatrixOperations<double>::multiply(*dcmBEDot, posSatE, velSatBPart2, 3, 3, 1);
|
|
|
|
VectorOperations<double>::add(velSatBPart1, velSatBPart2, velSatB, 3);
|
|
|
|
|
|
|
|
double normVelSatB = VectorOperations<double>::norm(velSatB, 3);
|
|
|
|
double normRefSatRate = normVelSatB / normTargetDirB;
|
|
|
|
|
|
|
|
double satRateDir[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(velSatB, targetDirB, satRateDir);
|
|
|
|
VectorOperations<double>::normalize(satRateDir, satRateDir, 3);
|
|
|
|
VectorOperations<double>::mulScalar(satRateDir, normRefSatRate, refSatRate, 3);
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of reference rotation rate in case of star tracker blinding
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
if (acsParameters.targetModeControllerParameters.avoidBlindStr) {
|
|
|
|
double sunDirB[3] = {0, 0, 0};
|
|
|
|
|
2022-12-14 11:46:58 +01:00
|
|
|
if (susDataProcessed->sunIjkModel.isValid()) {
|
2022-11-22 21:10:05 +01:00
|
|
|
double sunDirJ[3] = {0, 0, 0};
|
2022-11-03 10:43:27 +01:00
|
|
|
std::memcpy(sunDirJ, susDataProcessed->sunIjkModel.value, 3 * sizeof(double));
|
2022-10-12 15:06:24 +02:00
|
|
|
MatrixOperations<double>::multiply(*dcmBJ, sunDirJ, sunDirB, 3, 3, 1);
|
2022-11-03 10:43:27 +01:00
|
|
|
} else {
|
|
|
|
std::memcpy(sunDirB, susDataProcessed->susVecTot.value, 3 * sizeof(double));
|
2022-10-12 15:06:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
double exclAngle = acsParameters.strParameters.exclusionAngle,
|
|
|
|
blindStart = acsParameters.targetModeControllerParameters.blindAvoidStart,
|
|
|
|
blindEnd = acsParameters.targetModeControllerParameters.blindAvoidStop;
|
|
|
|
double sightAngleSun =
|
|
|
|
VectorOperations<double>::dot(acsParameters.strParameters.boresightAxis, sunDirB);
|
|
|
|
|
|
|
|
if (!(strBlindAvoidFlag)) {
|
|
|
|
double critSightAngle = blindStart * exclAngle;
|
|
|
|
|
|
|
|
if (sightAngleSun < critSightAngle) {
|
|
|
|
strBlindAvoidFlag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
if (sightAngleSun < blindEnd * exclAngle) {
|
|
|
|
double normBlindRefRate = acsParameters.targetModeControllerParameters.blindRotRate;
|
|
|
|
double blindRefRate[3] = {0, 0, 0};
|
|
|
|
|
|
|
|
if (sunDirB[1] < 0) {
|
|
|
|
blindRefRate[0] = normBlindRefRate;
|
|
|
|
blindRefRate[1] = 0;
|
|
|
|
blindRefRate[2] = 0;
|
|
|
|
} else {
|
|
|
|
blindRefRate[0] = -normBlindRefRate;
|
|
|
|
blindRefRate[1] = 0;
|
|
|
|
blindRefRate[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorOperations<double>::add(blindRefRate, refSatRate, refSatRate, 3);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
strBlindAvoidFlag = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-19 15:17:39 +02:00
|
|
|
}
|
|
|
|
|
2023-01-23 16:34:52 +01:00
|
|
|
void Guidance::refRotationRate(int8_t timeElapsedMax, timeval now, double quatInertialTarget[4],
|
|
|
|
double *refSatRate) {
|
2023-01-10 11:20:28 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of reference rotation rate
|
|
|
|
//-------------------------------------------------------------------------------------
|
2023-01-23 16:34:52 +01:00
|
|
|
double timeElapsed = now.tv_sec + now.tv_usec * pow(10, -6) -
|
|
|
|
(timeSavedQuaternion.tv_sec +
|
|
|
|
timeSavedQuaternion.tv_usec * pow((double)timeSavedQuaternion.tv_usec, -6));
|
2023-01-12 15:19:21 +01:00
|
|
|
if (timeElapsed < timeElapsedMax) {
|
2023-01-10 11:20:28 +01:00
|
|
|
double qDiff[4] = {0, 0, 0, 0};
|
2023-01-12 15:19:21 +01:00
|
|
|
VectorOperations<double>::subtract(quatInertialTarget, savedQuaternion, qDiff, 4);
|
2023-01-10 11:20:28 +01:00
|
|
|
VectorOperations<double>::mulScalar(qDiff, 1 / timeElapsed, qDiff, 4);
|
|
|
|
|
|
|
|
double tgtQuatVec[3] = {quatInertialTarget[0], quatInertialTarget[1], quatInertialTarget[2]},
|
|
|
|
qDiffVec[3] = {qDiff[0], qDiff[1], qDiff[2]};
|
|
|
|
double sum1[3] = {0, 0, 0}, sum2[3] = {0, 0, 0}, sum3[3] = {0, 0, 0}, sum[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(quatInertialTarget, qDiff, sum1);
|
|
|
|
VectorOperations<double>::mulScalar(tgtQuatVec, qDiff[3], sum2, 3);
|
|
|
|
VectorOperations<double>::mulScalar(qDiffVec, quatInertialTarget[3], sum3, 3);
|
|
|
|
VectorOperations<double>::add(sum1, sum2, sum, 3);
|
|
|
|
VectorOperations<double>::subtract(sum, sum3, sum, 3);
|
|
|
|
double omegaRefNew[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::mulScalar(sum, -2, omegaRefNew, 3);
|
|
|
|
|
|
|
|
VectorOperations<double>::mulScalar(omegaRefNew, 2, refSatRate, 3);
|
2023-01-12 15:19:21 +01:00
|
|
|
VectorOperations<double>::subtract(refSatRate, omegaRefSaved, refSatRate, 3);
|
|
|
|
omegaRefSaved[0] = omegaRefNew[0];
|
|
|
|
omegaRefSaved[1] = omegaRefNew[1];
|
|
|
|
omegaRefSaved[2] = omegaRefNew[2];
|
2023-01-10 11:20:28 +01:00
|
|
|
} else {
|
|
|
|
refSatRate[0] = 0;
|
|
|
|
refSatRate[1] = 0;
|
|
|
|
refSatRate[2] = 0;
|
|
|
|
}
|
|
|
|
|
2023-01-12 15:19:21 +01:00
|
|
|
timeSavedQuaternion = now;
|
|
|
|
savedQuaternion[0] = quatInertialTarget[0];
|
|
|
|
savedQuaternion[1] = quatInertialTarget[1];
|
|
|
|
savedQuaternion[2] = quatInertialTarget[2];
|
|
|
|
savedQuaternion[3] = quatInertialTarget[3];
|
2023-01-10 11:20:28 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 13:44:44 +01:00
|
|
|
void Guidance::targetQuatPtgThreeAxes(acsctrl::MekfData *mekfData, timeval now,
|
2022-12-14 11:46:58 +01:00
|
|
|
double targetQuat[4], double refSatRate[3]) {
|
2022-12-13 11:51:03 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of target quaternion for target pointing
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Transform longitude, latitude and altitude to cartesian coordiantes (earth
|
|
|
|
// fixed/centered frame)
|
2023-01-10 11:20:28 +01:00
|
|
|
double targetCart[3] = {0, 0, 0};
|
|
|
|
MathOperations<double>::cartesianFromLatLongAlt(
|
2023-01-23 16:34:52 +01:00
|
|
|
acsParameters.targetModeControllerParameters.latitudeTgt,
|
|
|
|
acsParameters.targetModeControllerParameters.longitudeTgt,
|
2023-01-12 15:19:21 +01:00
|
|
|
acsParameters.targetModeControllerParameters.altitudeTgt, targetCart);
|
2022-12-13 11:51:03 +01:00
|
|
|
double targetDirE[3] = {0, 0, 0};
|
2023-01-10 11:20:28 +01:00
|
|
|
VectorOperations<double>::subtract(targetCart, posSatE, targetDirE, 3);
|
2022-12-13 11:51:03 +01:00
|
|
|
|
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
|
|
|
|
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// Target Direction and position vector in the inertial frame
|
|
|
|
double targetDirJ[3] = {0, 0, 0}, posSatJ[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, targetDirE, targetDirJ, 3, 3, 1);
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, posSatE, posSatJ, 3, 3, 1);
|
|
|
|
|
|
|
|
// negative x-Axis aligned with target (Camera/E-band transmitter position)
|
|
|
|
double xAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::normalize(targetDirJ, xAxis, 3);
|
|
|
|
VectorOperations<double>::mulScalar(xAxis, -1, xAxis, 3);
|
|
|
|
|
|
|
|
// Transform velocity into inertial frame
|
2022-12-14 11:46:58 +01:00
|
|
|
double velocityE[3];
|
|
|
|
std::memcpy(velocityE, gpsDataProcessed->gpsVelocity.value, 3 * sizeof(double));
|
2022-12-13 11:51:03 +01:00
|
|
|
double velocityJ[3] = {0, 0, 0}, velPart1[3] = {0, 0, 0}, velPart2[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, velocityE, velPart1, 3, 3, 1);
|
|
|
|
MatrixOperations<double>::multiply(*dcmJEDot, posSatE, velPart2, 3, 3, 1);
|
|
|
|
VectorOperations<double>::add(velPart1, velPart2, velocityJ, 3);
|
|
|
|
|
|
|
|
// orbital normal vector
|
|
|
|
double orbitalNormalJ[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(posSatJ, velocityJ, orbitalNormalJ);
|
|
|
|
VectorOperations<double>::normalize(orbitalNormalJ, orbitalNormalJ, 3);
|
|
|
|
|
|
|
|
// y-Axis of satellite in orbit plane so that z-axis parallel to long side of picture resolution
|
|
|
|
double yAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(orbitalNormalJ, xAxis, yAxis);
|
|
|
|
VectorOperations<double>::normalize(yAxis, yAxis, 3);
|
|
|
|
|
|
|
|
// z-Axis completes RHS
|
|
|
|
double zAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(xAxis, yAxis, zAxis);
|
|
|
|
|
|
|
|
// Complete transformation matrix
|
|
|
|
double dcmTgt[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
|
|
|
|
{xAxis[1], yAxis[1], zAxis[1]},
|
|
|
|
{xAxis[2], yAxis[2], zAxis[2]}};
|
|
|
|
double quatInertialTarget[4] = {0, 0, 0, 0};
|
|
|
|
QuaternionOperations::fromDcm(dcmTgt, quatInertialTarget);
|
|
|
|
|
2023-01-12 15:19:21 +01:00
|
|
|
int8_t timeElapsedMax = acsParameters.targetModeControllerParameters.timeElapsedMax;
|
|
|
|
refRotationRate(timeElapsedMax, now, quatInertialTarget, refSatRate);
|
2023-01-10 11:20:28 +01:00
|
|
|
|
|
|
|
// Transform in system relative to satellite frame
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
|
|
|
QuaternionOperations::multiply(quatBJ, quatInertialTarget, targetQuat);
|
|
|
|
}
|
|
|
|
|
2023-02-17 13:44:44 +01:00
|
|
|
void Guidance::targetQuatPtgGs(timeval now, double targetQuat[4], double refSatRate[3]) {
|
2022-12-13 11:51:03 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
2023-01-10 11:20:28 +01:00
|
|
|
// Calculation of target quaternion for ground station pointing
|
2022-12-13 11:51:03 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
2023-01-10 11:20:28 +01:00
|
|
|
// Transform longitude, latitude and altitude to cartesian coordiantes (earth
|
|
|
|
// fixed/centered frame)
|
|
|
|
double groundStationCart[3] = {0, 0, 0};
|
2022-12-13 11:51:03 +01:00
|
|
|
|
2023-01-10 11:20:28 +01:00
|
|
|
MathOperations<double>::cartesianFromLatLongAlt(
|
2023-01-23 16:34:52 +01:00
|
|
|
acsParameters.targetModeControllerParameters.latitudeTgt,
|
|
|
|
acsParameters.targetModeControllerParameters.longitudeTgt,
|
2023-01-12 15:19:21 +01:00
|
|
|
acsParameters.targetModeControllerParameters.altitudeTgt, groundStationCart);
|
2023-01-10 11:20:28 +01:00
|
|
|
double targetDirE[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::subtract(groundStationCart, posSatE, targetDirE, 3);
|
2022-12-13 11:51:03 +01:00
|
|
|
|
2023-01-10 11:20:28 +01:00
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
2022-12-13 11:51:03 +01:00
|
|
|
|
2023-01-10 11:20:28 +01:00
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// Target Direction and position vector in the inertial frame
|
|
|
|
double targetDirJ[3] = {0, 0, 0}, posSatJ[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, targetDirE, targetDirJ, 3, 3, 1);
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, posSatE, posSatJ, 3, 3, 1);
|
|
|
|
|
|
|
|
// negative x-Axis aligned with target (Camera/E-band transmitter position)
|
|
|
|
double xAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::normalize(targetDirJ, xAxis, 3);
|
|
|
|
VectorOperations<double>::mulScalar(xAxis, -1, xAxis, 3);
|
|
|
|
|
2023-01-11 16:00:30 +01:00
|
|
|
// get Sun Vector Model in ECI
|
2023-01-10 11:20:28 +01:00
|
|
|
double sunJ[3];
|
|
|
|
std::memcpy(sunJ, susDataProcessed->sunIjkModel.value, 3 * sizeof(double));
|
|
|
|
VectorOperations<double>::normalize(sunJ, sunJ, 3);
|
|
|
|
|
2023-01-11 16:00:30 +01:00
|
|
|
// calculate z-axis as projection of sun vector into plane defined by x-axis as normal vector
|
|
|
|
// z = sPerpenticular = s - sParallel = s - (x*s)/norm(x)^2 * x
|
|
|
|
double xDotS = VectorOperations<double>::dot(xAxis, sunJ);
|
|
|
|
xDotS /= pow(VectorOperations<double>::norm(xAxis, 3), 2);
|
|
|
|
double sunParallel[3], zAxis[3];
|
|
|
|
VectorOperations<double>::mulScalar(xAxis, xDotS, sunParallel, 3);
|
|
|
|
VectorOperations<double>::subtract(sunJ, sunParallel, zAxis, 3);
|
|
|
|
VectorOperations<double>::normalize(zAxis, zAxis, 3);
|
|
|
|
|
2023-01-10 11:20:28 +01:00
|
|
|
// calculate y-axis
|
|
|
|
double yAxis[3];
|
2023-01-11 16:00:30 +01:00
|
|
|
VectorOperations<double>::cross(zAxis, xAxis, yAxis);
|
2023-01-10 11:20:28 +01:00
|
|
|
VectorOperations<double>::normalize(yAxis, yAxis, 3);
|
|
|
|
|
|
|
|
// Complete transformation matrix
|
|
|
|
double dcmTgt[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
|
|
|
|
{xAxis[1], yAxis[1], zAxis[1]},
|
|
|
|
{xAxis[2], yAxis[2], zAxis[2]}};
|
|
|
|
double quatInertialTarget[4] = {0, 0, 0, 0};
|
|
|
|
QuaternionOperations::fromDcm(dcmTgt, quatInertialTarget);
|
|
|
|
|
2023-01-12 15:19:21 +01:00
|
|
|
int8_t timeElapsedMax = acsParameters.targetModeControllerParameters.timeElapsedMax;
|
|
|
|
refRotationRate(timeElapsedMax, now, quatInertialTarget, refSatRate);
|
2022-12-13 11:51:03 +01:00
|
|
|
|
|
|
|
// Transform in system relative to satellite frame
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
2022-12-13 11:51:03 +01:00
|
|
|
QuaternionOperations::multiply(quatBJ, quatInertialTarget, targetQuat);
|
2022-11-24 13:40:55 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 13:54:36 +01:00
|
|
|
void Guidance::targetQuatPtgSun(timeval now, double targetQuat[4], double refSatRate[3]) {
|
2022-10-28 18:18:28 +02:00
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of target quaternion to sun
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
|
|
|
double dcmBJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
2022-10-28 18:18:28 +02:00
|
|
|
QuaternionOperations::toDcm(quatBJ, dcmBJ);
|
|
|
|
|
2022-11-24 13:40:55 +01:00
|
|
|
double sunDirJ[3] = {0, 0, 0}, sunDirB[3] = {0, 0, 0};
|
2022-12-14 11:46:58 +01:00
|
|
|
if (susDataProcessed->sunIjkModel.isValid()) {
|
|
|
|
std::memcpy(sunDirJ, susDataProcessed->sunIjkModel.value, 3 * sizeof(double));
|
2022-11-24 13:40:55 +01:00
|
|
|
MatrixOperations<double>::multiply(*dcmBJ, sunDirJ, sunDirB, 3, 3, 1);
|
2023-01-11 16:00:30 +01:00
|
|
|
} else if (susDataProcessed->susVecTot.isValid()) {
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(sunDirB, susDataProcessed->susVecTot.value, 3 * sizeof(double));
|
2023-01-11 16:00:30 +01:00
|
|
|
} else {
|
|
|
|
return;
|
2022-10-28 18:18:28 +02:00
|
|
|
}
|
|
|
|
|
2022-11-24 13:40:55 +01:00
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// positive z-Axis of EIVE in direction of sun
|
2022-12-13 11:51:03 +01:00
|
|
|
double zAxis[3] = {0, 0, 0};
|
2022-11-24 13:40:55 +01:00
|
|
|
VectorOperations<double>::normalize(sunDirB, zAxis, 3);
|
|
|
|
|
2023-01-16 15:23:20 +01:00
|
|
|
// Assign helper vector (north pole inertial)
|
|
|
|
double helperVec[3] = {0, 0, 1};
|
2022-11-24 13:40:55 +01:00
|
|
|
|
2023-02-17 11:39:18 +01:00
|
|
|
// Construct y-axis from helper vector and z-axis
|
2022-11-24 13:40:55 +01:00
|
|
|
double yAxis[3] = {0, 0, 0};
|
2023-01-12 11:48:57 +01:00
|
|
|
VectorOperations<double>::cross(zAxis, helperVec, yAxis);
|
2022-11-24 13:40:55 +01:00
|
|
|
VectorOperations<double>::normalize(yAxis, yAxis, 3);
|
|
|
|
|
2023-02-17 11:39:18 +01:00
|
|
|
// Construct x-axis from y- and z-axes
|
2022-11-24 13:40:55 +01:00
|
|
|
double xAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(yAxis, zAxis, xAxis);
|
2023-01-12 11:48:57 +01:00
|
|
|
VectorOperations<double>::normalize(xAxis, xAxis, 3);
|
2022-11-24 13:40:55 +01:00
|
|
|
|
|
|
|
// Transformation matrix to Sun, no further transforamtions, reference is already
|
|
|
|
// the EIVE body frame
|
2022-12-13 11:51:03 +01:00
|
|
|
double dcmTgt[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
|
|
|
|
{xAxis[1], yAxis[1], zAxis[1]},
|
|
|
|
{xAxis[2], yAxis[2], zAxis[2]}};
|
2022-11-24 13:40:55 +01:00
|
|
|
double quatSun[4] = {0, 0, 0, 0};
|
2022-12-13 11:51:03 +01:00
|
|
|
QuaternionOperations::fromDcm(dcmTgt, quatSun);
|
2022-11-24 13:40:55 +01:00
|
|
|
|
|
|
|
targetQuat[0] = quatSun[0];
|
|
|
|
targetQuat[1] = quatSun[1];
|
|
|
|
targetQuat[2] = quatSun[2];
|
|
|
|
targetQuat[3] = quatSun[3];
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2022-10-28 18:18:28 +02:00
|
|
|
// Calculation of reference rotation rate
|
2022-11-24 13:40:55 +01:00
|
|
|
//----------------------------------------------------------------------------
|
2022-10-28 18:18:28 +02:00
|
|
|
refSatRate[0] = 0;
|
|
|
|
refSatRate[1] = 0;
|
|
|
|
refSatRate[2] = 0;
|
|
|
|
}
|
|
|
|
|
2023-02-17 13:54:36 +01:00
|
|
|
void Guidance::targetQuatPtgNadirSingleAxis(timeval now, double targetQuat[4],
|
2022-12-13 11:51:03 +01:00
|
|
|
double refSatRate[3]) { // old version of Nadir Pointing
|
2022-11-08 13:48:50 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of target quaternion for Nadir pointing
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
double targetDirE[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::mulScalar(posSatE, -1, targetDirE, 3);
|
|
|
|
|
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
|
|
|
|
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// Transformation between ECEF and Body frame
|
|
|
|
double dcmBJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmBE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
2022-11-08 13:48:50 +01:00
|
|
|
QuaternionOperations::toDcm(quatBJ, dcmBJ);
|
|
|
|
MatrixOperations<double>::multiply(*dcmBJ, *dcmJE, *dcmBE, 3, 3, 3);
|
|
|
|
|
|
|
|
// Target Direction in the body frame
|
|
|
|
double targetDirB[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmBE, targetDirE, targetDirB, 3, 3, 1);
|
|
|
|
|
|
|
|
// rotation quaternion from two vectors
|
|
|
|
double refDir[3] = {0, 0, 0};
|
2023-01-12 15:19:21 +01:00
|
|
|
refDir[0] = acsParameters.nadirModeControllerParameters.refDirection[0];
|
|
|
|
refDir[1] = acsParameters.nadirModeControllerParameters.refDirection[1];
|
|
|
|
refDir[2] = acsParameters.nadirModeControllerParameters.refDirection[2];
|
2022-11-08 13:48:50 +01:00
|
|
|
double noramlizedTargetDirB[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::normalize(targetDirB, noramlizedTargetDirB, 3);
|
|
|
|
VectorOperations<double>::normalize(refDir, refDir, 3);
|
|
|
|
double normTargetDirB = VectorOperations<double>::norm(noramlizedTargetDirB, 3);
|
|
|
|
double normRefDir = VectorOperations<double>::norm(refDir, 3);
|
|
|
|
double crossDir[3] = {0, 0, 0};
|
|
|
|
double dotDirections = VectorOperations<double>::dot(noramlizedTargetDirB, refDir);
|
|
|
|
VectorOperations<double>::cross(noramlizedTargetDirB, refDir, crossDir);
|
|
|
|
targetQuat[0] = crossDir[0];
|
|
|
|
targetQuat[1] = crossDir[1];
|
|
|
|
targetQuat[2] = crossDir[2];
|
|
|
|
targetQuat[3] = sqrt(pow(normTargetDirB, 2) * pow(normRefDir, 2) + dotDirections);
|
|
|
|
VectorOperations<double>::normalize(targetQuat, targetQuat, 4);
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of reference rotation rate
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
refSatRate[0] = 0;
|
|
|
|
refSatRate[1] = 0;
|
|
|
|
refSatRate[2] = 0;
|
|
|
|
}
|
|
|
|
|
2023-02-17 13:44:44 +01:00
|
|
|
void Guidance::quatNadirPtgThreeAxes(double posSateE[3], double velSateE[3], timeval now,
|
|
|
|
double targetQuat[4], double refSatRate[3]) {
|
2022-12-13 11:51:03 +01:00
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
// Calculation of target quaternion for Nadir pointing
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
double targetDirE[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::mulScalar(posSatE, -1, targetDirE, 3);
|
|
|
|
|
|
|
|
// Transformation between ECEF and IJK frame
|
|
|
|
double dcmEJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmJE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
double dcmEJDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEJ, *dcmEJDot);
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJ, *dcmJE);
|
|
|
|
|
|
|
|
double dcmJEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
MathOperations<double>::inverseMatrixDimThree(*dcmEJDot, *dcmJEDot);
|
|
|
|
|
|
|
|
// Target Direction in the body frame
|
|
|
|
double targetDirJ[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, targetDirE, targetDirJ, 3, 3, 1);
|
|
|
|
|
|
|
|
// negative x-Axis aligned with target (Camera position)
|
|
|
|
double xAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::normalize(targetDirJ, xAxis, 3);
|
|
|
|
VectorOperations<double>::mulScalar(xAxis, -1, xAxis, 3);
|
|
|
|
|
|
|
|
// z-Axis parallel to long side of picture resolution
|
2023-02-17 13:44:44 +01:00
|
|
|
double zAxis[3] = {0, 0, 0};
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(velocityE, gpsDataProcessed->gpsVelocity.value, 3 * sizeof(double));
|
2022-12-13 11:51:03 +01:00
|
|
|
double velocityJ[3] = {0, 0, 0}, velPart1[3] = {0, 0, 0}, velPart2[3] = {0, 0, 0};
|
|
|
|
MatrixOperations<double>::multiply(*dcmJE, velocityE, velPart1, 3, 3, 1);
|
|
|
|
MatrixOperations<double>::multiply(*dcmJEDot, posSatE, velPart2, 3, 3, 1);
|
|
|
|
VectorOperations<double>::add(velPart1, velPart2, velocityJ, 3);
|
|
|
|
VectorOperations<double>::cross(xAxis, velocityJ, zAxis);
|
|
|
|
VectorOperations<double>::normalize(zAxis, zAxis, 3);
|
|
|
|
|
|
|
|
// y-Axis completes RHS
|
|
|
|
double yAxis[3] = {0, 0, 0};
|
|
|
|
VectorOperations<double>::cross(zAxis, xAxis, yAxis);
|
|
|
|
|
|
|
|
// Complete transformation matrix
|
|
|
|
double dcmTgt[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
|
|
|
|
{xAxis[1], yAxis[1], zAxis[1]},
|
|
|
|
{xAxis[2], yAxis[2], zAxis[2]}};
|
|
|
|
double quatInertialTarget[4] = {0, 0, 0, 0};
|
|
|
|
QuaternionOperations::fromDcm(dcmTgt, quatInertialTarget);
|
|
|
|
|
2023-01-12 15:19:21 +01:00
|
|
|
int8_t timeElapsedMax = acsParameters.nadirModeControllerParameters.timeElapsedMax;
|
|
|
|
refRotationRate(timeElapsedMax, now, quatInertialTarget, refSatRate);
|
2022-12-13 11:51:03 +01:00
|
|
|
|
|
|
|
// Transform in system relative to satellite frame
|
|
|
|
double quatBJ[4] = {0, 0, 0, 0};
|
2022-12-14 11:46:58 +01:00
|
|
|
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
2022-12-13 11:51:03 +01:00
|
|
|
QuaternionOperations::multiply(quatBJ, quatInertialTarget, targetQuat);
|
2022-11-22 21:10:05 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 13:54:36 +01:00
|
|
|
void Guidance::targetQuatPtgInertial(double targetQuat[4], double refSatRate[3]) {
|
2023-01-23 16:34:52 +01:00
|
|
|
std::memcpy(targetQuat, acsParameters.inertialModeControllerParameters.tgtQuat,
|
|
|
|
4 * sizeof(double));
|
|
|
|
std::memcpy(refSatRate, acsParameters.inertialModeControllerParameters.refRotRate,
|
|
|
|
3 * sizeof(double));
|
2022-11-14 17:16:47 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 13:44:44 +01:00
|
|
|
void Guidance::comparePtg(double targetQuat[4], double quatRef[4], double refSatRate[3],
|
|
|
|
double quatErrorComplete[4], double quatError[3], double deltaRate[3]) {
|
2022-10-12 15:06:24 +02:00
|
|
|
double satRate[3] = {0, 0, 0};
|
2022-11-03 10:43:27 +01:00
|
|
|
std::memcpy(satRate, mekfData->satRotRateMekf.value, 3 * sizeof(double));
|
2022-10-12 15:06:24 +02:00
|
|
|
VectorOperations<double>::subtract(satRate, refSatRate, deltaRate, 3);
|
|
|
|
// valid checks ?
|
|
|
|
double quatErrorMtx[4][4] = {{quatRef[3], quatRef[2], -quatRef[1], -quatRef[0]},
|
|
|
|
{-quatRef[2], quatRef[3], quatRef[0], -quatRef[1]},
|
|
|
|
{quatRef[1], -quatRef[0], quatRef[3], -quatRef[2]},
|
|
|
|
{quatRef[0], -quatRef[1], quatRef[2], quatRef[3]}};
|
|
|
|
|
|
|
|
MatrixOperations<double>::multiply(*quatErrorMtx, targetQuat, quatErrorComplete, 4, 4, 1);
|
|
|
|
|
|
|
|
if (quatErrorComplete[3] < 0) {
|
|
|
|
quatErrorComplete[3] *= -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
quatError[0] = quatErrorComplete[0];
|
|
|
|
quatError[1] = quatErrorComplete[1];
|
|
|
|
quatError[2] = quatErrorComplete[2];
|
|
|
|
|
2022-12-14 11:46:58 +01:00
|
|
|
// target flag in matlab, importance, does look like it only gives feedback if pointing control is
|
|
|
|
// under 150 arcsec ??
|
2022-09-19 15:17:39 +02:00
|
|
|
}
|
|
|
|
|
2023-02-16 15:40:16 +01:00
|
|
|
ReturnValue_t Guidance::getDistributionMatrixRw(ACS::SensorValues *sensorValues,
|
|
|
|
double *rwPseudoInv) {
|
|
|
|
bool rw1valid = (sensorValues->rw1Set.state.value && sensorValues->rw1Set.state.isValid());
|
|
|
|
bool rw2valid = (sensorValues->rw2Set.state.value && sensorValues->rw2Set.state.isValid());
|
|
|
|
bool rw3valid = (sensorValues->rw3Set.state.value && sensorValues->rw3Set.state.isValid());
|
|
|
|
bool rw4valid = (sensorValues->rw4Set.state.value && sensorValues->rw4Set.state.isValid());
|
|
|
|
|
|
|
|
if (rw1valid && rw2valid && rw3valid && rw4valid) {
|
|
|
|
std::memcpy(rwPseudoInv, acsParameters.rwMatrices.pseudoInverse, 12 * sizeof(double));
|
|
|
|
return returnvalue::OK;
|
|
|
|
} else if (!rw1valid && rw2valid && rw3valid && rw4valid) {
|
|
|
|
std::memcpy(rwPseudoInv, acsParameters.rwMatrices.without1, 12 * sizeof(double));
|
|
|
|
return returnvalue::OK;
|
|
|
|
} else if (rw1valid && !rw2valid && rw3valid && rw4valid) {
|
|
|
|
std::memcpy(rwPseudoInv, acsParameters.rwMatrices.without2, 12 * sizeof(double));
|
|
|
|
return returnvalue::OK;
|
|
|
|
} else if (rw1valid && rw2valid && !rw3valid && rw4valid) {
|
|
|
|
std::memcpy(rwPseudoInv, acsParameters.rwMatrices.without3, 12 * sizeof(double));
|
|
|
|
return returnvalue::OK;
|
|
|
|
} else if (rw1valid && rw2valid && rw3valid && !rw4valid) {
|
|
|
|
std::memcpy(rwPseudoInv, acsParameters.rwMatrices.without4, 12 * sizeof(double));
|
|
|
|
return returnvalue::OK;
|
|
|
|
} else {
|
2022-10-12 15:06:24 +02:00
|
|
|
// @note: This one takes the normal pseudoInverse of all four raction wheels valid.
|
|
|
|
// Does not make sense, but is implemented that way in MATLAB ?!
|
|
|
|
// Thought: It does not really play a role, because in case there are more then one
|
2022-10-28 18:18:28 +02:00
|
|
|
// reaction wheel invalid the pointing control is destined to fail.
|
2023-02-16 15:40:16 +01:00
|
|
|
return returnvalue::FAILED;
|
2022-10-12 15:06:24 +02:00
|
|
|
}
|
2022-09-19 15:17:39 +02:00
|
|
|
}
|