#include "SafeCtrl.h" #include #include #include #include #include #include #include "../util/MathOperations.h" SafeCtrl::SafeCtrl(AcsParameters *acsParameters_) { acsParameters = acsParameters_; } SafeCtrl::~SafeCtrl() {} ReturnValue_t SafeCtrl::safeCtrlStrategy(const bool magFieldValid, const ReturnValue_t mekfValid, const bool satRotRateValid, const bool sunDirValid) { if (not magFieldValid) { return SAFECTRL_NO_MAG_FIELD_FOR_CONTROL; } else if (mekfValid) { return SAFECTRL_USE_MEKF; } else if (satRotRateValid and sunDirValid) { return SAFECTRL_USE_NONMEKF; } else if (satRotRateValid and not sunDirValid) { return SAFECTRL_USE_DAMPING; } else { return SAFECTRL_NO_SENSORS_FOR_CONTROL; } } 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) { if (!quatBJValid || !magFieldModelValid || !sunDirModelValid || !rateMekfValid) { return SAFECTRL_MEKF_INPUT_INVALID; } double kRate = acsParameters->safeModeControllerParameters.k_rate_mekf; double kAlign = acsParameters->safeModeControllerParameters.k_align_mekf; // Calc sunDirB ,magFieldB with mekf output and model double dcmBJ[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MathOperations::dcmFromQuat(quatBJ, *dcmBJ); double sunDirB[3] = {0, 0, 0}, magFieldB[3] = {0, 0, 0}; MatrixOperations::multiply(*dcmBJ, sunDirModel, sunDirB, 3, 3, 1); MatrixOperations::multiply(*dcmBJ, magFieldModel, magFieldB, 3, 3, 1); // change unit from uT to T VectorOperations::mulScalar(magFieldB, 1e-6, magFieldB, 3); double crossSun[3] = {0, 0, 0}; VectorOperations::cross(sunDirRef, sunDirB, crossSun); double normCrossSun = VectorOperations::norm(crossSun, 3); // calc angle alpha between sunDirRef and sunDIr double dotSun = VectorOperations::dot(sunDirRef, sunDirB); double alpha = acos(dotSun); // 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 scalarFac = kAlign * alpha / normCrossSun; VectorOperations::mulScalar(crossSun, scalarFac, torqueAlign, 3); double rateSafeMode[3] = {0, 0, 0}; VectorOperations::subtract(satRateMekf, satRatRef, rateSafeMode, 3); VectorOperations::mulScalar(rateSafeMode, -kRate, torqueRate, 3); VectorOperations::add(torqueRate, torqueAlign, torqueAll, 3); // Adding factor of inertia for axes MatrixOperations::multiplyScalar(*(acsParameters->inertiaEIVE.inertiaMatrix), 10, *gainMatrixInertia, 3, 3); // why only for mekf one and not for no mekf MatrixOperations::multiply(*gainMatrixInertia, torqueAll, torqueCmd, 3, 3, 1); // MagMom B (orthogonal torque) double torqueMgt[3] = {0, 0, 0}; VectorOperations::cross(magFieldB, torqueCmd, torqueMgt); double normMag = VectorOperations::norm(magFieldB, 3); VectorOperations::mulScalar(torqueMgt, 1 / pow(normMag, 2), outputMagMomB, 3); *outputAngle = alpha; return returnvalue::OK; } void SafeCtrl::safeNoMekf(const double *magFieldB, const double *satRotRateB, const double *sunDirB, const double *sunDirRefB, const double *satRotRateRefB, double *magMomB, double &errorAngle) { // convert magFieldB from uT to T double magFieldBT[3] = {0, 0, 0}; VectorOperations::mulScalar(magFieldB, 1e-6, magFieldBT, 3); // calculate angle alpha between sunDirRef and sunDir double dotSun = VectorOperations::dot(sunDirRefB, sunDirB); errorAngle = acos(dotSun); // split rotational rate into parallel and orthogonal parts double satRotRateParallelB[3] = {0, 0, 0}, satRotRateOrthogonalB[3] = {0, 0, 0}; double parallelLength = VectorOperations::dot(satRotRateB, sunDirB) * pow(VectorOperations::norm(sunDirB, 3), -2); VectorOperations::mulScalar(sunDirB, parallelLength, satRotRateParallelB, 3); VectorOperations::subtract(satRotRateB, satRotRateParallelB, satRotRateOrthogonalB, 3); // calculate torque for parallel rotational rate double cmdParallel[3] = {0, 0, 0}; if (errorAngle < (double)acsParameters->safeModeControllerParameters.angleStartSpin) { VectorOperations::subtract(satRotRateRefB, satRotRateParallelB, cmdParallel, 3); VectorOperations::mulScalar( cmdParallel, acsParameters->safeModeControllerParameters.k_parallel_mekf, cmdParallel, 3); } // calculate torque for orthogonal rotational rate double cmdOrtho[3] = {0, 0, 0}; VectorOperations::mulScalar(satRotRateOrthogonalB, -acsParameters->safeModeControllerParameters.k_ortho_mekf, cmdOrtho, 3); // calculate torque for alignment double cmdAlign[3] = {0, 0, 0}, crossAlign[3] = {0, 0, 0}, alignFactor[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; MatrixOperations::multiplyScalar(*acsParameters->inertiaEIVE.inertiaMatrix, acsParameters->safeModeControllerParameters.k_align_mekf, *alignFactor, 3, 3); VectorOperations::cross(sunDirRefB, sunDirB, crossAlign); MatrixOperations::multiply(*alignFactor, *crossAlign, *cmdAlign, 3, 3, 1); // sum of all torques double cmdTorque[3] = {0, 0, 0}; for (uint8_t i = 0; i < 3; i++) { cmdTorque[i] = cmdAlign[i] + cmdOrtho[i] + cmdParallel[i]; } // MagMom B (orthogonal torque) double torqueMgt[3] = {0, 0, 0}; VectorOperations::cross(magFieldBT, cmdTorque, torqueMgt); double normMag = VectorOperations::norm(magFieldB, 3); VectorOperations::mulScalar(torqueMgt, pow(normMag, -2), magMomB, 3); }