21 #include <boost/algorithm/clamp.hpp>
63 template<
int ROWS,
int COLS,
int ORDER>
64 Eigen::MatrixXd
getTableNew(
const std::string& path,
const char* name){
65 std::vector<double> data;
68 throw std::invalid_argument(std::string(
"Wrong parameter name: ") + name);
71 return Eigen::Matrix<double, ROWS, COLS, ORDER>(data.data());
76 _tables.
CS_rudder = getTableNew<8, 20, Eigen::RowMajor>(path,
"CS_rudder_table");
77 _tables.
CS_beta = getTableNew<8, 90, Eigen::RowMajor>(path,
"CS_beta");
78 _tables.
AoA = getTableNew<1, 47, Eigen::RowMajor>(path,
"AoA");
79 _tables.
AoS = getTableNew<90, 1, Eigen::ColMajor>(path,
"AoS");
80 _tables.
actuator = getTableNew<20, 1, Eigen::ColMajor>(path,
"actuator_table");
81 _tables.
airspeed = getTableNew<8, 1, Eigen::ColMajor>(path,
"airspeed_table");
91 _tables.
prop = getTableNew<40, 5, Eigen::RowMajor>(path,
"prop");
109 _params.
inertia = getTableNew<3, 3, Eigen::RowMajor>(path,
"inertia");
113 std::vector<double> motorPositionX;
114 std::vector<double> motorPositionY;
115 std::vector<double> motorPositionZ;
116 std::vector<bool> motorDirectionCCW;
117 std::vector<double> motorAxisX;
118 std::vector<double> motorAxisZ;
127 size_t motors_amount = motorPositionX.size();
134 assert(motorPositionX.size() == motors_amount);
135 assert(motorPositionY.size() == motors_amount);
136 assert(motorPositionZ.size() == motors_amount);
137 assert(motorDirectionCCW.size() == motors_amount);
138 assert(motorAxisX.size() == motors_amount);
139 assert(motorAxisZ.size() == motors_amount);
142 for (
size_t motor_idx = 0; motor_idx < motors_amount; motor_idx++) {
144 geometry.
position << motorPositionX[motor_idx], motorPositionY[motor_idx], motorPositionZ[motor_idx];
145 geometry.
axis << motorAxisX[motor_idx], 0.0, motorAxisZ[motor_idx];
152 const Eigen::Quaterniond& attitudeXYZW){
159 const Eigen::Vector3d& angularVelocity){
180 constexpr
double MAG_ROTATION_SPEED = 2 * 3.1415 / 10;
191 if(prevCalibrationType != calType){
197 if(prevCalibrationType != calType){
203 if(prevCalibrationType != calType){
209 if(prevCalibrationType != calType){
215 if(prevCalibrationType != calType){
221 if(prevCalibrationType != calType){
227 _state.
angularVel << MAG_ROTATION_SPEED, MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
230 _state.
angularVel << -MAG_ROTATION_SPEED, MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
233 _state.
angularVel << MAG_ROTATION_SPEED, -MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
237 if(prevCalibrationType != calType){
243 if(prevCalibrationType != calType){
249 if(prevCalibrationType != calType){
255 if(prevCalibrationType != calType){
261 if(prevCalibrationType != calType){
267 if(prevCalibrationType != calType){
282 auto modeInteger =
static_cast<int>(calType);
283 if(prevCalibrationType != calType){
285 prevCalibrationType = calType;
290 constexpr
double DELTA_TIME = 0.001;
295 _state.
attitude.coeffs() += attitudeDelta.coeffs() * 0.5 * DELTA_TIME;
328 std::vector<double> input_cmd = cmd;
333 for (
size_t motor_idx = 0; motor_idx <
_motorsSpeed.size(); motor_idx++) {
339 for(
size_t servo_idx = 0; servo_idx <
SERVOS_AMOUNT; servo_idx++){
365 Eigen::Vector3d wind;
374 Eigen::Vector3d gust;
385 const Eigen::Vector3d& velocityNED,
386 const Eigen::Vector3d& windSpeedNED)
const{
387 Eigen::Vector3d airspeedFrd = rotationMatrix * (velocityNED + windSpeedNED);
388 if(abs(airspeedFrd[0]) > 40 || abs(airspeedFrd[1]) > 40 || abs(airspeedFrd[2]) > 40){
389 airspeedFrd[0] = boost::algorithm::clamp(airspeedFrd[0], -40, +40);
390 airspeedFrd[1] = boost::algorithm::clamp(airspeedFrd[1], -40, +40);
391 airspeedFrd[2] = boost::algorithm::clamp(airspeedFrd[2], -40, +40);
392 std::cout <<
"Warning: airspeed is out of limit." << std::endl;
408 double A = sqrt(airspeed_frd[0] * airspeed_frd[0] + airspeed_frd[2] * airspeed_frd[2]);
412 A = airspeed_frd[2] / A;
413 A = boost::algorithm::clamp(A, -1.0, +1.0);
414 A = (airspeed_frd[0] > 0) ? asin(A) : 3.1415 - asin(A);
415 return (A > 3.1415) ? A - 2 * 3.1415 : A;
419 double B = airspeed_frd.norm();
423 B = airspeed_frd[1] / B;
424 B = boost::algorithm::clamp(B, -1.0, +1.0);
437 const std::array<double, 3>& servos,
438 Eigen::Vector3d& Faero,
439 Eigen::Vector3d& Maero){
441 double AoA_deg = boost::algorithm::clamp(AoA * 180 / 3.1415, -45.0, +45.0);
442 double AoS_deg = boost::algorithm::clamp(AoS * 180 / 3.1415, -90.0, +90.0);
443 double airspeedMod = airspeed.norm();
445 double airspeedModClamped = boost::algorithm::clamp(airspeed.norm(), 5, 40);
448 Eigen::VectorXd polynomialCoeffs(7);
455 FL = (Eigen::Vector3d(0, 1, 0).cross(airspeed.normalized())) * CL;
461 FS = airspeed.cross(Eigen::Vector3d(0, 1, 0).cross(airspeed.normalized())) * (CS + CS_rudder + CS_beta);
464 double CD =
Math::polyval(polynomialCoeffs.block<5, 1>(0, 0), AoA_deg);
465 FD = (-1 * airspeed).normalized() * CD;
467 Faero = 0.5 * dynamicPressure * (FL + FS + FD);
508 double& thrust,
double& torque,
double& rpm)
const{
509 constexpr
size_t CONTROL_IDX = 0;
510 constexpr
size_t THRUST_IDX = 1;
511 constexpr
size_t TORQUE_IDX = 2;
512 constexpr
size_t RPM_IDX = 4;
515 size_t next_idx = prev_idx + 1;
519 auto t = (actuator - prev_row(CONTROL_IDX)) / (next_row(CONTROL_IDX) - prev_row(CONTROL_IDX));
520 thrust =
Math::lerp(prev_row(THRUST_IDX), next_row(THRUST_IDX), t);
521 torque =
Math::lerp(prev_row(TORQUE_IDX), next_row(TORQUE_IDX), t);
522 rpm =
Math::lerp(prev_row(RPM_IDX), next_row(RPM_IDX), t);
527 const Eigen::Vector3d& Faero,
528 const std::vector<double>& motors,
531 for(
size_t idx = 0; idx < motors.size(); idx++){
539 Eigen::Vector3d motorTorquesInBodyCS =
_params.
geometry[idx].axis * (-1.0) * ccw * torque;
550 _state.
attitude.coeffs() += attitudeDelta.coeffs() * 0.5 * dt_sec;
555 Eigen::Vector3d Fspecific = std::accumulate(&Fmotors[0], &Fmotors[motors.size()], Faero) /
_params.
mass;
580 Eigen::VectorXd& polynomialCoeffs)
const{
584 Eigen::VectorXd& polynomialCoeffs)
const{
588 Eigen::VectorXd& polynomialCoeffs)
const{
592 Eigen::VectorXd& polynomialCoeffs)
const{
596 Eigen::VectorXd& polynomialCoeffs)
const{
600 Eigen::VectorXd& polynomialCoeffs)
const{
621 const Eigen::Vector3d& moment,
622 const Eigen::Vector3d& prevAngVel)
const{
623 return inertia.inverse() * (moment - prevAngVel.cross(inertia * prevAngVel));
653 Eigen::Vector3d& gyroOutFrd){
663 Eigen::Quaterniond imuOrient(1, 0, 0, 0);
664 accOutFrd = imuOrient.inverse() * specificForce +
_params.
accelBias + accNoise;
665 gyroOutFrd = imuOrient.inverse() * angularVelocity +
_params.
gyroBias + gyroNoise;
672 double windVariance){
695 motorsRpm.push_back(motor_rpm);