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

288 lines
14 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
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
2024-02-05 09:39:35 +01:00
void Guidance::targetQuatPtgIdle(timeval timeAbsolute, const double timeDelta,
const double sunDirI[3], const double posSatF[4],
double targetQuat[4], double targetSatRotRate[3]) {
// positive z-Axis of EIVE in direction of sun
2024-02-02 14:32:12 +01:00
double zAxisXI[3] = {0, 0, 0};
VectorOperations<double>::normalize(sunDirI, zAxisXI, 3);
2022-10-12 15:06:24 +02:00
// determine helper vector to point x-Axis and therefore the STR away from Earth
double helperXI[3] = {0, 0, 0}, posSatI[3] = {0, 0, 0};
CoordinateTransformations::positionEcfToEci(posSatF, posSatI, &timeAbsolute);
VectorOperations<double>::normalize(posSatI, helperXI, 3);
2022-10-12 15:06:24 +02:00
// construct y-axis from helper vector and z-axis
2024-02-02 14:32:12 +01:00
double yAxisXI[3] = {0, 0, 0};
VectorOperations<double>::cross(zAxisXI, helperXI, yAxisXI);
VectorOperations<double>::normalize(yAxisXI, yAxisXI, 3);
2022-10-12 15:06:24 +02:00
// x-axis completes RHS
2024-02-02 14:32:12 +01:00
double xAxisXI[3] = {0, 0, 0};
VectorOperations<double>::cross(yAxisXI, zAxisXI, xAxisXI);
VectorOperations<double>::normalize(xAxisXI, xAxisXI, 3);
// join transformation matrix
double dcmXI[3][3] = {{xAxisXI[0], yAxisXI[0], zAxisXI[0]},
{xAxisXI[1], yAxisXI[1], zAxisXI[1]},
{xAxisXI[2], yAxisXI[2], zAxisXI[2]}};
QuaternionOperations::fromDcm(dcmXI, targetQuat);
// calculate of reference rotation rate
targetRotationRate(timeDelta, targetQuat, targetSatRotRate);
2022-09-19 15:17:39 +02:00
}
2024-02-02 14:32:12 +01:00
void Guidance::targetQuatPtgTarget(timeval timeAbsolute, const double timeDelta, double posSatF[3],
double velSatF[3], 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)
2024-02-02 14:32:12 +01:00
double targetF[3] = {0, 0, 0};
MathOperations<double>::cartesianFromLatLongAlt(
acsParameters->targetModeControllerParameters.latitudeTgt,
acsParameters->targetModeControllerParameters.longitudeTgt,
2024-02-02 14:32:12 +01:00
acsParameters->targetModeControllerParameters.altitudeTgt, targetF);
double targetDirF[3] = {0, 0, 0};
VectorOperations<double>::subtract(targetF, posSatF, targetDirF, 3);
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};
2024-02-02 14:32:12 +01:00
CoordinateTransformations::positionEcfToEci(posSatF, posSatI, &timeAbsolute);
CoordinateTransformations::positionEcfToEci(targetF, targetI, &timeAbsolute);
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
2024-02-02 14:32:12 +01:00
double xAxisXI[3] = {0, 0, 0};
VectorOperations<double>::normalize(targetDirI, xAxisXI, 3);
2022-12-13 11:51:03 +01:00
// transform velocity into inertial frame
2024-02-02 14:32:12 +01:00
double velSatI[3] = {0, 0, 0};
CoordinateTransformations::velocityEcfToEci(velSatF, posSatF, velSatI, &timeAbsolute);
2022-12-13 11:51:03 +01:00
// orbital normal vector of target and velocity vector
double orbitalNormalI[3] = {0, 0, 0};
2024-02-02 14:32:12 +01:00
VectorOperations<double>::cross(posSatI, velSatI, 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
2024-02-02 14:32:12 +01:00
double yAxisXI[3] = {0, 0, 0};
VectorOperations<double>::cross(orbitalNormalI, xAxisXI, yAxisXI);
VectorOperations<double>::normalize(yAxisXI, yAxisXI, 3);
2022-12-13 11:51:03 +01:00
// z-axis completes RHS
2024-02-02 14:32:12 +01:00
double zAxisXI[3] = {0, 0, 0};
VectorOperations<double>::cross(xAxisXI, yAxisXI, zAxisXI);
2022-12-13 11:51:03 +01:00
// join transformation matrix
2024-02-02 14:32:12 +01:00
double dcmIX[3][3] = {{xAxisXI[0], yAxisXI[0], zAxisXI[0]},
{xAxisXI[1], yAxisXI[1], zAxisXI[1]},
{xAxisXI[2], yAxisXI[2], zAxisXI[2]}};
2023-02-20 16:14:40 +01:00
QuaternionOperations::fromDcm(dcmIX, targetQuat);
2022-12-13 11:51:03 +01:00
2024-02-02 14:32:12 +01:00
targetRotationRate(timeDelta, targetQuat, targetSatRotRate);
}
2024-02-02 14:32:12 +01:00
void Guidance::targetQuatPtgGs(timeval timeAbsolute, const double timeDelta, double posSatF[3],
double sunDirI[3], double targetQuat[4],
2023-10-16 13:26:56 +02:00
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)
2024-02-02 14:32:12 +01:00
double posGroundStationF[3] = {0, 0, 0};
MathOperations<double>::cartesianFromLatLongAlt(
acsParameters->gsTargetModeControllerParameters.latitudeTgt,
acsParameters->gsTargetModeControllerParameters.longitudeTgt,
2024-02-02 14:32:12 +01:00
acsParameters->gsTargetModeControllerParameters.altitudeTgt, posGroundStationF);
// target direction in the ECI frame
2024-02-02 14:32:12 +01:00
double posSatI[3] = {0, 0, 0}, posGroundStationI[3] = {0, 0, 0}, groundStationDirI[3] = {0, 0, 0};
CoordinateTransformations::positionEcfToEci(posSatF, posSatI, &timeAbsolute);
CoordinateTransformations::positionEcfToEci(posGroundStationI, posGroundStationI, &timeAbsolute);
VectorOperations<double>::subtract(posGroundStationI, 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
2024-02-02 14:32:12 +01:00
double xAxisXI[3] = {0, 0, 0};
VectorOperations<double>::normalize(groundStationDirI, xAxisXI, 3);
VectorOperations<double>::mulScalar(xAxisXI, -1, xAxisXI, 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
2024-02-02 14:32:12 +01:00
double xDotS = VectorOperations<double>::dot(xAxisXI, sunDirI);
xDotS /= pow(VectorOperations<double>::norm(xAxisXI, 3), 2);
double sunParallel[3], zAxisXI[3];
VectorOperations<double>::mulScalar(xAxisXI, xDotS, sunParallel, 3);
VectorOperations<double>::subtract(sunDirI, sunParallel, zAxisXI, 3);
VectorOperations<double>::normalize(zAxisXI, zAxisXI, 3);
2023-02-20 15:59:01 +01:00
// y-axis completes RHS
2024-02-02 14:32:12 +01:00
double yAxisXI[3];
VectorOperations<double>::cross(zAxisXI, xAxisXI, yAxisXI);
VectorOperations<double>::normalize(yAxisXI, yAxisXI, 3);
2023-02-20 15:59:01 +01:00
// join transformation matrix
2024-02-02 14:32:12 +01:00
double dcmXI[3][3] = {{xAxisXI[0], yAxisXI[0], zAxisXI[0]},
{xAxisXI[1], yAxisXI[1], zAxisXI[1]},
{xAxisXI[2], yAxisXI[2], zAxisXI[2]}};
QuaternionOperations::fromDcm(dcmXI, targetQuat);
2024-02-02 14:32:12 +01:00
targetRotationRate(timeDelta, targetQuat, targetSatRotRate);
}
2024-02-02 14:33:50 +01:00
void Guidance::targetQuatPtgNadir(timeval timeAbsolute, const double timeDelta, 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
// satellite position in inertial reference frame
double posSatI[3] = {0, 0, 0};
2024-02-02 14:32:12 +01:00
CoordinateTransformations::positionEcfToEci(posSatE, posSatI, &timeAbsolute);
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
2024-02-02 14:32:12 +01:00
double xAxisXI[3] = {0, 0, 0};
VectorOperations<double>::normalize(posSatI, xAxisXI, 3);
VectorOperations<double>::mulScalar(xAxisXI, -1, xAxisXI, 3);
2022-12-13 11:51:03 +01:00
2023-02-20 16:14:40 +01:00
// make z-Axis parallel to major part of camera resolution
2024-02-02 14:32:12 +01:00
double zAxisXI[3] = {0, 0, 0};
double velSatI[3] = {0, 0, 0};
CoordinateTransformations::velocityEcfToEci(velSatE, posSatE, velSatI, &timeAbsolute);
VectorOperations<double>::cross(xAxisXI, velSatI, zAxisXI);
VectorOperations<double>::normalize(zAxisXI, zAxisXI, 3);
2022-12-13 11:51:03 +01:00
// y-Axis completes RHS
2024-02-02 14:32:12 +01:00
double yAxisXI[3] = {0, 0, 0};
VectorOperations<double>::cross(zAxisXI, xAxisXI, yAxisXI);
2022-12-13 11:51:03 +01:00
2023-02-20 16:14:40 +01:00
// join transformation matrix
2024-02-02 14:32:12 +01:00
double dcmXI[3][3] = {{xAxisXI[0], yAxisXI[0], zAxisXI[0]},
{xAxisXI[1], yAxisXI[1], zAxisXI[1]},
{xAxisXI[2], yAxisXI[2], zAxisXI[2]}};
QuaternionOperations::fromDcm(dcmXI, targetQuat);
2022-12-13 11:51:03 +01:00
2024-02-02 14:32:12 +01:00
targetRotationRate(timeDelta, targetQuat, refSatRate);
}
void Guidance::targetRotationRate(const double timeDelta, double quatIX[4], double *refSatRate) {
if (VectorOperations<double>::norm(quatIXprev, 4) == 0) {
std::memcpy(quatIXprev, quatIX, sizeof(quatIXprev));
}
if (timeDelta != 0.0) {
QuaternionOperations::rotationFromQuaternions(quatIX, quatIXprev, timeDelta, refSatRate);
} else {
std::memcpy(refSatRate, ZERO_VEC3, 3 * sizeof(double));
}
std::memcpy(quatIXprev, quatIX, sizeof(quatIXprev));
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) {
2024-02-05 09:24:41 +01:00
// First calculate error quaternion between current and target orientation without reference
// quaternion
double errorQuatWoRef[4] = {0, 0, 0, 0};
QuaternionOperations::multiply(currentQuat, targetQuat, errorQuatWoRef);
// Then add rotation from reference quaternion
QuaternionOperations::multiply(refQuat, errorQuatWoRef, 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);
2023-06-02 10:43:23 +02:00
// Calculate error satellite rotational rate
2024-01-26 13:16:27 +01:00
// Convert target rotational rate into body RF
double errorQuatInv[4] = {0, 0, 0, 0}, targetSatRotRateB[3] = {0, 0, 0};
QuaternionOperations::inverse(errorQuat, errorQuatInv);
2024-01-29 11:11:47 +01:00
QuaternionOperations::multiplyVector(errorQuatInv, targetSatRotRate, targetSatRotRateB);
2024-01-26 13:16:27 +01:00
// Combine the target and reference satellite rotational rates
2023-06-02 10:43:23 +02:00
double combinedRefSatRotRate[3] = {0, 0, 0};
VectorOperations<double>::add(targetSatRotRate, refSatRotRate, combinedRefSatRotRate, 3);
// Then subtract the combined required satellite rotational rates from the actual rate
VectorOperations<double>::subtract(currentSatRotRate, combinedRefSatRotRate, errorSatRotRate, 3);
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) {
double refQuat[4] = {0, 0, 0, 1}, refSatRotRate[3] = {0, 0, 0};
comparePtg(currentQuat, currentSatRotRate, targetQuat, targetSatRotRate, refQuat, refSatRotRate,
errorQuat, errorSatRotRate, errorAngle);
2022-09-19 15:17:39 +02:00
}
ReturnValue_t Guidance::getDistributionMatrixRw(ACS::SensorValues *sensorValues,
double *rwPseudoInv) {
2023-11-02 16:59:09 +01:00
bool rw1valid = (sensorValues->rw1Set.state.value and sensorValues->rw1Set.state.isValid());
bool rw2valid = (sensorValues->rw2Set.state.value and sensorValues->rw2Set.state.isValid());
bool rw3valid = (sensorValues->rw3Set.state.value and sensorValues->rw3Set.state.isValid());
bool rw4valid = (sensorValues->rw4Set.state.value and sensorValues->rw4Set.state.isValid());
2023-11-02 16:59:09 +01:00
if (rw1valid and rw2valid and rw3valid and rw4valid) {
std::memcpy(rwPseudoInv, acsParameters->rwMatrices.pseudoInverse, 12 * sizeof(double));
return returnvalue::OK;
2023-11-02 16:59:09 +01:00
} else if (not rw1valid and rw2valid and rw3valid and rw4valid) {
std::memcpy(rwPseudoInv, acsParameters->rwMatrices.pseudoInverseWithoutRW1,
12 * sizeof(double));
2024-01-29 11:08:47 +01:00
return acsctrl::SINGLE_RW_UNAVAILABLE;
2023-11-02 16:59:09 +01:00
} else if (rw1valid and not rw2valid and rw3valid and rw4valid) {
std::memcpy(rwPseudoInv, acsParameters->rwMatrices.pseudoInverseWithoutRW2,
12 * sizeof(double));
2024-01-29 11:08:47 +01:00
return acsctrl::SINGLE_RW_UNAVAILABLE;
2023-11-02 16:59:09 +01:00
} else if (rw1valid and rw2valid and not rw3valid and rw4valid) {
std::memcpy(rwPseudoInv, acsParameters->rwMatrices.pseudoInverseWithoutRW3,
12 * sizeof(double));
2024-01-29 11:08:47 +01:00
return acsctrl::SINGLE_RW_UNAVAILABLE;
2023-11-02 16:59:09 +01:00
} else if (rw1valid and rw2valid and rw3valid and not rw4valid) {
std::memcpy(rwPseudoInv, acsParameters->rwMatrices.pseudoInverseWithoutRW4,
12 * sizeof(double));
2024-01-29 11:08:47 +01:00
return acsctrl::SINGLE_RW_UNAVAILABLE;
2022-10-12 15:06:24 +02:00
}
2024-01-29 11:08:47 +01:00
return acsctrl::MULTIPLE_RW_UNAVAILABLE;
2022-09-19 15:17:39 +02:00
}
2023-02-22 17:08:42 +01:00
void Guidance::resetValues() { std::memcpy(quatIXprev, ZERO_VEC4, sizeof(quatIXprev)); }
2023-04-14 11:37:23 +02:00
void Guidance::getTargetParamsSafe(double sunTargetSafe[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-04-11 18:12:04 +02:00
3 * sizeof(double));
} else {
std::memcpy(sunTargetSafe, acsParameters->safeModeControllerParameters.sunTargetDirLeop,
2023-04-11 18:12:04 +02:00
3 * sizeof(double));
}
}
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;
}