Merge branch 'eggert/acs' into marquardt/ptgCtrl
Some checks failed
EIVE/eive-obsw/pipeline/head There was a failure building this commit
Some checks failed
EIVE/eive-obsw/pipeline/head There was a failure building this commit
# Conflicts: # mission/controller/AcsController.cpp # mission/controller/AcsController.h # mission/controller/acs/AcsParameters.h # mission/controller/acs/ActuatorCmd.h # mission/controller/acs/Guidance.cpp # mission/controller/acs/Guidance.h # mission/controller/acs/MultiplicativeKalmanFilter.cpp # mission/controller/acs/OutputValues.h # mission/controller/acs/SensorProcessing.cpp # mission/controller/acs/SensorProcessing.h # mission/controller/acs/control/Detumble.cpp # mission/controller/acs/control/Detumble.h # mission/controller/acs/control/PtgCtrl.cpp # mission/controller/acs/util/MathOperations.h
This commit is contained in:
@ -2,18 +2,28 @@
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
|
||||
#include "mission/devices/torquer.h"
|
||||
|
||||
AcsController::AcsController(object_id_t objectId)
|
||||
: ExtendedControllerBase(objectId, objects::NO_OBJECT),
|
||||
: ExtendedControllerBase(objectId),
|
||||
sensorProcessing(&acsParameters),
|
||||
navigation(&acsParameters),
|
||||
actuatorCmd(&acsParameters),
|
||||
guidance(&acsParameters),
|
||||
safeCtrl(&acsParameters),
|
||||
safeCtrl(&acsParameters),
|
||||
detumble(&acsParameters),
|
||||
ptgCtrl(&acsParameters),
|
||||
detumbleCounter{0},
|
||||
mgmData(this),
|
||||
susData(this) {}
|
||||
mgmDataRaw(this),
|
||||
mgmDataProcessed(this),
|
||||
susDataRaw(this),
|
||||
susDataProcessed(this),
|
||||
gyrDataRaw(this),
|
||||
gyrDataProcessed(this),
|
||||
gpsDataProcessed(this),
|
||||
mekfData(this),
|
||||
ctrlValData(this),
|
||||
actuatorCmdData(this) {}
|
||||
|
||||
ReturnValue_t AcsController::handleCommandMessage(CommandMessage *message) {
|
||||
return returnvalue::OK;
|
||||
@ -38,21 +48,14 @@ void AcsController::performControlOperation() {
|
||||
case SUBMODE_SAFE:
|
||||
performSafe();
|
||||
break;
|
||||
|
||||
case SUBMODE_DETUMBLE:
|
||||
performDetumble();
|
||||
break;
|
||||
|
||||
case SUBMODE_PTG_SUN:
|
||||
case SUBMODE_PTG_TARGET:
|
||||
performPointingCtrl();
|
||||
break;
|
||||
|
||||
case SUBMODE_PTG_SUN:
|
||||
performPointingCtrl();
|
||||
break;
|
||||
|
||||
case SUBMODE_PTG_NADIR:
|
||||
performPointingCtrl();
|
||||
case SUBMODE_PTG_INERTIAL:
|
||||
performPointingCtrl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -63,109 +66,191 @@ void AcsController::performControlOperation() {
|
||||
}
|
||||
|
||||
{
|
||||
PoolReadGuard pg(&mgmData);
|
||||
PoolReadGuard pg(&mgmDataRaw);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
copyMgmData();
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susData);
|
||||
PoolReadGuard pg(&susDataRaw);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
copySusData();
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG : REMOVE AFTER COMPLETION
|
||||
mode = MODE_ON;
|
||||
submode = SUBMODE_DETUMBLE;
|
||||
// DEBUG END
|
||||
{
|
||||
PoolReadGuard pg(&gyrDataRaw);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
copyGyrData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AcsController::performSafe() {
|
||||
ACS::SensorValues sensorValues;
|
||||
ACS::OutputValues outputValues;
|
||||
|
||||
timeval now;
|
||||
Clock::getClock_timeval(&now);
|
||||
|
||||
sensorProcessing.process(now, &sensorValues, &outputValues, &acsParameters);
|
||||
sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed,
|
||||
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
|
||||
ReturnValue_t validMekf;
|
||||
navigation.useMekf(&sensorValues, &outputValues, &validMekf);
|
||||
// Give desired satellite rate and sun direction to align
|
||||
double satRateSafe[3] = {0, 0, 0}, sunTargetDir[3] = {0, 0, 0};
|
||||
guidance.getTargetParamsSafe(sunTargetDir, satRateSafe);
|
||||
// IF MEKF is working
|
||||
double magMomMtq[3] = {0, 0, 0};
|
||||
bool magMomMtqValid = false;
|
||||
if ( !validMekf ) { // Valid = 0, Failed = 1
|
||||
safeCtrl.safeMekf(now, (outputValues.quatMekfBJ), &(outputValues.quatMekfBJValid),
|
||||
(outputValues.magFieldModel), &(outputValues.magFieldModelValid),
|
||||
(outputValues.sunDirModel), &(outputValues.sunDirModelValid),
|
||||
(outputValues.satRateMekf), &(outputValues.satRateMekfValid),
|
||||
sunTargetDir, satRateSafe, magMomMtq, &magMomMtqValid);
|
||||
}
|
||||
else {
|
||||
navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, &susDataProcessed,
|
||||
&mekfData, &validMekf);
|
||||
|
||||
safeCtrl.safeNoMekf(now, outputValues.sunDirEst, &outputValues.sunDirEstValid,
|
||||
outputValues.sunVectorDerivative, &(outputValues.sunVectorDerivativeValid),
|
||||
outputValues.magFieldEst, &(outputValues.magFieldEstValid),
|
||||
outputValues.magneticFieldVectorDerivative, &(outputValues.magneticFieldVectorDerivativeValid),
|
||||
sunTargetDir, satRateSafe, magMomMtq, &magMomMtqValid);
|
||||
// Give desired satellite rate and sun direction to align
|
||||
double satRateSafe[3] = {0, 0, 0}, sunTargetDir[3] = {0, 0, 0};
|
||||
guidance.getTargetParamsSafe(sunTargetDir, satRateSafe);
|
||||
// IF MEKF is working
|
||||
double magMomMtq[3] = {0, 0, 0}, errAng = 0.0;
|
||||
bool magMomMtqValid = false;
|
||||
if (validMekf == returnvalue::OK) {
|
||||
safeCtrl.safeMekf(now, mekfData.quatMekf.value, mekfData.quatMekf.isValid(),
|
||||
mgmDataProcessed.magIgrfModel.value, mgmDataProcessed.magIgrfModel.isValid(),
|
||||
susDataProcessed.sunIjkModel.value, susDataProcessed.isValid(),
|
||||
mekfData.satRotRateMekf.value, mekfData.satRotRateMekf.isValid(),
|
||||
sunTargetDir, satRateSafe, &errAng, magMomMtq, &magMomMtqValid);
|
||||
} else {
|
||||
safeCtrl.safeNoMekf(
|
||||
now, susDataProcessed.susVecTot.value, susDataProcessed.susVecTot.isValid(),
|
||||
susDataProcessed.susVecTotDerivative.value, susDataProcessed.susVecTotDerivative.isValid(),
|
||||
mgmDataProcessed.mgmVecTot.value, mgmDataProcessed.mgmVecTot.isValid(),
|
||||
mgmDataProcessed.mgmVecTotDerivative.value, mgmDataProcessed.mgmVecTotDerivative.isValid(),
|
||||
sunTargetDir, satRateSafe, &errAng, magMomMtq, &magMomMtqValid);
|
||||
}
|
||||
|
||||
}
|
||||
double dipolCmdUnits[3] = {0, 0, 0};
|
||||
actuatorCmd.cmdDipolMtq(magMomMtq, dipolCmdUnits);
|
||||
double dipolCmdUnits[3] = {0, 0, 0};
|
||||
actuatorCmd.cmdDipolMtq(magMomMtq, dipolCmdUnits);
|
||||
|
||||
{
|
||||
PoolReadGuard pg(&ctrlValData);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
double zeroQuat[4] = {0, 0, 0, 0};
|
||||
std::memcpy(ctrlValData.tgtQuat.value, zeroQuat, 4 * sizeof(double));
|
||||
ctrlValData.tgtQuat.setValid(false);
|
||||
std::memcpy(ctrlValData.errQuat.value, zeroQuat, 4 * sizeof(double));
|
||||
ctrlValData.errQuat.setValid(false);
|
||||
ctrlValData.errAng.value = errAng;
|
||||
ctrlValData.errAng.setValid(true);
|
||||
ctrlValData.setValidity(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Detumble check and switch
|
||||
if (mekfData.satRotRateMekf.isValid() &&
|
||||
VectorOperations<double>::norm(mekfData.satRotRateMekf.value, 3) >
|
||||
acsParameters.detumbleParameter.omegaDetumbleStart) {
|
||||
detumbleCounter++;
|
||||
} else if (gyrDataProcessed.gyrVecTot.isValid() &&
|
||||
VectorOperations<double>::norm(gyrDataProcessed.gyrVecTot.value, 3) >
|
||||
acsParameters.detumbleParameter.omegaDetumbleStart) {
|
||||
detumbleCounter++;
|
||||
} else {
|
||||
detumbleCounter = 0;
|
||||
}
|
||||
if (detumbleCounter > acsParameters.detumbleParameter.detumblecounter) {
|
||||
submode = SUBMODE_DETUMBLE;
|
||||
detumbleCounter = 0;
|
||||
triggerEvent(SAFE_RATE_VIOLATION);
|
||||
}
|
||||
|
||||
{
|
||||
PoolReadGuard pg(&actuatorCmdData);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
int32_t zeroVec[4] = {0, 0, 0, 0};
|
||||
std::memcpy(actuatorCmdData.rwTargetTorque.value, zeroVec, 4 * sizeof(int32_t));
|
||||
actuatorCmdData.rwTargetTorque.setValid(false);
|
||||
std::memcpy(actuatorCmdData.rwTargetSpeed.value, zeroVec, 4 * sizeof(int32_t));
|
||||
actuatorCmdData.rwTargetSpeed.setValid(false);
|
||||
std::memcpy(actuatorCmdData.mtqTargetDipole.value, dipolCmdUnits, 3 * sizeof(int16_t));
|
||||
actuatorCmdData.mtqTargetDipole.setValid(true);
|
||||
actuatorCmdData.setValidity(true, false);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// PoolReadGuard pg(&dipoleSet);
|
||||
// MutexGuard mg(torquer::lazyLock());
|
||||
// torquer::NEW_ACTUATION_FLAG = true;
|
||||
// dipoleSet.setDipoles(cmdDipolUnits[0], cmdDipolUnits[1], cmdDipolUnits[2], torqueDuration);
|
||||
// }
|
||||
}
|
||||
|
||||
void AcsController::performDetumble() {
|
||||
ACS::SensorValues sensorValues;
|
||||
ACS::OutputValues outputValues;
|
||||
|
||||
timeval now;
|
||||
Clock::getClock_timeval(&now);
|
||||
|
||||
sensorProcessing.process(now, &sensorValues, &outputValues, &acsParameters);
|
||||
sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed,
|
||||
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
|
||||
ReturnValue_t validMekf;
|
||||
navigation.useMekf(&sensorValues, &outputValues, &validMekf);
|
||||
navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, &susDataProcessed,
|
||||
&mekfData, &validMekf);
|
||||
|
||||
double magMomMtq[3] = {0, 0, 0};
|
||||
detumble.bDotLaw(outputValues.magneticFieldVectorDerivative,
|
||||
&outputValues.magneticFieldVectorDerivativeValid, outputValues.magFieldEst,
|
||||
&outputValues.magFieldEstValid, magMomMtq);
|
||||
detumble.bDotLaw(mgmDataProcessed.mgmVecTotDerivative.value,
|
||||
mgmDataProcessed.mgmVecTotDerivative.isValid(), mgmDataProcessed.mgmVecTot.value,
|
||||
mgmDataProcessed.mgmVecTot.isValid(), magMomMtq);
|
||||
double dipolCmdUnits[3] = {0, 0, 0};
|
||||
actuatorCmd.cmdDipolMtq(magMomMtq, dipolCmdUnits);
|
||||
|
||||
if (outputValues.satRateMekfValid && VectorOperations<double>::norm(outputValues.satRateMekf, 3) <
|
||||
acsParameters.detumbleParameter.omegaDetumbleEnd) {
|
||||
if (mekfData.satRotRateMekf.isValid() &&
|
||||
VectorOperations<double>::norm(mekfData.satRotRateMekf.value, 3) <
|
||||
acsParameters.detumbleParameter.omegaDetumbleEnd) {
|
||||
detumbleCounter++;
|
||||
}
|
||||
|
||||
else if (outputValues.satRateEstValid &&
|
||||
VectorOperations<double>::norm(outputValues.satRateEst, 3) <
|
||||
acsParameters.detumbleParameter.omegaDetumbleEnd) {
|
||||
} else if (gyrDataProcessed.gyrVecTot.isValid() &&
|
||||
VectorOperations<double>::norm(gyrDataProcessed.gyrVecTot.value, 3) <
|
||||
acsParameters.detumbleParameter.omegaDetumbleEnd) {
|
||||
detumbleCounter++;
|
||||
} else {
|
||||
detumbleCounter = 0;
|
||||
}
|
||||
|
||||
if (detumbleCounter > acsParameters.detumbleParameter.detumblecounter) {
|
||||
submode = SUBMODE_SAFE;
|
||||
detumbleCounter = 0;
|
||||
}
|
||||
|
||||
int16_t cmdDipolUnitsInt[3] = {0, 0, 0};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
cmdDipolUnitsInt[i] = std::round(dipolCmdUnits[i]);
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&actuatorCmdData);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
int32_t zeroVec[4] = {0, 0, 0, 0};
|
||||
std::memcpy(actuatorCmdData.rwTargetTorque.value, zeroVec, 4 * sizeof(double));
|
||||
actuatorCmdData.rwTargetTorque.setValid(false);
|
||||
std::memcpy(actuatorCmdData.rwTargetSpeed.value, zeroVec, 4 * sizeof(int32_t));
|
||||
actuatorCmdData.rwTargetSpeed.setValid(false);
|
||||
std::memcpy(actuatorCmdData.mtqTargetDipole.value, cmdDipolUnitsInt, 3 * sizeof(int16_t));
|
||||
actuatorCmdData.mtqTargetDipole.setValid(true);
|
||||
actuatorCmdData.setValidity(true, false);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// PoolReadGuard pg(&dipoleSet);
|
||||
// MutexGuard mg(torquer::lazyLock());
|
||||
// torquer::NEW_ACTUATION_FLAG = true;
|
||||
// dipoleSet.setDipoles(cmdDipolUnitsInt[0], cmdDipolUnitsInt[1], cmdDipolUnitsInt[2],
|
||||
// torqueDuration);
|
||||
// }
|
||||
}
|
||||
|
||||
void AcsController::performPointingCtrl() {
|
||||
ACS::SensorValues sensorValues;
|
||||
ACS::OutputValues outputValues;
|
||||
|
||||
timeval now;
|
||||
Clock::getClock_timeval(&now);
|
||||
|
||||
sensorProcessing.process(now, &sensorValues, &outputValues, &acsParameters);
|
||||
sensorProcessing.process(now, &sensorValues, &mgmDataProcessed, &susDataProcessed,
|
||||
&gyrDataProcessed, &gpsDataProcessed, &acsParameters);
|
||||
ReturnValue_t validMekf;
|
||||
navigation.useMekf(&sensorValues, &outputValues, &validMekf);
|
||||
double targetQuat[4] = {0, 0, 0, 0}, refSatRate[3] = {0, 0, 0};
|
||||
navigation.useMekf(&sensorValues, &gyrDataProcessed, &mgmDataProcessed, &susDataProcessed,
|
||||
&mekfData, &validMekf);
|
||||
|
||||
switch (submode) {
|
||||
double targetQuat[4] = {0, 0, 0, 0}, refSatRate[3] = {0, 0, 0};
|
||||
switch (submode) {
|
||||
case SUBMODE_PTG_TARGET:
|
||||
guidance.targetQuatPtg(&sensorValues, &outputValues, now, targetQuat, refSatRate);
|
||||
guidance.targetQuatPtg(&sensorValues, &mekfData, &susDataProcessed, now, targetQuat, refSatRate);
|
||||
break;
|
||||
case SUBMODE_PTG_SUN:
|
||||
guidance.sunQuatPtg(&sensorValues, &outputValues, now, targetQuat, refSatRate);
|
||||
@ -176,9 +261,9 @@ void AcsController::performPointingCtrl() {
|
||||
case SUBMODE_PTG_INERTIAL:
|
||||
guidance.inertialQuatPtg(targetQuat, refSatRate);
|
||||
break;
|
||||
}
|
||||
double quatError[3] = {0, 0, 0}, deltaRate[3] = {0, 0, 0};
|
||||
guidance.comparePtg(targetQuat, &outputValues, refSatRate, quatError, deltaRate);
|
||||
} double quatErrorComplete[4] = {0, 0, 0, 0}, quatError[3] = {0, 0, 0},
|
||||
deltaRate[3] = {0, 0, 0}; // ToDo: check if pointer needed
|
||||
guidance.comparePtg(targetQuat, &mekfData, refSatRate, quatErrorComplete, quatError, deltaRate);
|
||||
double rwPseudoInv[4][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
guidance.getDistributionMatrixRw(&sensorValues, *rwPseudoInv);
|
||||
double torquePtgRws[4] = {0, 0, 0, 0}, mode = 0;
|
||||
@ -203,45 +288,149 @@ void AcsController::performPointingCtrl() {
|
||||
&(sensorValues.rw1Set.currSpeed.value), &(sensorValues.rw2Set.currSpeed.value),
|
||||
&(sensorValues.rw3Set.currSpeed.value), &(sensorValues.rw4Set.currSpeed.value), torqueRwsScaled, cmdSpeedRws);
|
||||
double mgtDpDes[3] = {0, 0, 0}, dipolUnits[3] = {0, 0, 0}; // Desaturation Dipol
|
||||
ptgCtrl.ptgDesaturation(
|
||||
outputValues.magFieldEst, &outputValues.magFieldEstValid, outputValues.satRateMekf,
|
||||
&(sensorValues.rw1Set.currSpeed.value), &(sensorValues.rw2Set.currSpeed.value),
|
||||
&(sensorValues.rw3Set.currSpeed.value), &(sensorValues.rw4Set.currSpeed.value), mgtDpDes);
|
||||
ptgCtrl.ptgDesaturation(mgmDataProcessed.mgmVecTot.value, mgmDataProcessed.mgmVecTot.isValid(),
|
||||
mekfData.satRotRateMekf.value, &(sensorValues.rw1Set.currSpeed.value),
|
||||
&(sensorValues.rw2Set.currSpeed.value),
|
||||
&(sensorValues.rw3Set.currSpeed.value),
|
||||
&(sensorValues.rw4Set.currSpeed.value), mgtDpDes);
|
||||
actuatorCmd.cmdDipolMtq(mgtDpDes, dipolUnits);
|
||||
|
||||
int16_t cmdDipolUnitsInt[3] = {0, 0, 0};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
cmdDipolUnitsInt[i] = std::round(dipolUnits[i]);
|
||||
}
|
||||
int32_t cmdRwSpeedInt[4] = {0, 0, 0, 0};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
cmdRwSpeedInt[i] = std::round(cmdSpeedRws[i]);
|
||||
}
|
||||
|
||||
{
|
||||
PoolReadGuard pg(&actuatorCmdData);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(actuatorCmdData.rwTargetTorque.value, rwTrqNs, 4 * sizeof(double));
|
||||
std::memcpy(actuatorCmdData.rwTargetSpeed.value, cmdRwSpeedInt, 4 * sizeof(int32_t));
|
||||
std::memcpy(actuatorCmdData.mtqTargetDipole.value, cmdDipolUnitsInt, 3 * sizeof(int16_t));
|
||||
actuatorCmdData.setValidity(true, true);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// PoolReadGuard pg(&dipoleSet);
|
||||
// MutexGuard mg(torquer::lazyLock());
|
||||
// torquer::NEW_ACTUATION_FLAG = true;
|
||||
// dipoleSet.setDipoles(cmdDipolUnitsInt[0], cmdDipolUnitsInt[1], cmdDipolUnitsInt[2],
|
||||
// torqueDuration);
|
||||
// }
|
||||
}
|
||||
|
||||
ReturnValue_t AcsController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
// MGM
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_0_LIS3_UT, &mgm0PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_1_RM3100_UT, &mgm1PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_2_LIS3_UT, &mgm2PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_3_RM3100_UT, &mgm3PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_IMTQ_CAL_NT, &imtqMgmPoolVec);
|
||||
// MGM Raw
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_0_LIS3_UT, &mgm0VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_1_RM3100_UT, &mgm1VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_2_LIS3_UT, &mgm2VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_3_RM3100_UT, &mgm3VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_IMTQ_CAL_NT, &imtqMgmVecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_IMTQ_CAL_ACT_STATUS, &imtqCalActStatus);
|
||||
poolManager.subscribeForRegularPeriodicPacket({mgmData.getSid(), false, 5.0});
|
||||
// SUS
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_0_N_LOC_XFYFZM_PT_XF, &sus0PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_1_N_LOC_XBYFZM_PT_XB, &sus1PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_2_N_LOC_XFYBZB_PT_YB, &sus2PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_3_N_LOC_XFYBZF_PT_YF, &sus3PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_4_N_LOC_XMYFZF_PT_ZF, &sus4PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_5_N_LOC_XFYMZB_PT_ZB, &sus5PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_6_R_LOC_XFYBZM_PT_XF, &sus6PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_7_R_LOC_XBYBZM_PT_XB, &sus7PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_8_R_LOC_XBYBZB_PT_YB, &sus8PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_9_R_LOC_XBYBZB_PT_YF, &sus9PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_10_N_LOC_XMYBZF_PT_ZF, &sus10PoolVec);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_11_R_LOC_XBYMZB_PT_ZB, &sus11PoolVec);
|
||||
poolManager.subscribeForRegularPeriodicPacket({susData.getSid(), false, 5.0});
|
||||
poolManager.subscribeForRegularPeriodicPacket({mgmDataRaw.getSid(), false, 5.0});
|
||||
// MGM Processed
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_0_VEC, &mgm0VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_1_VEC, &mgm1VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_2_VEC, &mgm2VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_3_VEC, &mgm3VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_4_VEC, &mgm4VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_VEC_TOT, &mgmVecTot);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MGM_VEC_TOT_DERIVATIVE, &mgmVecTotDer);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MAG_IGRF_MODEL, &magIgrf);
|
||||
poolManager.subscribeForRegularPeriodicPacket({mgmDataProcessed.getSid(), false, 5.0});
|
||||
// SUS Raw
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_0_N_LOC_XFYFZM_PT_XF, &sus0ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_1_N_LOC_XBYFZM_PT_XB, &sus1ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_2_N_LOC_XFYBZB_PT_YB, &sus2ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_3_N_LOC_XFYBZF_PT_YF, &sus3ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_4_N_LOC_XMYFZF_PT_ZF, &sus4ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_5_N_LOC_XFYMZB_PT_ZB, &sus5ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_6_R_LOC_XFYBZM_PT_XF, &sus6ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_7_R_LOC_XBYBZM_PT_XB, &sus7ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_8_R_LOC_XBYBZB_PT_YB, &sus8ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_9_R_LOC_XBYBZB_PT_YF, &sus9ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_10_N_LOC_XMYBZF_PT_ZF, &sus10ValRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_11_R_LOC_XBYMZB_PT_ZB, &sus11ValRaw);
|
||||
poolManager.subscribeForRegularPeriodicPacket({susDataRaw.getSid(), false, 5.0});
|
||||
// SUS Processed
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_0_VEC, &sus0VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_1_VEC, &sus1VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_2_VEC, &sus2VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_3_VEC, &sus3VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_4_VEC, &sus4VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_5_VEC, &sus5VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_6_VEC, &sus6VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_7_VEC, &sus7VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_8_VEC, &sus8VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_9_VEC, &sus9VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_10_VEC, &sus10VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_11_VEC, &sus11VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_VEC_TOT, &susVecTot);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUS_VEC_TOT_DERIVATIVE, &susVecTotDer);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SUN_IJK_MODEL, &sunIjk);
|
||||
poolManager.subscribeForRegularPeriodicPacket({susDataProcessed.getSid(), false, 5.0});
|
||||
// GYR Raw
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_0_ADIS, &gyr0VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_1_L3, &gyr1VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_2_ADIS, &gyr2VecRaw);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_3_L3, &gyr3VecRaw);
|
||||
poolManager.subscribeForRegularPeriodicPacket({gyrDataRaw.getSid(), false, 5.0});
|
||||
// GYR Processed
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_0_VEC, &gyr0VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_1_VEC, &gyr1VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_2_VEC, &gyr2VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_3_VEC, &gyr3VecProc);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GYR_VEC_TOT, &gyrVecTot);
|
||||
poolManager.subscribeForRegularPeriodicPacket({gyrDataProcessed.getSid(), false, 5.0});
|
||||
// GPS Processed
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GC_LATITUDE, &gcLatitude);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::GD_LONGITUDE, &gdLongitude);
|
||||
poolManager.subscribeForRegularPeriodicPacket({gpsDataProcessed.getSid(), false, 5.0});
|
||||
// MEKF
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::QUAT_MEKF, &quatMekf);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::SAT_ROT_RATE_MEKF, &satRotRateMekf);
|
||||
poolManager.subscribeForRegularPeriodicPacket({mekfData.getSid(), false, 5.0});
|
||||
// Ctrl Values
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::TGT_QUAT, &tgtQuat);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::ERROR_QUAT, &errQuat);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::ERROR_ANG, &errAng);
|
||||
poolManager.subscribeForRegularPeriodicPacket({ctrlValData.getSid(), false, 5.0});
|
||||
// Actuator CMD
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::RW_TARGET_TORQUE, &rwTargetTorque);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::RW_TARGET_SPEED, &rwTargetSpeed);
|
||||
localDataPoolMap.emplace(acsctrl::PoolIds::MTQ_TARGET_DIPOLE, &mtqTargetDipole);
|
||||
poolManager.subscribeForRegularPeriodicPacket({actuatorCmdData.getSid(), false, 5.0});
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase *AcsController::getDataSetHandle(sid_t sid) {
|
||||
if (sid == mgmData.getSid()) {
|
||||
return &mgmData;
|
||||
} else if (sid == susData.getSid()) {
|
||||
return &susData;
|
||||
switch (sid.ownerSetId) {
|
||||
case acsctrl::MGM_SENSOR_DATA:
|
||||
return &mgmDataRaw;
|
||||
case acsctrl::MGM_PROCESSED_DATA:
|
||||
return &mgmDataProcessed;
|
||||
case acsctrl::SUS_SENSOR_DATA:
|
||||
return &susDataRaw;
|
||||
case acsctrl::SUS_PROCESSED_DATA:
|
||||
return &susDataProcessed;
|
||||
case acsctrl::GYR_SENSOR_DATA:
|
||||
return &gyrDataRaw;
|
||||
case acsctrl::GYR_PROCESSED_DATA:
|
||||
return &gyrDataProcessed;
|
||||
case acsctrl::GPS_PROCESSED_DATA:
|
||||
return &gpsDataProcessed;
|
||||
case acsctrl::MEKF_DATA:
|
||||
return &mekfData;
|
||||
case acsctrl::CTRL_VAL_DATA:
|
||||
return &ctrlValData;
|
||||
case acsctrl::ACTUATOR_CMD_DATA:
|
||||
return &actuatorCmdData;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -255,7 +444,7 @@ ReturnValue_t AcsController::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
} else if ((mode == MODE_ON) || (mode == MODE_NORMAL)) {
|
||||
if ((submode > 5) || (submode < 2)) {
|
||||
if ((submode > 6) || (submode < 2)) {
|
||||
return INVALID_SUBMODE;
|
||||
} else {
|
||||
return returnvalue::OK;
|
||||
@ -269,110 +458,195 @@ void AcsController::modeChanged(Mode_t mode, Submode_t submode) {}
|
||||
void AcsController::announceMode(bool recursive) {}
|
||||
|
||||
void AcsController::copyMgmData() {
|
||||
ACS::SensorValues sensorValues;
|
||||
{
|
||||
PoolReadGuard pg(&mgm0Lis3Set);
|
||||
PoolReadGuard pg(&sensorValues.mgm0Lis3Set);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmData.mgm0Lis3.value, mgm0Lis3Set.fieldStrengths.value, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataRaw.mgm0Lis3.value, sensorValues.mgm0Lis3Set.fieldStrengths.value,
|
||||
3 * sizeof(float));
|
||||
mgmDataRaw.mgm0Lis3.setValid(sensorValues.mgm0Lis3Set.fieldStrengths.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&mgm1Rm3100Set);
|
||||
PoolReadGuard pg(&sensorValues.mgm1Rm3100Set);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmData.mgm1Rm3100.value, mgm1Rm3100Set.fieldStrengths.value, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataRaw.mgm1Rm3100.value, sensorValues.mgm1Rm3100Set.fieldStrengths.value,
|
||||
3 * sizeof(float));
|
||||
mgmDataRaw.mgm1Rm3100.setValid(sensorValues.mgm1Rm3100Set.fieldStrengths.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&mgm2Lis3Set);
|
||||
PoolReadGuard pg(&sensorValues.mgm2Lis3Set);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmData.mgm2Lis3.value, mgm2Lis3Set.fieldStrengths.value, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataRaw.mgm2Lis3.value, sensorValues.mgm2Lis3Set.fieldStrengths.value,
|
||||
3 * sizeof(float));
|
||||
mgmDataRaw.mgm2Lis3.setValid(sensorValues.mgm2Lis3Set.fieldStrengths.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&mgm3Rm3100Set);
|
||||
PoolReadGuard pg(&sensorValues.mgm3Rm3100Set);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmData.mgm3Rm3100.value, mgm3Rm3100Set.fieldStrengths.value, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataRaw.mgm3Rm3100.value, sensorValues.mgm3Rm3100Set.fieldStrengths.value,
|
||||
3 + sizeof(float));
|
||||
mgmDataRaw.mgm3Rm3100.setValid(sensorValues.mgm3Rm3100Set.fieldStrengths.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&imtqMgmSet);
|
||||
PoolReadGuard pg(&sensorValues.imtqMgmSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmData.imtqRaw.value, imtqMgmSet.mtmRawNt.value, 3 * sizeof(float));
|
||||
mgmData.actuationCalStatus.value = imtqMgmSet.coilActuationStatus.value;
|
||||
std::memcpy(mgmDataRaw.imtqRaw.value, sensorValues.imtqMgmSet.mtmRawNt.value,
|
||||
3 * sizeof(float));
|
||||
mgmDataRaw.imtqRaw.setValid(sensorValues.imtqMgmSet.mtmRawNt.isValid());
|
||||
mgmDataRaw.actuationCalStatus.value = sensorValues.imtqMgmSet.coilActuationStatus.value;
|
||||
mgmDataRaw.actuationCalStatus.setValid(sensorValues.imtqMgmSet.coilActuationStatus.isValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AcsController::copySusData() {
|
||||
ACS::SensorValues sensorValues;
|
||||
{
|
||||
PoolReadGuard pg(&susSets[0]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[0]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus0.value, susSets[0].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus0.value, sensorValues.susSets[0].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus0.setValid(sensorValues.susSets[0].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[1]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[1]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus1.value, susSets[1].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus1.value, sensorValues.susSets[1].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus1.setValid(sensorValues.susSets[1].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[2]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[2]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus2.value, susSets[2].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus2.value, sensorValues.susSets[2].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus2.setValid(sensorValues.susSets[2].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[3]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[3]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus3.value, susSets[3].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus3.value, sensorValues.susSets[3].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus3.setValid(sensorValues.susSets[3].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[4]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[4]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus4.value, susSets[4].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus4.value, sensorValues.susSets[4].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus4.setValid(sensorValues.susSets[4].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[5]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[5]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus5.value, susSets[5].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus5.value, sensorValues.susSets[5].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus5.setValid(sensorValues.susSets[5].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[6]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[6]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus6.value, susSets[6].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus6.value, sensorValues.susSets[6].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus6.setValid(sensorValues.susSets[6].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[7]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[7]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus7.value, susSets[7].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus7.value, sensorValues.susSets[7].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus7.setValid(sensorValues.susSets[7].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[8]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[8]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus8.value, susSets[8].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus8.value, sensorValues.susSets[8].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus8.setValid(sensorValues.susSets[8].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[9]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[9]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus9.value, susSets[9].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus9.value, sensorValues.susSets[9].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus9.setValid(sensorValues.susSets[9].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[10]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[10]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus10.value, susSets[10].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus10.value, sensorValues.susSets[10].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus10.setValid(sensorValues.susSets[10].channels.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&susSets[11]);
|
||||
PoolReadGuard pg(&sensorValues.susSets[11]);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susData.sus11.value, susSets[11].channels.value, 6 * sizeof(uint16_t));
|
||||
std::memcpy(susDataRaw.sus11.value, sensorValues.susSets[11].channels.value,
|
||||
6 * sizeof(uint16_t));
|
||||
susDataRaw.sus11.setValid(sensorValues.susSets[11].channels.isValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AcsController::copyGyrData() {
|
||||
ACS::SensorValues sensorValues;
|
||||
{
|
||||
PoolReadGuard pg(&sensorValues.gyr0AdisSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
gyrDataRaw.gyr0Adis.value[0] = sensorValues.gyr0AdisSet.angVelocX.value;
|
||||
gyrDataRaw.gyr0Adis.value[1] = sensorValues.gyr0AdisSet.angVelocY.value;
|
||||
gyrDataRaw.gyr0Adis.value[2] = sensorValues.gyr0AdisSet.angVelocZ.value;
|
||||
gyrDataRaw.gyr0Adis.setValid(sensorValues.gyr0AdisSet.angVelocX.isValid() &&
|
||||
sensorValues.gyr0AdisSet.angVelocY.isValid() &&
|
||||
sensorValues.gyr0AdisSet.angVelocZ.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&sensorValues.gyr1L3gSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
gyrDataRaw.gyr1L3.value[0] = sensorValues.gyr1L3gSet.angVelocX.value;
|
||||
gyrDataRaw.gyr1L3.value[1] = sensorValues.gyr1L3gSet.angVelocY.value;
|
||||
gyrDataRaw.gyr1L3.value[2] = sensorValues.gyr1L3gSet.angVelocZ.value;
|
||||
gyrDataRaw.gyr1L3.setValid(sensorValues.gyr1L3gSet.angVelocX.isValid() &&
|
||||
sensorValues.gyr1L3gSet.angVelocY.isValid() &&
|
||||
sensorValues.gyr1L3gSet.angVelocZ.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&sensorValues.gyr2AdisSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
gyrDataRaw.gyr2Adis.value[0] = sensorValues.gyr2AdisSet.angVelocX.value;
|
||||
gyrDataRaw.gyr2Adis.value[1] = sensorValues.gyr2AdisSet.angVelocY.value;
|
||||
gyrDataRaw.gyr2Adis.value[2] = sensorValues.gyr2AdisSet.angVelocZ.value;
|
||||
gyrDataRaw.gyr2Adis.setValid(sensorValues.gyr2AdisSet.angVelocX.isValid() &&
|
||||
sensorValues.gyr2AdisSet.angVelocY.isValid() &&
|
||||
sensorValues.gyr2AdisSet.angVelocZ.isValid());
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(&sensorValues.gyr3L3gSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
gyrDataRaw.gyr3L3.value[0] = sensorValues.gyr3L3gSet.angVelocX.value;
|
||||
gyrDataRaw.gyr3L3.value[1] = sensorValues.gyr3L3gSet.angVelocY.value;
|
||||
gyrDataRaw.gyr3L3.value[2] = sensorValues.gyr3L3gSet.angVelocZ.value;
|
||||
gyrDataRaw.gyr3L3.setValid(sensorValues.gyr3L3gSet.angVelocX.isValid() &&
|
||||
sensorValues.gyr3L3gSet.angVelocY.isValid() &&
|
||||
sensorValues.gyr3L3gSet.angVelocZ.isValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef MISSION_CONTROLLER_ACSCONTROLLER_H_
|
||||
#define MISSION_CONTROLLER_ACSCONTROLLER_H_
|
||||
|
||||
#include <commonObjects.h>
|
||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
|
||||
@ -9,14 +8,15 @@
|
||||
#include "acs/Guidance.h"
|
||||
#include "acs/Navigation.h"
|
||||
#include "acs/SensorProcessing.h"
|
||||
#include "acs/control/SafeCtrl.h"
|
||||
#include "acs/control/Detumble.h"
|
||||
#include "acs/control/PtgCtrl.h"
|
||||
#include "acs/control/SafeCtrl.h"
|
||||
#include "controllerdefinitions/AcsCtrlDefinitions.h"
|
||||
#include "eive/objects.h"
|
||||
#include "fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h"
|
||||
#include "fsfw_hal/devicehandlers/MgmRM3100Handler.h"
|
||||
#include "mission/devices/devicedefinitions/IMTQHandlerDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/SusDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/imtqHandlerDefinitions.h"
|
||||
|
||||
class AcsController : public ExtendedControllerBase {
|
||||
public:
|
||||
@ -31,8 +31,11 @@ class AcsController : public ExtendedControllerBase {
|
||||
static const Submode_t SUBMODE_PTG_SUN = 6;
|
||||
static const Submode_t SUBMODE_PTG_INERTIAL = 7;
|
||||
|
||||
protected:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::ACS_SUBSYSTEM;
|
||||
static const Event SAFE_RATE_VIOLATION =
|
||||
MAKE_EVENT(0, severity::MEDIUM); //!< The limits for the rotation in safe mode were violated.
|
||||
|
||||
protected:
|
||||
void performSafe();
|
||||
void performDetumble();
|
||||
void performPointingCtrl();
|
||||
@ -67,62 +70,98 @@ class AcsController : public ExtendedControllerBase {
|
||||
void modeChanged(Mode_t mode, Submode_t submode);
|
||||
void announceMode(bool recursive);
|
||||
|
||||
/* ACS Datasets */
|
||||
IMTQ::DipoleActuationSet dipoleSet = IMTQ::DipoleActuationSet(objects::IMTQ_HANDLER);
|
||||
// MGMs
|
||||
acsctrl::MgmDataRaw mgmData;
|
||||
|
||||
MGMLIS3MDL::MgmPrimaryDataset mgm0Lis3Set =
|
||||
MGMLIS3MDL::MgmPrimaryDataset(objects::MGM_0_LIS3_HANDLER);
|
||||
RM3100::Rm3100PrimaryDataset mgm1Rm3100Set =
|
||||
RM3100::Rm3100PrimaryDataset(objects::MGM_1_RM3100_HANDLER);
|
||||
MGMLIS3MDL::MgmPrimaryDataset mgm2Lis3Set =
|
||||
MGMLIS3MDL::MgmPrimaryDataset(objects::MGM_2_LIS3_HANDLER);
|
||||
RM3100::Rm3100PrimaryDataset mgm3Rm3100Set =
|
||||
RM3100::Rm3100PrimaryDataset(objects::MGM_3_RM3100_HANDLER);
|
||||
IMTQ::RawMtmMeasurementSet imtqMgmSet = IMTQ::RawMtmMeasurementSet(objects::IMTQ_HANDLER);
|
||||
|
||||
PoolEntry<float> mgm0PoolVec = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm1PoolVec = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm2PoolVec = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm3PoolVec = PoolEntry<float>(3);
|
||||
PoolEntry<float> imtqMgmPoolVec = PoolEntry<float>(3);
|
||||
acsctrl::MgmDataRaw mgmDataRaw;
|
||||
PoolEntry<float> mgm0VecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm1VecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm2VecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm3VecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<float> imtqMgmVecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<uint8_t> imtqCalActStatus = PoolEntry<uint8_t>();
|
||||
|
||||
void copyMgmData();
|
||||
|
||||
// Sun Sensors
|
||||
|
||||
acsctrl::SusDataRaw susData;
|
||||
|
||||
std::array<SUS::SusDataset, 12> susSets{
|
||||
SUS::SusDataset(objects::SUS_0_N_LOC_XFYFZM_PT_XF),
|
||||
SUS::SusDataset(objects::SUS_1_N_LOC_XBYFZM_PT_XB),
|
||||
SUS::SusDataset(objects::SUS_2_N_LOC_XFYBZB_PT_YB),
|
||||
SUS::SusDataset(objects::SUS_3_N_LOC_XFYBZF_PT_YF),
|
||||
SUS::SusDataset(objects::SUS_4_N_LOC_XMYFZF_PT_ZF),
|
||||
SUS::SusDataset(objects::SUS_5_N_LOC_XFYMZB_PT_ZB),
|
||||
SUS::SusDataset(objects::SUS_6_R_LOC_XFYBZM_PT_XF),
|
||||
SUS::SusDataset(objects::SUS_7_R_LOC_XBYBZM_PT_XB),
|
||||
SUS::SusDataset(objects::SUS_8_R_LOC_XBYBZB_PT_YB),
|
||||
SUS::SusDataset(objects::SUS_9_R_LOC_XBYBZB_PT_YF),
|
||||
SUS::SusDataset(objects::SUS_10_N_LOC_XMYBZF_PT_ZF),
|
||||
SUS::SusDataset(objects::SUS_11_R_LOC_XBYMZB_PT_ZB),
|
||||
};
|
||||
|
||||
PoolEntry<uint16_t> sus0PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus1PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus2PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus3PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus4PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus5PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus6PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus7PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus8PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus9PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus10PoolVec = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus11PoolVec = PoolEntry<uint16_t>(6);
|
||||
acsctrl::MgmDataProcessed mgmDataProcessed;
|
||||
PoolEntry<float> mgm0VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm1VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm2VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm3VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> mgm4VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<double> mgmVecTot = PoolEntry<double>(3);
|
||||
PoolEntry<double> mgmVecTotDer = PoolEntry<double>(3);
|
||||
PoolEntry<double> magIgrf = PoolEntry<double>(3);
|
||||
|
||||
// SUSs
|
||||
acsctrl::SusDataRaw susDataRaw;
|
||||
PoolEntry<uint16_t> sus0ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus1ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus2ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus3ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus4ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus5ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus6ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus7ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus8ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus9ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus10ValRaw = PoolEntry<uint16_t>(6);
|
||||
PoolEntry<uint16_t> sus11ValRaw = PoolEntry<uint16_t>(6);
|
||||
void copySusData();
|
||||
|
||||
acsctrl::SusDataProcessed susDataProcessed;
|
||||
PoolEntry<float> sus0VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus1VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus2VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus3VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus4VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus5VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus6VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus7VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus8VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus9VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus10VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<float> sus11VecProc = PoolEntry<float>(3);
|
||||
PoolEntry<double> susVecTot = PoolEntry<double>(3);
|
||||
PoolEntry<double> susVecTotDer = PoolEntry<double>(3);
|
||||
PoolEntry<double> sunIjk = PoolEntry<double>(3);
|
||||
|
||||
// GYRs
|
||||
acsctrl::GyrDataRaw gyrDataRaw;
|
||||
PoolEntry<double> gyr0VecRaw = PoolEntry<double>(3);
|
||||
PoolEntry<float> gyr1VecRaw = PoolEntry<float>(3);
|
||||
PoolEntry<double> gyr2VecRaw = PoolEntry<double>(3);
|
||||
PoolEntry<float> gyr3VecRaw = PoolEntry<float>(3);
|
||||
void copyGyrData();
|
||||
|
||||
acsctrl::GyrDataProcessed gyrDataProcessed;
|
||||
PoolEntry<double> gyr0VecProc = PoolEntry<double>(3);
|
||||
PoolEntry<double> gyr1VecProc = PoolEntry<double>(3);
|
||||
PoolEntry<double> gyr2VecProc = PoolEntry<double>(3);
|
||||
PoolEntry<double> gyr3VecProc = PoolEntry<double>(3);
|
||||
PoolEntry<double> gyrVecTot = PoolEntry<double>(3);
|
||||
|
||||
// GPS
|
||||
acsctrl::GpsDataProcessed gpsDataProcessed;
|
||||
PoolEntry<double> gcLatitude = PoolEntry<double>();
|
||||
PoolEntry<double> gdLongitude = PoolEntry<double>();
|
||||
|
||||
// MEKF
|
||||
acsctrl::MekfData mekfData;
|
||||
PoolEntry<double> quatMekf = PoolEntry<double>(4);
|
||||
PoolEntry<double> satRotRateMekf = PoolEntry<double>(3);
|
||||
|
||||
// Ctrl Values
|
||||
acsctrl::CtrlValData ctrlValData;
|
||||
PoolEntry<double> tgtQuat = PoolEntry<double>(4);
|
||||
PoolEntry<double> errQuat = PoolEntry<double>(4);
|
||||
PoolEntry<double> errAng = PoolEntry<double>();
|
||||
|
||||
// Actuator CMD
|
||||
acsctrl::ActuatorCmdData actuatorCmdData;
|
||||
PoolEntry<double> rwTargetTorque = PoolEntry<double>(4);
|
||||
PoolEntry<int32_t> rwTargetSpeed = PoolEntry<int32_t>(4);
|
||||
PoolEntry<int16_t> mtqTargetDipole = PoolEntry<int16_t>(3);
|
||||
|
||||
// Initial delay to make sure all pool variables have been initialized their owners
|
||||
Countdown initialCountdown = Countdown(INIT_DELAY);
|
||||
};
|
||||
|
@ -3,4 +3,4 @@ if(TGT_BSP MATCHES "arm/q7s" OR TGT_BSP MATCHES "")
|
||||
AcsController.cpp)
|
||||
endif()
|
||||
|
||||
add_subdirectory(acs)
|
||||
add_subdirectory(acs)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ class ThermalController : public ExtendedControllerBase {
|
||||
public:
|
||||
static const uint16_t INVALID_TEMPERATURE = 999;
|
||||
|
||||
ThermalController(object_id_t objectId, object_id_t parentId);
|
||||
ThermalController(object_id_t objectId);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -55,8 +55,11 @@ class ThermalController : public ExtendedControllerBase {
|
||||
MAX31865::Max31865Set max31865Set13;
|
||||
MAX31865::Max31865Set max31865Set14;
|
||||
MAX31865::Max31865Set max31865Set15;
|
||||
TMP1075::Tmp1075Dataset tmp1075Set1;
|
||||
TMP1075::Tmp1075Dataset tmp1075Set2;
|
||||
TMP1075::Tmp1075Dataset tmp1075SetTcs0;
|
||||
TMP1075::Tmp1075Dataset tmp1075SetTcs1;
|
||||
TMP1075::Tmp1075Dataset tmp1075SetPlPcdu0;
|
||||
TMP1075::Tmp1075Dataset tmp1075SetPlPcdu1;
|
||||
TMP1075::Tmp1075Dataset tmp1075SetIfBoard;
|
||||
|
||||
// SUS
|
||||
SUS::SusDataset susSet0;
|
||||
@ -75,6 +78,13 @@ class ThermalController : public ExtendedControllerBase {
|
||||
// Initial delay to make sure all pool variables have been initialized their owners
|
||||
Countdown initialCountdown = Countdown(DELAY);
|
||||
|
||||
PoolEntry<float> tmp1075Tcs0 = PoolEntry<float>(10.0);
|
||||
PoolEntry<float> tmp1075Tcs1 = PoolEntry<float>(10.0);
|
||||
PoolEntry<float> tmp1075PlPcdu0 = PoolEntry<float>(10.0);
|
||||
PoolEntry<float> tmp1075PlPcdu1 = PoolEntry<float>(10.0);
|
||||
PoolEntry<float> tmp1075IfBrd = PoolEntry<float>(10.0);
|
||||
|
||||
static constexpr dur_millis_t MUTEX_TIMEOUT = 50;
|
||||
void copySensors();
|
||||
void copySus();
|
||||
void copyDevices();
|
||||
|
@ -3,15 +3,542 @@
|
||||
#include <fsfw/src/fsfw/globalfunctions/constants.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
AcsParameters::AcsParameters() {}
|
||||
AcsParameters::AcsParameters(){}; //(uint8_t parameterModuleId) :
|
||||
// parameterModuleId(parameterModuleId) {}
|
||||
|
||||
AcsParameters::~AcsParameters() {}
|
||||
/*
|
||||
ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint16_t parameterId,
|
||||
|
||||
/*ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint16_t parameterId,
|
||||
ParameterWrapper* parameterWrapper,
|
||||
const ParameterWrapper* newValues,
|
||||
uint16_t startAtIndex) {
|
||||
return returnvalue::OK;
|
||||
if (domainId == parameterModuleId) {
|
||||
switch (parameterId >> 8) {
|
||||
case 0x0: // direct members
|
||||
switch (parameterId & 0xFF) {
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case 0x1: // OnBoardParams
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(onBoardParams.sampleTime);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case 0x2: // InertiaEIVE
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(inertiaEIVE.inertiaMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(inertiaEIVE.inertiaMatrixInverse);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case 0x3: // MgmHandlingParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm0orientationMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm1orientationMatrix);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm2orientationMatrix);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm3orientationMatrix);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm4orientationMatrix);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm0hardIronOffset);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm1hardIronOffset);
|
||||
break;
|
||||
case 0x7:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm2hardIronOffset);
|
||||
break;
|
||||
case 0x8:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm3hardIronOffset);
|
||||
break;
|
||||
case 0x9:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm4hardIronOffset);
|
||||
break;
|
||||
case 0xA:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm0softIronInverse);
|
||||
break;
|
||||
case 0xB:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm1softIronInverse);
|
||||
break;
|
||||
case 0xC:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm2softIronInverse);
|
||||
break;
|
||||
case 0xD:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm3softIronInverse);
|
||||
break;
|
||||
case 0xE:
|
||||
parameterWrapper->set(mgmHandlingParameters.mgm4softIronInverse);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case 0x4: // SusHandlingParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(susHandlingParameters.sus0orientationMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(susHandlingParameters.sus1orientationMatrix);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(susHandlingParameters.sus2orientationMatrix);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(susHandlingParameters.sus3orientationMatrix);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(susHandlingParameters.sus4orientationMatrix);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(susHandlingParameters.sus5orientationMatrix);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(susHandlingParameters.sus6orientationMatrix);
|
||||
break;
|
||||
case 0x7:
|
||||
parameterWrapper->set(susHandlingParameters.sus7orientationMatrix);
|
||||
break;
|
||||
case 0x8:
|
||||
parameterWrapper->set(susHandlingParameters.sus8orientationMatrix);
|
||||
break;
|
||||
case 0x9:
|
||||
parameterWrapper->set(susHandlingParameters.sus9orientationMatrix);
|
||||
break;
|
||||
case 0xA:
|
||||
parameterWrapper->set(susHandlingParameters.sus10orientationMatrix);
|
||||
break;
|
||||
case 0xB:
|
||||
parameterWrapper->set(susHandlingParameters.sus11orientationMatrix);
|
||||
break;
|
||||
case 0xC:
|
||||
parameterWrapper->set(susHandlingParameters.sus0coeffAlpha);
|
||||
break;
|
||||
case 0xD:
|
||||
parameterWrapper->set(susHandlingParameters.sus0coeffBeta);
|
||||
break;
|
||||
case 0xE:
|
||||
parameterWrapper->set(susHandlingParameters.sus1coeffAlpha);
|
||||
break;
|
||||
case 0xF:
|
||||
parameterWrapper->set(susHandlingParameters.sus1coeffBeta);
|
||||
break;
|
||||
case 0x10:
|
||||
parameterWrapper->set(susHandlingParameters.sus2coeffAlpha);
|
||||
break;
|
||||
case 0x11:
|
||||
parameterWrapper->set(susHandlingParameters.sus2coeffBeta);
|
||||
break;
|
||||
case 0x12:
|
||||
parameterWrapper->set(susHandlingParameters.sus3coeffAlpha);
|
||||
break;
|
||||
case 0x13:
|
||||
parameterWrapper->set(susHandlingParameters.sus3coeffBeta);
|
||||
break;
|
||||
case 0x14:
|
||||
parameterWrapper->set(susHandlingParameters.sus4coeffAlpha);
|
||||
break;
|
||||
case 0x15:
|
||||
parameterWrapper->set(susHandlingParameters.sus4coeffBeta);
|
||||
break;
|
||||
case 0x16:
|
||||
parameterWrapper->set(susHandlingParameters.sus5coeffAlpha);
|
||||
break;
|
||||
case 0x17:
|
||||
parameterWrapper->set(susHandlingParameters.sus5coeffBeta);
|
||||
break;
|
||||
case 0x18:
|
||||
parameterWrapper->set(susHandlingParameters.sus6coeffAlpha);
|
||||
break;
|
||||
case 0x19:
|
||||
parameterWrapper->set(susHandlingParameters.sus6coeffBeta);
|
||||
break;
|
||||
case 0x1A:
|
||||
parameterWrapper->set(susHandlingParameters.sus7coeffAlpha);
|
||||
break;
|
||||
case 0x1B:
|
||||
parameterWrapper->set(susHandlingParameters.sus7coeffBeta);
|
||||
break;
|
||||
case 0x1C:
|
||||
parameterWrapper->set(susHandlingParameters.sus8coeffAlpha);
|
||||
break;
|
||||
case 0x1D:
|
||||
parameterWrapper->set(susHandlingParameters.sus8coeffBeta);
|
||||
break;
|
||||
case 0x1E:
|
||||
parameterWrapper->set(susHandlingParameters.sus9coeffAlpha);
|
||||
break;
|
||||
case 0x1F:
|
||||
parameterWrapper->set(susHandlingParameters.sus9coeffBeta);
|
||||
break;
|
||||
case 0x20:
|
||||
parameterWrapper->set(susHandlingParameters.sus10coeffAlpha);
|
||||
break;
|
||||
case 0x21:
|
||||
parameterWrapper->set(susHandlingParameters.sus10coeffBeta);
|
||||
break;
|
||||
case 0x22:
|
||||
parameterWrapper->set(susHandlingParameters.sus11coeffAlpha);
|
||||
break;
|
||||
case 0x23:
|
||||
parameterWrapper->set(susHandlingParameters.sus11coeffBeta);
|
||||
break;
|
||||
case 0x24:
|
||||
parameterWrapper->set(susHandlingParameters.filterAlpha);
|
||||
break;
|
||||
case 0x25:
|
||||
parameterWrapper->set(susHandlingParameters.sunThresh);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x5): // GyrHandlingParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(gyrHandlingParameters.gyr0orientationMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(gyrHandlingParameters.gyr1orientationMatrix);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(gyrHandlingParameters.gyr2orientationMatrix);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(gyrHandlingParameters.gyr3orientationMatrix);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(gyrHandlingParameters.gyrFusionWeight);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x6): // RwHandlingParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(rwHandlingParameters.rw0orientationMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(rwHandlingParameters.rw1orientationMatrix);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(rwHandlingParameters.rw2orientationMatrix);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(rwHandlingParameters.rw3orientationMatrix);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(rwHandlingParameters.inertiaWheel);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(rwHandlingParameters.maxTrq);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x7): // RwMatrices
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(rwMatrices.alignmentMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(rwMatrices.pseudoInverse);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(rwMatrices.without0);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(rwMatrices.without1);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(rwMatrices.without2);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(rwMatrices.without3);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x8): // SafeModeControllerParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(safeModeControllerParameters.k_rate_mekf);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(safeModeControllerParameters.k_align_mekf);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(safeModeControllerParameters.k_rate_no_mekf);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(safeModeControllerParameters.k_align_no_mekf);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(safeModeControllerParameters.sunMagAngleMin);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(safeModeControllerParameters.sunTargetDir);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(safeModeControllerParameters.satRateRef);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x9): // DetumbleCtrlParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(detumbleCtrlParameters.gainD);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xA): // PointingModeControllerParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(targetModeControllerParameters.updtFlag);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(targetModeControllerParameters.A_rw);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(targetModeControllerParameters.refDirection);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(targetModeControllerParameters.refRotRate);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(targetModeControllerParameters.quatRef);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(targetModeControllerParameters.avoidBlindStr);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(targetModeControllerParameters.blindAvoidStart);
|
||||
break;
|
||||
case 0x7:
|
||||
parameterWrapper->set(targetModeControllerParameters.blindAvoidStop);
|
||||
break;
|
||||
case 0x8:
|
||||
parameterWrapper->set(targetModeControllerParameters.blindRotRate);
|
||||
break;
|
||||
case 0x9:
|
||||
parameterWrapper->set(targetModeControllerParameters.zeta);
|
||||
break;
|
||||
case 0xA:
|
||||
parameterWrapper->set(targetModeControllerParameters.zetaLow);
|
||||
break;
|
||||
case 0xB:
|
||||
parameterWrapper->set(targetModeControllerParameters.om);
|
||||
break;
|
||||
case 0xC:
|
||||
parameterWrapper->set(targetModeControllerParameters.omLow);
|
||||
break;
|
||||
case 0xD:
|
||||
parameterWrapper->set(targetModeControllerParameters.omMax);
|
||||
break;
|
||||
case 0xE:
|
||||
parameterWrapper->set(targetModeControllerParameters.qiMin);
|
||||
break;
|
||||
case 0xF:
|
||||
parameterWrapper->set(targetModeControllerParameters.gainNullspace);
|
||||
break;
|
||||
case 0x10:
|
||||
parameterWrapper->set(targetModeControllerParameters.desatMomentumRef);
|
||||
break;
|
||||
case 0x11:
|
||||
parameterWrapper->set(targetModeControllerParameters.deSatGainFactor);
|
||||
break;
|
||||
case 0x12:
|
||||
parameterWrapper->set(targetModeControllerParameters.desatOn);
|
||||
break;
|
||||
case 0x13:
|
||||
parameterWrapper->set(targetModeControllerParameters.omegaEarth);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xB): // StrParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(strParameters.exclusionAngle);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(strParameters.boresightAxis);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xC): // GpsParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xD): // GroundStationParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(groundStationParameters.latitudeGs);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(groundStationParameters.longitudeGs);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(groundStationParameters.altitudeGs);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(groundStationParameters.earthRadiusEquat);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(groundStationParameters.earthRadiusPolar);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xE): // SunModelParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(sunModelParameters.useSunModel);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(sunModelParameters.domega);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(sunModelParameters.omega_0);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(sunModelParameters.m_0);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(sunModelParameters.dm);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(sunModelParameters.e);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(sunModelParameters.e1);
|
||||
break;
|
||||
case 0x7:
|
||||
parameterWrapper->set(sunModelParameters.p1);
|
||||
break;
|
||||
case 0x8:
|
||||
parameterWrapper->set(sunModelParameters.p2);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0xF): // KalmanFilterParameters
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(kalmanFilterParameters.activateKalmanFilter);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(kalmanFilterParameters.requestResetFlag);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(
|
||||
kalmanFilterParameters.maxToleratedTimeBetweenKalmanFilterExecutionSteps);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(kalmanFilterParameters.processNoiseOmega);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(kalmanFilterParameters.processNoiseQuaternion);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseSTR);
|
||||
break;
|
||||
case 0x6:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseSS);
|
||||
break;
|
||||
case 0x7:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseMAG);
|
||||
break;
|
||||
case 0x8:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseGYR);
|
||||
break;
|
||||
case 0x9:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseArwGYR);
|
||||
break;
|
||||
case 0xA:
|
||||
parameterWrapper->set(kalmanFilterParameters.sensorNoiseBsGYR);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x10): // MagnetorquesParameter
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(magnetorquesParameter.mtq0orientationMatrix);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(magnetorquesParameter.mtq1orientationMatrix);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(magnetorquesParameter.mtq2orientationMatrix);
|
||||
break;
|
||||
case 0x3:
|
||||
parameterWrapper->set(magnetorquesParameter.alignmentMatrixMtq);
|
||||
break;
|
||||
case 0x4:
|
||||
parameterWrapper->set(magnetorquesParameter.inverseAlignment);
|
||||
break;
|
||||
case 0x5:
|
||||
parameterWrapper->set(magnetorquesParameter.DipolMax);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
case (0x11): // DetumbleParameter
|
||||
switch (parameterId & 0xFF) {
|
||||
case 0x0:
|
||||
parameterWrapper->set(detumbleParameter.detumblecounter);
|
||||
break;
|
||||
case 0x1:
|
||||
parameterWrapper->set(detumbleParameter.omegaDetumbleStart);
|
||||
break;
|
||||
case 0x2:
|
||||
parameterWrapper->set(detumbleParameter.omegaDetumbleEnd);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
return INVALID_DOMAIN_ID;
|
||||
}
|
||||
}*/
|
||||
|
@ -45,10 +45,10 @@ class AcsParameters /*: public HasParametersIF*/ {
|
||||
} inertiaEIVE;
|
||||
|
||||
struct MgmHandlingParameters {
|
||||
float mgm0orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}}; // Documentation not consistent
|
||||
float mgm1orientationMatrix[3][3] = {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}}; // Documentation not consistent
|
||||
float mgm2orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}}; // Documentation not consistent
|
||||
float mgm3orientationMatrix[3][3] = {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}}; // Documentation not consistent
|
||||
float mgm0orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}};
|
||||
float mgm1orientationMatrix[3][3] = {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}};
|
||||
float mgm2orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}};
|
||||
float mgm3orientationMatrix[3][3] = {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}};
|
||||
float mgm4orientationMatrix[3][3] = {{0, 0, -1}, {-1, 0, 0}, {0, 1, 0}};
|
||||
|
||||
float mgm0hardIronOffset[3] = {19.89364, -29.94111, -31.07508};
|
||||
@ -68,6 +68,9 @@ class AcsParameters /*: public HasParametersIF*/ {
|
||||
{15.67482e-2, -6.958760e-2, 94.50124e-2}};
|
||||
float mgm3softIronInverse[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
|
||||
float mgm4softIronInverse[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
|
||||
float mgm02variance[3] = {1, 1, 1};
|
||||
float mgm13variance[3] = {1, 1, 1};
|
||||
float mgm4variance[3] = {1, 1, 1};
|
||||
|
||||
} mgmHandlingParameters;
|
||||
|
||||
@ -767,6 +770,14 @@ class AcsParameters /*: public HasParametersIF*/ {
|
||||
double gyr1orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}};
|
||||
double gyr2orientationMatrix[3][3] = {{0, 0, -1}, {0, -1, 0}, {-1, 0, 0}};
|
||||
double gyr3orientationMatrix[3][3] = {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}};
|
||||
// var = sqrt(sigma), sigma = RND*sqrt(freq), following values are RND^2 and not var as freq is
|
||||
// assumed to be equal for the same class of sensors
|
||||
float gyr02variance[3] = {pow(3.0e-3 * sqrt(2), 2), // RND_x = 3.0e-3 deg/s/sqrt(Hz) rms
|
||||
pow(3.0e-3 * sqrt(2), 2), // RND_y = 3.0e-3 deg/s/sqrt(Hz) rms
|
||||
pow(4.3e-3 * sqrt(2), 2)}; // RND_z = 4.3e-3 deg/s/sqrt(Hz) rms
|
||||
float gyr13variance[3] = {pow(11e-3, 2), pow(11e-3, 2), pow(11e-3, 2)};
|
||||
enum PreferAdis { NO = 0, YES = 1 };
|
||||
uint8_t preferAdis = PreferAdis::YES;
|
||||
} gyrHandlingParameters;
|
||||
|
||||
struct RwHandlingParameters {
|
||||
@ -821,8 +832,8 @@ class AcsParameters /*: public HasParametersIF*/ {
|
||||
double k_align_no_mekf = 0.000056875;;
|
||||
double sunMagAngleMin; // ???
|
||||
|
||||
double sunTargetDir[3] = {0, 0, 1}; // Geometry Frame
|
||||
double satRateRef[3] = {0, 0, 0}; // Geometry Frame
|
||||
double sunTargetDir[3] = {0, 0, 1};
|
||||
double satRateRef[3] = {0, 0, 0};
|
||||
|
||||
} safeModeControllerParameters;
|
||||
|
||||
|
@ -5,23 +5,21 @@
|
||||
* Author: Robin Marquardt
|
||||
*/
|
||||
|
||||
|
||||
#include "ActuatorCmd.h"
|
||||
#include "util/MathOperations.h"
|
||||
#include "util/CholeskyDecomposition.h"
|
||||
#include <cmath>
|
||||
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
|
||||
ActuatorCmd::ActuatorCmd(AcsParameters *acsParameters_) {
|
||||
acsParameters = *acsParameters_;
|
||||
}
|
||||
#include <cmath>
|
||||
|
||||
ActuatorCmd::~ActuatorCmd(){
|
||||
#include "util/CholeskyDecomposition.h"
|
||||
#include "util/MathOperations.h"
|
||||
|
||||
}
|
||||
ActuatorCmd::ActuatorCmd(AcsParameters *acsParameters_) { acsParameters = *acsParameters_; }
|
||||
|
||||
ActuatorCmd::~ActuatorCmd() {}
|
||||
|
||||
void ActuatorCmd::scalingTorqueRws(const double *rwTrq, double *rwTrqScaled) {
|
||||
// Scaling the commanded torque to a maximum value
|
||||
@ -46,7 +44,7 @@ void ActuatorCmd::cmdSpeedToRws(const int32_t *speedRw0, const int32_t *speedRw1
|
||||
using namespace Math;
|
||||
|
||||
// Calculating the commanded speed in RPM for every reaction wheel
|
||||
double speedRws[4] = {*speedRw0, *speedRw1, *speedRw2, *speedRw3};
|
||||
double speedRws[4] = {(double)*speedRw0, (double)*speedRw1, (double)*speedRw2, (double)*speedRw3};
|
||||
double deltaSpeed[4] = {0, 0, 0, 0};
|
||||
double commandTime = acsParameters.onBoardParams.sampleTime,
|
||||
inertiaWheel = acsParameters.rwHandlingParameters.inertiaWheel;
|
||||
@ -58,22 +56,20 @@ void ActuatorCmd::cmdSpeedToRws(const int32_t *speedRw0, const int32_t *speedRw1
|
||||
}
|
||||
|
||||
void ActuatorCmd::cmdDipolMtq(const double *dipolMoment, double *dipolMomentUnits) {
|
||||
// Convert to Unit frame
|
||||
MatrixOperations<double>::multiply(*acsParameters.magnetorquesParameter.inverseAlignment,
|
||||
dipolMoment, dipolMomentUnits, 3, 3, 1);
|
||||
// Scaling along largest element if dipol exceeds maximum
|
||||
double maxDipol = acsParameters.magnetorquesParameter.DipolMax;
|
||||
double maxValue = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (abs(dipolMomentUnits[i]) > maxDipol) {
|
||||
maxValue = abs(dipolMomentUnits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to Unit frame
|
||||
MatrixOperations<double>::multiply(*acsParameters.magnetorquesParameter.inverseAlignment, dipolMoment, dipolMomentUnits, 3, 3, 1);
|
||||
// Scaling along largest element if dipol exceeds maximum
|
||||
double maxDipol = acsParameters.magnetorquesParameter.DipolMax;
|
||||
double maxValue = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (abs(dipolMomentUnits[i]) > maxDipol) {
|
||||
maxValue = abs(dipolMomentUnits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxValue > maxDipol) {
|
||||
|
||||
double scalingFactor = maxDipol / maxValue;
|
||||
VectorOperations<double>::mulScalar(dipolMomentUnits, scalingFactor, dipolMomentUnits, 3);
|
||||
|
||||
}
|
||||
if (maxValue > maxDipol) {
|
||||
double scalingFactor = maxDipol / maxValue;
|
||||
VectorOperations<double>::mulScalar(dipolMomentUnits, scalingFactor, dipolMomentUnits, 3);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,10 @@
|
||||
/*
|
||||
* ActuatorCmd.h
|
||||
*
|
||||
* Created on: 4 Aug 2022
|
||||
* Author: Robin Marquardt
|
||||
*/
|
||||
|
||||
#ifndef ACTUATORCMD_H_
|
||||
#define ACTUATORCMD_H_
|
||||
|
||||
|
||||
#include "AcsParameters.h"
|
||||
#include "SensorProcessing.h"
|
||||
#include "MultiplicativeKalmanFilter.h"
|
||||
#include "SensorProcessing.h"
|
||||
#include "SensorValues.h"
|
||||
#include "OutputValues.h"
|
||||
|
||||
class ActuatorCmd{
|
||||
public:
|
||||
@ -48,10 +39,9 @@ public:
|
||||
*/
|
||||
void cmdDipolMtq(const double *dipolMoment, double *dipolMomentUnits);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
AcsParameters acsParameters;
|
||||
protected:
|
||||
private:
|
||||
AcsParameters acsParameters;
|
||||
};
|
||||
|
||||
#endif /* ACTUATORCMD_H_ */
|
||||
|
@ -1,14 +1,13 @@
|
||||
target_sources(
|
||||
${LIB_EIVE_MISSION}
|
||||
PRIVATE AcsParameters.cpp
|
||||
ActuatorCmd.cpp
|
||||
Guidance.cpp
|
||||
Igrf13Model.cpp
|
||||
MultiplicativeKalmanFilter.cpp
|
||||
Navigation.cpp
|
||||
OutputValues.cpp
|
||||
SensorProcessing.cpp
|
||||
SensorValues.cpp
|
||||
SusConverter.cpp)
|
||||
|
||||
ActuatorCmd.cpp
|
||||
Guidance.cpp
|
||||
Igrf13Model.cpp
|
||||
MultiplicativeKalmanFilter.cpp
|
||||
Navigation.cpp
|
||||
SensorProcessing.cpp
|
||||
SensorValues.cpp
|
||||
SusConverter.cpp)
|
||||
|
||||
add_subdirectory(control)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "Guidance.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
@ -29,8 +30,9 @@ void Guidance::getTargetParamsSafe(double sunTargetSafe[3], double satRateSafe[3
|
||||
// memcpy(sunTargetSafe, acsParameters.safeModeControllerParameters.sunTargetDir, 24);
|
||||
}
|
||||
|
||||
void Guidance::targetQuatPtgOldVersion(ACS::SensorValues *sensorValues, ACS::OutputValues *outputValues,
|
||||
timeval now, double targetQuat[4], double refSatRate[3]) {
|
||||
void Guidance::targetQuatPtg(ACS::SensorValues *sensorValues, acsctrl::MekfData *mekfData,
|
||||
acsctrl::SusDataProcessed *susDataProcessed, timeval now,
|
||||
double targetQuat[4], double refSatRate[3]) {
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Calculation of target quaternion to groundstation or given latitude, longitude and altitude
|
||||
//-------------------------------------------------------------------------------------
|
||||
@ -68,10 +70,8 @@ void Guidance::targetQuatPtgOldVersion(ACS::SensorValues *sensorValues, ACS::Out
|
||||
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};
|
||||
quatBJ[0] = outputValues->quatMekfBJ[0];
|
||||
quatBJ[1] = outputValues->quatMekfBJ[1];
|
||||
quatBJ[2] = outputValues->quatMekfBJ[2];
|
||||
quatBJ[3] = outputValues->quatMekfBJ[3];
|
||||
std::memcpy(quatBJ, mekfData->quatMekf.value, 4 * sizeof(double));
|
||||
|
||||
QuaternionOperations::toDcm(quatBJ, dcmBJ);
|
||||
MatrixOperations<double>::multiply(*dcmBJ, *dcmJE, *dcmBE, 3, 3, 3);
|
||||
|
||||
@ -129,22 +129,15 @@ void Guidance::targetQuatPtgOldVersion(ACS::SensorValues *sensorValues, ACS::Out
|
||||
|
||||
if (outputValues->sunDirModelValid) {
|
||||
double sunDirJ[3] = {0, 0, 0};
|
||||
sunDirJ[0] = outputValues->sunDirModel[0];
|
||||
sunDirJ[1] = outputValues->sunDirModel[1];
|
||||
sunDirJ[2] = outputValues->sunDirModel[2];
|
||||
std::memcpy(sunDirJ, susDataProcessed->sunIjkModel.value, 3 * sizeof(double));
|
||||
MatrixOperations<double>::multiply(*dcmBJ, sunDirJ, sunDirB, 3, 3, 1);
|
||||
}
|
||||
|
||||
else {
|
||||
sunDirB[0] = outputValues->sunDirEst[0];
|
||||
sunDirB[1] = outputValues->sunDirEst[1];
|
||||
sunDirB[2] = outputValues->sunDirEst[2];
|
||||
} else {
|
||||
std::memcpy(sunDirB, susDataProcessed->susVecTot.value, 3 * sizeof(double));
|
||||
}
|
||||
|
||||
double exclAngle = acsParameters.strParameters.exclusionAngle,
|
||||
blindStart = acsParameters.targetModeControllerParameters.blindAvoidStart,
|
||||
blindEnd = acsParameters.targetModeControllerParameters.blindAvoidStop;
|
||||
|
||||
double sightAngleSun =
|
||||
VectorOperations<double>::dot(acsParameters.strParameters.boresightAxis, sunDirB);
|
||||
|
||||
@ -588,8 +581,8 @@ void Guidance::inertialQuatPtg(double targetQuat[4], double refSatRate[3]) {
|
||||
}
|
||||
}
|
||||
|
||||
void Guidance::comparePtg(double targetQuat[4], ACS::OutputValues *outputValues,
|
||||
double refSatRate[3], double quatError[3], double deltaRate[3]) {
|
||||
void Guidance::comparePtg(double targetQuat[4], acsctrl::MekfData *mekfData, double refSatRate[3],
|
||||
double quatErrorComplete[4], double quatError[3], double deltaRate[3]) {
|
||||
double quatRef[4] = {0, 0, 0, 0};
|
||||
quatRef[0] = acsParameters.targetModeControllerParameters.quatRef[0];
|
||||
quatRef[1] = acsParameters.targetModeControllerParameters.quatRef[1];
|
||||
@ -597,9 +590,7 @@ void Guidance::comparePtg(double targetQuat[4], ACS::OutputValues *outputValues,
|
||||
quatRef[3] = acsParameters.targetModeControllerParameters.quatRef[3];
|
||||
|
||||
double satRate[3] = {0, 0, 0};
|
||||
satRate[0] = outputValues->satRateMekf[0];
|
||||
satRate[1] = outputValues->satRateMekf[1];
|
||||
satRate[2] = outputValues->satRateMekf[2];
|
||||
std::memcpy(satRate, mekfData->satRotRateMekf.value, 3 * sizeof(double));
|
||||
VectorOperations<double>::subtract(satRate, refSatRate, deltaRate, 3);
|
||||
// valid checks ?
|
||||
double quatErrorMtx[4][4] = {{quatRef[3], quatRef[2], -quatRef[1], -quatRef[0]},
|
||||
@ -623,8 +614,8 @@ void Guidance::comparePtg(double targetQuat[4], ACS::OutputValues *outputValues,
|
||||
}
|
||||
|
||||
void Guidance::getDistributionMatrixRw(ACS::SensorValues *sensorValues, double *rwPseudoInv) {
|
||||
if (sensorValues->rw1Set.isValid() && sensorValues->rw2Set.isValid() && sensorValues->rw3Set.isValid() &&
|
||||
sensorValues->rw4Set.isValid()) {
|
||||
if (sensorValues->rw1Set.isValid() && sensorValues->rw2Set.isValid() &&
|
||||
sensorValues->rw3Set.isValid() && sensorValues->rw4Set.isValid()) {
|
||||
rwPseudoInv[0] = acsParameters.rwMatrices.pseudoInverse[0][0];
|
||||
rwPseudoInv[1] = acsParameters.rwMatrices.pseudoInverse[0][1];
|
||||
rwPseudoInv[2] = acsParameters.rwMatrices.pseudoInverse[0][2];
|
||||
|
@ -8,25 +8,26 @@
|
||||
#ifndef GUIDANCE_H_
|
||||
#define GUIDANCE_H_
|
||||
|
||||
|
||||
#include "AcsParameters.h"
|
||||
#include "SensorValues.h"
|
||||
#include "OutputValues.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "../controllerdefinitions/AcsCtrlDefinitions.h"
|
||||
#include "AcsParameters.h"
|
||||
#include "SensorValues.h"
|
||||
|
||||
class Guidance {
|
||||
public:
|
||||
Guidance(AcsParameters *acsParameters_);
|
||||
virtual ~Guidance();
|
||||
public:
|
||||
Guidance(AcsParameters *acsParameters_);
|
||||
virtual ~Guidance();
|
||||
|
||||
void getTargetParamsSafe(double sunTargetSafe[3], double satRateRef[3]);
|
||||
void getTargetParamsSafe(double sunTargetSafe[3], double satRateRef[3]);
|
||||
|
||||
// Function to get the target quaternion and refence rotation rate from gps position and position of the ground station
|
||||
void targetQuatPtgOldVersion(ACS::SensorValues* sensorValues, ACS::OutputValues *outputValues, timeval now,
|
||||
double targetQuat[4], double refSatRate[3]);
|
||||
void targetQuatPtg(ACS::SensorValues* sensorValues, ACS::OutputValues *outputValues, timeval now,
|
||||
double targetQuat[4], double refSatRate[3]);
|
||||
void targetQuatPtgOldVersion(ACS::SensorValues *sensorValues, acsctrl::MekfData *mekfData,
|
||||
acsctrl::SusDataProcessed *susDataProcessed, timeval now, double targetQuat[4],
|
||||
double refSatRate[3]);
|
||||
void targetQuatPtg(ACS::SensorValues *sensorValues, acsctrl::MekfData *mekfData,
|
||||
acsctrl::SusDataProcessed *susDataProcessed, timeval now, double targetQuat[4],
|
||||
double refSatRate[3]);
|
||||
|
||||
// Function to get the target quaternion and refence rotation rate for sun pointing after ground station
|
||||
void sunQuatPtg(ACS::SensorValues* sensorValues, ACS::OutputValues *outputValues, timeval now,
|
||||
@ -42,20 +43,21 @@ public:
|
||||
// Function to get the target quaternion and refence rotation rate from parameters for inertial pointing
|
||||
void inertialQuatPtg(double targetQuat[4], double refSatRate[3]);
|
||||
|
||||
// @note: compares target Quaternion and reference quaternion, also actual satellite rate and desired
|
||||
void comparePtg( double targetQuat[4], ACS::OutputValues *outputValues, double refSatRate[3], double quatError[3], double deltaRate[3] );
|
||||
// @note: compares target Quaternion and reference quaternion, also actual satellite rate and
|
||||
// desired
|
||||
void comparePtg(double targetQuat[4], acsctrl::MekfData *mekfData, double refSatRate[3],
|
||||
double quatErrorComplete[4], double quatError[3], double deltaRate[3]);
|
||||
|
||||
// @note: will give back the pseudoinverse matrix for the reaction wheel depending on the valid reation wheel
|
||||
// maybe can be done in "commanding.h"
|
||||
void getDistributionMatrixRw(ACS::SensorValues* sensorValues, double *rwPseudoInv);
|
||||
// @note: will give back the pseudoinverse matrix for the reaction wheel depending on the valid
|
||||
// reation wheel maybe can be done in "commanding.h"
|
||||
void getDistributionMatrixRw(ACS::SensorValues *sensorValues, double *rwPseudoInv);
|
||||
|
||||
|
||||
private:
|
||||
AcsParameters acsParameters;
|
||||
bool strBlindAvoidFlag = false;
|
||||
timeval timeSavedQuaternionNadir;
|
||||
double savedQuaternionNadir[4] = {0, 0, 0, 0};
|
||||
double omegaRefSavedNadir[3] = {0, 0, 0};
|
||||
private:
|
||||
AcsParameters acsParameters;
|
||||
bool strBlindAvoidFlag = false;
|
||||
timeval timeSavedQuaternionNadir;
|
||||
double savedQuaternionNadir[4] = {0, 0, 0, 0};
|
||||
double omegaRefSavedNadir[3] = {0, 0, 0};
|
||||
};
|
||||
|
||||
#endif /* ACS_GUIDANCE_H_ */
|
||||
|
@ -1,125 +1,152 @@
|
||||
/*
|
||||
* Igrf13Model.cpp
|
||||
*
|
||||
* Created on: 10 Mar 2022
|
||||
* Author: Robin Marquardt
|
||||
*/
|
||||
|
||||
#include "Igrf13Model.h"
|
||||
#include "util/MathOperations.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <fsfw/src/fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/src/fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/src/fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/src/fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
//#include <time.h>
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
Igrf13Model::Igrf13Model(){
|
||||
}
|
||||
Igrf13Model::~Igrf13Model(){
|
||||
}
|
||||
#include "util/MathOperations.h"
|
||||
|
||||
using namespace Math;
|
||||
|
||||
Igrf13Model::Igrf13Model() {}
|
||||
Igrf13Model::~Igrf13Model() {}
|
||||
|
||||
void Igrf13Model::magFieldComp(const double longitude, const double gcLatitude,
|
||||
const double altitude, timeval timeOfMagMeasurement, double* magFieldModelInertial) {
|
||||
const double altitude, timeval timeOfMagMeasurement,
|
||||
double* magFieldModelInertial) {
|
||||
double phi = longitude, theta = gcLatitude; // geocentric
|
||||
/* Here is the co-latitude needed*/
|
||||
theta -= 90 * PI / 180;
|
||||
theta *= (-1);
|
||||
|
||||
double phi = longitude, theta = gcLatitude; //geocentric
|
||||
/* Here is the co-latitude needed*/
|
||||
theta -= 90*Math::PI/180;
|
||||
theta *= (-1);
|
||||
double rE = 6371200.0; // radius earth [m]
|
||||
/* Predefine recursive associated Legendre polynomials */
|
||||
double P11 = 1;
|
||||
double P10 = P11; // P10 = P(n-1,m-0)
|
||||
double dP11 = 0; // derivative
|
||||
double dP10 = dP11; // derivative
|
||||
|
||||
double rE = 6371200.0; // radius earth [m]
|
||||
/* Predefine recursive associated Legendre polynomials */
|
||||
double P11 = 1;
|
||||
double P10 = P11; //P10 = P(n-1,m-0)
|
||||
double dP11 = 0; //derivative
|
||||
double dP10 = dP11; //derivative
|
||||
double P2 = 0, dP2 = 0, P20 = 0, dP20 = 0, K = 0;
|
||||
|
||||
double P2 = 0, dP2 = 0, P20 = 0, dP20 = 0, K = 0;
|
||||
for (int m = 0; m <= igrfOrder; m++) {
|
||||
for (int n = 1; n <= igrfOrder; n++) {
|
||||
if (m <= n) {
|
||||
/* Calculation of Legendre Polynoms (normalised) */
|
||||
if (n == m) {
|
||||
P2 = sin(theta) * P11;
|
||||
dP2 = sin(theta) * dP11 + cos(theta) * P11;
|
||||
P11 = P2;
|
||||
P10 = P11;
|
||||
P20 = 0;
|
||||
dP11 = dP2;
|
||||
dP10 = dP11;
|
||||
dP20 = 0;
|
||||
} else if (n == 1) {
|
||||
P2 = cos(theta) * P10;
|
||||
dP2 = cos(theta) * dP10 - sin(theta) * P10;
|
||||
P20 = P10;
|
||||
P10 = P2;
|
||||
dP20 = dP10;
|
||||
dP10 = dP2;
|
||||
} else {
|
||||
K = (pow((n - 1), 2) - pow(m, 2)) / ((2 * n - 1) * (2 * n - 3));
|
||||
P2 = cos(theta) * P10 - K * P20;
|
||||
dP2 = cos(theta) * dP10 - sin(theta) * P10 - K * dP20;
|
||||
P20 = P10;
|
||||
P10 = P2;
|
||||
dP20 = dP10;
|
||||
dP10 = dP2;
|
||||
}
|
||||
/* gradient of scalar potential towards radius */
|
||||
magFieldModel[0] +=
|
||||
pow(rE / (altitude + rE), (n + 2)) * (n + 1) *
|
||||
((updatedG[m][n - 1] * cos(m * phi) + updatedH[m][n - 1] * sin(m * phi)) * P2);
|
||||
/* gradient of scalar potential towards theta */
|
||||
magFieldModel[1] +=
|
||||
pow(rE / (altitude + rE), (n + 2)) *
|
||||
((updatedG[m][n - 1] * cos(m * phi) + updatedH[m][n - 1] * sin(m * phi)) * dP2);
|
||||
/* gradient of scalar potential towards phi */
|
||||
magFieldModel[2] +=
|
||||
pow(rE / (altitude + rE), (n + 2)) *
|
||||
((-updatedG[m][n - 1] * sin(m * phi) + updatedH[m][n - 1] * cos(m * phi)) * P2 * m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int m = 0; m <= igrfOrder; m++) {
|
||||
for (int n = 1; n <= igrfOrder; n++) {
|
||||
if (m <= n) {
|
||||
/* Calculation of Legendre Polynoms (normalised) */
|
||||
if (n == m) {
|
||||
P2 = sin(theta) * P11;
|
||||
dP2 = sin(theta) * dP11 - cos(theta) * P11;
|
||||
P11 = P2;
|
||||
P10 = P11;
|
||||
P20 = 0;
|
||||
dP11 = dP2;
|
||||
dP10 = dP11;
|
||||
dP20 = 0;
|
||||
} else if (n == 1) {
|
||||
P2 = cos(theta) * P10;
|
||||
dP2 = cos(theta) * dP10 - sin(theta) * P10;
|
||||
P20 = P10;
|
||||
P10 = P2;
|
||||
dP20 = dP10;
|
||||
dP10 = dP2;
|
||||
} else {
|
||||
K = (pow((n - 1), 2) - pow(m, 2))
|
||||
/ ((2 * n - 1) * (2 * n - 3));
|
||||
P2 = cos(theta) * P10 - K * P20;
|
||||
dP2 = cos(theta) * dP10 - sin(theta) * P10 - K * dP20;
|
||||
P20 = P10;
|
||||
P10 = P2;
|
||||
dP20 = dP10;
|
||||
dP10 = dP2;
|
||||
}
|
||||
/* gradient of scalar potential towards radius */
|
||||
magFieldModel[0]+=pow(rE/(altitude+rE),(n+2))*(n+1)*
|
||||
((updatedG[m][n-1]*cos(m*phi) + updatedH[m][n-1]*sin(m*phi))*P2);
|
||||
/* gradient of scalar potential towards phi */
|
||||
magFieldModel[1]+=pow(rE/(altitude+rE),(n+2))*
|
||||
((updatedG[m][n-1]*cos(m*phi) + updatedH[m][n-1]*sin(m*phi))*dP2);
|
||||
/* gradient of scalar potential towards theta */
|
||||
magFieldModel[2]+=pow(rE/(altitude+rE),(n+2))*
|
||||
((-updatedG[m][n-1]*sin(m*phi) + updatedH[m][n-1]*cos(m*phi))*P2*m);
|
||||
}
|
||||
}
|
||||
}
|
||||
magFieldModel[1] *= -1;
|
||||
magFieldModel[2] *= (-1 / sin(theta));
|
||||
|
||||
magFieldModel[1] *= -1;
|
||||
magFieldModel[2] *= (-1 / sin(theta));
|
||||
double JD2000 = MathOperations<double>::convertUnixToJD2000(timeOfMagMeasurement);
|
||||
double UT1 = JD2000 / 36525.;
|
||||
|
||||
/* Next step: transform into inertial KOS (IJK)*/
|
||||
//Julean Centuries
|
||||
double JD2000Floor = 0;
|
||||
double JD2000 = MathOperations<double>::convertUnixToJD2000(timeOfMagMeasurement);
|
||||
JD2000Floor = floor(JD2000);
|
||||
double JC2000 = JD2000Floor / 36525;
|
||||
double gst =
|
||||
280.46061837 + 360.98564736629 * JD2000 + 0.0003875 * pow(UT1, 2) - 2.6e-8 * pow(UT1, 3);
|
||||
gst = std::fmod(gst, 360.);
|
||||
gst *= PI / 180.;
|
||||
double lst = gst + longitude; // local sidereal time [rad]
|
||||
|
||||
double gst = 100.4606184 + 36000.77005361 * JC2000 + 0.00038793 * pow(JC2000,2)
|
||||
- 0.000000026 * pow(JC2000,3); //greenwich sidereal time
|
||||
gst *= PI/180; //convert to radians
|
||||
double sec = (JD2000 - JD2000Floor) * 86400; // Seconds on this day (Universal time) // FROM GPS ?
|
||||
double omega0 = 0.00007292115; // mean angular velocity earth [rad/s]
|
||||
gst +=omega0 * sec;
|
||||
magFieldModelInertial[0] =
|
||||
(magFieldModel[0] * cos(gcLatitude) + magFieldModel[1] * sin(gcLatitude)) * cos(lst) -
|
||||
magFieldModel[2] * sin(lst);
|
||||
magFieldModelInertial[1] =
|
||||
(magFieldModel[0] * cos(gcLatitude) + magFieldModel[1] * sin(gcLatitude)) * sin(lst) +
|
||||
magFieldModel[2] * cos(lst);
|
||||
magFieldModelInertial[2] =
|
||||
magFieldModel[0] * sin(gcLatitude) - magFieldModel[1] * cos(gcLatitude);
|
||||
|
||||
double lst = gst + longitude; //local sidereal time [rad]
|
||||
double normVecMagFieldInert[3] = {0, 0, 0};
|
||||
VectorOperations<double>::normalize(magFieldModelInertial, normVecMagFieldInert, 3);
|
||||
|
||||
|
||||
|
||||
magFieldModelInertial[0] = magFieldModel[0] * cos(theta) + magFieldModel[1] * sin(theta)*cos(lst) - magFieldModel[1] * sin(lst);
|
||||
magFieldModelInertial[1] = magFieldModel[0] * cos(theta) + magFieldModel[1] * sin(theta)*sin(lst) + magFieldModel[1] * cos(lst);
|
||||
magFieldModelInertial[2] = magFieldModel[0] * sin(theta) + magFieldModel[1] * cos(lst);
|
||||
|
||||
double normVecMagFieldInert[3] = {0,0,0};
|
||||
VectorOperations<double>::normalize(magFieldModelInertial, normVecMagFieldInert, 3);
|
||||
magFieldModel[0] = 0;
|
||||
magFieldModel[1] = 0;
|
||||
magFieldModel[2] = 0;
|
||||
}
|
||||
|
||||
void Igrf13Model::updateCoeffGH(timeval timeOfMagMeasurement){
|
||||
|
||||
double JD2000Igrf = (2458850.0-2451545); //Begin of IGRF-13 (2020-01-01,00:00:00) in JD2000
|
||||
double JD2000 = MathOperations<double>::convertUnixToJD2000(timeOfMagMeasurement);
|
||||
double days = ceil(JD2000-JD2000Igrf);
|
||||
for(int i = 0;i <= igrfOrder; i++){
|
||||
for(int j = 0;j <= (igrfOrder-1); j++){
|
||||
updatedG[i][j] = coeffG[i][j] + svG[i][j] * (days/365);
|
||||
updatedH[i][j] = coeffH[i][j] + svH[i][j] * (days/365);
|
||||
}
|
||||
}
|
||||
void Igrf13Model::updateCoeffGH(timeval timeOfMagMeasurement) {
|
||||
double JD2000Igrf = (2458850.0 - 2451545); // Begin of IGRF-13 (2020-01-01,00:00:00) in JD2000
|
||||
double JD2000 = MathOperations<double>::convertUnixToJD2000(timeOfMagMeasurement);
|
||||
double days = ceil(JD2000 - JD2000Igrf);
|
||||
for (int i = 0; i <= igrfOrder; i++) {
|
||||
for (int j = 0; j <= (igrfOrder - 1); j++) {
|
||||
updatedG[i][j] = coeffG[i][j] + svG[i][j] * (days / 365);
|
||||
updatedH[i][j] = coeffH[i][j] + svH[i][j] * (days / 365);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Igrf13Model::schmidtNormalization() {
|
||||
double kronDelta = 0;
|
||||
schmidtFactors[0][0] = 1;
|
||||
for (int n = 1; n <= igrfOrder; n++) {
|
||||
if (n == 1) {
|
||||
schmidtFactors[0][n - 1] = 1;
|
||||
} else {
|
||||
schmidtFactors[0][n - 1] = schmidtFactors[0][n - 2] * (2 * n - 1) / n;
|
||||
}
|
||||
for (int m = 1; m <= igrfOrder; m++) {
|
||||
if (m == 1) {
|
||||
kronDelta = 1;
|
||||
} else {
|
||||
kronDelta = 0;
|
||||
}
|
||||
schmidtFactors[m][n - 1] =
|
||||
schmidtFactors[m - 1][n - 1] * sqrt((n - m + 1) * (kronDelta + 1) / (n + m));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i <= igrfOrder; i++) {
|
||||
for (int j = 0; j <= (igrfOrder - 1); j++) {
|
||||
coeffG[i][j] = schmidtFactors[i][j] * coeffG[i][j];
|
||||
coeffH[i][j] = schmidtFactors[i][j] * coeffH[i][j];
|
||||
|
||||
svG[i][j] = schmidtFactors[i][j] * svG[i][j];
|
||||
svH[i][j] = schmidtFactors[i][j] * svH[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,103 +16,124 @@
|
||||
#ifndef IGRF13MODEL_H_
|
||||
#define IGRF13MODEL_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <fsfw/parameters/HasParametersIF.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fsfw/parameters/HasParametersIF.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// Output should be transformed to [T] instead of [nT]
|
||||
// Updating Coefficients has to be implemented yet. Question, updating everyday ?
|
||||
class Igrf13Model/*:public HasParametersIF*/{
|
||||
class Igrf13Model /*:public HasParametersIF*/ {
|
||||
public:
|
||||
Igrf13Model();
|
||||
virtual ~Igrf13Model();
|
||||
|
||||
public:
|
||||
Igrf13Model();
|
||||
virtual ~Igrf13Model();
|
||||
// Main Function
|
||||
void magFieldComp(const double longitude, const double gcLatitude, const double altitude,
|
||||
timeval timeOfMagMeasurement, double* magFieldModelInertial);
|
||||
// Right now the radius for igrf is simply with r0 + altitude calculated. In reality the radius is
|
||||
// oriented from the satellite to earth COM Difference up to 25 km, which is 5 % of the total
|
||||
// flight altitude
|
||||
/* Inputs:
|
||||
* - longitude: geocentric longitude [rad]
|
||||
* - latitude: geocentric latitude [rad]
|
||||
* - altitude: [m]
|
||||
* - timeOfMagMeasurement: time of actual measurement [s]
|
||||
*
|
||||
* Outputs:
|
||||
* - magFieldModelInertial: Magnetic Field Vector in IJK RF [nT]*/
|
||||
|
||||
// Main Function
|
||||
void magFieldComp(const double longitude, const double gcLatitude, const double altitude, timeval timeOfMagMeasurement,double* magFieldModelInertial);
|
||||
// Right now the radius for igrf is simply with r0 + altitude calculated. In reality the radius is oriented from the satellite to earth COM
|
||||
// Difference up to 25 km, which is 5 % of the total flight altitude
|
||||
/* Inputs:
|
||||
* - longitude: geocentric longitude [rad]
|
||||
* - latitude: geocentric latitude [rad]
|
||||
* - altitude: [m]
|
||||
* - timeOfMagMeasurement: time of actual measurement [s]
|
||||
*
|
||||
* Outputs:
|
||||
* - magFieldModelInertial: Magnetic Field Vector in IJK KOS [nT]*/
|
||||
// Coefficient wary over year, could be updated sometimes.
|
||||
void updateCoeffGH(timeval timeOfMagMeasurement); // Secular variation (SV)
|
||||
double magFieldModel[3];
|
||||
void schmidtNormalization();
|
||||
|
||||
private:
|
||||
double coeffG[14][13] = {
|
||||
{-29404.8, -2499.6, 1363.2, 903.0, -234.3, 66.0, 80.6, 23.7, 5.0, -1.9, 3.0, -2.0, 0.1},
|
||||
{-1450.9, 2982.0, -2381.2, 809.5, 363.2, 65.5, -76.7, 9.7, 8.4, -6.2, -1.4, -0.1, -0.9},
|
||||
{0.0, 1677.0, 1236.2, 86.3, 187.8, 72.9, -8.2, -17.6, 2.9, -0.1, -2.5, 0.5, 0.5},
|
||||
{0.0, 0.0, 525.7, -309.4, -140.7, -121.5, 56.5, -0.5, -1.5, 1.7, 2.3, 1.3, 0.7},
|
||||
{0.0, 0.0, 0.0, 48.0, -151.2, -36.2, 15.8, -21.1, -1.1, -0.9, -0.9, -1.2, -0.3},
|
||||
{0.0, 0.0, 0.0, 0.0, 13.5, 13.5, 6.4, 15.3, -13.2, 0.7, 0.3, 0.7, 0.8},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, -64.7, -7.2, 13.7, 1.1, -0.9, -0.7, 0.3, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.8, -16.5, 8.8, 1.9, -0.1, 0.5, 0.8},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.3, -9.3, 1.4, 1.4, -0.3, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -11.9, -2.4, -0.6, -0.5, 0.4},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -3.8, 0.2, 0.1, 0.1},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.1, -1.1, 0.5},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.3, -0.5},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.4}}; // [m][n] in nT
|
||||
|
||||
// Coefficient wary over year, could be updated sometimes.
|
||||
void updateCoeffGH(timeval timeOfMagMeasurement); //Secular variation (SV)
|
||||
double magFieldModel[3];
|
||||
double coeffH[14][13] = {
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0},
|
||||
{4652.5, -2991.6, -82.1, 281.9, 47.7, -19.1, -51.5, 8.4, -23.4, 3.4, 0.0, -1.2, -0.9},
|
||||
{0.0, -734.6, 241.9, -158.4, 208.3, 25.1, -16.9, -15.3, 11.0, -0.2, 2.5, 0.5, 0.6},
|
||||
{0.0, 0.0, -543.4, 199.7, -121.2, 52.8, 2.2, 12.8, 9.8, 3.6, -0.6, 1.4, 1.4},
|
||||
{0.0, 0.0, 0.0, -349.7, 32.3, -64.5, 23.5, -11.7, -5.1, 4.8, -0.4, -1.8, -0.4},
|
||||
{0.0, 0.0, 0.0, 0.0, 98.9, 8.9, -2.2, 14.9, -6.3, -8.6, 0.6, 0.1, -1.3},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 68.1, -27.2, 3.6, 7.8, -0.1, -0.2, 0.8, -0.1},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.8, -6.9, 0.4, -4.3, -1.7, -0.2, 0.3},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.8, -1.4, -3.4, -1.6, 0.6, -0.1},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.6, -0.1, -3.0, 0.2, 0.5},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -8.8, -2.0, -0.9, 0.5},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.6, 0.0, -0.4},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, -0.4},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.6}}; // [m][n] in nT
|
||||
|
||||
private:
|
||||
const double coeffG[14][13] = {{-29404.8,-2499.6, 1363.2, 903.0,-234.3, 66.0, 80.6, 23.7, 5.0,-1.9, 3.0,-2.0, 0.1},
|
||||
{ -1450.9, 2982.0,-2381.2, 809.5, 363.2, 65.5,-76.7, 9.7, 8.4,-6.2,-1.4,-0.1,-0.9},
|
||||
{ 0.0, 1677.0, 1236.2, 86.3, 187.8, 72.9, -8.2,-17.6, 2.9,-0.1,-2.5, 0.5, 0.5},
|
||||
{ 0.0, 0.0, 525.7,-309.4,-140.7,-121.5, 56.5, -0.5, -1.5, 1.7, 2.3, 1.3, 0.7},
|
||||
{ 0.0, 0.0, 0.0, 48.0,-151.2, -36.2, 15.8,-21.1, -1.1,-0.9,-0.9,-1.2,-0.3},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 13.5, 13.5, 6.4, 15.3,-13.2, 0.7, 0.3, 0.7, 0.8},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, -64.7, -7.2, 13.7, 1.1,-0.9,-0.7, 0.3, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.8,-16.5, 8.8, 1.9,-0.1, 0.5, 0.8},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.3, -9.3, 1.4, 1.4,-0.3, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-11.9,-2.4,-0.6,-0.5, 0.4},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-3.8, 0.2, 0.1, 0.1},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.1,-1.1, 0.5},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-0.3,-0.5},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-0.4}}; // [m][n] in nT
|
||||
double svG[14][13] = {
|
||||
{5.7, -11.0, 2.2, -1.2, -0.3, -0.5, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{7.4, -7.0, -5.9, -1.6, 0.5, -0.3, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2.1, 3.1, -5.9, -0.6, 0.4, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -12.0, 5.2, 0.2, 1.3, 0.7, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, -5.1, 1.3, -1.4, 0.1, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.9, 0.0, -0.5, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.9, -0.8, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.8, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; // [m][n] in nT
|
||||
|
||||
const double coeffH[14][13] = {{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0 },
|
||||
{4652.5,-2991.6, -82.1, 281.9, 47.7,-19.1,-51.5, 8.4,-23.4, 3.4, 0.0,-1.2,-0.9},
|
||||
{ 0.0, -734.6, 241.9,-158.4, 208.3, 25.1,-16.9,-15.3, 11.0,-0.2, 2.5, 0.5, 0.6},
|
||||
{ 0.0, 0.0,-543.4, 199.7,-121.2, 52.8, 2.2, 12.8, 9.8, 3.6,-0.6, 1.4, 1.4},
|
||||
{ 0.0, 0.0, 0.0,-349.7, 32.3,-64.5, 23.5,-11.7, -5.1, 4.8,-0.4,-1.8,-0.4},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 98.9, 8.9, -2.2, 14.9, -6.3,-8.6, 0.6, 0.1,-1.3},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 68.1,-27.2, 3.6, 7.8,-0.1,-0.2, 0.8,-0.1},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.8, -6.9, 0.4,-4.3,-1.7,-0.2, 0.3},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.8, -1.4,-3.4,-1.6, 0.6,-0.1},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.6,-0.1,-3.0, 0.2, 0.5},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-8.8,-2.0,-0.9, 0.5},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-2.6, 0.0,-0.4},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5,-0.4},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,-0.6}}; // [m][n] in nT
|
||||
double svH[14][13] = {
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-25.9, -30.2, 6.0, -0.1, 0.0, 0.0, 0.6, -0.2, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -22.4, -1.1, 6.5, 2.5, -1.6, 0.6, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.5, 3.6, -0.6, -1.3, -0.8, -0.2, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, -5.0, 3.0, 0.8, -0.2, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.3, 0.0, -1.1, -0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.1, -0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; // [m][n] in nT
|
||||
|
||||
double schmidtFactors[14][13] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
;
|
||||
|
||||
const double svG[14][13] = {{5.7,-11.0, 2.2,-1.2,-0.3,-0.5,-0.1, 0.0, 0.0, 0.0, 0.0, 0.0 ,0.0},
|
||||
{7.4, -7.0, -5.9,-1.6, 0.5,-0.3,-0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2.1, 3.1,-5.9,-0.6, 0.4, 0.0,-0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0,-12.0, 5.2, 0.2, 1.3, 0.7, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0,-5.1, 1.3,-1.4, 0.1,-0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.9, 0.0,-0.5, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.9,-0.8, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.8,-0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; // [m][n] in nT
|
||||
|
||||
const double svH[14][13] = {{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-25.9,-30.2, 6.0,-0.1, 0.0, 0.0, 0.6,-0.2, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0,-22.4,-1.1, 6.5, 2.5,-1.6, 0.6, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.5, 3.6,-0.6,-1.3,-0.8,-0.2, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0,-5.0, 3.0, 0.8,-0.2, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.3, 0.0,-1.1,-0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.1,-0.4, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; // [m][n] in nT
|
||||
|
||||
double updatedG[14][13];
|
||||
double updatedH[14][13];
|
||||
static const int igrfOrder = 13; // degree of truncation
|
||||
double updatedG[14][13];
|
||||
double updatedH[14][13];
|
||||
static const int igrfOrder = 13; // degree of truncation
|
||||
};
|
||||
|
||||
#endif /* IGRF13MODEL_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,101 +7,94 @@
|
||||
* @brief: This class handles the calculation of an estimated quaternion and the gyro bias by
|
||||
* means of the spacecraft attitude sensors
|
||||
*
|
||||
* @note: A description of the used algorithms can be found in the bachelor thesis of Robin Marquardt
|
||||
* @note: A description of the used algorithms can be found in the bachelor thesis of Robin
|
||||
* Marquardt
|
||||
* https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_Studenten/Marquardt_Robin&openfile=500811
|
||||
*/
|
||||
|
||||
#ifndef MULTIPLICATIVEKALMANFILTER_H_
|
||||
#define MULTIPLICATIVEKALMANFILTER_H_
|
||||
|
||||
#include "config/classIds.h"
|
||||
#include <stdint.h> //uint8_t
|
||||
#include <time.h> /*purpose, timeval ?*/
|
||||
//#include <_timeval.h>
|
||||
#include <stdint.h> //uint8_t
|
||||
#include <time.h> /*purpose, timeval ?*/
|
||||
|
||||
#include "../controllerdefinitions/AcsCtrlDefinitions.h"
|
||||
#include "AcsParameters.h"
|
||||
#include "config/classIds.h"
|
||||
|
||||
class MultiplicativeKalmanFilter{
|
||||
public:
|
||||
/* @brief: Constructor
|
||||
* @param: acsParameters_ Pointer to object which defines the ACS configuration parameters
|
||||
*/
|
||||
MultiplicativeKalmanFilter(AcsParameters *acsParameters_);
|
||||
virtual ~MultiplicativeKalmanFilter();
|
||||
class MultiplicativeKalmanFilter {
|
||||
public:
|
||||
/* @brief: Constructor
|
||||
* @param: acsParameters_ Pointer to object which defines the ACS configuration parameters
|
||||
*/
|
||||
MultiplicativeKalmanFilter(AcsParameters *acsParameters_);
|
||||
virtual ~MultiplicativeKalmanFilter();
|
||||
|
||||
void reset(); // NOT YET DEFINED - should only reset all mekf variables
|
||||
void reset(); // NOT YET DEFINED - should only reset all mekf variables
|
||||
|
||||
/* @brief: init() - This function initializes the Kalman Filter and will provide the first quaternion through
|
||||
* the QUEST algorithm
|
||||
* @param: magneticField_ magnetic field vector in the body frame
|
||||
* sunDir_ sun direction vector in the body frame
|
||||
* sunDirJ sun direction vector in the ECI frame
|
||||
* magFieldJ magnetic field vector in the ECI frame
|
||||
*/
|
||||
void init(const double *magneticField_, const bool *validMagField_,
|
||||
const double *sunDir_, const bool *validSS,
|
||||
const double *sunDirJ, const bool *validSSModel,
|
||||
const double *magFieldJ,const bool *validMagModel);
|
||||
/* @brief: init() - This function initializes the Kalman Filter and will provide the first
|
||||
* quaternion through the QUEST algorithm
|
||||
* @param: magneticField_ magnetic field vector in the body frame
|
||||
* sunDir_ sun direction vector in the body frame
|
||||
* sunDirJ sun direction vector in the ECI frame
|
||||
* magFieldJ magnetic field vector in the ECI frame
|
||||
*/
|
||||
void init(const double *magneticField_, const bool validMagField_, const double *sunDir_,
|
||||
const bool validSS, const double *sunDirJ, const bool validSSModel,
|
||||
const double *magFieldJ, const bool validMagModel);
|
||||
|
||||
/* @brief: mekfEst() - This function calculates the quaternion and gyro bias of the Kalman Filter for the current step
|
||||
* after the initalization
|
||||
* @param: quaternionSTR Star Tracker Quaternion between from body to ECI frame
|
||||
* rateRMUs_ Estimated satellite rotation rate from the Rate Measurement Units [rad/s]
|
||||
* magneticField_ magnetic field vector in the body frame
|
||||
* sunDir_ sun direction vector in the body frame
|
||||
* sunDirJ sun direction vector in the ECI frame
|
||||
* magFieldJ magnetic field vector in the ECI frame
|
||||
* outputQuat Stores the calculated quaternion
|
||||
* outputSatRate Stores the adjusted satellite rate
|
||||
* @return ReturnValue_t Feedback of this class, KALMAN_NO_RMU_MEAS if no satellite rate from the sensors was provided,
|
||||
* KALMAN_NO_MODEL if no sunDirJ or magFieldJ was given from the model calculations,
|
||||
* KALMAN_INVERSION_FAILED if the calculation of the Gain matrix was not possible,
|
||||
* RETURN_OK else
|
||||
*/
|
||||
ReturnValue_t mekfEst(
|
||||
const double *quaternionSTR, const bool *validSTR_,
|
||||
const double *rateRMUs_, const bool *validRMUs_,
|
||||
const double *magneticField_, const bool *validMagField_,
|
||||
const double *sunDir_, const bool *validSS,
|
||||
const double *sunDirJ, const bool *validSSModel,
|
||||
const double *magFieldJ,const bool *validMagModel,
|
||||
double *outputQuat, double *outputSatRate);
|
||||
/* @brief: mekfEst() - This function calculates the quaternion and gyro bias of the Kalman Filter
|
||||
* for the current step after the initalization
|
||||
* @param: quaternionSTR Star Tracker Quaternion between from body to ECI frame
|
||||
* rateGYRs_ Estimated satellite rotation rate from the
|
||||
* Gyroscopes [rad/s] magneticField_ magnetic field vector in the body frame sunDir_
|
||||
* sun direction vector in the body frame sunDirJ sun direction vector in the ECI
|
||||
* frame magFieldJ magnetic field vector in the ECI frame
|
||||
* outputQuat Stores the calculated quaternion
|
||||
* outputSatRate Stores the adjusted satellite rate
|
||||
* @return ReturnValue_t Feedback of this class, KALMAN_NO_GYR_MEAS if no satellite rate from
|
||||
* the sensors was provided, KALMAN_NO_MODEL if no sunDirJ or magFieldJ was given from the model
|
||||
* calculations, KALMAN_INVERSION_FAILED if the calculation of the Gain matrix was not possible,
|
||||
* RETURN_OK else
|
||||
*/
|
||||
ReturnValue_t mekfEst(const double *quaternionSTR, const bool validSTR_, const double *rateGYRs_,
|
||||
const bool validGYRs_, const double *magneticField_,
|
||||
const bool validMagField_, const double *sunDir_, const bool validSS,
|
||||
const double *sunDirJ, const bool validSSModel, const double *magFieldJ,
|
||||
const bool validMagModel, acsctrl::MekfData *mekfData);
|
||||
|
||||
// Declaration of Events (like init) and memberships
|
||||
// static const uint8_t INTERFACE_ID = CLASS_ID::MEKF; //CLASS IDS ND
|
||||
// (/config/returnvalues/classIDs.h) static const Event RESET =
|
||||
// MAKE_EVENT(1,severity::INFO);//typedef uint32_t Event (Event.h), should be
|
||||
// resetting Mekf
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::KALMAN;
|
||||
static const ReturnValue_t KALMAN_NO_GYR_MEAS = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t KALMAN_NO_MODEL = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t KALMAN_INVERSION_FAILED = MAKE_RETURN_CODE(0x03);
|
||||
|
||||
// Declaration of Events (like init) and memberships
|
||||
//static const uint8_t INTERFACE_ID = CLASS_ID::MEKF; //CLASS IDS ND (/config/returnvalues/classIDs.h)
|
||||
//static const Event RESET = MAKE_EVENT(1,severity::INFO);//typedef uint32_t Event (Event.h), should be
|
||||
// resetting Mekf
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::KALMAN;
|
||||
static const ReturnValue_t KALMAN_NO_RMU_MEAS = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t KALMAN_NO_MODEL = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t KALMAN_INVERSION_FAILED = MAKE_RETURN_CODE(0x03);
|
||||
private:
|
||||
/*Parameters*/
|
||||
AcsParameters::InertiaEIVE *inertiaEIVE;
|
||||
AcsParameters::KalmanFilterParameters *kalmanFilterParameters;
|
||||
double quaternion_STR_SB[4];
|
||||
bool validInit;
|
||||
double sampleTime = 0.1;
|
||||
|
||||
private:
|
||||
/*Parameters*/
|
||||
AcsParameters::InertiaEIVE* inertiaEIVE;
|
||||
AcsParameters::KalmanFilterParameters* kalmanFilterParameters;
|
||||
double quaternion_STR_SB[4];
|
||||
bool validInit;
|
||||
double sampleTime = 0.1;
|
||||
/*States*/
|
||||
double initialQuaternion[4]; /*after reset?QUEST*/
|
||||
double initialCovarianceMatrix[6][6]; /*after reset?QUEST*/
|
||||
double propagatedQuaternion[4]; /*Filter Quaternion for next step*/
|
||||
bool validMekf;
|
||||
uint8_t sensorsAvail;
|
||||
|
||||
|
||||
/*States*/
|
||||
double initialQuaternion[4]; /*after reset?QUEST*/
|
||||
double initialCovarianceMatrix[6][6];/*after reset?QUEST*/
|
||||
double propagatedQuaternion[4]; /*Filter Quaternion for next step*/
|
||||
bool validMekf;
|
||||
uint8_t sensorsAvail;
|
||||
|
||||
/*Outputs*/
|
||||
double quatBJ[4]; /* Output Quaternion */
|
||||
double biasRMU[3]; /*Between measured and estimated sat Rate*/
|
||||
/*Parameter INIT*/
|
||||
//double alpha, gamma, beta;
|
||||
/*Functions*/
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
/*Outputs*/
|
||||
double quatBJ[4]; /* Output Quaternion */
|
||||
double biasGYR[3]; /*Between measured and estimated sat Rate*/
|
||||
/*Parameter INIT*/
|
||||
// double alpha, gamma, beta;
|
||||
/*Functions*/
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* ACS_MULTIPLICATIVEKALMANFILTER_H_ */
|
||||
|
@ -21,31 +21,37 @@ Navigation::Navigation(AcsParameters *acsParameters_) : multiplicativeKalmanFilt
|
||||
|
||||
Navigation::~Navigation() {}
|
||||
|
||||
void Navigation::useMekf(ACS::SensorValues *sensorValues, ACS::OutputValues *outputValues,
|
||||
void Navigation::useMekf(ACS::SensorValues *sensorValues,
|
||||
acsctrl::GyrDataProcessed *gyrDataProcessed,
|
||||
acsctrl::MgmDataProcessed *mgmDataProcessed,
|
||||
acsctrl::SusDataProcessed *susDataProcessed, acsctrl::MekfData *mekfData,
|
||||
ReturnValue_t *mekfValid) {
|
||||
double quatJB[4] = {sensorValues->strSet.caliQx.value, sensorValues->strSet.caliQy.value,
|
||||
sensorValues->strSet.caliQz.value, sensorValues->strSet.caliQw.value};
|
||||
bool quatJBValid =
|
||||
(sensorValues->strSet.caliQx.isValid() && sensorValues->strSet.caliQy.isValid() &&
|
||||
sensorValues->strSet.caliQz.isValid() && sensorValues->strSet.caliQw.isValid());
|
||||
bool quatJBValid = sensorValues->strSet.caliQx.isValid() &&
|
||||
sensorValues->strSet.caliQy.isValid() &&
|
||||
sensorValues->strSet.caliQz.isValid() && sensorValues->strSet.caliQw.isValid();
|
||||
|
||||
if (kalmanInit) {
|
||||
*mekfValid = multiplicativeKalmanFilter.mekfEst(
|
||||
quatJB, &quatJBValid, outputValues->satRateEst, &outputValues->satRateEstValid,
|
||||
outputValues->magFieldEst, &outputValues->magFieldEstValid, outputValues->sunDirEst,
|
||||
&outputValues->sunDirEstValid, outputValues->sunDirModel, &outputValues->sunDirModelValid,
|
||||
outputValues->magFieldModel, &outputValues->magFieldModelValid, outputValues->quatMekfBJ,
|
||||
outputValues->satRateMekf); // VALIDS FOR QUAT AND RATE ??
|
||||
}
|
||||
else {
|
||||
multiplicativeKalmanFilter.init(outputValues->magFieldEst, &outputValues->magFieldEstValid,
|
||||
outputValues->sunDirEst, &outputValues->sunDirEstValid,
|
||||
outputValues->sunDirModel, &outputValues->sunDirModelValid,
|
||||
outputValues->magFieldModel, &outputValues->magFieldModelValid);
|
||||
quatJB, quatJBValid, gyrDataProcessed->gyrVecTot.value,
|
||||
gyrDataProcessed->gyrVecTot.isValid(), mgmDataProcessed->mgmVecTot.value,
|
||||
mgmDataProcessed->mgmVecTot.isValid(), susDataProcessed->susVecTot.value,
|
||||
susDataProcessed->susVecTot.isValid(), susDataProcessed->sunIjkModel.value,
|
||||
susDataProcessed->sunIjkModel.isValid(), mgmDataProcessed->magIgrfModel.value,
|
||||
mgmDataProcessed->magIgrfModel.isValid(),
|
||||
mekfData); // VALIDS FOR QUAT AND RATE ??
|
||||
} else {
|
||||
multiplicativeKalmanFilter.init(
|
||||
mgmDataProcessed->mgmVecTot.value, mgmDataProcessed->mgmVecTot.isValid(),
|
||||
susDataProcessed->susVecTot.value, susDataProcessed->susVecTot.isValid(),
|
||||
susDataProcessed->sunIjkModel.value, susDataProcessed->sunIjkModel.isValid(),
|
||||
mgmDataProcessed->magIgrfModel.value, mgmDataProcessed->magIgrfModel.isValid());
|
||||
kalmanInit = true;
|
||||
*mekfValid = 0;
|
||||
*mekfValid = returnvalue::OK;
|
||||
|
||||
// Maybe we need feedback from kalmanfilter to identify if there was a problem with the init
|
||||
//of kalman filter where does this class know from that kalman filter was not initialized ?
|
||||
// Maybe we need feedback from kalmanfilter to identify if there was a problem with the
|
||||
// init of kalman filter where does this class know from that kalman filter was not
|
||||
// initialized ?
|
||||
}
|
||||
}
|
||||
|
@ -8,28 +8,28 @@
|
||||
#ifndef NAVIGATION_H_
|
||||
#define NAVIGATION_H_
|
||||
|
||||
|
||||
#include "../controllerdefinitions/AcsCtrlDefinitions.h"
|
||||
#include "AcsParameters.h"
|
||||
#include "SensorProcessing.h"
|
||||
#include "MultiplicativeKalmanFilter.h"
|
||||
#include "SensorProcessing.h"
|
||||
#include "SensorValues.h"
|
||||
#include "OutputValues.h"
|
||||
|
||||
class Navigation{
|
||||
public:
|
||||
Navigation(AcsParameters *acsParameters_); //Input mode ?
|
||||
virtual ~Navigation();
|
||||
class Navigation {
|
||||
public:
|
||||
Navigation(AcsParameters *acsParameters_); // Input mode ?
|
||||
virtual ~Navigation();
|
||||
|
||||
void useMekf(ACS::SensorValues* sensorValues, ACS::OutputValues *outputValues, ReturnValue_t *mekfValid);
|
||||
void processSensorData();
|
||||
void useMekf(ACS::SensorValues *sensorValues, acsctrl::GyrDataProcessed *gyrDataProcessed,
|
||||
acsctrl::MgmDataProcessed *mgmDataProcessed,
|
||||
acsctrl::SusDataProcessed *susDataProcessed, acsctrl::MekfData *mekfData,
|
||||
ReturnValue_t *mekfValid);
|
||||
void processSensorData();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
MultiplicativeKalmanFilter multiplicativeKalmanFilter;
|
||||
AcsParameters acsParameters;
|
||||
bool kalmanInit = false;
|
||||
protected:
|
||||
private:
|
||||
MultiplicativeKalmanFilter multiplicativeKalmanFilter;
|
||||
AcsParameters acsParameters;
|
||||
bool kalmanInit = false;
|
||||
};
|
||||
|
||||
#endif /* ACS_NAVIGATION_H_ */
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* OutputValues.cpp
|
||||
*
|
||||
* Created on: 30 Mar 2022
|
||||
* Author: rooob
|
||||
*/
|
||||
#include "OutputValues.h"
|
||||
|
||||
namespace ACS {
|
||||
|
||||
OutputValues::OutputValues(){
|
||||
|
||||
}
|
||||
|
||||
OutputValues::~OutputValues(){
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* OutputValues.h
|
||||
*
|
||||
* Created on: 30 Mar 2022
|
||||
* Author: rooob
|
||||
*/
|
||||
|
||||
#ifndef OUTPUTVALUES_H_
|
||||
#define OUTPUTVALUES_H_
|
||||
|
||||
|
||||
namespace ACS {
|
||||
|
||||
class OutputValues {
|
||||
|
||||
public:
|
||||
|
||||
OutputValues();
|
||||
virtual ~OutputValues();
|
||||
|
||||
double magFieldEst[3]; // sensor fusion (G)
|
||||
bool magFieldEstValid;
|
||||
double magFieldModel[3]; //igrf (IJK)
|
||||
bool magFieldModelValid;
|
||||
double magneticFieldVectorDerivative[3];
|
||||
bool magneticFieldVectorDerivativeValid;
|
||||
|
||||
bool mgmUpdated;
|
||||
|
||||
double sunDirEst[3]; // sensor fusion (G)
|
||||
bool sunDirEstValid;
|
||||
double sunDirModel[3]; //sun model (IJK)
|
||||
bool sunDirModelValid;
|
||||
|
||||
double quatMekfBJ[4]; //mekf
|
||||
bool quatMekfBJValid;
|
||||
|
||||
double satRateEst[3];
|
||||
bool satRateEstValid;
|
||||
double satRateMekf[3]; // after mekf with correction of bias
|
||||
bool satRateMekfValid;
|
||||
double sunVectorDerivative[3];
|
||||
bool sunVectorDerivativeValid;
|
||||
|
||||
double gcLatitude; // geocentric latitude, radian
|
||||
double gdLongitude; // Radian longitude
|
||||
double gpsVelocity[3]; //earth fixed frame
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /*OUTPUTVALUES_H_*/
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "SensorProcessing.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
@ -20,27 +21,35 @@
|
||||
|
||||
using namespace Math;
|
||||
|
||||
SensorProcessing::SensorProcessing(AcsParameters *acsParameters_) : savedMagFieldEst{0, 0, 0} {
|
||||
validMagField = false;
|
||||
validGcLatitude = false;
|
||||
}
|
||||
SensorProcessing::SensorProcessing(AcsParameters *acsParameters_)
|
||||
: savedMgmVecTot{0, 0, 0}, validMagField(false), validGcLatitude(false) {}
|
||||
|
||||
SensorProcessing::~SensorProcessing() {}
|
||||
|
||||
bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const float *mgm1Value,
|
||||
void SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const float *mgm1Value,
|
||||
bool mgm1valid, const float *mgm2Value, bool mgm2valid,
|
||||
const float *mgm3Value, bool mgm3valid, const float *mgm4Value,
|
||||
bool mgm4valid, timeval timeOfMgmMeasurement,
|
||||
const AcsParameters::MgmHandlingParameters *mgmParameters,
|
||||
const double gpsLatitude, const double gpsLongitude,
|
||||
const double gpsAltitude, bool gpsValid, double *magFieldEst,
|
||||
bool *outputValid, double *magFieldModel,
|
||||
bool *magFieldModelValid, double *magneticFieldVectorDerivative,
|
||||
bool *magneticFieldVectorDerivativeValid) {
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed,
|
||||
const double gpsAltitude, bool gpsValid,
|
||||
acsctrl::MgmDataProcessed *mgmDataProcessed) {
|
||||
if (!mgm0valid && !mgm1valid && !mgm2valid && !mgm3valid && !mgm4valid) {
|
||||
*outputValid = false;
|
||||
validMagField = false;
|
||||
return false;
|
||||
{
|
||||
PoolReadGuard pg(mgmDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmDataProcessed->mgm0vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgm1vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgm2vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgm3vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgm4vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgmVecTot.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->mgmVecTotDerivative.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(mgmDataProcessed->magIgrfModel.value, zeroVector, 3 * sizeof(double));
|
||||
mgmDataProcessed->setValidity(false, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
float mgm0ValueNoBias[3] = {0, 0, 0}, mgm1ValueNoBias[3] = {0, 0, 0},
|
||||
mgm2ValueNoBias[3] = {0, 0, 0}, mgm3ValueNoBias[3] = {0, 0, 0},
|
||||
@ -49,9 +58,8 @@ bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const
|
||||
mgm3ValueCalib[3] = {0, 0, 0}, mgm4ValueCalib[3] = {0, 0, 0};
|
||||
float mgm0ValueBody[3] = {0, 0, 0}, mgm1ValueBody[3] = {0, 0, 0}, mgm2ValueBody[3] = {0, 0, 0},
|
||||
mgm3ValueBody[3] = {0, 0, 0}, mgm4ValueBody[3] = {0, 0, 0};
|
||||
float sensorFusionNumerator[3] = {0, 0, 0}, sensorFusionDenominator[3] = {0, 0, 0};
|
||||
|
||||
bool validUnit[5] = {false, false, false, false, false};
|
||||
uint8_t validCount = 0;
|
||||
if (mgm0valid) {
|
||||
VectorOperations<float>::subtract(mgm0Value, mgmParameters->mgm0hardIronOffset, mgm0ValueNoBias,
|
||||
3);
|
||||
@ -59,8 +67,10 @@ bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const
|
||||
mgm0ValueCalib, 3, 3, 1);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm0orientationMatrix[0], mgm0ValueCalib,
|
||||
mgm0ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[0] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += mgm0ValueBody[i] / mgmParameters->mgm02variance[i];
|
||||
sensorFusionDenominator[i] += 1 / mgmParameters->mgm02variance[i];
|
||||
}
|
||||
}
|
||||
if (mgm1valid) {
|
||||
VectorOperations<float>::subtract(mgm1Value, mgmParameters->mgm1hardIronOffset, mgm1ValueNoBias,
|
||||
@ -69,8 +79,10 @@ bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const
|
||||
mgm1ValueCalib, 3, 3, 1);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm1orientationMatrix[0], mgm1ValueCalib,
|
||||
mgm1ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[1] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += mgm1ValueBody[i] / mgmParameters->mgm13variance[i];
|
||||
sensorFusionDenominator[i] += 1 / mgmParameters->mgm13variance[i];
|
||||
}
|
||||
}
|
||||
if (mgm2valid) {
|
||||
VectorOperations<float>::subtract(mgm2Value, mgmParameters->mgm2hardIronOffset, mgm2ValueNoBias,
|
||||
@ -79,8 +91,10 @@ bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const
|
||||
mgm2ValueCalib, 3, 3, 1);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm2orientationMatrix[0], mgm2ValueCalib,
|
||||
mgm2ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[2] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += mgm2ValueBody[i] / mgmParameters->mgm02variance[i];
|
||||
sensorFusionDenominator[i] += 1 / mgmParameters->mgm02variance[i];
|
||||
}
|
||||
}
|
||||
if (mgm3valid) {
|
||||
VectorOperations<float>::subtract(mgm3Value, mgmParameters->mgm3hardIronOffset, mgm3ValueNoBias,
|
||||
@ -89,81 +103,79 @@ bool SensorProcessing::processMgm(const float *mgm0Value, bool mgm0valid, const
|
||||
mgm3ValueCalib, 3, 3, 1);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm3orientationMatrix[0], mgm3ValueCalib,
|
||||
mgm3ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[3] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += mgm3ValueBody[i] / mgmParameters->mgm13variance[i];
|
||||
sensorFusionDenominator[i] += 1 / mgmParameters->mgm13variance[i];
|
||||
}
|
||||
}
|
||||
if (mgm4valid) {
|
||||
VectorOperations<float>::subtract(mgm4Value, mgmParameters->mgm4hardIronOffset, mgm4ValueNoBias,
|
||||
3);
|
||||
float mgm4ValueNT[3];
|
||||
VectorOperations<float>::mulScalar(mgm4Value, 1e3, mgm4ValueNT, 3); // uT to nT
|
||||
VectorOperations<float>::subtract(mgm4ValueNT, mgmParameters->mgm4hardIronOffset,
|
||||
mgm4ValueNoBias, 3);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm4softIronInverse[0], mgm4ValueNoBias,
|
||||
mgm4ValueCalib, 3, 3, 1);
|
||||
MatrixOperations<float>::multiply(mgmParameters->mgm4orientationMatrix[0], mgm4ValueCalib,
|
||||
mgm4ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[4] = true;
|
||||
}
|
||||
|
||||
/* -------- MagFieldEst: Middle Value ------- */
|
||||
float mgmValues[3][5] = {
|
||||
{mgm0ValueBody[0], mgm1ValueBody[0], mgm2ValueBody[0], mgm3ValueBody[0], mgm4ValueBody[0]},
|
||||
{mgm0ValueBody[1], mgm1ValueBody[1], mgm2ValueBody[1], mgm3ValueBody[1], mgm4ValueBody[1]},
|
||||
{mgm0ValueBody[2], mgm1ValueBody[2], mgm2ValueBody[2], mgm3ValueBody[2], mgm4ValueBody[2]}};
|
||||
double mgmValidValues[3][validCount];
|
||||
uint8_t j = 0;
|
||||
for (uint8_t i = 0; i < validCount; i++) {
|
||||
if (validUnit[i]) {
|
||||
mgmValidValues[0][j] = mgmValues[0][i];
|
||||
mgmValidValues[1][j] = mgmValues[1][i];
|
||||
mgmValidValues[2][j] = mgmValues[2][i];
|
||||
j += 1;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += mgm4ValueBody[i] / mgmParameters->mgm4variance[i];
|
||||
sensorFusionDenominator[i] += 1 / mgmParameters->mgm4variance[i];
|
||||
}
|
||||
}
|
||||
// Selection Sort
|
||||
double mgmValidValuesSort[3][validCount];
|
||||
MathOperations<double>::selectionSort(*mgmValidValues, *mgmValidValuesSort, 3, validCount);
|
||||
|
||||
uint8_t n = ceil(validCount / 2);
|
||||
magFieldEst[0] = mgmValidValuesSort[0][n];
|
||||
magFieldEst[1] = mgmValidValuesSort[1][n];
|
||||
magFieldEst[2] = mgmValidValuesSort[2][n];
|
||||
validMagField = true;
|
||||
|
||||
//-----------------------Mag Rate Computation ---------------------------------------------------
|
||||
double timeDiff = timevalOperations::toDouble(timeOfMgmMeasurement - timeOfSavedMagFieldEst);
|
||||
double mgmVecTot[3] = {0.0, 0.0, 0.0};
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
magneticFieldVectorDerivative[i] = (magFieldEst[i] - savedMagFieldEst[i]) / timeDiff;
|
||||
savedMagFieldEst[i] = magFieldEst[i];
|
||||
mgmVecTot[i] = sensorFusionNumerator[i] / sensorFusionDenominator[i];
|
||||
}
|
||||
|
||||
*magneticFieldVectorDerivativeValid = true;
|
||||
if (timeOfSavedMagFieldEst.tv_sec == 0) {
|
||||
magneticFieldVectorDerivative[0] = 0;
|
||||
magneticFieldVectorDerivative[1] = 0;
|
||||
magneticFieldVectorDerivative[2] = 0;
|
||||
*magneticFieldVectorDerivativeValid = false;
|
||||
//-----------------------Mgm Rate Computation ---------------------------------------------------
|
||||
double mgmVecTotDerivative[3] = {0.0, 0.0, 0.0};
|
||||
bool mgmVecTotDerivativeValid = false;
|
||||
double timeDiff = timevalOperations::toDouble(timeOfMgmMeasurement - timeOfSavedMagFieldEst);
|
||||
if (timeOfSavedMagFieldEst.tv_sec != 0) {
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
mgmVecTotDerivative[i] = (mgmVecTot[i] - savedMgmVecTot[i]) / timeDiff;
|
||||
savedMgmVecTot[i] = mgmVecTot[i];
|
||||
}
|
||||
}
|
||||
|
||||
timeOfSavedMagFieldEst = timeOfMgmMeasurement;
|
||||
|
||||
*outputValid = true;
|
||||
|
||||
// ---------------- IGRF- 13 Implementation here ------------------------------------------------
|
||||
if (!gpsValid) {
|
||||
*magFieldModelValid = false;
|
||||
} else {
|
||||
double magIgrfModel[3] = {0.0, 0.0, 0.0};
|
||||
if (gpsValid) {
|
||||
// Should be existing class object which will be called and modified here.
|
||||
Igrf13Model igrf13;
|
||||
// So the line above should not be done here. Update: Can be done here as long updated coffs
|
||||
// stored in acsParameters ?
|
||||
igrf13.schmidtNormalization();
|
||||
igrf13.updateCoeffGH(timeOfMgmMeasurement);
|
||||
// maybe put a condition here, to only update after a full day, this
|
||||
// class function has around 700 steps to perform
|
||||
igrf13.magFieldComp(gpsLongitude, gpsLatitude, gpsAltitude, timeOfMgmMeasurement,
|
||||
magFieldModel);
|
||||
*magFieldModelValid = false;
|
||||
igrf13.magFieldComp(gpsDataProcessed->gdLongitude.value, gpsDataProcessed->gcLatitude.value,
|
||||
gpsAltitude, timeOfMgmMeasurement, magIgrfModel);
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(mgmDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(mgmDataProcessed->mgm0vec.value, mgm0ValueBody, 3 * sizeof(float));
|
||||
mgmDataProcessed->mgm0vec.setValid(mgm0valid);
|
||||
std::memcpy(mgmDataProcessed->mgm1vec.value, mgm1ValueBody, 3 * sizeof(float));
|
||||
mgmDataProcessed->mgm1vec.setValid(mgm1valid);
|
||||
std::memcpy(mgmDataProcessed->mgm2vec.value, mgm2ValueBody, 3 * sizeof(float));
|
||||
mgmDataProcessed->mgm2vec.setValid(mgm2valid);
|
||||
std::memcpy(mgmDataProcessed->mgm3vec.value, mgm3ValueBody, 3 * sizeof(float));
|
||||
mgmDataProcessed->mgm3vec.setValid(mgm3valid);
|
||||
std::memcpy(mgmDataProcessed->mgm4vec.value, mgm4ValueBody, 3 * sizeof(float));
|
||||
mgmDataProcessed->mgm4vec.setValid(mgm4valid);
|
||||
std::memcpy(mgmDataProcessed->mgmVecTot.value, mgmVecTot, 3 * sizeof(double));
|
||||
mgmDataProcessed->mgmVecTot.setValid(true);
|
||||
std::memcpy(mgmDataProcessed->mgmVecTotDerivative.value, mgmVecTotDerivative,
|
||||
3 * sizeof(double));
|
||||
mgmDataProcessed->mgmVecTotDerivative.setValid(mgmVecTotDerivativeValid);
|
||||
std::memcpy(mgmDataProcessed->magIgrfModel.value, magIgrfModel, 3 * sizeof(double));
|
||||
mgmDataProcessed->magIgrfModel.setValid(gpsValid);
|
||||
mgmDataProcessed->setValidity(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SensorProcessing::processSus(
|
||||
@ -174,9 +186,8 @@ void SensorProcessing::processSus(
|
||||
const uint16_t *sus8Value, bool sus8valid, const uint16_t *sus9Value, bool sus9valid,
|
||||
const uint16_t *sus10Value, bool sus10valid, const uint16_t *sus11Value, bool sus11valid,
|
||||
timeval timeOfSusMeasurement, const AcsParameters::SusHandlingParameters *susParameters,
|
||||
const AcsParameters::SunModelParameters *sunModelParameters, double *sunDirEst,
|
||||
bool *sunDirEstValid, double *sunVectorInertial, bool *sunVectorInertialValid,
|
||||
double *sunVectorDerivative, bool *sunVectorDerivativeValid) {
|
||||
const AcsParameters::SunModelParameters *sunModelParameters,
|
||||
acsctrl::SusDataProcessed *susDataProcessed) {
|
||||
if (sus0valid) {
|
||||
sus0valid = susConverter.checkSunSensorData(sus0Value);
|
||||
}
|
||||
@ -216,142 +227,176 @@ void SensorProcessing::processSus(
|
||||
|
||||
if (!sus0valid && !sus1valid && !sus2valid && !sus3valid && !sus4valid && !sus5valid &&
|
||||
!sus6valid && !sus7valid && !sus8valid && !sus9valid && !sus10valid && !sus11valid) {
|
||||
*sunDirEstValid = false;
|
||||
return;
|
||||
} else {
|
||||
// WARNING: NOT TRANSFORMED IN BODY FRAME YET
|
||||
// Transformation into Geomtry Frame
|
||||
float sus0VecBody[3] = {0, 0, 0}, sus1VecBody[3] = {0, 0, 0}, sus2VecBody[3] = {0, 0, 0},
|
||||
sus3VecBody[3] = {0, 0, 0}, sus4VecBody[3] = {0, 0, 0}, sus5VecBody[3] = {0, 0, 0},
|
||||
sus6VecBody[3] = {0, 0, 0}, sus7VecBody[3] = {0, 0, 0}, sus8VecBody[3] = {0, 0, 0},
|
||||
sus9VecBody[3] = {0, 0, 0}, sus10VecBody[3] = {0, 0, 0}, sus11VecBody[3] = {0, 0, 0};
|
||||
|
||||
if (sus0valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus0orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus0Value, susParameters->sus0coeffAlpha,
|
||||
susParameters->sus0coeffBeta),
|
||||
sus0VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus1valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus1orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus1Value, susParameters->sus1coeffAlpha,
|
||||
susParameters->sus1coeffBeta),
|
||||
sus1VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus2valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus2orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus2Value, susParameters->sus2coeffAlpha,
|
||||
susParameters->sus2coeffBeta),
|
||||
sus2VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus3valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus3orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus3Value, susParameters->sus3coeffAlpha,
|
||||
susParameters->sus3coeffBeta),
|
||||
sus3VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus4valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus4orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus4Value, susParameters->sus4coeffAlpha,
|
||||
susParameters->sus4coeffBeta),
|
||||
sus4VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus5valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus5orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus5Value, susParameters->sus5coeffAlpha,
|
||||
susParameters->sus5coeffBeta),
|
||||
sus5VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus6valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus6orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus6Value, susParameters->sus6coeffAlpha,
|
||||
susParameters->sus6coeffBeta),
|
||||
sus6VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus7valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus7orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus7Value, susParameters->sus7coeffAlpha,
|
||||
susParameters->sus7coeffBeta),
|
||||
sus7VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus8valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus8orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus8Value, susParameters->sus8coeffAlpha,
|
||||
susParameters->sus8coeffBeta),
|
||||
sus8VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus9valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus9orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus9Value, susParameters->sus9coeffAlpha,
|
||||
susParameters->sus9coeffBeta),
|
||||
sus9VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus10valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus10orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus10Value, susParameters->sus10coeffAlpha,
|
||||
susParameters->sus10coeffBeta),
|
||||
sus10VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus11valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus11orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus11Value, susParameters->sus11coeffAlpha,
|
||||
susParameters->sus11coeffBeta),
|
||||
sus11VecBody, 3, 3, 1);
|
||||
}
|
||||
|
||||
/* ------ Mean Value: susDirEst ------ */
|
||||
bool validIds[12] = {sus0valid, sus1valid, sus2valid, sus3valid, sus4valid, sus5valid,
|
||||
sus6valid, sus7valid, sus8valid, sus9valid, sus10valid, sus11valid};
|
||||
float susVecBody[3][12] = {{sus0VecBody[0], sus1VecBody[0], sus2VecBody[0], sus3VecBody[0],
|
||||
sus4VecBody[0], sus5VecBody[0], sus6VecBody[0], sus7VecBody[0],
|
||||
sus8VecBody[0], sus9VecBody[0], sus10VecBody[0], sus11VecBody[0]},
|
||||
{sus0VecBody[1], sus1VecBody[1], sus2VecBody[1], sus3VecBody[1],
|
||||
sus4VecBody[1], sus5VecBody[1], sus6VecBody[1], sus7VecBody[1],
|
||||
sus8VecBody[1], sus9VecBody[1], sus10VecBody[1], sus11VecBody[1]},
|
||||
{sus0VecBody[2], sus1VecBody[2], sus2VecBody[2], sus3VecBody[2],
|
||||
sus4VecBody[2], sus5VecBody[2], sus6VecBody[2], sus7VecBody[2],
|
||||
sus8VecBody[2], sus9VecBody[2], sus10VecBody[2], sus11VecBody[2]}};
|
||||
|
||||
double susMeanValue[3] = {0, 0, 0};
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
if (validIds[i]) {
|
||||
susMeanValue[0] += susVecBody[0][i];
|
||||
susMeanValue[1] += susVecBody[1][i];
|
||||
susMeanValue[2] += susVecBody[2][i];
|
||||
{
|
||||
PoolReadGuard pg(susDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susDataProcessed->sus0vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus1vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus2vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus3vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus4vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus5vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus6vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus7vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus8vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus9vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus10vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sus11vec.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->susVecTot.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->susVecTotDerivative.value, zeroVector, 3 * sizeof(float));
|
||||
std::memcpy(susDataProcessed->sunIjkModel.value, zeroVector, 3 * sizeof(double));
|
||||
susDataProcessed->setValidity(false, true);
|
||||
}
|
||||
}
|
||||
VectorOperations<double>::normalize(susMeanValue, sunDirEst, 3);
|
||||
*sunDirEstValid = true;
|
||||
return;
|
||||
}
|
||||
// WARNING: NOT TRANSFORMED IN BODY FRAME YET
|
||||
// Transformation into Geomtry Frame
|
||||
float sus0VecBody[3] = {0, 0, 0}, sus1VecBody[3] = {0, 0, 0}, sus2VecBody[3] = {0, 0, 0},
|
||||
sus3VecBody[3] = {0, 0, 0}, sus4VecBody[3] = {0, 0, 0}, sus5VecBody[3] = {0, 0, 0},
|
||||
sus6VecBody[3] = {0, 0, 0}, sus7VecBody[3] = {0, 0, 0}, sus8VecBody[3] = {0, 0, 0},
|
||||
sus9VecBody[3] = {0, 0, 0}, sus10VecBody[3] = {0, 0, 0}, sus11VecBody[3] = {0, 0, 0};
|
||||
|
||||
if (sus0valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus0orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus0Value, susParameters->sus0coeffAlpha,
|
||||
susParameters->sus0coeffBeta),
|
||||
sus0VecBody, 3, 3, 1);
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(susDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susDataProcessed->sus0vec.value, sus0VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus0vec.setValid(sus0valid);
|
||||
if (!sus0valid) {
|
||||
std::memcpy(susDataProcessed->sus0vec.value, zeroVector, 3 * sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sus1valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus1orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus1Value, susParameters->sus1coeffAlpha,
|
||||
susParameters->sus1coeffBeta),
|
||||
sus1VecBody, 3, 3, 1);
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(susDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susDataProcessed->sus1vec.value, sus1VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus1vec.setValid(sus1valid);
|
||||
if (!sus1valid) {
|
||||
std::memcpy(susDataProcessed->sus1vec.value, zeroVector, 3 * sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sus2valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus2orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus2Value, susParameters->sus2coeffAlpha,
|
||||
susParameters->sus2coeffBeta),
|
||||
sus2VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus3valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus3orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus3Value, susParameters->sus3coeffAlpha,
|
||||
susParameters->sus3coeffBeta),
|
||||
sus3VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus4valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus4orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus4Value, susParameters->sus4coeffAlpha,
|
||||
susParameters->sus4coeffBeta),
|
||||
sus4VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus5valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus5orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus5Value, susParameters->sus5coeffAlpha,
|
||||
susParameters->sus5coeffBeta),
|
||||
sus5VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus6valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus6orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus6Value, susParameters->sus6coeffAlpha,
|
||||
susParameters->sus6coeffBeta),
|
||||
sus6VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus7valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus7orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus7Value, susParameters->sus7coeffAlpha,
|
||||
susParameters->sus7coeffBeta),
|
||||
sus7VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus8valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus8orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus8Value, susParameters->sus8coeffAlpha,
|
||||
susParameters->sus8coeffBeta),
|
||||
sus8VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus9valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus9orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus9Value, susParameters->sus9coeffAlpha,
|
||||
susParameters->sus9coeffBeta),
|
||||
sus9VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus10valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus10orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus10Value, susParameters->sus10coeffAlpha,
|
||||
susParameters->sus10coeffBeta),
|
||||
sus10VecBody, 3, 3, 1);
|
||||
}
|
||||
if (sus11valid) {
|
||||
MatrixOperations<float>::multiply(
|
||||
susParameters->sus11orientationMatrix[0],
|
||||
susConverter.getSunVectorSensorFrame(sus11Value, susParameters->sus11coeffAlpha,
|
||||
susParameters->sus11coeffBeta),
|
||||
sus11VecBody, 3, 3, 1);
|
||||
}
|
||||
|
||||
/* ------ Mean Value: susDirEst ------ */
|
||||
bool validIds[12] = {sus0valid, sus1valid, sus2valid, sus3valid, sus4valid, sus5valid,
|
||||
sus6valid, sus7valid, sus8valid, sus9valid, sus10valid, sus11valid};
|
||||
float susVecBody[3][12] = {{sus0VecBody[0], sus1VecBody[0], sus2VecBody[0], sus3VecBody[0],
|
||||
sus4VecBody[0], sus5VecBody[0], sus6VecBody[0], sus7VecBody[0],
|
||||
sus8VecBody[0], sus9VecBody[0], sus10VecBody[0], sus11VecBody[0]},
|
||||
{sus0VecBody[1], sus1VecBody[1], sus2VecBody[1], sus3VecBody[1],
|
||||
sus4VecBody[1], sus5VecBody[1], sus6VecBody[1], sus7VecBody[1],
|
||||
sus8VecBody[1], sus9VecBody[1], sus10VecBody[1], sus11VecBody[1]},
|
||||
{sus0VecBody[2], sus1VecBody[2], sus2VecBody[2], sus3VecBody[2],
|
||||
sus4VecBody[2], sus5VecBody[2], sus6VecBody[2], sus7VecBody[2],
|
||||
sus8VecBody[2], sus9VecBody[2], sus10VecBody[2], sus11VecBody[2]}};
|
||||
|
||||
double susMeanValue[3] = {0, 0, 0};
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
if (validIds[i]) {
|
||||
susMeanValue[0] += susVecBody[0][i];
|
||||
susMeanValue[1] += susVecBody[1][i];
|
||||
susMeanValue[2] += susVecBody[2][i];
|
||||
}
|
||||
}
|
||||
double susVecTot[3] = {0.0, 0.0, 0.0};
|
||||
VectorOperations<double>::normalize(susMeanValue, susVecTot, 3);
|
||||
|
||||
/* -------- Sun Derivatiative --------------------- */
|
||||
|
||||
double susVecTotDerivative[3] = {0.0, 0.0, 0.0};
|
||||
bool susVecTotDerivativeValid = false;
|
||||
double timeDiff = timevalOperations::toDouble(timeOfSusMeasurement - timeOfSavedSusDirEst);
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sunVectorDerivative[i] = (sunDirEst[i] - savedSunVector[i]) / timeDiff;
|
||||
savedSunVector[i] = sunDirEst[i];
|
||||
if (timeOfSavedSusDirEst.tv_sec != 0) {
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
susVecTotDerivative[i] = (susVecTot[i] - savedSusVecTot[i]) / timeDiff;
|
||||
savedSusVecTot[i] = susVecTot[i];
|
||||
}
|
||||
}
|
||||
|
||||
*sunVectorDerivativeValid = true;
|
||||
if (timeOfSavedSusDirEst.tv_sec == 0) {
|
||||
sunVectorDerivative[0] = 0;
|
||||
sunVectorDerivative[1] = 0;
|
||||
sunVectorDerivative[2] = 0;
|
||||
*sunVectorDerivativeValid = false;
|
||||
}
|
||||
|
||||
timeOfSavedSusDirEst = timeOfSusMeasurement;
|
||||
|
||||
/* -------- Sun Model Direction (IJK frame) ------- */
|
||||
@ -359,10 +404,11 @@ void SensorProcessing::processSus(
|
||||
double JD2000 = MathOperations<double>::convertUnixToJD2000(timeOfSusMeasurement);
|
||||
|
||||
// Julean Centuries
|
||||
double JC2000 = JD2000 / 36525;
|
||||
double sunIjkModel[3] = {0.0, 0.0, 0.0};
|
||||
double JC2000 = JD2000 / 36525.;
|
||||
|
||||
double meanLongitude =
|
||||
(sunModelParameters->omega_0 + (sunModelParameters->domega) * JC2000) * PI / 180;
|
||||
sunModelParameters->omega_0 + (sunModelParameters->domega * JC2000) * PI / 180.;
|
||||
double meanAnomaly = (sunModelParameters->m_0 + sunModelParameters->dm * JC2000) * PI / 180.;
|
||||
|
||||
double eclipticLongitude = meanLongitude + sunModelParameters->p1 * sin(meanAnomaly) +
|
||||
@ -370,11 +416,46 @@ void SensorProcessing::processSus(
|
||||
|
||||
double epsilon = sunModelParameters->e - (sunModelParameters->e1) * JC2000;
|
||||
|
||||
sunVectorInertial[0] = cos(eclipticLongitude);
|
||||
sunVectorInertial[1] = sin(eclipticLongitude) * cos(epsilon);
|
||||
sunVectorInertial[2] = sin(eclipticLongitude) * sin(epsilon);
|
||||
|
||||
*sunVectorInertialValid = true;
|
||||
sunIjkModel[0] = cos(eclipticLongitude);
|
||||
sunIjkModel[1] = sin(eclipticLongitude) * cos(epsilon);
|
||||
sunIjkModel[2] = sin(eclipticLongitude) * sin(epsilon);
|
||||
{
|
||||
PoolReadGuard pg(susDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(susDataProcessed->sus0vec.value, sus0VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus0vec.setValid(sus0valid);
|
||||
std::memcpy(susDataProcessed->sus1vec.value, sus1VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus1vec.setValid(sus1valid);
|
||||
std::memcpy(susDataProcessed->sus2vec.value, sus2VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus2vec.setValid(sus2valid);
|
||||
std::memcpy(susDataProcessed->sus3vec.value, sus3VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus3vec.setValid(sus3valid);
|
||||
std::memcpy(susDataProcessed->sus4vec.value, sus4VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus4vec.setValid(sus4valid);
|
||||
std::memcpy(susDataProcessed->sus5vec.value, sus5VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus5vec.setValid(sus5valid);
|
||||
std::memcpy(susDataProcessed->sus6vec.value, sus6VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus6vec.setValid(sus6valid);
|
||||
std::memcpy(susDataProcessed->sus7vec.value, sus7VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus7vec.setValid(sus7valid);
|
||||
std::memcpy(susDataProcessed->sus8vec.value, sus8VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus8vec.setValid(sus8valid);
|
||||
std::memcpy(susDataProcessed->sus9vec.value, sus9VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus9vec.setValid(sus9valid);
|
||||
std::memcpy(susDataProcessed->sus10vec.value, sus10VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus10vec.setValid(sus10valid);
|
||||
std::memcpy(susDataProcessed->sus11vec.value, sus11VecBody, 3 * sizeof(float));
|
||||
susDataProcessed->sus11vec.setValid(sus11valid);
|
||||
std::memcpy(susDataProcessed->susVecTot.value, susVecTot, 3 * sizeof(double));
|
||||
susDataProcessed->susVecTot.setValid(true);
|
||||
std::memcpy(susDataProcessed->susVecTotDerivative.value, susVecTotDerivative,
|
||||
3 * sizeof(double));
|
||||
susDataProcessed->susVecTotDerivative.setValid(susVecTotDerivativeValid);
|
||||
std::memcpy(susDataProcessed->sunIjkModel.value, sunIjkModel, 3 * sizeof(double));
|
||||
susDataProcessed->sunIjkModel.setValid(true);
|
||||
susDataProcessed->setValidity(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SensorProcessing::processGyr(
|
||||
@ -385,87 +466,110 @@ void SensorProcessing::processGyr(
|
||||
const double gyr2axZvalue, bool gyr2axZvalid, const double gyr3axXvalue, bool gyr3axXvalid,
|
||||
const double gyr3axYvalue, bool gyr3axYvalid, const double gyr3axZvalue, bool gyr3axZvalid,
|
||||
timeval timeOfGyrMeasurement, const AcsParameters::GyrHandlingParameters *gyrParameters,
|
||||
double *satRatEst, bool *satRateEstValid) {
|
||||
if (!gyr0axXvalid && !gyr0axYvalid && !gyr0axZvalid && !gyr1axXvalid && !gyr1axYvalid &&
|
||||
!gyr1axZvalid && !gyr2axXvalid && !gyr2axYvalid && !gyr2axZvalid && !gyr3axXvalid &&
|
||||
!gyr3axYvalid && !gyr3axZvalid) {
|
||||
*satRateEstValid = false;
|
||||
acsctrl::GyrDataProcessed *gyrDataProcessed) {
|
||||
bool gyr0valid = (gyr0axXvalid && gyr0axYvalid && gyr0axZvalid);
|
||||
bool gyr1valid = (gyr1axXvalid && gyr1axYvalid && gyr1axZvalid);
|
||||
bool gyr2valid = (gyr2axXvalid && gyr2axYvalid && gyr2axZvalid);
|
||||
bool gyr3valid = (gyr3axXvalid && gyr3axYvalid && gyr3axZvalid);
|
||||
if (!gyr0valid && !gyr1valid && !gyr2valid && !gyr3valid) {
|
||||
{
|
||||
PoolReadGuard pg(gyrDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(gyrDataProcessed->gyr0vec.value, zeroVector, 3 * sizeof(double));
|
||||
std::memcpy(gyrDataProcessed->gyr1vec.value, zeroVector, 3 * sizeof(double));
|
||||
std::memcpy(gyrDataProcessed->gyr2vec.value, zeroVector, 3 * sizeof(double));
|
||||
std::memcpy(gyrDataProcessed->gyr3vec.value, zeroVector, 3 * sizeof(double));
|
||||
std::memcpy(gyrDataProcessed->gyrVecTot.value, zeroVector, 3 * sizeof(double));
|
||||
gyrDataProcessed->setValidity(false, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Transforming Values to the Body Frame (actually it is the geometry frame atm)
|
||||
double gyr0ValueBody[3] = {0, 0, 0}, gyr1ValueBody[3] = {0, 0, 0}, gyr2ValueBody[3] = {0, 0, 0},
|
||||
gyr3ValueBody[3] = {0, 0, 0};
|
||||
float sensorFusionNumerator[3] = {0, 0, 0}, sensorFusionDenominator[3] = {0, 0, 0};
|
||||
|
||||
bool validUnit[4] = {false, false, false, false};
|
||||
uint8_t validCount = 0;
|
||||
if (gyr0axXvalid && gyr0axYvalid && gyr0axZvalid) {
|
||||
if (gyr0valid) {
|
||||
const double gyr0Value[3] = {gyr0axXvalue, gyr0axYvalue, gyr0axZvalue};
|
||||
MatrixOperations<double>::multiply(gyrParameters->gyr0orientationMatrix[0], gyr0Value,
|
||||
gyr0ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[0] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += gyr0ValueBody[i] / gyrParameters->gyr02variance[i];
|
||||
sensorFusionDenominator[i] += 1 / gyrParameters->gyr02variance[i];
|
||||
}
|
||||
}
|
||||
if (gyr1axXvalid && gyr1axYvalid && gyr1axZvalid) {
|
||||
if (gyr1valid) {
|
||||
const double gyr1Value[3] = {gyr1axXvalue, gyr1axYvalue, gyr1axZvalue};
|
||||
MatrixOperations<double>::multiply(gyrParameters->gyr1orientationMatrix[0], gyr1Value,
|
||||
gyr1ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[1] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += gyr1ValueBody[i] / gyrParameters->gyr13variance[i];
|
||||
sensorFusionDenominator[i] += 1 / gyrParameters->gyr13variance[i];
|
||||
}
|
||||
}
|
||||
if (gyr2axXvalid && gyr2axYvalid && gyr2axZvalid) {
|
||||
if (gyr2valid) {
|
||||
const double gyr2Value[3] = {gyr2axXvalue, gyr2axYvalue, gyr2axZvalue};
|
||||
MatrixOperations<double>::multiply(gyrParameters->gyr2orientationMatrix[0], gyr2Value,
|
||||
gyr2ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[2] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += gyr2ValueBody[i] / gyrParameters->gyr02variance[i];
|
||||
sensorFusionDenominator[i] += 1 / gyrParameters->gyr02variance[i];
|
||||
}
|
||||
}
|
||||
if (gyr3axXvalid && gyr3axYvalid && gyr3axZvalid) {
|
||||
if (gyr3valid) {
|
||||
const double gyr3Value[3] = {gyr3axXvalue, gyr3axYvalue, gyr3axZvalue};
|
||||
MatrixOperations<double>::multiply(gyrParameters->gyr3orientationMatrix[0], gyr3Value,
|
||||
gyr3ValueBody, 3, 3, 1);
|
||||
validCount += 1;
|
||||
validUnit[3] = true;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
sensorFusionNumerator[i] += gyr3ValueBody[i] / gyrParameters->gyr13variance[i];
|
||||
sensorFusionDenominator[i] += 1 / gyrParameters->gyr13variance[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- SatRateEst: Middle Value ------- */
|
||||
double gyrValues[3][4] = {
|
||||
{gyr0ValueBody[0], gyr1ValueBody[0], gyr2ValueBody[0], gyr3ValueBody[0]},
|
||||
{gyr0ValueBody[1], gyr1ValueBody[1], gyr2ValueBody[1], gyr3ValueBody[1]},
|
||||
{gyr0ValueBody[2], gyr1ValueBody[2], gyr2ValueBody[2], gyr3ValueBody[2]}};
|
||||
double gyrValidValues[3][validCount];
|
||||
uint8_t j = 0;
|
||||
for (uint8_t i = 0; i < validCount; i++) {
|
||||
if (validUnit[i]) {
|
||||
gyrValidValues[0][j] = gyrValues[0][i];
|
||||
gyrValidValues[1][j] = gyrValues[1][i];
|
||||
gyrValidValues[2][j] = gyrValues[2][i];
|
||||
j += 1;
|
||||
// take ADIS measurements, if both avail
|
||||
// if just one ADIS measurement avail, perform sensor fusion
|
||||
double gyrVecTot[3] = {0.0, 0.0, 0.0};
|
||||
if ((gyr0valid && gyr2valid) && gyrParameters->preferAdis == gyrParameters->PreferAdis::YES) {
|
||||
double gyr02ValuesSum[3];
|
||||
VectorOperations<double>::add(gyr0ValueBody, gyr2ValueBody, gyr02ValuesSum, 3);
|
||||
VectorOperations<double>::mulScalar(gyr02ValuesSum, .5, gyrVecTot, 3);
|
||||
} else {
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
gyrVecTot[i] = sensorFusionNumerator[i] / sensorFusionDenominator[i];
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(gyrDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
std::memcpy(gyrDataProcessed->gyr0vec.value, gyr0ValueBody, 3 * sizeof(double));
|
||||
gyrDataProcessed->gyr0vec.setValid(gyr0valid);
|
||||
std::memcpy(gyrDataProcessed->gyr1vec.value, gyr1ValueBody, 3 * sizeof(double));
|
||||
gyrDataProcessed->gyr1vec.setValid(gyr1valid);
|
||||
std::memcpy(gyrDataProcessed->gyr2vec.value, gyr2ValueBody, 3 * sizeof(double));
|
||||
gyrDataProcessed->gyr2vec.setValid(gyr2valid);
|
||||
std::memcpy(gyrDataProcessed->gyr3vec.value, gyr3ValueBody, 3 * sizeof(double));
|
||||
gyrDataProcessed->gyr3vec.setValid(gyr3valid);
|
||||
std::memcpy(gyrDataProcessed->gyrVecTot.value, gyrVecTot, 3 * sizeof(double));
|
||||
gyrDataProcessed->gyrVecTot.setValid(true);
|
||||
gyrDataProcessed->setValidity(true, false);
|
||||
}
|
||||
}
|
||||
// Selection Sort
|
||||
double gyrValidValuesSort[3][validCount];
|
||||
MathOperations<double>::selectionSort(*gyrValidValues, *gyrValidValuesSort, 3, validCount);
|
||||
|
||||
uint8_t n = ceil(validCount / 2);
|
||||
satRatEst[0] = gyrValidValuesSort[0][n];
|
||||
satRatEst[1] = gyrValidValuesSort[1][n];
|
||||
satRatEst[2] = gyrValidValuesSort[2][n];
|
||||
*satRateEstValid = true;
|
||||
}
|
||||
|
||||
void SensorProcessing::processGps(const double gps0latitude, const double gps0longitude,
|
||||
const double gps0altitude, const uint32_t gps0UnixSeconds,
|
||||
const bool validGps, const AcsParameters::GpsParameters *gpsParameters,
|
||||
double *gcLatitude, double *gdLongitude, double *gpsVelocityE) {
|
||||
void SensorProcessing::processGps(const double gpsLatitude, const double gpsLongitude,
|
||||
const bool validGps,
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed) {
|
||||
// name to convert not process
|
||||
double gdLongitude, gcLatitude;
|
||||
if (validGps) {
|
||||
// Transforming from Degree to Radians and calculation geocentric lattitude from geodetic
|
||||
*gdLongitude = gps0longitude * PI / 180;
|
||||
double latitudeRad = gps0latitude * PI / 180;
|
||||
gdLongitude = gpsLongitude * PI / 180;
|
||||
double latitudeRad = gpsLatitude * PI / 180;
|
||||
double eccentricityWgs84 = 0.0818195;
|
||||
double factor = 1 - pow(eccentricityWgs84, 2);
|
||||
*gcLatitude = atan(factor * tan(latitudeRad));
|
||||
validGcLatitude = true;
|
||||
gcLatitude = atan(factor * tan(latitudeRad));
|
||||
|
||||
// Calculation of the satellite velocity in earth fixed frame
|
||||
double posSatE[3] = {0, 0, 0}, deltaDistance[3] = {0, 0, 0};
|
||||
@ -476,6 +580,18 @@ void SensorProcessing::processGps(const double gps0latitude, const double gps0lo
|
||||
double timeDiffGpsMeas = gps0UnixSeconds - timeOfSavedPosSatE;
|
||||
VectorOperations<double>::mulScalar(deltaDistance, 1/timeDiffGpsMeas, gpsVelocityE, 3);
|
||||
}
|
||||
}
|
||||
{
|
||||
PoolReadGuard pg(gpsDataProcessed);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
gpsDataProcessed->gdLongitude.value = gdLongitude;
|
||||
gpsDataProcessed->gcLatitude.value = gcLatitude;
|
||||
gpsDataProcessed->setValidity(validGps, validGps);
|
||||
if (!validGps) {
|
||||
gpsDataProcessed->gdLongitude.value = 0.0;
|
||||
gpsDataProcessed->gcLatitude.value = 0.0;
|
||||
}
|
||||
}
|
||||
savedPosSatE[0] = posSatE[0];
|
||||
savedPosSatE[1] = posSatE[1];
|
||||
savedPosSatE[2] = posSatE[2];
|
||||
@ -489,30 +605,31 @@ void SensorProcessing::processGps(const double gps0latitude, const double gps0lo
|
||||
}
|
||||
|
||||
void SensorProcessing::process(timeval now, ACS::SensorValues *sensorValues,
|
||||
ACS::OutputValues *outputValues,
|
||||
acsctrl::MgmDataProcessed *mgmDataProcessed,
|
||||
acsctrl::SusDataProcessed *susDataProcessed,
|
||||
acsctrl::GyrDataProcessed *gyrDataProcessed,
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed,
|
||||
const AcsParameters *acsParameters) {
|
||||
sensorValues->update();
|
||||
processGps(sensorValues->gpsSet.latitude.value, sensorValues->gpsSet.longitude.value,
|
||||
sensorValues->gpsSet.altitude.value, sensorValues->gpsSet.unixSeconds.value,
|
||||
sensorValues->gpsSet.isValid(), &acsParameters->gpsParameters,
|
||||
&outputValues->gcLatitude, &outputValues->gdLongitude,
|
||||
outputValues->gpsVelocity);
|
||||
(sensorValues->gpsSet.latitude.isValid() && sensorValues->gpsSet.longitude.isValid() &&
|
||||
sensorValues->gpsSet.altitude.isValid()),
|
||||
gpsDataProcessed);
|
||||
|
||||
outputValues->mgmUpdated = processMgm(
|
||||
sensorValues->mgm0Lis3Set.fieldStrengths.value,
|
||||
sensorValues->mgm0Lis3Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm1Rm3100Set.fieldStrengths.value,
|
||||
sensorValues->mgm1Rm3100Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm2Lis3Set.fieldStrengths.value,
|
||||
sensorValues->mgm2Lis3Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm3Rm3100Set.fieldStrengths.value,
|
||||
sensorValues->mgm3Rm3100Set.fieldStrengths.isValid(), sensorValues->imtqMgmSet.mtmRawNt.value,
|
||||
sensorValues->imtqMgmSet.mtmRawNt.isValid(), now, &acsParameters->mgmHandlingParameters,
|
||||
outputValues->gcLatitude, outputValues->gdLongitude, sensorValues->gpsSet.altitude.value,
|
||||
sensorValues->gpsSet.isValid(), outputValues->magFieldEst, &outputValues->magFieldEstValid,
|
||||
outputValues->magFieldModel, &outputValues->magFieldModelValid,
|
||||
outputValues->magneticFieldVectorDerivative,
|
||||
&outputValues->magneticFieldVectorDerivativeValid); // VALID outputs- PoolVariable ?
|
||||
processMgm(sensorValues->mgm0Lis3Set.fieldStrengths.value,
|
||||
sensorValues->mgm0Lis3Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm1Rm3100Set.fieldStrengths.value,
|
||||
sensorValues->mgm1Rm3100Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm2Lis3Set.fieldStrengths.value,
|
||||
sensorValues->mgm2Lis3Set.fieldStrengths.isValid(),
|
||||
sensorValues->mgm3Rm3100Set.fieldStrengths.value,
|
||||
sensorValues->mgm3Rm3100Set.fieldStrengths.isValid(),
|
||||
sensorValues->imtqMgmSet.mtmRawNt.value, sensorValues->imtqMgmSet.mtmRawNt.isValid(),
|
||||
now, &acsParameters->mgmHandlingParameters, gpsDataProcessed,
|
||||
sensorValues->gpsSet.altitude.value,
|
||||
(sensorValues->gpsSet.latitude.isValid() && sensorValues->gpsSet.longitude.isValid() &&
|
||||
sensorValues->gpsSet.altitude.isValid()),
|
||||
mgmDataProcessed);
|
||||
|
||||
processSus(sensorValues->susSets[0].channels.value, sensorValues->susSets[0].channels.isValid(),
|
||||
sensorValues->susSets[1].channels.value, sensorValues->susSets[1].channels.isValid(),
|
||||
@ -527,10 +644,7 @@ void SensorProcessing::process(timeval now, ACS::SensorValues *sensorValues,
|
||||
sensorValues->susSets[10].channels.value, sensorValues->susSets[10].channels.isValid(),
|
||||
sensorValues->susSets[11].channels.value, sensorValues->susSets[11].channels.isValid(),
|
||||
now, &acsParameters->susHandlingParameters, &acsParameters->sunModelParameters,
|
||||
outputValues->sunDirEst, &outputValues->sunDirEstValid, outputValues->sunDirModel,
|
||||
&outputValues->sunDirModelValid, outputValues->sunVectorDerivative,
|
||||
&outputValues->sunVectorDerivativeValid);
|
||||
// VALID outputs ?
|
||||
susDataProcessed);
|
||||
|
||||
processGyr(
|
||||
sensorValues->gyr0AdisSet.angVelocX.value, sensorValues->gyr0AdisSet.angVelocX.isValid(),
|
||||
@ -545,6 +659,5 @@ void SensorProcessing::process(timeval now, ACS::SensorValues *sensorValues,
|
||||
sensorValues->gyr3L3gSet.angVelocX.value, sensorValues->gyr3L3gSet.angVelocX.isValid(),
|
||||
sensorValues->gyr3L3gSet.angVelocY.value, sensorValues->gyr3L3gSet.angVelocY.isValid(),
|
||||
sensorValues->gyr3L3gSet.angVelocZ.value, sensorValues->gyr3L3gSet.angVelocZ.isValid(), now,
|
||||
&acsParameters->gyrHandlingParameters, outputValues->satRateEst,
|
||||
&outputValues->satRateEstValid);
|
||||
&acsParameters->gyrHandlingParameters, gyrDataProcessed);
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "../controllerdefinitions/AcsCtrlDefinitions.h"
|
||||
#include "AcsParameters.h"
|
||||
#include "OutputValues.h"
|
||||
#include "SensorValues.h"
|
||||
#include "SusConverter.h"
|
||||
#include "config/classIds.h"
|
||||
@ -23,19 +22,21 @@ class SensorProcessing {
|
||||
SensorProcessing(AcsParameters *acsParameters_);
|
||||
virtual ~SensorProcessing();
|
||||
|
||||
void process(timeval now, ACS::SensorValues *sensorValues, ACS::OutputValues *outputValues,
|
||||
void process(timeval now, ACS::SensorValues *sensorValues,
|
||||
acsctrl::MgmDataProcessed *mgmDataProcessed,
|
||||
acsctrl::SusDataProcessed *susDataProcessed,
|
||||
acsctrl::GyrDataProcessed *gyrDataProcessed,
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed,
|
||||
const AcsParameters *acsParameters); // Will call protected functions
|
||||
private:
|
||||
protected:
|
||||
// short description needed for every function
|
||||
bool processMgm(const float *mgm0Value, bool mgm0valid, const float *mgm1Value, bool mgm1valid,
|
||||
void processMgm(const float *mgm0Value, bool mgm0valid, const float *mgm1Value, bool mgm1valid,
|
||||
const float *mgm2Value, bool mgm2valid, const float *mgm3Value, bool mgm3valid,
|
||||
const float *mgm4Value, bool mgm4valid, timeval timeOfMgmMeasurement,
|
||||
const AcsParameters::MgmHandlingParameters *mgmParameters,
|
||||
const double gpsLatitude, const double gpsLongitude, const double gpsAltitude,
|
||||
bool gpsValid, double *magFieldEst, bool *outputValid, double *magFieldModel,
|
||||
bool *magFieldModelValid, double *magneticFieldVectorDerivative,
|
||||
bool *magneticFieldVectorDerivativeValid); // Output
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed, const double gpsAltitude,
|
||||
bool gpsValid, acsctrl::MgmDataProcessed *mgmDataProcessed);
|
||||
|
||||
void processSus(const uint16_t *sus0Value, bool sus0valid, const uint16_t *sus1Value,
|
||||
bool sus1valid, const uint16_t *sus2Value, bool sus2valid,
|
||||
@ -47,9 +48,8 @@ class SensorProcessing {
|
||||
bool sus10valid, const uint16_t *sus11Value, bool sus11valid,
|
||||
timeval timeOfSusMeasurement,
|
||||
const AcsParameters::SusHandlingParameters *susParameters,
|
||||
const AcsParameters::SunModelParameters *sunModelParameters, double *sunDirEst,
|
||||
bool *sunDirEstValid, double *sunVectorInertial, bool *sunVectorInertialValid,
|
||||
double *sunVectorDerivative, bool *sunVectorDerivativeValid);
|
||||
const AcsParameters::SunModelParameters *sunModelParameters,
|
||||
acsctrl::SusDataProcessed *susDataProcessed);
|
||||
|
||||
void processGyr(const double gyr0axXvalue, bool gyr0axXvalid, const double gyr0axYvalue,
|
||||
bool gyr0axYvalid, const double gyr0axZvalue, bool gyr0axZvalid,
|
||||
@ -60,19 +60,17 @@ class SensorProcessing {
|
||||
const double gyr3axXvalue, bool gyr3axXvalid, const double gyr3axYvalue,
|
||||
bool gyr3axYvalid, const double gyr3axZvalue, bool gyr3axZvalid,
|
||||
timeval timeOfGyrMeasurement,
|
||||
const AcsParameters::GyrHandlingParameters *gyrParameters, double *satRatEst,
|
||||
bool *satRateEstValid);
|
||||
const AcsParameters::GyrHandlingParameters *gyrParameters,
|
||||
acsctrl::GyrDataProcessed *gyrDataProcessed);
|
||||
|
||||
void processStr();
|
||||
|
||||
void processGps(const double gps0latitude, const double gps0longitude,
|
||||
const double gps0altitude, const uint32_t gps0UnixSeconds,
|
||||
const bool validGps, const AcsParameters::GpsParameters *gpsParameters,
|
||||
double *gcLatitude, double *gdLongitude, double *gpsVelocityE);
|
||||
void processGps(const double gps0latitude, const double gps0longitude, const bool validGps,
|
||||
acsctrl::GpsDataProcessed *gpsDataProcessed);
|
||||
|
||||
double savedMagFieldEst[3];
|
||||
double savedMgmVecTot[3];
|
||||
timeval timeOfSavedMagFieldEst;
|
||||
double savedSunVector[3];
|
||||
double savedSusVecTot[3];
|
||||
timeval timeOfSavedSusDirEst;
|
||||
bool validMagField;
|
||||
bool validGcLatitude;
|
||||
@ -80,6 +78,7 @@ class SensorProcessing {
|
||||
double savedPosSatE[3];
|
||||
uint32_t timeOfSavedPosSatE;
|
||||
bool validSavedPosSatE;
|
||||
const float zeroVector[3] = {0.0, 0.0, 0.0};
|
||||
|
||||
SusConverter susConverter;
|
||||
AcsParameters acsParameters;
|
||||
|
@ -82,12 +82,14 @@ ReturnValue_t SensorValues::update() {
|
||||
ReturnValue_t susUpdate = updateSus();
|
||||
ReturnValue_t gyrUpdate = updateGyr();
|
||||
ReturnValue_t strUpdate = updateStr();
|
||||
ReturnValue_t gpsUpdate = updateGps();
|
||||
ReturnValue_t rwUpdate = updateRw();
|
||||
|
||||
if ((mgmUpdate && susUpdate && gyrUpdate && strUpdate) == returnvalue::FAILED) {
|
||||
if ((mgmUpdate && susUpdate && gyrUpdate && strUpdate && gpsUpdate && rwUpdate) ==
|
||||
returnvalue::FAILED) {
|
||||
return returnvalue::FAILED;
|
||||
};
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
} // namespace ACS
|
||||
// namespace ACS
|
||||
|
@ -1,17 +1,15 @@
|
||||
#ifndef SENSORVALUES_H_
|
||||
#define SENSORVALUES_H_
|
||||
|
||||
#include <commonObjects.h>
|
||||
|
||||
#include "fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h"
|
||||
#include "fsfw_hal/devicehandlers/MgmRM3100Handler.h"
|
||||
#include "linux/devices/devicedefinitions/StarTrackerDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/GPSDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/GyroADIS1650XDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/GyroL3GD20Definitions.h"
|
||||
#include "mission/devices/devicedefinitions/IMTQHandlerDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/RwDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/SusDefinitions.h"
|
||||
#include "mission/devices/devicedefinitions/imtqHandlerDefinitions.h"
|
||||
|
||||
namespace ACS {
|
||||
|
||||
|
@ -107,17 +107,17 @@ void SusConverter::calibration(const float coeffAlpha[9][10], const float coeffB
|
||||
|
||||
float* SusConverter::calculateSunVector() {
|
||||
// Calculate the normalized Sun Vector
|
||||
sunVectorBodyFrame[0] = (tan(alphaBetaCalibrated[0] * (M_PI / 180)) /
|
||||
(sqrt((powf(tan(alphaBetaCalibrated[0] * (M_PI / 180)), 2)) +
|
||||
powf(tan((alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
sunVectorBodyFrame[1] = (tan(alphaBetaCalibrated[1] * (M_PI / 180)) /
|
||||
(sqrt(powf((tan(alphaBetaCalibrated[0] * (M_PI / 180))), 2) +
|
||||
powf(tan((alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
sunVectorBodyFrame[2] =
|
||||
(-1 / (sqrt(powf((tan(alphaBetaCalibrated[0] * (M_PI / 180))), 2) +
|
||||
powf((tan(alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
sunVectorSensorFrame[0] = -(tan(alphaBetaCalibrated[0] * (M_PI / 180)) /
|
||||
(sqrt((powf(tan(alphaBetaCalibrated[0] * (M_PI / 180)), 2)) +
|
||||
powf(tan((alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
sunVectorSensorFrame[1] = -(tan(alphaBetaCalibrated[1] * (M_PI / 180)) /
|
||||
(sqrt(powf((tan(alphaBetaCalibrated[0] * (M_PI / 180))), 2) +
|
||||
powf(tan((alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
sunVectorSensorFrame[2] =
|
||||
-(-1 / (sqrt(powf((tan(alphaBetaCalibrated[0] * (M_PI / 180))), 2) +
|
||||
powf((tan(alphaBetaCalibrated[1] * (M_PI / 180))), 2) + (1))));
|
||||
|
||||
return sunVectorBodyFrame;
|
||||
return sunVectorSensorFrame;
|
||||
}
|
||||
|
||||
float* SusConverter::getSunVectorSensorFrame(const uint16_t susChannel[6],
|
||||
|
@ -27,11 +27,11 @@ class SusConverter {
|
||||
const float coeffBeta[9][10]);
|
||||
|
||||
private:
|
||||
float alphaBetaRaw[2]; //[°]
|
||||
// float coeffAlpha[9][10];
|
||||
// float coeffBeta[9][10];
|
||||
float alphaBetaCalibrated[2]; //[°]
|
||||
float sunVectorBodyFrame[3]; //[-]
|
||||
float alphaBetaRaw[2]; //[°]
|
||||
// float coeffAlpha[9][10];
|
||||
// float coeffBeta[9][10];
|
||||
float alphaBetaCalibrated[2]; //[°]
|
||||
float sunVectorSensorFrame[3]; //[-]
|
||||
|
||||
bool validFlag[12] = {returnvalue::OK, returnvalue::OK, returnvalue::OK, returnvalue::OK,
|
||||
returnvalue::OK, returnvalue::OK, returnvalue::OK, returnvalue::OK,
|
||||
|
@ -1,26 +1,18 @@
|
||||
/*
|
||||
* classIds.h
|
||||
*
|
||||
* Created on: 1 Mar 2022
|
||||
* Author: rooob
|
||||
*/
|
||||
|
||||
#ifndef ACS_CONFIG_CLASSIDS_H_
|
||||
#define ACS_CONFIG_CLASSIDS_H_
|
||||
|
||||
#include <common/config/commonClassIds.h>
|
||||
#include <common/config/eive/resultClassIds.h>
|
||||
#include <fsfw/returnvalues/FwClassIds.h>
|
||||
|
||||
namespace CLASS_ID {
|
||||
enum eiveclassIds: uint8_t {
|
||||
EIVE_CLASS_ID_START = COMMON_CLASS_ID_END,
|
||||
KALMAN,
|
||||
SAFE,
|
||||
PTG,
|
||||
DETUMBLE,
|
||||
EIVE_CLASS_ID_END // [EXPORT] : [END]
|
||||
enum eiveclassIds : uint8_t {
|
||||
EIVE_CLASS_ID_START = COMMON_CLASS_ID_END,
|
||||
KALMAN,
|
||||
SAFE,
|
||||
PTG,
|
||||
DETUMBLE,
|
||||
EIVE_CLASS_ID_END // [EXPORT] : [END]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* ACS_CONFIG_CLASSIDS_H_ */
|
||||
|
@ -1,5 +1,2 @@
|
||||
target_sources(
|
||||
${LIB_EIVE_MISSION}
|
||||
PRIVATE Detumble.cpp
|
||||
PtgCtrl.cpp
|
||||
SafeCtrl.cpp)
|
||||
target_sources(${LIB_EIVE_MISSION} PRIVATE Detumble.cpp PtgCtrl.cpp
|
||||
SafeCtrl.cpp)
|
||||
|
@ -6,33 +6,26 @@
|
||||
* Author: Robin Marquardt
|
||||
*/
|
||||
|
||||
|
||||
#include "Detumble.h"
|
||||
#include "../util/MathOperations.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <fsfw/globalfunctions/sign.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../util/MathOperations.h"
|
||||
|
||||
Detumble::Detumble(AcsParameters *acsParameters_){
|
||||
loadAcsParameters(acsParameters_);
|
||||
Detumble::Detumble(AcsParameters *acsParameters_) { loadAcsParameters(acsParameters_); }
|
||||
|
||||
Detumble::~Detumble() {}
|
||||
|
||||
void Detumble::loadAcsParameters(AcsParameters *acsParameters_) {
|
||||
detumbleCtrlParameters = &(acsParameters_->detumbleCtrlParameters);
|
||||
magnetorquesParameter = &(acsParameters_->magnetorquesParameter);
|
||||
}
|
||||
|
||||
Detumble::~Detumble(){
|
||||
|
||||
}
|
||||
|
||||
void Detumble::loadAcsParameters(AcsParameters *acsParameters_){
|
||||
|
||||
detumbleParameter = &(acsParameters_->detumbleParameter);
|
||||
magnetorquesParameter = &(acsParameters_->magnetorquesParameter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t Detumble::bDotLaw(const double *magRate, const bool *magRateValid,
|
||||
const double *magField, const bool *magFieldValid,
|
||||
double *magMom) {
|
||||
@ -47,18 +40,16 @@ ReturnValue_t Detumble::bDotLaw(const double *magRate, const bool *magRateValid,
|
||||
|
||||
}
|
||||
|
||||
ReturnValue_t Detumble::bangbangLaw(const double *magRate, const bool *magRateValid, double *magMom) {
|
||||
ReturnValue_t Detumble::bangbangLaw(const double *magRate, const bool magRateValid,
|
||||
double *magMom) {
|
||||
if (!magRateValid) {
|
||||
return DETUMBLE_NO_SENSORDATA;
|
||||
}
|
||||
|
||||
if (!magRateValid) {
|
||||
return DETUMBLE_NO_SENSORDATA;
|
||||
}
|
||||
|
||||
double dipolMax = magnetorquesParameter->DipolMax;
|
||||
for (int i = 0; i<3; i++) {
|
||||
|
||||
magMom[i] = - dipolMax * sign(magRate[i]);
|
||||
|
||||
}
|
||||
double dipolMax = magnetorquesParameter->DipolMax;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
magMom[i] = -dipolMax * sign(magRate[i]);
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
|
||||
|
@ -8,33 +8,32 @@
|
||||
#ifndef ACS_CONTROL_DETUMBLE_H_
|
||||
#define ACS_CONTROL_DETUMBLE_H_
|
||||
|
||||
#include "../SensorValues.h"
|
||||
#include "../OutputValues.h"
|
||||
#include "../AcsParameters.h"
|
||||
#include "../config/classIds.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../AcsParameters.h"
|
||||
#include "../SensorValues.h"
|
||||
#include "../config/classIds.h"
|
||||
|
||||
class Detumble{
|
||||
class Detumble {
|
||||
public:
|
||||
Detumble(AcsParameters *acsParameters_);
|
||||
virtual ~Detumble();
|
||||
|
||||
public:
|
||||
Detumble(AcsParameters *acsParameters_);
|
||||
virtual ~Detumble();
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DETUMBLE;
|
||||
static const ReturnValue_t DETUMBLE_NO_SENSORDATA = MAKE_RETURN_CODE(0x01);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DETUMBLE;
|
||||
static const ReturnValue_t DETUMBLE_NO_SENSORDATA = MAKE_RETURN_CODE(0x01);
|
||||
/* @brief: Load AcsParameters für this class
|
||||
* @param: acsParameters_ Pointer to object which defines the ACS configuration parameters
|
||||
*/
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
|
||||
/* @brief: Load AcsParameters für this class
|
||||
* @param: acsParameters_ Pointer to object which defines the ACS configuration parameters
|
||||
*/
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
ReturnValue_t bDotLaw(const double *magRate, const bool magRateValid, const double *magField,
|
||||
const bool magFieldValid, double *magMom);
|
||||
|
||||
ReturnValue_t bDotLaw(const double *magRate, const bool *magRateValid,
|
||||
const double *magField, const bool *magFieldValid,
|
||||
double *magMom);
|
||||
ReturnValue_t bangbangLaw(const double *magRate, const bool magRateValid, double *magMom);
|
||||
|
||||
ReturnValue_t bangbangLaw(const double *magRate, const bool *magRateValid, double *magMom);
|
||||
|
||||
@ -48,4 +47,3 @@ private:
|
||||
};
|
||||
|
||||
#endif /*ACS_CONTROL_DETUMBLE_H_*/
|
||||
|
||||
|
@ -5,10 +5,8 @@
|
||||
* Author: Robin Marquardt
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "PtgCtrl.h"
|
||||
#include "../util/MathOperations.h"
|
||||
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
@ -16,77 +14,76 @@
|
||||
#include <fsfw/globalfunctions/sign.h>
|
||||
#include <math.h>
|
||||
|
||||
PtgCtrl::PtgCtrl(AcsParameters *acsParameters_): torqueMemory {0, 0, 0, 0}, omegaMemory {0, 0, 0, 0} {
|
||||
#include "../util/MathOperations.h"
|
||||
|
||||
PtgCtrl::PtgCtrl(AcsParameters *acsParameters_){
|
||||
loadAcsParameters(acsParameters_);
|
||||
}
|
||||
|
||||
PtgCtrl::~PtgCtrl(){
|
||||
PtgCtrl::~PtgCtrl() {}
|
||||
|
||||
}
|
||||
|
||||
void PtgCtrl::loadAcsParameters(AcsParameters *acsParameters_){
|
||||
pointingModeControllerParameters = &(acsParameters_->targetModeControllerParameters);
|
||||
inertiaEIVE = &(acsParameters_->inertiaEIVE);
|
||||
rwHandlingParameters = &(acsParameters_->rwHandlingParameters);
|
||||
rwMatrices =&(acsParameters_->rwMatrices);
|
||||
void PtgCtrl::loadAcsParameters(AcsParameters *acsParameters_) {
|
||||
pointingModeControllerParameters = &(acsParameters_->targetModeControllerParameters);
|
||||
inertiaEIVE = &(acsParameters_->inertiaEIVE);
|
||||
rwHandlingParameters = &(acsParameters_->rwHandlingParameters);
|
||||
rwMatrices = &(acsParameters_->rwMatrices);
|
||||
}
|
||||
|
||||
void PtgCtrl::ptgLaw(const double mode, const double *qError, const double *deltaRate,const double *rwPseudoInv, double *torqueRws){
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Compute gain matrix K and P matrix
|
||||
//------------------------------------------------------------------------------------------------
|
||||
double om = pointingModeControllerParameters->om;
|
||||
double zeta = pointingModeControllerParameters->zeta;
|
||||
double qErrorMin = pointingModeControllerParameters->qiMin;
|
||||
double omMax = pointingModeControllerParameters->omMax;
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Compute gain matrix K and P matrix
|
||||
//------------------------------------------------------------------------------------------------
|
||||
double om = pointingModeControllerParameters->om;
|
||||
double zeta = pointingModeControllerParameters->zeta;
|
||||
double qErrorMin = pointingModeControllerParameters->qiMin;
|
||||
double omMax = pointingModeControllerParameters->omMax;
|
||||
double cInt = 2 * om * zeta;
|
||||
double kInt = 2 * pow(om, 2);
|
||||
|
||||
double cInt = 2 * om * zeta;
|
||||
double kInt = 2 * pow(om,2);
|
||||
double qErrorLaw[3] = {0, 0, 0};
|
||||
|
||||
double qErrorLaw[3] = {0, 0, 0};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (abs(qError[i]) < qErrorMin) {
|
||||
qErrorLaw[i] = qErrorMin;
|
||||
} else {
|
||||
qErrorLaw[i] = abs(qError[i]);
|
||||
}
|
||||
}
|
||||
double qErrorLawNorm = VectorOperations<double>::norm(qErrorLaw, 3);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (abs(qError[i]) < qErrorMin) {
|
||||
qErrorLaw[i] = qErrorMin;
|
||||
}
|
||||
else {
|
||||
qErrorLaw[i] = abs(qError[i]);
|
||||
}
|
||||
}
|
||||
double qErrorLawNorm = VectorOperations<double>::norm(qErrorLaw, 3);
|
||||
double gain1 = cInt * omMax / qErrorLawNorm;
|
||||
double gainVector[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(qErrorLaw, gain1, gainVector, 3);
|
||||
|
||||
double gain1 = cInt * omMax / qErrorLawNorm;
|
||||
double gainVector[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(qErrorLaw, gain1, gainVector, 3);
|
||||
double gainMatrixDiagonal[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
double gainMatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
gainMatrixDiagonal[0][0] = gainVector[0];
|
||||
gainMatrixDiagonal[1][1] = gainVector[1];
|
||||
gainMatrixDiagonal[2][2] = gainVector[2];
|
||||
MatrixOperations<double>::multiply(*gainMatrixDiagonal, *(inertiaEIVE->inertiaMatrix),
|
||||
*gainMatrix, 3, 3, 3);
|
||||
|
||||
double gainMatrixDiagonal[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
double gainMatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
gainMatrixDiagonal[0][0] = gainVector[0];
|
||||
gainMatrixDiagonal[1][1] = gainVector[1];
|
||||
gainMatrixDiagonal[2][2] = gainVector[2];
|
||||
MatrixOperations<double>::multiply( *gainMatrixDiagonal, *(inertiaEIVE->inertiaMatrix), *gainMatrix, 3, 3, 3);
|
||||
// Inverse of gainMatrix
|
||||
double gainMatrixInverse[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
gainMatrixInverse[0][0] = 1 / gainMatrix[0][0];
|
||||
gainMatrixInverse[1][1] = 1 / gainMatrix[1][1];
|
||||
gainMatrixInverse[2][2] = 1 / gainMatrix[2][2];
|
||||
|
||||
// Inverse of gainMatrix
|
||||
double gainMatrixInverse[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
gainMatrixInverse[0][0] = 1 / gainMatrix[0][0];
|
||||
gainMatrixInverse[1][1] = 1 / gainMatrix[1][1];
|
||||
gainMatrixInverse[2][2] = 1 / gainMatrix[2][2];
|
||||
double pMatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
MatrixOperations<double>::multiply(*gainMatrixInverse, *(inertiaEIVE->inertiaMatrix), *pMatrix, 3,
|
||||
3, 3);
|
||||
MatrixOperations<double>::multiplyScalar(*pMatrix, kInt, *pMatrix, 3, 3);
|
||||
|
||||
double pMatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
MatrixOperations<double>::multiply(*gainMatrixInverse, *(inertiaEIVE->inertiaMatrix), *pMatrix, 3, 3, 3);
|
||||
MatrixOperations<double>::multiplyScalar(*pMatrix, kInt, *pMatrix, 3, 3);
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Torque Calculations for the reaction wheels
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Torque Calculations for the reaction wheels
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
double pError[3] = {0, 0, 0};
|
||||
MatrixOperations<double>::multiply(*pMatrix, qError, pError, 3, 3, 1);
|
||||
double pErrorSign[3] = {0, 0, 0};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
double pError[3] = {0, 0, 0};
|
||||
MatrixOperations<double>::multiply(*pMatrix, qError, pError, 3, 3, 1);
|
||||
double pErrorSign[3] = {0, 0, 0};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (abs(pError[i]) > 1) {
|
||||
pErrorSign[i] = sign(pError[i]);
|
||||
}
|
||||
@ -113,7 +110,7 @@ void PtgCtrl::ptgLaw(const double mode, const double *qError, const double *delt
|
||||
|
||||
}
|
||||
|
||||
void PtgCtrl::ptgDesaturation(double *magFieldEst, bool *magFieldEstValid, double *satRate,
|
||||
void PtgCtrl::ptgDesaturation(double *magFieldEst, bool magFieldEstValid, double *satRate,
|
||||
int32_t *speedRw0, int32_t *speedRw1, int32_t *speedRw2,
|
||||
int32_t *speedRw3, double *mgtDpDes) {
|
||||
if (!(magFieldEstValid) || !(pointingModeControllerParameters->desatOn)) {
|
||||
@ -124,7 +121,7 @@ void PtgCtrl::ptgDesaturation(double *magFieldEst, bool *magFieldEstValid, doubl
|
||||
}
|
||||
|
||||
// calculating momentum of satellite and momentum of reaction wheels
|
||||
double speedRws[4] = {*speedRw0, *speedRw1, *speedRw2, *speedRw3};
|
||||
double speedRws[4] = {(double)*speedRw0, (double)*speedRw1, (double)*speedRw2, (double)*speedRw3};
|
||||
double momentumRwU[4] = {0, 0, 0, 0}, momentumRw[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(speedRws, rwHandlingParameters->inertiaWheel, momentumRwU, 4);
|
||||
MatrixOperations<double>::multiply(*(rwMatrices->alignmentMatrix), momentumRwU, momentumRw, 3, 4,
|
||||
@ -146,7 +143,7 @@ void PtgCtrl::ptgDesaturation(double *magFieldEst, bool *magFieldEstValid, doubl
|
||||
|
||||
void PtgCtrl::ptgNullspace(const int32_t *speedRw0, const int32_t *speedRw1,
|
||||
const int32_t *speedRw2, const int32_t *speedRw3, double *rwTrqNs) {
|
||||
double speedRws[4] = {*speedRw0, *speedRw1, *speedRw2, *speedRw3};
|
||||
double speedRws[4] = {(double)*speedRw0, (double)*speedRw1, (double)*speedRw2, (double)*speedRw3};
|
||||
double wheelMomentum[4] = {0, 0, 0, 0};
|
||||
double rpmOffset[4] = {1, 1, 1, -1}, factor = 350 * 2 * Math::PI / 60;
|
||||
// Conversion to [rad/s] for further calculations
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "../AcsParameters.h"
|
||||
#include "../OutputValues.h"
|
||||
#include "../SensorValues.h"
|
||||
#include "../config/classIds.h"
|
||||
|
||||
@ -45,7 +44,7 @@ class PtgCtrl {
|
||||
void ptgLaw(const double mode, const double *qError, const double *deltaRate,
|
||||
const double *rwPseudoInv, double *torqueRws);
|
||||
|
||||
void ptgDesaturation(double *magFieldEst, bool *magFieldEstValid, double *satRate,
|
||||
void ptgDesaturation(double *magFieldEst, bool magFieldEstValid, double *satRate,
|
||||
int32_t *speedRw0, int32_t *speedRw1, int32_t *speedRw2, int32_t *speedRw3,
|
||||
double *mgtDpDes);
|
||||
|
||||
|
@ -6,182 +6,173 @@
|
||||
*/
|
||||
|
||||
#include "SafeCtrl.h"
|
||||
#include "../util/MathOperations.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <fsfw/globalfunctions/math/QuaternionOperations.h>
|
||||
#include <fsfw/globalfunctions/math/VectorOperations.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../util/MathOperations.h"
|
||||
|
||||
SafeCtrl::SafeCtrl(AcsParameters *acsParameters_){
|
||||
loadAcsParameters(acsParameters_);
|
||||
MatrixOperations<double>::multiplyScalar(*(inertiaEIVE->inertiaMatrix), 10, *gainMatrixInertia, 3, 3);
|
||||
SafeCtrl::SafeCtrl(AcsParameters *acsParameters_) {
|
||||
loadAcsParameters(acsParameters_);
|
||||
MatrixOperations<double>::multiplyScalar(*(inertiaEIVE->inertiaMatrix), 10, *gainMatrixInertia, 3,
|
||||
3);
|
||||
}
|
||||
|
||||
SafeCtrl::~SafeCtrl(){
|
||||
SafeCtrl::~SafeCtrl() {}
|
||||
|
||||
void SafeCtrl::loadAcsParameters(AcsParameters *acsParameters_) {
|
||||
safeModeControllerParameters = &(acsParameters_->safeModeControllerParameters);
|
||||
inertiaEIVE = &(acsParameters_->inertiaEIVE);
|
||||
}
|
||||
|
||||
void SafeCtrl::loadAcsParameters(AcsParameters *acsParameters_){
|
||||
safeModeControllerParameters = &(acsParameters_->safeModeControllerParameters);
|
||||
inertiaEIVE = &(acsParameters_->inertiaEIVE);
|
||||
}
|
||||
ReturnValue_t SafeCtrl::safeMekf(timeval now, double *quatBJ, bool quatBJValid,
|
||||
double *magFieldModel, bool magFieldModelValid,
|
||||
double *sunDirModel, bool sunDirModelValid, double *satRateMekf,
|
||||
bool rateMekfValid, double *sunDirRef, double *satRatRef,
|
||||
double *outputAngle, double *outputMagMomB, bool *outputValid) {
|
||||
if (!quatBJValid || !magFieldModelValid || !sunDirModelValid || !rateMekfValid) {
|
||||
*outputValid = false;
|
||||
return SAFECTRL_MEKF_INPUT_INVALID;
|
||||
}
|
||||
|
||||
ReturnValue_t SafeCtrl::safeMekf(timeval now, double *quatBJ, bool *quatBJValid,
|
||||
double *magFieldModel, bool *magFieldModelValid,
|
||||
double *sunDirModel, bool *sunDirModelValid,
|
||||
double *satRateMekf, bool *rateMekfValid,
|
||||
double *sunDirRef, double *satRatRef,
|
||||
double *outputMagMomB, bool *outputValid){
|
||||
double kRate = 0, kAlign = 0;
|
||||
kRate = safeModeControllerParameters->k_rate_mekf;
|
||||
kAlign = safeModeControllerParameters->k_align_mekf;
|
||||
|
||||
if ( !(*quatBJValid) || !(*magFieldModelValid) || !(*sunDirModelValid) ||
|
||||
!(*rateMekfValid)) {
|
||||
*outputValid = false;
|
||||
return SAFECTRL_MEKF_INPUT_INVALID;
|
||||
}
|
||||
// Calc sunDirB ,magFieldB with mekf output and model
|
||||
double dcmBJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||
MathOperations<double>::dcmFromQuat(quatBJ, *dcmBJ);
|
||||
double sunDirB[3] = {0, 0, 0}, magFieldB[3] = {0, 0, 0};
|
||||
MatrixOperations<double>::multiply(*dcmBJ, sunDirModel, sunDirB, 3, 3, 1);
|
||||
MatrixOperations<double>::multiply(*dcmBJ, magFieldModel, magFieldB, 3, 3, 1);
|
||||
|
||||
double kRate = 0, kAlign = 0;
|
||||
kRate = safeModeControllerParameters->k_rate_mekf;
|
||||
kAlign = safeModeControllerParameters->k_align_mekf;
|
||||
double crossSun[3] = {0, 0, 0};
|
||||
|
||||
// Calc sunDirB ,magFieldB with mekf output and model
|
||||
double dcmBJ[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
|
||||
MathOperations<double>::dcmFromQuat(quatBJ, *dcmBJ);
|
||||
double sunDirB[3] = {0,0,0}, magFieldB[3] = {0,0,0};
|
||||
MatrixOperations<double>::multiply(*dcmBJ, sunDirModel, sunDirB, 3, 3, 1);
|
||||
MatrixOperations<double>::multiply(*dcmBJ, magFieldModel, magFieldB, 3, 3, 1);
|
||||
VectorOperations<double>::cross(sunDirRef, sunDirB, crossSun);
|
||||
double normCrossSun = VectorOperations<double>::norm(crossSun, 3);
|
||||
|
||||
double crossSun[3] = {0, 0, 0};
|
||||
// calc angle alpha between sunDirRef and sunDIr
|
||||
double alpha = 0, dotSun = 0;
|
||||
dotSun = VectorOperations<double>::dot(sunDirRef, sunDirB);
|
||||
alpha = acos(dotSun);
|
||||
|
||||
VectorOperations<double>::cross(sunDirRef, sunDirB, crossSun);
|
||||
double normCrossSun = VectorOperations<double>::norm(crossSun, 3);
|
||||
// Law Torque calculations
|
||||
double torqueCmd[3] = {0, 0, 0}, torqueAlign[3] = {0, 0, 0}, torqueRate[3] = {0, 0, 0},
|
||||
torqueAll[3] = {0, 0, 0};
|
||||
|
||||
// calc angle alpha between sunDirRef and sunDIr
|
||||
double alpha = 0, dotSun = 0;
|
||||
dotSun = VectorOperations<double>::dot(sunDirRef, sunDirB);
|
||||
alpha = acos(dotSun);
|
||||
double scalarFac = 0;
|
||||
scalarFac = kAlign * alpha / normCrossSun;
|
||||
VectorOperations<double>::mulScalar(crossSun, scalarFac, torqueAlign, 3);
|
||||
|
||||
// Law Torque calculations
|
||||
double torqueCmd[3] = {0, 0, 0}, torqueAlign[3] = {0, 0, 0},
|
||||
torqueRate[3] = {0, 0, 0}, torqueAll[3] = {0, 0, 0};
|
||||
double rateSafeMode[3] = {0, 0, 0};
|
||||
VectorOperations<double>::subtract(satRateMekf, satRatRef, rateSafeMode, 3);
|
||||
VectorOperations<double>::mulScalar(rateSafeMode, -kRate, torqueRate, 3);
|
||||
|
||||
double scalarFac = 0;
|
||||
scalarFac = kAlign * alpha / normCrossSun;
|
||||
VectorOperations<double>::mulScalar(crossSun, scalarFac, torqueAlign, 3);
|
||||
VectorOperations<double>::add(torqueRate, torqueAlign, torqueAll, 3);
|
||||
// Adding factor of inertia for axes
|
||||
MatrixOperations<double>::multiply(*gainMatrixInertia, torqueAll, torqueCmd, 3, 3, 1);
|
||||
|
||||
double rateSafeMode[3] = {0,0,0};
|
||||
VectorOperations<double>::subtract(satRateMekf, satRatRef, rateSafeMode, 3);
|
||||
VectorOperations<double>::mulScalar(rateSafeMode, -kRate, torqueRate, 3);
|
||||
// MagMom B (orthogonal torque)
|
||||
double torqueMgt[3] = {0, 0, 0};
|
||||
VectorOperations<double>::cross(magFieldB, torqueCmd, torqueMgt);
|
||||
double normMag = VectorOperations<double>::norm(magFieldB, 3);
|
||||
VectorOperations<double>::mulScalar(torqueMgt, 1 / pow(normMag, 2), outputMagMomB, 3);
|
||||
|
||||
VectorOperations<double>::add(torqueRate, torqueAlign, torqueAll, 3);
|
||||
// Adding factor of inertia for axes
|
||||
MatrixOperations<double>::multiply(*gainMatrixInertia, torqueAll, torqueCmd, 3, 3, 1);
|
||||
|
||||
// MagMom B (orthogonal torque)
|
||||
double torqueMgt[3] = {0,0,0};
|
||||
VectorOperations<double>::cross(magFieldB, torqueCmd, torqueMgt);
|
||||
double normMag = VectorOperations<double>::norm(magFieldB, 3);
|
||||
VectorOperations<double>::mulScalar(torqueMgt, 1/pow(normMag,2), outputMagMomB, 3);
|
||||
*outputValid = true;
|
||||
|
||||
return returnvalue::OK;
|
||||
*outputAngle = alpha;
|
||||
*outputValid = true;
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
// Will be the version in worst case scenario in event of no working MEKF (nor RMUs)
|
||||
void SafeCtrl::safeNoMekf(timeval now, double *susDirB, bool *susDirBValid,
|
||||
double *sunRateB, bool *sunRateBValid,
|
||||
double *magFieldB, bool *magFieldBValid,
|
||||
double *magRateB, bool *magRateBValid,
|
||||
double *sunDirRef, double *satRateRef,
|
||||
double *outputMagMomB, bool *outputValid){
|
||||
void SafeCtrl::safeNoMekf(timeval now, double *susDirB, bool susDirBValid, double *sunRateB,
|
||||
bool sunRateBValid, double *magFieldB, bool magFieldBValid,
|
||||
double *magRateB, bool magRateBValid, double *sunDirRef,
|
||||
double *satRateRef, double *outputAngle, double *outputMagMomB,
|
||||
bool *outputValid) {
|
||||
// Check for invalid Inputs
|
||||
if (!susDirBValid || !magFieldBValid || !magRateBValid) {
|
||||
*outputValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for invalid Inputs
|
||||
if ( !susDirBValid || !magFieldBValid || !magRateBValid) {
|
||||
*outputValid = false;
|
||||
return;
|
||||
}
|
||||
// normalize sunDir and magDir
|
||||
double magDirB[3] = {0, 0, 0};
|
||||
VectorOperations<double>::normalize(magFieldB, magDirB, 3);
|
||||
VectorOperations<double>::normalize(susDirB, susDirB, 3);
|
||||
|
||||
// normalize sunDir and magDir
|
||||
double magDirB[3] = {0, 0, 0};
|
||||
VectorOperations<double>::normalize(magFieldB, magDirB, 3);
|
||||
VectorOperations<double>::normalize(susDirB, susDirB, 3);
|
||||
// Cosinus angle between sunDir and magDir
|
||||
double cosAngleSunMag = VectorOperations<double>::dot(magDirB, susDirB);
|
||||
|
||||
// Cosinus angle between sunDir and magDir
|
||||
double cosAngleSunMag = VectorOperations<double>::dot(magDirB, susDirB);
|
||||
// Rate parallel to sun direction and magnetic field direction
|
||||
double rateParaSun = 0, rateParaMag = 0;
|
||||
double dotSunRateMag = 0, dotmagRateSun = 0, rateFactor = 0;
|
||||
dotSunRateMag = VectorOperations<double>::dot(sunRateB, magDirB);
|
||||
dotmagRateSun = VectorOperations<double>::dot(magRateB, susDirB);
|
||||
rateFactor = 1 - pow(cosAngleSunMag, 2);
|
||||
rateParaSun = (dotmagRateSun + cosAngleSunMag * dotSunRateMag) / rateFactor;
|
||||
rateParaMag = (dotSunRateMag + cosAngleSunMag * dotmagRateSun) / rateFactor;
|
||||
|
||||
// Rate parallel to sun direction and magnetic field direction
|
||||
double rateParaSun = 0, rateParaMag = 0;
|
||||
double dotSunRateMag = 0, dotmagRateSun = 0,
|
||||
rateFactor = 0;
|
||||
dotSunRateMag = VectorOperations<double>::dot(sunRateB, magDirB);
|
||||
dotmagRateSun = VectorOperations<double>::dot(magRateB, susDirB);
|
||||
rateFactor = 1 - pow(cosAngleSunMag,2);
|
||||
rateParaSun = ( dotmagRateSun + cosAngleSunMag * dotSunRateMag ) / rateFactor;
|
||||
rateParaMag = ( dotSunRateMag + cosAngleSunMag * dotmagRateSun ) / rateFactor;
|
||||
// Full rate or estimate
|
||||
double estSatRate[3] = {0, 0, 0};
|
||||
double estSatRateMag[3] = {0, 0, 0}, estSatRateSun[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(susDirB, rateParaSun, estSatRateSun, 3);
|
||||
VectorOperations<double>::add(sunRateB, estSatRateSun, estSatRateSun, 3);
|
||||
VectorOperations<double>::mulScalar(magDirB, rateParaMag, estSatRateMag, 3);
|
||||
VectorOperations<double>::add(magRateB, estSatRateMag, estSatRateMag, 3);
|
||||
VectorOperations<double>::add(estSatRateSun, estSatRateMag, estSatRate, 3);
|
||||
VectorOperations<double>::mulScalar(estSatRate, 0.5, estSatRate, 3);
|
||||
|
||||
// Full rate or estimate
|
||||
double estSatRate[3] = {0, 0, 0};
|
||||
double estSatRateMag[3] = {0, 0, 0}, estSatRateSun[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(susDirB, rateParaSun, estSatRateSun, 3);
|
||||
VectorOperations<double>::add(sunRateB, estSatRateSun, estSatRateSun, 3);
|
||||
VectorOperations<double>::mulScalar(magDirB, rateParaMag, estSatRateMag, 3);
|
||||
VectorOperations<double>::add(magRateB, estSatRateMag, estSatRateMag, 3);
|
||||
VectorOperations<double>::add(estSatRateSun, estSatRateMag, estSatRate, 3);
|
||||
VectorOperations<double>::mulScalar(estSatRate, 0.5, estSatRate, 3);
|
||||
/* Only valid if angle between sun direction and magnetic field direction
|
||||
is sufficiently large */
|
||||
|
||||
/* Only valid if angle between sun direction and magnetic field direction
|
||||
is sufficiently large */
|
||||
double sinAngle = 0;
|
||||
sinAngle = sin(acos(cos(cosAngleSunMag)));
|
||||
|
||||
double sinAngle = 0;
|
||||
sinAngle = sin(acos(cos(cosAngleSunMag)));
|
||||
if (!(sinAngle > sin(safeModeControllerParameters->sunMagAngleMin * M_PI / 180))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !(sinAngle > sin( safeModeControllerParameters->sunMagAngleMin * M_PI / 180))) {
|
||||
return;
|
||||
}
|
||||
// Rate for Torque Calculation
|
||||
double diffRate[3] = {0, 0, 0}; /* ADD TO MONITORING */
|
||||
VectorOperations<double>::subtract(estSatRate, satRateRef, diffRate, 3);
|
||||
|
||||
// Rate for Torque Calculation
|
||||
double diffRate[3] = {0, 0, 0}; /* ADD TO MONITORING */
|
||||
VectorOperations<double>::subtract(estSatRate, satRateRef, diffRate, 3);
|
||||
// Torque Align calculation
|
||||
double kRateNoMekf = 0, kAlignNoMekf = 0;
|
||||
kRateNoMekf = safeModeControllerParameters->k_rate_no_mekf;
|
||||
kAlignNoMekf = safeModeControllerParameters->k_align_no_mekf;
|
||||
|
||||
// Torque Align calculation
|
||||
double kRateNoMekf = 0, kAlignNoMekf = 0;
|
||||
kRateNoMekf = safeModeControllerParameters->k_rate_no_mekf;
|
||||
kAlignNoMekf = safeModeControllerParameters->k_align_no_mekf;
|
||||
double cosAngleAlignErr = VectorOperations<double>::dot(sunDirRef, susDirB);
|
||||
double crossSusSunRef[3] = {0, 0, 0};
|
||||
VectorOperations<double>::cross(sunDirRef, susDirB, crossSusSunRef);
|
||||
double sinAngleAlignErr = VectorOperations<double>::norm(crossSusSunRef, 3);
|
||||
|
||||
double cosAngleAlignErr = VectorOperations<double>::dot(sunDirRef, susDirB);
|
||||
double crossSusSunRef[3] = {0, 0, 0};
|
||||
VectorOperations<double>::cross(sunDirRef, susDirB, crossSusSunRef);
|
||||
double sinAngleAlignErr = VectorOperations<double>::norm(crossSusSunRef, 3);
|
||||
double torqueAlign[3] = {0, 0, 0};
|
||||
double angleAlignErr = acos(cosAngleAlignErr);
|
||||
double torqueAlignFactor = kAlignNoMekf * angleAlignErr / sinAngleAlignErr;
|
||||
VectorOperations<double>::mulScalar(crossSusSunRef, torqueAlignFactor, torqueAlign, 3);
|
||||
|
||||
double torqueAlign[3] = {0, 0, 0};
|
||||
double angleAlignErr = acos(cosAngleAlignErr);
|
||||
double torqueAlignFactor = kAlignNoMekf * angleAlignErr / sinAngleAlignErr;
|
||||
VectorOperations<double>::mulScalar(crossSusSunRef, torqueAlignFactor, torqueAlign, 3);
|
||||
// Torque Rate Calculations
|
||||
double torqueRate[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(diffRate, -kRateNoMekf, torqueRate, 3);
|
||||
|
||||
//Torque Rate Calculations
|
||||
double torqueRate[3] = {0, 0, 0};
|
||||
VectorOperations<double>::mulScalar(diffRate, -kRateNoMekf, torqueRate, 3);
|
||||
// Final torque
|
||||
double torqueB[3] = {0, 0, 0}, torqueAlignRate[3] = {0, 0, 0};
|
||||
VectorOperations<double>::add(torqueRate, torqueAlign, torqueAlignRate, 3);
|
||||
MatrixOperations<double>::multiply(*(inertiaEIVE->inertiaMatrix), torqueAlignRate, torqueB, 3, 3,
|
||||
1);
|
||||
|
||||
//Final torque
|
||||
double torqueB[3] = {0, 0, 0}, torqueAlignRate[3] = {0, 0, 0};
|
||||
VectorOperations<double>::add(torqueRate, torqueAlign, torqueAlignRate, 3);
|
||||
MatrixOperations<double>::multiply(*(inertiaEIVE->inertiaMatrix), torqueAlignRate, torqueB, 3, 3, 1);
|
||||
|
||||
//Magnetic moment
|
||||
double magMomB[3] = {0, 0, 0};
|
||||
double crossMagFieldTorque[3] = {0, 0, 0};
|
||||
VectorOperations<double>::cross(magFieldB, torqueB, crossMagFieldTorque);
|
||||
double magMomFactor = pow( VectorOperations<double>::norm(magFieldB, 3), 2 );
|
||||
VectorOperations<double>::mulScalar(crossMagFieldTorque, 1/magMomFactor, magMomB, 3);
|
||||
|
||||
outputMagMomB[0] = magMomB[0];
|
||||
outputMagMomB[1] = magMomB[1];
|
||||
outputMagMomB[2] = magMomB[2];
|
||||
|
||||
*outputValid = true;
|
||||
// Magnetic moment
|
||||
double magMomB[3] = {0, 0, 0};
|
||||
double crossMagFieldTorque[3] = {0, 0, 0};
|
||||
VectorOperations<double>::cross(magFieldB, torqueB, crossMagFieldTorque);
|
||||
double magMomFactor = pow(VectorOperations<double>::norm(magFieldB, 3), 2);
|
||||
VectorOperations<double>::mulScalar(crossMagFieldTorque, 1 / magMomFactor, magMomB, 3);
|
||||
|
||||
std::memcpy(outputMagMomB, magMomB, 3 * sizeof(double));
|
||||
*outputAngle = angleAlignErr;
|
||||
*outputValid = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,57 +8,45 @@
|
||||
#ifndef SAFECTRL_H_
|
||||
#define SAFECTRL_H_
|
||||
|
||||
#include "../SensorValues.h"
|
||||
#include "../OutputValues.h"
|
||||
#include "../AcsParameters.h"
|
||||
#include "../config/classIds.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include "../AcsParameters.h"
|
||||
#include "../SensorValues.h"
|
||||
#include "../config/classIds.h"
|
||||
|
||||
class SafeCtrl{
|
||||
class SafeCtrl {
|
||||
public:
|
||||
SafeCtrl(AcsParameters *acsParameters_);
|
||||
virtual ~SafeCtrl();
|
||||
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::SAFE;
|
||||
static const ReturnValue_t SAFECTRL_MEKF_INPUT_INVALID = MAKE_RETURN_CODE(0x01);
|
||||
|
||||
SafeCtrl(AcsParameters *acsParameters_);
|
||||
virtual ~SafeCtrl();
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::SAFE;
|
||||
static const ReturnValue_t SAFECTRL_MEKF_INPUT_INVALID = MAKE_RETURN_CODE(0x01);
|
||||
ReturnValue_t safeMekf(timeval now, double *quatBJ, bool quatBJValid, double *magFieldModel,
|
||||
bool magFieldModelValid, double *sunDirModel, bool sunDirModelValid,
|
||||
double *satRateMekf, bool rateMekfValid, double *sunDirRef,
|
||||
double *satRatRef, // From Guidance (!)
|
||||
double *outputAngle, double *outputMagMomB, bool *outputValid);
|
||||
|
||||
void loadAcsParameters(AcsParameters *acsParameters_);
|
||||
void safeNoMekf(timeval now, double *susDirB, bool susDirBValid, double *sunRateB,
|
||||
bool sunRateBValid, double *magFieldB, bool magFieldBValid, double *magRateB,
|
||||
bool magRateBValid, double *sunDirRef, double *satRateRef, double *outputAngle,
|
||||
double *outputMagMomB, bool *outputValid);
|
||||
|
||||
ReturnValue_t safeMekf(timeval now, double *quatBJ, bool *quatBJValid,
|
||||
double *magFieldModel, bool *magFieldModelValid,
|
||||
double *sunDirModel, bool *sunDirModelValid,
|
||||
double *satRateMekf, bool *rateMekfValid,
|
||||
double *sunDirRef, double *satRatRef, // From Guidance (!)
|
||||
double *outputMagMomB, bool *outputValid);
|
||||
void idleSunPointing(); // with reaction wheels
|
||||
|
||||
void safeNoMekf(timeval now, double *susDirB, bool *susDirBValid,
|
||||
double *sunRateB, bool *sunRateBValid,
|
||||
double *magFieldB, bool *magFieldBValid,
|
||||
double *magRateB, bool *magRateBValid,
|
||||
double *sunDirRef, double *satRateRef,
|
||||
double *outputMagMomB, bool *outputValid);
|
||||
|
||||
void idleSunPointing(); // with reaction wheels
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
AcsParameters::SafeModeControllerParameters* safeModeControllerParameters;
|
||||
AcsParameters::InertiaEIVE* inertiaEIVE;
|
||||
double gainMatrixInertia[3][3];
|
||||
|
||||
double magFieldBState[3];
|
||||
timeval magFieldBStateTime;
|
||||
protected:
|
||||
private:
|
||||
AcsParameters::SafeModeControllerParameters *safeModeControllerParameters;
|
||||
AcsParameters::InertiaEIVE *inertiaEIVE;
|
||||
double gainMatrixInertia[3][3];
|
||||
|
||||
double magFieldBState[3];
|
||||
timeval magFieldBStateTime;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* ACS_CONTROL_SAFECTRL_H_ */
|
||||
|
||||
|
@ -8,95 +8,91 @@
|
||||
#ifndef CHOLESKYDECOMPOSITION_H_
|
||||
#define CHOLESKYDECOMPOSITION_H_
|
||||
#include <math.h>
|
||||
//typedef unsigned int uint8_t;
|
||||
// typedef unsigned int uint8_t;
|
||||
|
||||
template<typename T1, typename T2=T1, typename T3=T2>
|
||||
template <typename T1, typename T2 = T1, typename T3 = T2>
|
||||
class CholeskyDecomposition {
|
||||
public:
|
||||
static int invertCholesky(T1 *matrix, T2 *result, T3 *tempMatrix, const uint8_t dimension)
|
||||
{
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
return cholsl(matrix, result, tempMatrix, dimension);
|
||||
}
|
||||
private:
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t choldc1(double * a, double * p, uint8_t n) {
|
||||
int8_t i,j,k;
|
||||
double sum;
|
||||
public:
|
||||
static int invertCholesky(T1 *matrix, T2 *result, T3 *tempMatrix, const uint8_t dimension) {
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
return cholsl(matrix, result, tempMatrix, dimension);
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = i; j < n; j++) {
|
||||
sum = a[i*n+j];
|
||||
for (k = i - 1; k >= 0; k--) {
|
||||
sum -= a[i*n+k] * a[j*n+k];
|
||||
}
|
||||
if (i == j) {
|
||||
if (sum <= 0) {
|
||||
return 1; /* error */
|
||||
}
|
||||
p[i] = sqrt(sum);
|
||||
}
|
||||
else {
|
||||
a[j*n+i] = sum / p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t choldc1(double *a, double *p, uint8_t n) {
|
||||
int8_t i, j, k;
|
||||
double sum;
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = i; j < n; j++) {
|
||||
sum = a[i * n + j];
|
||||
for (k = i - 1; k >= 0; k--) {
|
||||
sum -= a[i * n + k] * a[j * n + k];
|
||||
}
|
||||
if (i == j) {
|
||||
if (sum <= 0) {
|
||||
return 1; /* error */
|
||||
}
|
||||
p[i] = sqrt(sum);
|
||||
} else {
|
||||
a[j * n + i] = sum / p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t choldcsl(double * A, double * a, double * p, uint8_t n)
|
||||
{
|
||||
uint8_t i,j,k; double sum;
|
||||
for (i = 0; i < n; i++)
|
||||
for (j = 0; j < n; j++)
|
||||
a[i*n+j] = A[i*n+j];
|
||||
if (choldc1(a, p, n)) return 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i*n+i] = 1 / p[i];
|
||||
for (j = i + 1; j < n; j++) {
|
||||
sum = 0;
|
||||
for (k = i; k < j; k++) {
|
||||
sum -= a[j*n+k] * a[k*n+i];
|
||||
}
|
||||
a[j*n+i] = sum / p[j];
|
||||
}
|
||||
}
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t choldcsl(double *A, double *a, double *p, uint8_t n) {
|
||||
uint8_t i, j, k;
|
||||
double sum;
|
||||
for (i = 0; i < n; i++)
|
||||
for (j = 0; j < n; j++) a[i * n + j] = A[i * n + j];
|
||||
if (choldc1(a, p, n)) return 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i * n + i] = 1 / p[i];
|
||||
for (j = i + 1; j < n; j++) {
|
||||
sum = 0;
|
||||
for (k = i; k < j; k++) {
|
||||
sum -= a[j * n + k] * a[k * n + i];
|
||||
}
|
||||
a[j * n + i] = sum / p[j];
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t cholsl(double * A,double * a,double * p, uint8_t n)
|
||||
{
|
||||
uint8_t i,j,k;
|
||||
if (choldcsl(A,a,p,n)) return 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = i + 1; j < n; j++) {
|
||||
a[i*n+j] = 0.0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i*n+i] *= a[i*n+i];
|
||||
for (k = i + 1; k < n; k++) {
|
||||
a[i*n+i] += a[k*n+i] * a[k*n+i];
|
||||
}
|
||||
for (j = i + 1; j < n; j++) {
|
||||
for (k = j; k < n; k++) {
|
||||
a[i*n+j] += a[k*n+i] * a[k*n+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < i; j++) {
|
||||
a[i*n+j] = a[j*n+i];
|
||||
}
|
||||
}
|
||||
// https://github.com/simondlevy/TinyEKF/blob/master/tiny_ekf.c
|
||||
static uint8_t cholsl(double *A, double *a, double *p, uint8_t n) {
|
||||
uint8_t i, j, k;
|
||||
if (choldcsl(A, a, p, n)) return 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = i + 1; j < n; j++) {
|
||||
a[i * n + j] = 0.0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i * n + i] *= a[i * n + i];
|
||||
for (k = i + 1; k < n; k++) {
|
||||
a[i * n + i] += a[k * n + i] * a[k * n + i];
|
||||
}
|
||||
for (j = i + 1; j < n; j++) {
|
||||
for (k = j; k < n; k++) {
|
||||
a[i * n + j] += a[k * n + i] * a[k * n + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < i; j++) {
|
||||
a[i * n + j] = a[j * n + i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
return 0; /* success */
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* CONTRIB_MATH_CHOLESKYDECOMPOSITION_H_ */
|
||||
|
@ -1,107 +1,97 @@
|
||||
/*
|
||||
* MathOperations.h
|
||||
*
|
||||
* Created on: 3 Mar 2022
|
||||
* Author: rooob
|
||||
*/
|
||||
|
||||
#ifndef MATH_MATHOPERATIONS_H_
|
||||
#define MATH_MATHOPERATIONS_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <fsfw/src/fsfw/globalfunctions/constants.h>
|
||||
#include <fsfw/src/fsfw/globalfunctions/math/MatrixOperations.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace Math;
|
||||
|
||||
template<typename T1, typename T2 = T1>
|
||||
template <typename T1, typename T2 = T1>
|
||||
class MathOperations {
|
||||
public:
|
||||
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;
|
||||
}
|
||||
static void vecTransposeVecMatrix(const T1 vector1[], const T1 transposeVector2[],
|
||||
T2 *result, uint8_t size = 3) {
|
||||
// Looks like MatrixOpertions::multiply is able to do the same thing
|
||||
for (uint8_t resultColumn = 0; resultColumn < size; resultColumn++) {
|
||||
for (uint8_t resultRow = 0; resultRow < size; resultRow++) {
|
||||
result[resultColumn + size * resultRow] = vector1[resultRow]
|
||||
* transposeVector2[resultColumn];
|
||||
public:
|
||||
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;
|
||||
}
|
||||
static void vecTransposeVecMatrix(const T1 vector1[], const T1 transposeVector2[], T2 *result,
|
||||
uint8_t size = 3) {
|
||||
// Looks like MatrixOpertions::multiply is able to do the same thing
|
||||
for (uint8_t resultColumn = 0; resultColumn < size; resultColumn++) {
|
||||
for (uint8_t resultRow = 0; resultRow < size; resultRow++) {
|
||||
result[resultColumn + size * resultRow] =
|
||||
vector1[resultRow] * transposeVector2[resultColumn];
|
||||
}
|
||||
}
|
||||
/*matrixSun[i][j] = sunEstB[i] * sunEstB[j];
|
||||
matrixMag[i][j] = magEstB[i] * magEstB[j];
|
||||
matrixSunMag[i][j] = sunEstB[i] * magEstB[j];
|
||||
matrixMagSun[i][j] = magEstB[i] * sunEstB[j];*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*matrixSun[i][j] = sunEstB[i] * sunEstB[j];
|
||||
matrixMag[i][j] = magEstB[i] * magEstB[j];
|
||||
matrixSunMag[i][j] = sunEstB[i] * magEstB[j];
|
||||
matrixMagSun[i][j] = magEstB[i] * sunEstB[j];*/
|
||||
}
|
||||
|
||||
static void selectionSort(const T1 *matrix, T1 *result, uint8_t rowSize,
|
||||
uint8_t colSize) {
|
||||
int min_idx;
|
||||
T1 temp;
|
||||
memcpy(result, matrix, rowSize * colSize * sizeof(*result));
|
||||
// One by one move boundary of unsorted subarray
|
||||
for (int k = 0; k < rowSize; k++) {
|
||||
for (int i = 0; i < colSize - 1; i++) {
|
||||
// Find the minimum element in unsorted array
|
||||
min_idx = i;
|
||||
for (int j = i + 1; j < colSize; j++) {
|
||||
if (result[j + k * colSize]
|
||||
< result[min_idx + k * colSize]) {
|
||||
min_idx = j;
|
||||
}
|
||||
}
|
||||
// Swap the found minimum element with the first element
|
||||
temp = result[i + k * colSize];
|
||||
result[i + k * colSize] = result[min_idx + k * colSize];
|
||||
result[min_idx + k * colSize] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void selectionSort(const T1 *matrix, T1 *result, uint8_t rowSize, uint8_t colSize) {
|
||||
int min_idx;
|
||||
T1 temp;
|
||||
memcpy(result, matrix, rowSize * colSize * sizeof(*result));
|
||||
// One by one move boundary of unsorted subarray
|
||||
for (int k = 0; k < rowSize; k++) {
|
||||
for (int i = 0; i < colSize - 1; i++) {
|
||||
// Find the minimum element in unsorted array
|
||||
min_idx = i;
|
||||
for (int j = i + 1; j < colSize; j++) {
|
||||
if (result[j + k * colSize] < result[min_idx + k * colSize]) {
|
||||
min_idx = j;
|
||||
}
|
||||
}
|
||||
// Swap the found minimum element with the first element
|
||||
temp = result[i + k * colSize];
|
||||
result[i + k * colSize] = result[min_idx + k * colSize];
|
||||
result[min_idx + k * colSize] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void convertDateToJD2000(const T1 time, T2 julianDate){
|
||||
|
||||
// time = { Y, M, D, h, m,s}
|
||||
// time in sec and microsec -> The Epoch (unixtime)
|
||||
julianDate = 1721013.5 + 367*time[0]- floor(7/4*(time[0]+(time[1]+9)/12))
|
||||
+floor(275*time[1]/9)+time[2]+(60*time[3]+time[4]+(time(5)/60))/1440;
|
||||
}
|
||||
|
||||
static T1 convertUnixToJD2000(timeval time){
|
||||
//time = {{s},{us}}
|
||||
T1 julianDate2000;
|
||||
julianDate2000 = (time.tv_sec/86400.0)+2440587.5-2451545;
|
||||
return julianDate2000;
|
||||
}
|
||||
static T1 convertUnixToJD2000(timeval time) {
|
||||
// time = {{s},{us}}
|
||||
T1 julianDate2000;
|
||||
julianDate2000 = (time.tv_sec / 86400.0) + 2440587.5 - 2451545;
|
||||
return julianDate2000;
|
||||
}
|
||||
|
||||
static void dcmFromQuat(const T1 vector[], T1 *outputDcm){
|
||||
// convention q = [qx,qy,qz, qw]
|
||||
outputDcm[0] = pow(vector[0],2) - pow(vector[1],2) - pow(vector[2],2) + pow(vector[3],2);
|
||||
outputDcm[1] = 2*(vector[0]*vector[1] + vector[2]*vector[3]);
|
||||
outputDcm[2] = 2*(vector[0]*vector[2] - vector[1]*vector[3]);
|
||||
static void dcmFromQuat(const T1 vector[], T1 *outputDcm) {
|
||||
// convention q = [qx,qy,qz, qw]
|
||||
outputDcm[0] = pow(vector[0], 2) - pow(vector[1], 2) - pow(vector[2], 2) + pow(vector[3], 2);
|
||||
outputDcm[1] = 2 * (vector[0] * vector[1] + vector[2] * vector[3]);
|
||||
outputDcm[2] = 2 * (vector[0] * vector[2] - vector[1] * vector[3]);
|
||||
|
||||
outputDcm[3] = 2*(vector[1]*vector[0] - vector[2]*vector[3]);
|
||||
outputDcm[4] = -pow(vector[0],2) + pow(vector[1],2) - pow(vector[2],2) + pow(vector[3],2);
|
||||
outputDcm[5] = 2*(vector[1]*vector[2] + vector[0]*vector[3]);
|
||||
outputDcm[3] = 2 * (vector[1] * vector[0] - vector[2] * vector[3]);
|
||||
outputDcm[4] = -pow(vector[0], 2) + pow(vector[1], 2) - pow(vector[2], 2) + pow(vector[3], 2);
|
||||
outputDcm[5] = 2 * (vector[1] * vector[2] + vector[0] * vector[3]);
|
||||
|
||||
outputDcm[6] = 2*(vector[2]*vector[0] + vector[1]*vector[3]);
|
||||
outputDcm[7] = 2*(vector[2]*vector[1] - vector[0]*vector[3]);
|
||||
outputDcm[8] = -pow(vector[0],2) - pow(vector[1],2) + pow(vector[2],2) + pow(vector[3],2);
|
||||
|
||||
}
|
||||
outputDcm[6] = 2 * (vector[2] * vector[0] + vector[1] * vector[3]);
|
||||
outputDcm[7] = 2 * (vector[2] * vector[1] - vector[0] * vector[3]);
|
||||
outputDcm[8] = -pow(vector[0], 2) - pow(vector[1], 2) + pow(vector[2], 2) + pow(vector[3], 2);
|
||||
}
|
||||
|
||||
static void cartesianFromLatLongAlt(const T1 lat, const T1 longi, const T1 alt, T2 *cartesianOutput){
|
||||
/* @brief: cartesianFromLatLongAlt() - calculates cartesian coordinates in ECEF from latitude,
|
||||
@ -123,7 +113,6 @@ public:
|
||||
cartesianOutput[2] = ((1 - pow(eccentricity,2)) * auxRadius + alt) * sin(lat);
|
||||
|
||||
}
|
||||
|
||||
static void dcmEJ(timeval time, T1 * outputDcmEJ, T1 * outputDotDcmEJ){
|
||||
/* @brief: dcmEJ() - calculates the transformation matrix between ECEF and ECI frame
|
||||
* @param: time Current time
|
||||
@ -142,26 +131,26 @@ public:
|
||||
JD2000Floor += 0.5;
|
||||
}
|
||||
|
||||
double JC2000 = JD2000Floor / 36525;
|
||||
double sec = (JD2000 - JD2000Floor) * 86400;
|
||||
double gmst = 0; //greenwich mean sidereal time
|
||||
gmst = 24110.54841 + 8640184.812866 * JC2000 + 0.093104 * pow(JC2000,2) -
|
||||
0.0000062 * pow(JC2000,3) + 1.002737909350795 * sec;
|
||||
double rest = gmst / 86400;
|
||||
double FloorRest = floor(rest);
|
||||
double secOfDay = rest-FloorRest;
|
||||
secOfDay *= 86400;
|
||||
gmst = secOfDay / 240 * PI / 180;
|
||||
double JC2000 = JD2000Floor / 36525;
|
||||
double sec = (JD2000 - JD2000Floor) * 86400;
|
||||
double gmst = 0; // greenwich mean sidereal time
|
||||
gmst = 24110.54841 + 8640184.812866 * JC2000 + 0.093104 * pow(JC2000, 2) -
|
||||
0.0000062 * pow(JC2000, 3) + 1.002737909350795 * sec;
|
||||
double rest = gmst / 86400;
|
||||
double FloorRest = floor(rest);
|
||||
double secOfDay = rest - FloorRest;
|
||||
secOfDay *= 86400;
|
||||
gmst = secOfDay / 240 * PI / 180;
|
||||
|
||||
outputDcmEJ[0] = cos(gmst);
|
||||
outputDcmEJ[1] = sin(gmst);
|
||||
outputDcmEJ[2] = 0;
|
||||
outputDcmEJ[3] = -sin(gmst);
|
||||
outputDcmEJ[4] = cos(gmst);
|
||||
outputDcmEJ[5] = 0;
|
||||
outputDcmEJ[6] = 0;
|
||||
outputDcmEJ[7] = 0;
|
||||
outputDcmEJ[8] = 1;
|
||||
outputDcmEJ[0] = cos(gmst);
|
||||
outputDcmEJ[1] = sin(gmst);
|
||||
outputDcmEJ[2] = 0;
|
||||
outputDcmEJ[3] = -sin(gmst);
|
||||
outputDcmEJ[4] = cos(gmst);
|
||||
outputDcmEJ[5] = 0;
|
||||
outputDcmEJ[6] = 0;
|
||||
outputDcmEJ[7] = 0;
|
||||
outputDcmEJ[8] = 1;
|
||||
|
||||
// Derivative of dmcEJ WITHOUT PRECISSION AND NUTATION
|
||||
double dcmEJCalc[3][3] = {{outputDcmEJ[0], outputDcmEJ[1], outputDcmEJ[2]},
|
||||
@ -172,8 +161,8 @@ public:
|
||||
double dotDcmEJ[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
|
||||
MatrixOperations<double>::multiply(*dcmDot, *dcmEJCalc, *dotDcmEJ, 3, 3, 3);
|
||||
MatrixOperations<double>::multiplyScalar(*dotDcmEJ, omegaEarth, outputDotDcmEJ, 3, 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* @brief: ecfToEciWithNutPre() - calculates the transformation matrix between ECEF and ECI frame
|
||||
* give also the back the derivative of this matrix
|
||||
@ -259,7 +248,7 @@ public:
|
||||
double de = 9.203 * arcsecFactor *cos(Om);
|
||||
|
||||
// % true obliquity of the ecliptic eps p.71 (simplified)
|
||||
double e = 23.43929111 * PI / 180 - 46.8150 / 3600 * JC2000TT * PI / 180;;
|
||||
double e = 23.43929111 * PI / 180 - 46.8150 / 3600 * JC2000TT * PI / 180;
|
||||
|
||||
nutation[0][0]=cos(dp);
|
||||
nutation[1][0]=cos(e+de)*sin(dp);
|
||||
@ -290,9 +279,7 @@ public:
|
||||
MatrixOperations<double>::multiply(*nutationPrecession, *thetaDot, outputDotDcmEJ, 3, 3, 3);
|
||||
|
||||
}
|
||||
|
||||
static void inverseMatrixDimThree(const T1 *matrix, T1 * output){
|
||||
|
||||
int i,j;
|
||||
double determinant;
|
||||
double mat[3][3] = {{matrix[0], matrix[1], matrix[2]},{matrix[3], matrix[4], matrix[5]},
|
||||
@ -310,6 +297,113 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static float matrixDeterminant(const T1 *inputMatrix, uint8_t size) {
|
||||
float det = 0;
|
||||
T1 matrix[size][size], submatrix[size - 1][size - 1];
|
||||
for (uint8_t row = 0; row < size; row++) {
|
||||
for (uint8_t col = 0; col < size; col++) {
|
||||
matrix[row][col] = inputMatrix[row * size + col];
|
||||
}
|
||||
}
|
||||
if (size == 2)
|
||||
return ((matrix[0][0] * matrix[1][1]) - (matrix[1][0] * matrix[0][1]));
|
||||
else {
|
||||
for (uint8_t col = 0; col < size; col++) {
|
||||
int subRow = 0;
|
||||
for (uint8_t rowIndex = 1; rowIndex < size; rowIndex++) {
|
||||
int subCol = 0;
|
||||
for (uint8_t colIndex = 0; colIndex < size; colIndex++) {
|
||||
if (colIndex == col) continue;
|
||||
submatrix[subRow][subCol] = matrix[rowIndex][colIndex];
|
||||
subCol++;
|
||||
}
|
||||
subRow++;
|
||||
}
|
||||
det += (pow(-1, col) * matrix[0][col] *
|
||||
MathOperations<T1>::matrixDeterminant(*submatrix, size - 1));
|
||||
}
|
||||
}
|
||||
return det;
|
||||
}
|
||||
|
||||
static int inverseMatrix(const T1 *inputMatrix, T1 *inverse, uint8_t size) {
|
||||
if (MathOperations<T1>::matrixDeterminant(inputMatrix, size) == 0) {
|
||||
return 1; // Matrix is singular and not invertible
|
||||
}
|
||||
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
|
||||
// should not be needed as such a matrix has a det=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 1; // 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 1; // 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 0; // successful inversion
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ACS_MATH_MATHOPERATIONS_H_ */
|
||||
|
@ -0,0 +1,14 @@
|
||||
#ifndef MISSION_CONTROLLER_CONTROLLERDEFINITIONS_ACSCONTROLLERDEFINITIONS_H_
|
||||
#define MISSION_CONTROLLER_CONTROLLERDEFINITIONS_ACSCONTROLLERDEFINITIONS_H_
|
||||
|
||||
#include <fsfw/modes/HasModesIF.h>
|
||||
|
||||
namespace acs {
|
||||
|
||||
enum CtrlModes { OFF = HasModesIF::MODE_OFF, SAFE = 1, DETUMBLE = 2, IDLE = 3, TARGET_PT = 4 };
|
||||
|
||||
static constexpr Submode_t IDLE_CHARGE = 1;
|
||||
|
||||
} // namespace acs
|
||||
|
||||
#endif /* MISSION_CONTROLLER_CONTROLLERDEFINITIONS_ACSCONTROLLERDEFINITIONS_H_ */
|
@ -8,16 +8,37 @@
|
||||
|
||||
namespace acsctrl {
|
||||
|
||||
enum SetIds : uint32_t { MGM_SENSOR_DATA, SUS_SENSOR_DATA };
|
||||
enum SetIds : uint32_t {
|
||||
MGM_SENSOR_DATA,
|
||||
MGM_PROCESSED_DATA,
|
||||
SUS_SENSOR_DATA,
|
||||
SUS_PROCESSED_DATA,
|
||||
GYR_SENSOR_DATA,
|
||||
GYR_PROCESSED_DATA,
|
||||
GPS_PROCESSED_DATA,
|
||||
MEKF_DATA,
|
||||
CTRL_VAL_DATA,
|
||||
ACTUATOR_CMD_DATA
|
||||
};
|
||||
|
||||
enum PoolIds : lp_id_t {
|
||||
// MGM Raw
|
||||
MGM_0_LIS3_UT,
|
||||
MGM_1_RM3100_UT,
|
||||
MGM_2_LIS3_UT,
|
||||
MGM_3_RM3100_UT,
|
||||
MGM_IMTQ_CAL_NT,
|
||||
MGM_IMTQ_CAL_ACT_STATUS,
|
||||
|
||||
// MGM Processed
|
||||
MGM_0_VEC,
|
||||
MGM_1_VEC,
|
||||
MGM_2_VEC,
|
||||
MGM_3_VEC,
|
||||
MGM_4_VEC,
|
||||
MGM_VEC_TOT,
|
||||
MGM_VEC_TOT_DERIVATIVE,
|
||||
MAG_IGRF_MODEL,
|
||||
// SUS Raw
|
||||
SUS_0_N_LOC_XFYFZM_PT_XF,
|
||||
SUS_6_R_LOC_XFYBZM_PT_XF,
|
||||
|
||||
@ -35,15 +56,64 @@ enum PoolIds : lp_id_t {
|
||||
|
||||
SUS_5_N_LOC_XFYMZB_PT_ZB,
|
||||
SUS_11_R_LOC_XBYMZB_PT_ZB,
|
||||
// SUS Processed
|
||||
SUS_0_VEC,
|
||||
SUS_1_VEC,
|
||||
SUS_2_VEC,
|
||||
SUS_3_VEC,
|
||||
SUS_4_VEC,
|
||||
SUS_5_VEC,
|
||||
SUS_6_VEC,
|
||||
SUS_7_VEC,
|
||||
SUS_8_VEC,
|
||||
SUS_9_VEC,
|
||||
SUS_10_VEC,
|
||||
SUS_11_VEC,
|
||||
SUS_VEC_TOT,
|
||||
SUS_VEC_TOT_DERIVATIVE,
|
||||
SUN_IJK_MODEL,
|
||||
// GYR Raw
|
||||
GYR_0_ADIS,
|
||||
GYR_1_L3,
|
||||
GYR_2_ADIS,
|
||||
GYR_3_L3,
|
||||
// GYR Processed
|
||||
GYR_0_VEC,
|
||||
GYR_1_VEC,
|
||||
GYR_2_VEC,
|
||||
GYR_3_VEC,
|
||||
GYR_VEC_TOT,
|
||||
// GPS Processed
|
||||
GC_LATITUDE,
|
||||
GD_LONGITUDE,
|
||||
// MEKF
|
||||
SAT_ROT_RATE_MEKF,
|
||||
QUAT_MEKF,
|
||||
// Ctrl Values
|
||||
TGT_QUAT,
|
||||
ERROR_QUAT,
|
||||
ERROR_ANG,
|
||||
// Actuator Cmd
|
||||
RW_TARGET_TORQUE,
|
||||
RW_TARGET_SPEED,
|
||||
MTQ_TARGET_DIPOLE,
|
||||
};
|
||||
|
||||
static constexpr uint8_t MGM_SET_ENTRIES = 10;
|
||||
static constexpr uint8_t SUS_SET_ENTRIES = 12;
|
||||
static constexpr uint8_t MGM_SET_RAW_ENTRIES = 10;
|
||||
static constexpr uint8_t MGM_SET_PROCESSED_ENTRIES = 8;
|
||||
static constexpr uint8_t SUS_SET_RAW_ENTRIES = 12;
|
||||
static constexpr uint8_t SUS_SET_PROCESSED_ENTRIES = 15;
|
||||
static constexpr uint8_t GYR_SET_RAW_ENTRIES = 4;
|
||||
static constexpr uint8_t GYR_SET_PROCESSED_ENTRIES = 5;
|
||||
static constexpr uint8_t GPS_SET_PROCESSED_ENTRIES = 2;
|
||||
static constexpr uint8_t MEKF_SET_ENTRIES = 2;
|
||||
static constexpr uint8_t CTRL_VAL_SET_ENTRIES = 3;
|
||||
static constexpr uint8_t ACT_CMD_SET_ENTRIES = 3;
|
||||
|
||||
/**
|
||||
* @brief Raw MGM sensor data. Includes the IMTQ sensor data and actuator status.
|
||||
*/
|
||||
class MgmDataRaw : public StaticLocalDataSet<MGM_SET_ENTRIES> {
|
||||
class MgmDataRaw : public StaticLocalDataSet<MGM_SET_RAW_ENTRIES> {
|
||||
public:
|
||||
MgmDataRaw(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, MGM_SENSOR_DATA) {}
|
||||
|
||||
@ -60,7 +130,24 @@ class MgmDataRaw : public StaticLocalDataSet<MGM_SET_ENTRIES> {
|
||||
private:
|
||||
};
|
||||
|
||||
class SusDataRaw : public StaticLocalDataSet<SUS_SET_ENTRIES> {
|
||||
class MgmDataProcessed : public StaticLocalDataSet<MGM_SET_PROCESSED_ENTRIES> {
|
||||
public:
|
||||
MgmDataProcessed(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, MGM_PROCESSED_DATA) {}
|
||||
|
||||
lp_vec_t<float, 3> mgm0vec = lp_vec_t<float, 3>(sid.objectId, MGM_0_VEC, this);
|
||||
lp_vec_t<float, 3> mgm1vec = lp_vec_t<float, 3>(sid.objectId, MGM_1_VEC, this);
|
||||
lp_vec_t<float, 3> mgm2vec = lp_vec_t<float, 3>(sid.objectId, MGM_2_VEC, this);
|
||||
lp_vec_t<float, 3> mgm3vec = lp_vec_t<float, 3>(sid.objectId, MGM_3_VEC, this);
|
||||
lp_vec_t<float, 3> mgm4vec = lp_vec_t<float, 3>(sid.objectId, MGM_4_VEC, this);
|
||||
lp_vec_t<double, 3> mgmVecTot = lp_vec_t<double, 3>(sid.objectId, MGM_VEC_TOT, this);
|
||||
lp_vec_t<double, 3> mgmVecTotDerivative =
|
||||
lp_vec_t<double, 3>(sid.objectId, MGM_VEC_TOT_DERIVATIVE, this);
|
||||
lp_vec_t<double, 3> magIgrfModel = lp_vec_t<double, 3>(sid.objectId, MAG_IGRF_MODEL, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class SusDataRaw : public StaticLocalDataSet<SUS_SET_RAW_ENTRIES> {
|
||||
public:
|
||||
SusDataRaw(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, SUS_SENSOR_DATA) {}
|
||||
|
||||
@ -74,8 +161,102 @@ class SusDataRaw : public StaticLocalDataSet<SUS_SET_ENTRIES> {
|
||||
lp_vec_t<uint16_t, 6> sus7 = lp_vec_t<uint16_t, 6>(sid.objectId, SUS_7_R_LOC_XBYBZM_PT_XB, this);
|
||||
lp_vec_t<uint16_t, 6> sus8 = lp_vec_t<uint16_t, 6>(sid.objectId, SUS_8_R_LOC_XBYBZB_PT_YB, this);
|
||||
lp_vec_t<uint16_t, 6> sus9 = lp_vec_t<uint16_t, 6>(sid.objectId, SUS_9_R_LOC_XBYBZB_PT_YF, this);
|
||||
lp_vec_t<uint16_t, 6> sus10 = lp_vec_t<uint16_t, 6>(sid.objectId, SUS_10_N_LOC_XMYBZF_PT_ZF, this);
|
||||
lp_vec_t<uint16_t, 6> sus11 = lp_vec_t<uint16_t, 6>(sid.objectId, SUS_11_R_LOC_XBYMZB_PT_ZB, this);
|
||||
lp_vec_t<uint16_t, 6> sus10 =
|
||||
lp_vec_t<uint16_t, 6>(sid.objectId, SUS_10_N_LOC_XMYBZF_PT_ZF, this);
|
||||
lp_vec_t<uint16_t, 6> sus11 =
|
||||
lp_vec_t<uint16_t, 6>(sid.objectId, SUS_11_R_LOC_XBYMZB_PT_ZB, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class SusDataProcessed : public StaticLocalDataSet<SUS_SET_PROCESSED_ENTRIES> {
|
||||
public:
|
||||
SusDataProcessed(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, SUS_PROCESSED_DATA) {}
|
||||
|
||||
lp_vec_t<float, 3> sus0vec = lp_vec_t<float, 3>(sid.objectId, SUS_0_VEC, this);
|
||||
lp_vec_t<float, 3> sus1vec = lp_vec_t<float, 3>(sid.objectId, SUS_1_VEC, this);
|
||||
lp_vec_t<float, 3> sus2vec = lp_vec_t<float, 3>(sid.objectId, SUS_2_VEC, this);
|
||||
lp_vec_t<float, 3> sus3vec = lp_vec_t<float, 3>(sid.objectId, SUS_3_VEC, this);
|
||||
lp_vec_t<float, 3> sus4vec = lp_vec_t<float, 3>(sid.objectId, SUS_4_VEC, this);
|
||||
lp_vec_t<float, 3> sus5vec = lp_vec_t<float, 3>(sid.objectId, SUS_5_VEC, this);
|
||||
lp_vec_t<float, 3> sus6vec = lp_vec_t<float, 3>(sid.objectId, SUS_6_VEC, this);
|
||||
lp_vec_t<float, 3> sus7vec = lp_vec_t<float, 3>(sid.objectId, SUS_7_VEC, this);
|
||||
lp_vec_t<float, 3> sus8vec = lp_vec_t<float, 3>(sid.objectId, SUS_8_VEC, this);
|
||||
lp_vec_t<float, 3> sus9vec = lp_vec_t<float, 3>(sid.objectId, SUS_8_VEC, this);
|
||||
lp_vec_t<float, 3> sus10vec = lp_vec_t<float, 3>(sid.objectId, SUS_8_VEC, this);
|
||||
lp_vec_t<float, 3> sus11vec = lp_vec_t<float, 3>(sid.objectId, SUS_8_VEC, this);
|
||||
lp_vec_t<double, 3> susVecTot = lp_vec_t<double, 3>(sid.objectId, SUS_VEC_TOT, this);
|
||||
lp_vec_t<double, 3> susVecTotDerivative =
|
||||
lp_vec_t<double, 3>(sid.objectId, SUS_VEC_TOT_DERIVATIVE, this);
|
||||
lp_vec_t<double, 3> sunIjkModel = lp_vec_t<double, 3>(sid.objectId, SUN_IJK_MODEL, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class GyrDataRaw : public StaticLocalDataSet<GYR_SET_RAW_ENTRIES> {
|
||||
public:
|
||||
GyrDataRaw(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, GYR_SENSOR_DATA) {}
|
||||
|
||||
lp_vec_t<double, 3> gyr0Adis = lp_vec_t<double, 3>(sid.objectId, GYR_0_ADIS, this);
|
||||
lp_vec_t<float, 3> gyr1L3 = lp_vec_t<float, 3>(sid.objectId, GYR_1_L3, this);
|
||||
lp_vec_t<double, 3> gyr2Adis = lp_vec_t<double, 3>(sid.objectId, GYR_2_ADIS, this);
|
||||
lp_vec_t<float, 3> gyr3L3 = lp_vec_t<float, 3>(sid.objectId, GYR_3_L3, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class GyrDataProcessed : public StaticLocalDataSet<GYR_SET_PROCESSED_ENTRIES> {
|
||||
public:
|
||||
GyrDataProcessed(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, GYR_PROCESSED_DATA) {}
|
||||
|
||||
lp_vec_t<double, 3> gyr0vec = lp_vec_t<double, 3>(sid.objectId, GYR_0_VEC, this);
|
||||
lp_vec_t<double, 3> gyr1vec = lp_vec_t<double, 3>(sid.objectId, GYR_1_VEC, this);
|
||||
lp_vec_t<double, 3> gyr2vec = lp_vec_t<double, 3>(sid.objectId, GYR_2_VEC, this);
|
||||
lp_vec_t<double, 3> gyr3vec = lp_vec_t<double, 3>(sid.objectId, GYR_3_VEC, this);
|
||||
lp_vec_t<double, 3> gyrVecTot = lp_vec_t<double, 3>(sid.objectId, GYR_VEC_TOT, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class GpsDataProcessed : public StaticLocalDataSet<GPS_SET_PROCESSED_ENTRIES> {
|
||||
public:
|
||||
GpsDataProcessed(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, GPS_PROCESSED_DATA) {}
|
||||
|
||||
lp_var_t<double> gcLatitude = lp_var_t<double>(sid.objectId, GC_LATITUDE, this);
|
||||
lp_var_t<double> gdLongitude = lp_var_t<double>(sid.objectId, GD_LONGITUDE, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class MekfData : public StaticLocalDataSet<MEKF_SET_ENTRIES> {
|
||||
public:
|
||||
MekfData(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, MEKF_DATA) {}
|
||||
|
||||
lp_vec_t<double, 4> quatMekf = lp_vec_t<double, 4>(sid.objectId, QUAT_MEKF, this);
|
||||
lp_vec_t<double, 3> satRotRateMekf = lp_vec_t<double, 3>(sid.objectId, SAT_ROT_RATE_MEKF, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class CtrlValData : public StaticLocalDataSet<CTRL_VAL_SET_ENTRIES> {
|
||||
public:
|
||||
CtrlValData(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, CTRL_VAL_DATA) {}
|
||||
|
||||
lp_vec_t<double, 4> tgtQuat = lp_vec_t<double, 4>(sid.objectId, TGT_QUAT, this);
|
||||
lp_vec_t<double, 4> errQuat = lp_vec_t<double, 4>(sid.objectId, ERROR_QUAT, this);
|
||||
lp_var_t<double> errAng = lp_var_t<double>(sid.objectId, ERROR_ANG, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class ActuatorCmdData : public StaticLocalDataSet<ACT_CMD_SET_ENTRIES> {
|
||||
public:
|
||||
ActuatorCmdData(HasLocalDataPoolIF* hkOwner) : StaticLocalDataSet(hkOwner, ACTUATOR_CMD_DATA) {}
|
||||
|
||||
lp_vec_t<double, 4> rwTargetTorque = lp_vec_t<double, 4>(sid.objectId, RW_TARGET_TORQUE, this);
|
||||
lp_vec_t<int32_t, 4> rwTargetSpeed = lp_vec_t<int32_t, 4>(sid.objectId, RW_TARGET_SPEED, this);
|
||||
lp_vec_t<int16_t, 3> mtqTargetDipole =
|
||||
lp_vec_t<int16_t, 3>(sid.objectId, MTQ_TARGET_DIPOLE, this);
|
||||
|
||||
private:
|
||||
};
|
||||
|
@ -30,8 +30,11 @@ enum PoolIds : lp_id_t {
|
||||
SENSOR_PLPCDU_HEATSPREADER,
|
||||
SENSOR_TCS_BOARD,
|
||||
SENSOR_MAGNETTORQUER,
|
||||
SENSOR_TMP1075_1,
|
||||
SENSOR_TMP1075_2,
|
||||
SENSOR_TMP1075_TCS_0,
|
||||
SENSOR_TMP1075_TCS_1,
|
||||
SENSOR_TMP1075_PLPCDU_0,
|
||||
SENSOR_TMP1075_PLPCDU_1,
|
||||
SENSOR_TMP1075_IF_BOARD,
|
||||
|
||||
SUS_0_N_LOC_XFYFZM_PT_XF,
|
||||
SUS_6_R_LOC_XFYBZM_PT_XF,
|
||||
@ -75,7 +78,7 @@ enum PoolIds : lp_id_t {
|
||||
TEMP_ADC_PAYLOAD_PCDU
|
||||
};
|
||||
|
||||
static const uint8_t ENTRIES_SENSOR_TEMPERATURE_SET = 18;
|
||||
static const uint8_t ENTRIES_SENSOR_TEMPERATURE_SET = 25;
|
||||
static const uint8_t ENTRIES_DEVICE_TEMPERATURE_SET = 25;
|
||||
static const uint8_t ENTRIES_SUS_TEMPERATURE_SET = 12;
|
||||
|
||||
@ -111,8 +114,14 @@ class SensorTemperatures : public StaticLocalDataSet<ENTRIES_SENSOR_TEMPERATURE_
|
||||
lp_var_t<float> sensor_tcs_board = lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TCS_BOARD, this);
|
||||
lp_var_t<float> sensor_magnettorquer =
|
||||
lp_var_t<float>(sid.objectId, PoolIds::SENSOR_MAGNETTORQUER, this);
|
||||
lp_var_t<float> sensor_tmp1075_1 = lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_1, this);
|
||||
lp_var_t<float> sensor_tmp1075_2 = lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_2, this);
|
||||
lp_var_t<float> tmp1075Tcs0 = lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_TCS_0, this);
|
||||
lp_var_t<float> tmp1075Tcs1 = lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_TCS_1, this);
|
||||
lp_var_t<float> tmp1075PlPcdu0 =
|
||||
lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_PLPCDU_0, this);
|
||||
lp_var_t<float> tmp1075PlPcdu1 =
|
||||
lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_PLPCDU_1, this);
|
||||
lp_var_t<float> tmp1075IfBrd =
|
||||
lp_var_t<float>(sid.objectId, PoolIds::SENSOR_TMP1075_IF_BOARD, this);
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user