eive-obsw/mission/controller/acs/Guidance.cpp

577 lines
28 KiB
C++
Raw Normal View History

2022-09-19 15:17:39 +02:00
#include "Guidance.h"
2022-10-12 15:06:24 +02: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
#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
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::targetQuatPtgSingleAxis(timeval now, double posSatE[3], double velSatE[3],
double sunDirI[3], double refDirB[3], double quatBI[4],
double targetQuat[4], double targetSatRotRate[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
//-------------------------------------------------------------------------------------
// transform longitude, latitude and altitude to ECEF
double targetE[3] = {0, 0, 0};
2022-10-12 15:06:24 +02:00
MathOperations<double>::cartesianFromLatLongAlt(
acsParameters->targetModeControllerParameters.latitudeTgt,
acsParameters->targetModeControllerParameters.longitudeTgt,
acsParameters->targetModeControllerParameters.altitudeTgt, targetE);
2022-10-12 15:06:24 +02:00
// target direction in the ECEF frame
2022-10-12 15:06:24 +02:00
double targetDirE[3] = {0, 0, 0};
VectorOperations<double>::subtract(targetE, posSatE, targetDirE, 3);
2022-10-12 15:06:24 +02:00
// transformation between ECEF and ECI frame
2023-02-20 15:59:01 +01:00
double dcmEI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmIE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmEIDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEI, *dcmEIDot);
MathOperations<double>::inverseMatrixDimThree(*dcmEI, *dcmIE);
2022-10-12 15:06:24 +02:00
2023-02-20 15:59:01 +01:00
double dcmIEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::inverseMatrixDimThree(*dcmEIDot, *dcmIEDot);
2022-10-12 15:06:24 +02:00
// transformation between ECEF and Body frame
double dcmBI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
2022-10-12 15:06:24 +02:00
double dcmBE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
QuaternionOperations::toDcm(quatBI, dcmBI);
MatrixOperations<double>::multiply(*dcmBI, *dcmIE, *dcmBE, 3, 3, 3);
2022-10-12 15:06:24 +02:00
// target Direction in the body frame
2022-10-12 15:06:24 +02:00
double targetDirB[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmBE, targetDirE, targetDirB, 3, 3, 1);
// rotation quaternion from two vectors
2022-10-12 15:06:24 +02:00
double refDir[3] = {0, 0, 0};
refDir[0] = acsParameters->targetModeControllerParameters.refDirection[0];
refDir[1] = acsParameters->targetModeControllerParameters.refDirection[1];
refDir[2] = acsParameters->targetModeControllerParameters.refDirection[2];
2022-10-12 15:06:24 +02: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
2022-10-12 15:06:24 +02:00
//-------------------------------------------------------------------------------------
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
2022-10-12 15:06:24 +02:00
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(*dcmBI, *dcmIEDot, *dcmBEDot, 3, 3, 3);
2022-10-12 15:06:24 +02:00
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, targetSatRotRate, 3);
2022-10-12 15:06:24 +02:00
//-------------------------------------------------------------------------------------
// Calculation of reference rotation rate in case of star tracker blinding
//-------------------------------------------------------------------------------------
if (acsParameters->targetModeControllerParameters.avoidBlindStr) {
2022-10-12 15:06:24 +02:00
double sunDirB[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmBI, sunDirI, sunDirB, 3, 3, 1);
2022-10-12 15:06:24 +02:00
double exclAngle = acsParameters->strParameters.exclusionAngle,
blindStart = acsParameters->targetModeControllerParameters.blindAvoidStart,
blindEnd = acsParameters->targetModeControllerParameters.blindAvoidStop;
2022-10-12 15:06:24 +02:00
double sightAngleSun =
VectorOperations<double>::dot(acsParameters->strParameters.boresightAxis, sunDirB);
2022-10-12 15:06:24 +02:00
if (!(strBlindAvoidFlag)) {
double critSightAngle = blindStart * exclAngle;
if (sightAngleSun < critSightAngle) {
strBlindAvoidFlag = true;
}
} else {
2022-10-12 15:06:24 +02:00
if (sightAngleSun < blindEnd * exclAngle) {
double normBlindRefRate = acsParameters->targetModeControllerParameters.blindRotRate;
2022-10-12 15:06:24 +02:00
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, targetSatRotRate, targetSatRotRate, 3);
2022-10-12 15:06:24 +02:00
} else {
strBlindAvoidFlag = false;
}
}
}
2023-02-21 10:38:10 +01:00
// revert calculated quaternion from qBX to qIX
double quatIB[4] = {0, 0, 0, 1};
QuaternionOperations::inverse(quatBI, quatIB);
QuaternionOperations::multiply(quatIB, targetQuat, targetQuat);
2022-09-19 15:17:39 +02:00
}
void Guidance::targetQuatPtgThreeAxes(timeval now, double posSatE[3], double velSatE[3],
2023-02-20 16:14:40 +01:00
double targetQuat[4], double targetSatRotRate[3]) {
2022-12-13 11:51:03 +01:00
//-------------------------------------------------------------------------------------
// Calculation of target quaternion for target pointing
//-------------------------------------------------------------------------------------
2023-02-20 15:59:01 +01:00
// transform longitude, latitude and altitude to cartesian coordiantes (ECEF)
double targetE[3] = {0, 0, 0};
MathOperations<double>::cartesianFromLatLongAlt(
acsParameters->targetModeControllerParameters.latitudeTgt,
acsParameters->targetModeControllerParameters.longitudeTgt,
acsParameters->targetModeControllerParameters.altitudeTgt, targetE);
2022-12-13 11:51:03 +01:00
double targetDirE[3] = {0, 0, 0};
VectorOperations<double>::subtract(targetE, posSatE, targetDirE, 3);
2022-12-13 11:51:03 +01:00
2023-02-20 15:59:01 +01:00
// transformation between ECEF and ECI frame
double dcmEI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmIE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmEIDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEI, *dcmEIDot);
MathOperations<double>::inverseMatrixDimThree(*dcmEI, *dcmIE);
2022-12-13 11:51:03 +01:00
double dcmIEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::inverseMatrixDimThree(*dcmEIDot, *dcmIEDot);
2022-12-13 11:51:03 +01:00
// target direction in the ECI frame
double posSatI[3] = {0, 0, 0}, targetI[3] = {0, 0, 0}, targetDirI[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmIE, posSatE, posSatI, 3, 3, 1);
MatrixOperations<double>::multiply(*dcmIE, targetE, targetI, 3, 3, 1);
VectorOperations<double>::subtract(targetI, posSatI, targetDirI, 3);
2022-12-13 11:51:03 +01:00
// x-axis aligned with target direction
// this aligns with the camera, E- and S-band antennas
2022-12-13 11:51:03 +01:00
double xAxis[3] = {0, 0, 0};
VectorOperations<double>::normalize(targetDirI, xAxis, 3);
2022-12-13 11:51:03 +01:00
// transform velocity into inertial frame
double velocityI[3] = {0, 0, 0}, velPart1[3] = {0, 0, 0}, velPart2[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmIE, velSatE, velPart1, 3, 3, 1);
MatrixOperations<double>::multiply(*dcmIEDot, posSatE, velPart2, 3, 3, 1);
VectorOperations<double>::add(velPart1, velPart2, velocityI, 3);
2022-12-13 11:51:03 +01:00
// orbital normal vector of target and velocity vector
double orbitalNormalI[3] = {0, 0, 0};
VectorOperations<double>::cross(posSatI, velocityI, orbitalNormalI);
VectorOperations<double>::normalize(orbitalNormalI, orbitalNormalI, 3);
2022-12-13 11:51:03 +01:00
// y-axis of satellite in orbit plane so that z-axis is parallel to long side of picture
// resolution
2022-12-13 11:51:03 +01:00
double yAxis[3] = {0, 0, 0};
VectorOperations<double>::cross(orbitalNormalI, xAxis, yAxis);
2022-12-13 11:51:03 +01:00
VectorOperations<double>::normalize(yAxis, yAxis, 3);
// z-axis completes RHS
2022-12-13 11:51:03 +01:00
double zAxis[3] = {0, 0, 0};
VectorOperations<double>::cross(xAxis, yAxis, zAxis);
// join transformation matrix
double dcmIX[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
{xAxis[1], yAxis[1], zAxis[1]},
{xAxis[2], yAxis[2], zAxis[2]}};
2023-02-20 16:14:40 +01:00
QuaternionOperations::fromDcm(dcmIX, targetQuat);
2022-12-13 11:51:03 +01:00
int8_t timeElapsedMax = acsParameters->targetModeControllerParameters.timeElapsedMax;
2023-02-20 16:14:40 +01:00
targetRotationRate(timeElapsedMax, now, targetQuat, targetSatRotRate);
}
2023-02-20 16:14:40 +01:00
void Guidance::targetQuatPtgGs(timeval now, double posSatE[3], double sunDirI[3],
double targetQuat[4], double targetSatRotRate[3]) {
2022-12-13 11:51:03 +01:00
//-------------------------------------------------------------------------------------
// Calculation of target quaternion for ground station pointing
2022-12-13 11:51:03 +01:00
//-------------------------------------------------------------------------------------
2023-02-20 15:59:01 +01:00
// transform longitude, latitude and altitude to cartesian coordiantes (ECEF)
double groundStationE[3] = {0, 0, 0};
2022-12-13 11:51:03 +01:00
MathOperations<double>::cartesianFromLatLongAlt(
acsParameters->gsTargetModeControllerParameters.latitudeTgt,
acsParameters->gsTargetModeControllerParameters.longitudeTgt,
acsParameters->gsTargetModeControllerParameters.altitudeTgt, groundStationE);
double targetDirE[3] = {0, 0, 0};
2023-02-20 15:59:01 +01:00
VectorOperations<double>::subtract(groundStationE, posSatE, targetDirE, 3);
2022-12-13 11:51:03 +01:00
2023-02-20 15:59:01 +01:00
// transformation between ECEF and ECI frame
double dcmEI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmIE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmEIDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEI, *dcmEIDot);
MathOperations<double>::inverseMatrixDimThree(*dcmEI, *dcmIE);
2022-12-13 11:51:03 +01:00
2023-02-20 15:59:01 +01:00
double dcmIEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::inverseMatrixDimThree(*dcmEIDot, *dcmIEDot);
// target direction in the ECI frame
double posSatI[3] = {0, 0, 0}, groundStationI[3] = {0, 0, 0}, groundStationDirI[3] = {0, 0, 0};
2023-02-20 15:59:01 +01:00
MatrixOperations<double>::multiply(*dcmIE, posSatE, posSatI, 3, 3, 1);
MatrixOperations<double>::multiply(*dcmIE, groundStationE, groundStationI, 3, 3, 1);
VectorOperations<double>::subtract(groundStationI, posSatI, groundStationDirI, 3);
2023-02-20 17:39:03 +01:00
// negative x-axis aligned with target direction
2023-02-20 15:59:01 +01:00
// this aligns with the camera, E- and S-band antennas
double xAxis[3] = {0, 0, 0};
VectorOperations<double>::normalize(groundStationDirI, xAxis, 3);
VectorOperations<double>::mulScalar(xAxis, -1, xAxis, 3);
2023-02-20 15:59:01 +01:00
// get sun vector model in ECI
VectorOperations<double>::normalize(sunDirI, sunDirI, 3);
// 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
2023-02-20 15:59:01 +01:00
double xDotS = VectorOperations<double>::dot(xAxis, sunDirI);
xDotS /= pow(VectorOperations<double>::norm(xAxis, 3), 2);
double sunParallel[3], zAxis[3];
VectorOperations<double>::mulScalar(xAxis, xDotS, sunParallel, 3);
2023-02-20 15:59:01 +01:00
VectorOperations<double>::subtract(sunDirI, sunParallel, zAxis, 3);
VectorOperations<double>::normalize(zAxis, zAxis, 3);
2023-02-20 15:59:01 +01:00
// y-axis completes RHS
double yAxis[3];
VectorOperations<double>::cross(zAxis, xAxis, yAxis);
VectorOperations<double>::normalize(yAxis, yAxis, 3);
2023-02-20 15:59:01 +01:00
// join transformation matrix
double dcmTgt[3][3] = {{xAxis[0], yAxis[0], zAxis[0]},
{xAxis[1], yAxis[1], zAxis[1]},
{xAxis[2], yAxis[2], zAxis[2]}};
2023-02-20 16:14:40 +01:00
QuaternionOperations::fromDcm(dcmTgt, targetQuat);
2022-12-13 11:51:03 +01:00
int8_t timeElapsedMax = acsParameters->gsTargetModeControllerParameters.timeElapsedMax;
2023-02-20 16:14:40 +01:00
targetRotationRate(timeElapsedMax, now, targetQuat, targetSatRotRate);
}
2023-02-20 15:59:01 +01:00
void Guidance::targetQuatPtgSun(double sunDirI[3], double targetQuat[4], double refSatRate[3]) {
//-------------------------------------------------------------------------------------
// Calculation of target quaternion to sun
//-------------------------------------------------------------------------------------
2023-02-20 15:59:01 +01:00
// positive z-Axis of EIVE in direction of sun
2022-12-13 11:51:03 +01:00
double zAxis[3] = {0, 0, 0};
2023-02-20 15:59:01 +01:00
VectorOperations<double>::normalize(sunDirI, zAxis, 3);
2023-02-20 15:59:01 +01:00
// assign helper vector (north pole inertial)
2023-01-16 15:23:20 +01:00
double helperVec[3] = {0, 0, 1};
2023-02-20 15:59:01 +01:00
// construct y-axis from helper vector and z-axis
double yAxis[3] = {0, 0, 0};
VectorOperations<double>::cross(zAxis, helperVec, yAxis);
VectorOperations<double>::normalize(yAxis, yAxis, 3);
2023-02-20 16:14:40 +01:00
// x-axis completes RHS
double xAxis[3] = {0, 0, 0};
VectorOperations<double>::cross(yAxis, zAxis, xAxis);
VectorOperations<double>::normalize(xAxis, xAxis, 3);
2023-02-20 15:59:01 +01:00
// join transformation matrix
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]}};
2023-02-20 15:59:01 +01:00
QuaternionOperations::fromDcm(dcmTgt, targetQuat);
//----------------------------------------------------------------------------
// Calculation of reference rotation rate
//----------------------------------------------------------------------------
refSatRate[0] = 0;
refSatRate[1] = 0;
refSatRate[2] = 0;
}
2023-02-21 10:44:02 +01:00
void Guidance::targetQuatPtgNadirSingleAxis(timeval now, double posSatE[3], double quatBI[4],
double targetQuat[4], double refDirB[3],
2023-02-20 17:39:03 +01:00
double refSatRate[3]) {
//-------------------------------------------------------------------------------------
// Calculation of target quaternion for Nadir pointing
//-------------------------------------------------------------------------------------
double targetDirE[3] = {0, 0, 0};
VectorOperations<double>::mulScalar(posSatE, -1, targetDirE, 3);
2023-02-20 17:39:03 +01:00
// transformation between ECEF and ECI frame
2023-02-21 10:44:02 +01:00
double dcmEI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmIE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmEIDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEI, *dcmEIDot);
MathOperations<double>::inverseMatrixDimThree(*dcmEI, *dcmIE);
2023-02-21 10:44:02 +01:00
double dcmIEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::inverseMatrixDimThree(*dcmEIDot, *dcmIEDot);
2023-02-20 17:39:03 +01:00
// transformation between ECEF and Body frame
2023-02-21 10:44:02 +01:00
double dcmBI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmBE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
2023-02-21 10:44:02 +01:00
QuaternionOperations::toDcm(quatBI, dcmBI);
MatrixOperations<double>::multiply(*dcmBI, *dcmIE, *dcmBE, 3, 3, 3);
2023-02-20 17:39:03 +01:00
// target Direction in the body frame
double targetDirB[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmBE, targetDirE, targetDirB, 3, 3, 1);
2023-02-20 17:39:03 +01:00
// rotation quaternion from two vectors
double refDir[3] = {0, 0, 0};
refDir[0] = acsParameters->nadirModeControllerParameters.refDirection[0];
refDir[1] = acsParameters->nadirModeControllerParameters.refDirection[1];
refDir[2] = acsParameters->nadirModeControllerParameters.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
//-------------------------------------------------------------------------------------
refSatRate[0] = 0;
refSatRate[1] = 0;
refSatRate[2] = 0;
2023-02-21 10:44:02 +01:00
// revert calculated quaternion from qBX to qIX
double quatIB[4] = {0, 0, 0, 1};
QuaternionOperations::inverse(quatBI, quatIB);
QuaternionOperations::multiply(quatIB, targetQuat, targetQuat);
}
2023-02-20 16:20:54 +01:00
void Guidance::targetQuatPtgNadirThreeAxes(timeval now, double posSatE[3], double velSatE[3],
double targetQuat[4], double refSatRate[3]) {
2022-12-13 11:51:03 +01:00
//-------------------------------------------------------------------------------------
// Calculation of target quaternion for Nadir pointing
//-------------------------------------------------------------------------------------
2023-02-20 16:14:40 +01:00
// transformation between ECEF and ECI frame
double dcmEI[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmIE[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double dcmEIDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::ecfToEciWithNutPre(now, *dcmEI, *dcmEIDot);
MathOperations<double>::inverseMatrixDimThree(*dcmEI, *dcmIE);
2022-12-13 11:51:03 +01:00
2023-02-20 16:14:40 +01:00
double dcmIEDot[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
MathOperations<double>::inverseMatrixDimThree(*dcmEIDot, *dcmIEDot);
2022-12-13 11:51:03 +01:00
2023-02-20 16:14:40 +01:00
// satellite position in inertial reference frame
double posSatI[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmIE, posSatE, posSatI, 3, 3, 1);
2022-12-13 11:51:03 +01:00
2023-02-20 16:14:40 +01:00
// negative x-axis aligned with position vector
// this aligns with the camera, E- and S-band antennas
2022-12-13 11:51:03 +01:00
double xAxis[3] = {0, 0, 0};
2023-02-20 16:14:40 +01:00
VectorOperations<double>::normalize(posSatI, xAxis, 3);
2022-12-13 11:51:03 +01:00
VectorOperations<double>::mulScalar(xAxis, -1, xAxis, 3);
2023-02-20 16:14:40 +01:00
// make z-Axis parallel to major part of camera resolution
2023-02-17 13:44:44 +01:00
double zAxis[3] = {0, 0, 0};
2023-02-20 16:14:40 +01:00
double velocityI[3] = {0, 0, 0}, velPart1[3] = {0, 0, 0}, velPart2[3] = {0, 0, 0};
MatrixOperations<double>::multiply(*dcmIE, velSatE, velPart1, 3, 3, 1);
MatrixOperations<double>::multiply(*dcmIEDot, posSatE, velPart2, 3, 3, 1);
VectorOperations<double>::add(velPart1, velPart2, velocityI, 3);
VectorOperations<double>::cross(xAxis, velocityI, zAxis);
2022-12-13 11:51:03 +01:00
VectorOperations<double>::normalize(zAxis, zAxis, 3);
// y-Axis completes RHS
double yAxis[3] = {0, 0, 0};
VectorOperations<double>::cross(zAxis, xAxis, yAxis);
2023-02-20 16:14:40 +01:00
// join transformation matrix
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]}};
2023-02-20 16:14:40 +01:00
QuaternionOperations::fromDcm(dcmTgt, targetQuat);
2022-12-13 11:51:03 +01:00
int8_t timeElapsedMax = acsParameters->nadirModeControllerParameters.timeElapsedMax;
2023-02-20 16:20:54 +01:00
targetRotationRate(timeElapsedMax, now, targetQuat, refSatRate);
2022-11-22 21:10:05 +01:00
}
void Guidance::comparePtg(double currentQuat[4], double currentSatRotRate[3], double targetQuat[4],
double targetSatRotRate[3], double refQuat[4], double refSatRotRate[3],
double errorQuat[4], double errorSatRotRate[3], double errorAngle) {
// First calculate error quaternion between current and target orientation
QuaternionOperations::multiply(currentQuat, targetQuat, errorQuat);
// Last calculate add rotation from reference quaternion
QuaternionOperations::multiply(refQuat, errorQuat, errorQuat);
// Keep scalar part of quaternion positive
if (errorQuat[3] < 0) {
VectorOperations<double>::mulScalar(errorQuat, -1, errorQuat, 4);
}
// Calculate error angle
errorAngle = QuaternionOperations::getAngle(errorQuat, true);
// Only give back error satellite rotational rate if orientation has already been aquired
if (errorAngle < 2. / 180. * M_PI) {
// First combine the target and reference satellite rotational rates
double combinedRefSatRotRate[3] = {0, 0, 0};
VectorOperations<double>::add(targetSatRotRate, refSatRotRate, combinedRefSatRotRate, 3);
// Then substract the combined required satellite rotational rates from the actual rate
VectorOperations<double>::subtract(currentSatRotRate, combinedRefSatRotRate, errorSatRotRate,
3);
} else {
// If orientation has not been aquired yet set satellite rotational rate to zero
errorSatRotRate = 0;
2022-10-12 15:06:24 +02:00
}
// target flag in matlab, importance, does look like it only gives feedback if pointing control is
// under 150 arcsec ??
2022-11-14 17:16:47 +01:00
}
2023-02-20 15:59:01 +01:00
void Guidance::comparePtg(double currentQuat[4], double currentSatRotRate[3], double targetQuat[4],
double targetSatRotRate[3], double errorQuat[4],
double errorSatRotRate[3], double errorAngle) {
// First calculate error quaternion between current and target orientation
QuaternionOperations::multiply(currentQuat, targetQuat, errorQuat);
// Keep scalar part of quaternion positive
if (errorQuat[3] < 0) {
VectorOperations<double>::mulScalar(errorQuat, -1, errorQuat, 4);
2022-10-12 15:06:24 +02:00
}
2023-02-20 15:59:01 +01:00
// Calculate error angle
errorAngle = QuaternionOperations::getAngle(errorQuat, true);
2022-10-12 15:06:24 +02:00
2023-02-20 15:59:01 +01:00
// Only give back error satellite rotational rate if orientation has already been aquired
if (errorAngle < 2. / 180. * M_PI) {
// Then substract the combined required satellite rotational rates from the actual rate
VectorOperations<double>::subtract(currentSatRotRate, targetSatRotRate, errorSatRotRate, 3);
} else {
// If orientation has not been aquired yet set satellite rotational rate to zero
errorSatRotRate = 0;
}
2022-10-12 15:06:24 +02: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
}
void Guidance::targetRotationRate(int8_t timeElapsedMax, timeval now, double quatInertialTarget[4],
double *refSatRate) {
//-------------------------------------------------------------------------------------
// Calculation of target rotation rate
//-------------------------------------------------------------------------------------
double timeElapsed = now.tv_sec + now.tv_usec * pow(10, -6) -
(timeSavedQuaternion.tv_sec +
timeSavedQuaternion.tv_usec * pow((double)timeSavedQuaternion.tv_usec, -6));
if (timeElapsed < timeElapsedMax) {
double qDiff[4] = {0, 0, 0, 0};
VectorOperations<double>::subtract(quatInertialTarget, savedQuaternion, qDiff, 4);
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);
VectorOperations<double>::subtract(refSatRate, omegaRefSaved, refSatRate, 3);
omegaRefSaved[0] = omegaRefNew[0];
omegaRefSaved[1] = omegaRefNew[1];
omegaRefSaved[2] = omegaRefNew[2];
} else {
refSatRate[0] = 0;
refSatRate[1] = 0;
refSatRate[2] = 0;
}
timeSavedQuaternion = now;
savedQuaternion[0] = quatInertialTarget[0];
savedQuaternion[1] = quatInertialTarget[1];
savedQuaternion[2] = quatInertialTarget[2];
savedQuaternion[3] = quatInertialTarget[3];
}
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
// reaction wheel invalid the pointing control is destined to fail.
return returnvalue::FAILED;
2022-10-12 15:06:24 +02:00
}
2022-09-19 15:17:39 +02:00
}
2023-02-22 17:08:42 +01:00
2023-03-24 14:51:45 +01:00
void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3],
double inertiaEive[3][3]) {
2023-03-08 14:50:25 +01:00
std::error_code e;
if (not std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e) or
2023-03-10 10:30:01 +01:00
not std::filesystem::exists(SD_1_SKEWED_PTG_FILE, e)) {
2023-03-10 09:44:30 +01:00
std::memcpy(sunTargetSafe, acsParameters->safeModeControllerParameters.sunTargetDir,
2023-03-24 14:51:45 +01:00
sizeof(&sunTargetSafe));
std::memcpy(inertiaEive, acsParameters->inertiaEIVE.inertiaMatrixDeployed,
sizeof(&inertiaEive));
} else {
std::memcpy(sunTargetSafe, acsParameters->safeModeControllerParameters.sunTargetDirLeop,
2023-03-24 14:51:45 +01:00
sizeof(&sunTargetSafe));
std::memcpy(inertiaEive, acsParameters->inertiaEIVE.inertiaMatrixUndeployed,
sizeof(&inertiaEive));
}
std::memcpy(satRateSafe, acsParameters->safeModeControllerParameters.satRateRef,
2023-03-24 14:51:45 +01:00
sizeof(&satRateSafe));
}
2023-02-22 17:08:42 +01:00
ReturnValue_t Guidance::solarArrayDeploymentComplete() {
2023-03-08 14:50:25 +01:00
std::error_code e;
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e)) {
2023-02-22 17:08:42 +01:00
std::remove(SD_0_SKEWED_PTG_FILE);
2023-03-08 14:50:25 +01:00
if (std::filesystem::exists(SD_0_SKEWED_PTG_FILE, e)) {
2023-02-22 17:08:42 +01:00
return returnvalue::FAILED;
}
}
2023-03-08 14:50:25 +01:00
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE, e)) {
2023-02-22 17:08:42 +01:00
std::remove(SD_1_SKEWED_PTG_FILE);
2023-03-08 14:50:25 +01:00
if (std::filesystem::exists(SD_1_SKEWED_PTG_FILE, e)) {
2023-02-22 17:08:42 +01:00
return returnvalue::FAILED;
}
}
return returnvalue::OK;
}