vtolDynamicsSim.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2023 RaccoonLab.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, version 3.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Author: Dmitry Ponomarev <ponomarevda96@gmail.com>
17  */
18 
19 #include <iostream>
20 #include <cmath>
21 #include <boost/algorithm/clamp.hpp>
22 #include <algorithm>
23 #include "vtolDynamicsSim.hpp"
24 #include <ros/package.h>
25 #include <array>
26 #include "cs_converter.hpp"
27 #include "common_math.hpp"
28 
29 
31  state_.angularVel.setZero();
32  state_.linearVel.setZero();
33  environment_.windVelocity.setZero();
35  params_.accelBias.setZero();
36  params_.gyroBias.setZero();
38  for(size_t idx = 0; idx < 8; idx++){
39  state_.prevActuators.push_back(0);
40  state_.crntActuators.push_back(0);
41  }
42 }
43 
45  loadTables("/uav/aerodynamics_coeffs/");
46  loadParams("/uav/vtol_params/");
47  return 0;
48 }
49 
50 template<int ROWS, int COLS, int ORDER>
51 Eigen::MatrixXd getTableNew(const std::string& path, const char* name){
52  std::vector<double> data;
53 
54  if(ros::param::get(path + name, data) == false){
55  throw std::invalid_argument(std::string("Wrong parameter name: ") + name);
56  }
57 
58  return Eigen::Matrix<double, ROWS, COLS, ORDER>(data.data());
59 }
60 
61 
62 void InnoVtolDynamicsSim::loadTables(const std::string& path){
63  tables_.CS_rudder = getTableNew<8, 20, Eigen::RowMajor>(path, "CS_rudder_table");
64  tables_.CS_beta = getTableNew<8, 90, Eigen::RowMajor>(path, "CS_beta");
65  tables_.AoA = getTableNew<1, 47, Eigen::RowMajor>(path, "AoA");
66  tables_.AoS = getTableNew<90, 1, Eigen::ColMajor>(path, "AoS");
67  tables_.actuator = getTableNew<20, 1, Eigen::ColMajor>(path, "actuator_table");
68  tables_.airspeed = getTableNew<8, 1, Eigen::ColMajor>(path, "airspeed_table");
69  tables_.CLPolynomial = getTableNew<8, 8, Eigen::RowMajor>(path, "CLPolynomial");
70  tables_.CSPolynomial = getTableNew<8, 8, Eigen::RowMajor>(path, "CSPolynomial");
71  tables_.CDPolynomial = getTableNew<8, 6, Eigen::RowMajor>(path, "CDPolynomial");
72  tables_.CmxPolynomial = getTableNew<8, 8, Eigen::RowMajor>(path, "CmxPolynomial");
73  tables_.CmyPolynomial = getTableNew<8, 8, Eigen::RowMajor>(path, "CmyPolynomial");
74  tables_.CmzPolynomial = getTableNew<8, 8, Eigen::RowMajor>(path, "CmzPolynomial");
75  tables_.CmxAileron = getTableNew<8, 20, Eigen::RowMajor>(path, "CmxAileron");
76  tables_.CmyElevator = getTableNew<8, 20, Eigen::RowMajor>(path, "CmyElevator");
77  tables_.CmzRudder = getTableNew<8, 20, Eigen::RowMajor>(path, "CmzRudder");
78  tables_.prop = getTableNew<40, 5, Eigen::RowMajor>(path, "prop");
79  if(ros::param::get(path + "actuatorTimeConstants", tables_.actuatorTimeConstants) == false){
80  throw std::invalid_argument(std::string("Wrong parameter name: ") + "actuatorTimeConstants");
81  }
82 }
83 
84 void InnoVtolDynamicsSim::loadParams(const std::string& path){
85  double propLocX;
86  double propLocY;
87  double propLocZ;
88  double mainEngineLocX;
89 
90  if(!ros::param::get(path + "mass", params_.mass) ||
91  !ros::param::get(path + "gravity", params_.gravity) ||
92  !ros::param::get(path + "atmoRho", params_.atmoRho) ||
93  !ros::param::get(path + "wingArea", params_.wingArea) ||
94  !ros::param::get(path + "characteristicLength", params_.characteristicLength) ||
95  !ros::param::get(path + "propellersLocationX", propLocX) ||
96  !ros::param::get(path + "propellersLocationY", propLocY) ||
97  !ros::param::get(path + "propellersLocationZ", propLocZ) ||
98  !ros::param::get(path + "mainEngineLocationX", mainEngineLocX) ||
99  !ros::param::get(path + "actuatorMin", params_.actuatorMin) ||
100  !ros::param::get(path + "actuatorMax", params_.actuatorMax) ||
101  !ros::param::get(path + "accVariance", params_.accVariance) ||
102  !ros::param::get(path + "gyroVariance", params_.gyroVariance)) {
103  // error
104  }
105 
106  params_.propellersLocation[0] << propLocX, propLocY, propLocZ;
107  params_.propellersLocation[1] << -propLocX, -propLocY, propLocZ;
108  params_.propellersLocation[2] << propLocX, -propLocY, propLocZ;
109  params_.propellersLocation[3] << -propLocX, propLocY, propLocZ;
110  params_.propellersLocation[4] << mainEngineLocX, 0, 0;
111  params_.inertia = getTableNew<3, 3, Eigen::RowMajor>(path, "inertia");
112 }
113 
114 void InnoVtolDynamicsSim::setInitialPosition(const Eigen::Vector3d & position,
115  const Eigen::Quaterniond& attitude){
116  state_.position = position;
117  state_.attitude = attitude;
118  state_.initialPose = position;
119  state_.initialAttitude = attitude;
120 }
121 void InnoVtolDynamicsSim::setInitialVelocity(const Eigen::Vector3d & linearVelocity,
122  const Eigen::Vector3d& angularVelocity){
123  state_.linearVel = linearVelocity;
124  state_.angularVel = angularVelocity;
125 }
126 
129  state_.linearVel.setZero();
130  state_.position[2] = 0.00;
131 
133  state_.angularVel.setZero();
134 
135  std::fill(std::begin(state_.motorsRpm), std::end(state_.motorsRpm), 0.0);
136 }
137 
139  constexpr double MAG_ROTATION_SPEED = 2 * 3.1415 / 10;
140  static SimMode_t prevCalibrationType = SimMode_t::NORMAL;
141  state_.linearVel.setZero();
142  state_.position[2] = 0.00;
143 
144  switch(calType) {
145  case SimMode_t::NORMAL:
146  state_.attitude = Eigen::Quaterniond(1, 0, 0, 0);
147  state_.angularVel.setZero();
148  break;
150  if(prevCalibrationType != calType){
151  state_.attitude = Eigen::Quaterniond(1, 0, 0, 0);
152  }
153  state_.angularVel << 0.000, 0.000, -MAG_ROTATION_SPEED;
154  break;
156  if(prevCalibrationType != calType){
157  state_.attitude = Eigen::Quaterniond(0, 1, 0, 0);
158  }
159  state_.angularVel << 0.000, 0.000, MAG_ROTATION_SPEED;
160  break;
162  if(prevCalibrationType != calType){
163  state_.attitude = Eigen::Quaterniond(0.707, 0, -0.707, 0);
164  }
165  state_.angularVel << -MAG_ROTATION_SPEED, 0.000, 0.000;
166  break;
168  if(prevCalibrationType != calType){
169  state_.attitude = Eigen::Quaterniond(0.707, 0, 0.707, 0);
170  }
171  state_.angularVel << MAG_ROTATION_SPEED, 0.000, 0.000;
172  break;
174  if(prevCalibrationType != calType){
175  state_.attitude = Eigen::Quaterniond(0.707, -0.707, 0, 0);
176  }
177  state_.angularVel << 0.000, MAG_ROTATION_SPEED, 0.000;
178  break;
180  if(prevCalibrationType != calType){
181  state_.attitude = Eigen::Quaterniond(0.707, 0.707, 0, 0);
182  }
183  state_.angularVel << 0.000, -MAG_ROTATION_SPEED, 0.000;
184  break;
186  state_.angularVel << MAG_ROTATION_SPEED, MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
187  break;
189  state_.angularVel << -MAG_ROTATION_SPEED, MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
190  break;
192  state_.angularVel << MAG_ROTATION_SPEED, -MAG_ROTATION_SPEED, MAG_ROTATION_SPEED;
193  break;
194 
196  if(prevCalibrationType != calType){
197  state_.attitude = Eigen::Quaterniond(1, 0, 0, 0);
198  }
199  state_.angularVel.setZero();
200  break;
202  if(prevCalibrationType != calType){
203  state_.attitude = Eigen::Quaterniond(0, 1, 0, 0);
204  }
205  state_.angularVel.setZero();
206  break;
208  if(prevCalibrationType != calType){
209  state_.attitude = Eigen::Quaterniond(0.707, 0, -0.707, 0);
210  }
211  state_.angularVel.setZero();
212  break;
214  if(prevCalibrationType != calType){
215  state_.attitude = Eigen::Quaterniond(0.707, 0, 0.707, 0);
216  }
217  state_.angularVel.setZero();
218  break;
220  if(prevCalibrationType != calType){
221  state_.attitude = Eigen::Quaterniond(0.707, -0.707, 0, 0);
222  }
223  state_.angularVel.setZero();
224  break;
226  if(prevCalibrationType != calType){
227  state_.attitude = Eigen::Quaterniond(0.707, 0.707, 0, 0);
228  }
229  state_.angularVel.setZero();
230  break;
231  case SimMode_t::AIRSPEED:
232  state_.attitude = Eigen::Quaterniond(1, 0, 0, 0);
233  state_.angularVel.setZero();
234  state_.linearVel[0] = 10.0;
235  state_.linearVel[1] = 10.0;
236  break;
237  default:
238  break;
239  }
240 
241  auto modeInteger = static_cast<int>(calType);
242  if(prevCalibrationType != calType){
243  ROS_WARN_STREAM_THROTTLE(1, "init cal " << modeInteger);
244  prevCalibrationType = calType;
245  }else{
246  ROS_WARN_STREAM_THROTTLE(1, "cal " << modeInteger);
247  }
248 
249  constexpr double DELTA_TIME = 0.001;
250 
252  Eigen::Quaterniond quaternion(0, state_.angularVel(0), state_.angularVel(1), state_.angularVel(2));
253  Eigen::Quaterniond attitudeDelta = state_.attitude * quaternion;
254  state_.attitude.coeffs() += attitudeDelta.coeffs() * 0.5 * DELTA_TIME;
255  state_.attitude.normalize();
256  return 1;
257 }
258 
259 void InnoVtolDynamicsSim::process(double dtSecs,
260  const std::vector<double>& motorCmd,
261  bool isCmdPercent){
262  Eigen::Vector3d vel_w = calculateWind();
263  Eigen::Matrix3d rotationMatrix = calculateRotationMatrix();
264  Eigen::Vector3d airSpeed = calculateAirSpeed(rotationMatrix, state_.linearVel, vel_w);
265  double AoA = calculateAnglesOfAtack(airSpeed);
266  double AoS = calculateAnglesOfSideslip(airSpeed);
267  auto actuators = isCmdPercent ? mapCmdToActuatorInnoVTOL(motorCmd) : motorCmd;
268  updateActuators(actuators, dtSecs);
269  calculateAerodynamics(airSpeed, AoA, AoS, actuators[5], actuators[6], actuators[7],
271  calculateNewState(state_.moments.aero, state_.forces.aero, actuators, dtSecs);
272 }
273 
274 
284 std::vector<double> InnoVtolDynamicsSim::mapCmdToActuatorStandardVTOL(const std::vector<double>& cmd) const{
285  if(cmd.size() != 8){
286  std::cerr << "ERROR: InnoVtolDynamicsSim wrong control size. It is " << cmd.size()
287  << ", but should be 8" << std::endl;
288  return cmd;
289  }
290 
291  std::vector<double> actuators(8);
292  actuators[0] = cmd[0];
293  actuators[1] = cmd[1];
294  actuators[2] = cmd[2];
295  actuators[3] = cmd[3];
296  actuators[4] = cmd[4];
297  actuators[5] = (cmd[5] - cmd[6]) / 2; // aileron roll
298  actuators[6] = -cmd[7]; // elevator pitch
299  actuators[7] = 0.0; // rudder yaw
300 
301  for(size_t idx = 0; idx < 5; idx++){
302  actuators[idx] = boost::algorithm::clamp(actuators[idx], 0.0, +1.0);
303  actuators[idx] *= params_.actuatorMax[idx];
304  }
305 
306  for(size_t idx = 5; idx < 8; idx++){
307  actuators[idx] = boost::algorithm::clamp(actuators[idx], -1.0, +1.0);
308  actuators[idx] *= (actuators[idx] >= 0) ? params_.actuatorMax[idx] : -params_.actuatorMin[idx];
309  }
310 
311  return actuators;
312 }
313 
329 std::vector<double> InnoVtolDynamicsSim::mapCmdToActuatorInnoVTOL(const std::vector<double>& cmd) const{
330  if(cmd.size() != 8){
331  std::cerr << "ERROR: InnoVtolDynamicsSim wrong control size. It is " << cmd.size()
332  << ", but should be 8" << std::endl;
333  return cmd;
334  }
335 
336  std::vector<double> actuators(8);
337  actuators[0] = cmd[0];
338  actuators[1] = cmd[1];
339  actuators[2] = cmd[2];
340  actuators[3] = cmd[3];
341 
342  actuators[4] = cmd[7];
343  actuators[5] = cmd[4]; // aileron
344  actuators[6] = cmd[5]; // elevator
345  actuators[7] = cmd[6]; // rudder
346 
347  for(size_t idx = 0; idx < 5; idx++){
348  actuators[idx] = boost::algorithm::clamp(actuators[idx], 0.0, +1.0);
349  actuators[idx] *= params_.actuatorMax[idx];
350  }
351 
352  actuators[5] = (actuators[5] - 0.5) * 2;
353  for(size_t idx = 5; idx < 8; idx++){
354  actuators[idx] = boost::algorithm::clamp(actuators[idx], -1.0, +1.0);
355  actuators[idx] *= (actuators[idx] >= 0) ? params_.actuatorMax[idx] : -params_.actuatorMin[idx];
356  }
357 
358  return actuators;
359 }
360 
361 void InnoVtolDynamicsSim::updateActuators(std::vector<double>& cmd, double dtSecs){
363  for(size_t idx = 0; idx < 8; idx++){
364  auto cmd_delta = state_.prevActuators[idx] - cmd[idx];
365  cmd[idx] += cmd_delta * (1 - pow(2.71, -dtSecs/tables_.actuatorTimeConstants[idx]));
366  state_.crntActuators[idx] = cmd[idx];
367  }
368 }
369 
371  Eigen::Vector3d wind;
375 
380  Eigen::Vector3d gust;
381  gust.setZero();
382 
383  return wind + gust;
384 }
385 
387  return state_.attitude.toRotationMatrix().transpose();
388 }
389 
390 Eigen::Vector3d InnoVtolDynamicsSim::calculateAirSpeed(const Eigen::Matrix3d& rotationMatrix,
391  const Eigen::Vector3d& velocity,
392  const Eigen::Vector3d& windSpeed) const{
393  Eigen::Vector3d airspeed = rotationMatrix * (velocity - windSpeed);
394  if(abs(airspeed[0]) > 40 || abs(airspeed[1]) > 40 || abs(airspeed[2]) > 40){
395  airspeed[0] = boost::algorithm::clamp(airspeed[0], -40, +40);
396  airspeed[1] = boost::algorithm::clamp(airspeed[1], -40, +40);
397  airspeed[2] = boost::algorithm::clamp(airspeed[2], -40, +40);
398  std::cout << "Warning: airspeed is out of limit." << std::endl;
399  }
400  return airspeed;
401 }
402 
403 double InnoVtolDynamicsSim::calculateDynamicPressure(double airSpeedMod) const{
404  return params_.atmoRho * airSpeedMod * airSpeedMod * params_.wingArea;
405 }
406 
412 double InnoVtolDynamicsSim::calculateAnglesOfAtack(const Eigen::Vector3d& airSpeed) const{
413  double A = sqrt(airSpeed[0] * airSpeed[0] + airSpeed[2] * airSpeed[2]);
414  if(A < 0.001){
415  return 0;
416  }
417  A = airSpeed[2] / A;
418  A = boost::algorithm::clamp(A, -1.0, +1.0);
419  A = (airSpeed[0] > 0) ? asin(A) : 3.1415 - asin(A);
420  return (A > 3.1415) ? A - 2 * 3.1415 : A;
421 }
422 
423 double InnoVtolDynamicsSim::calculateAnglesOfSideslip(const Eigen::Vector3d& airSpeed) const{
424  double B = airSpeed.norm();
425  if(B < 0.001){
426  return 0;
427  }
428  B = airSpeed[1] / B;
429  B = boost::algorithm::clamp(B, -1.0, +1.0);
430  return asin(B);
431 }
432 
439 void InnoVtolDynamicsSim::calculateAerodynamics(const Eigen::Vector3d& airspeed,
440  double AoA,
441  double AoS,
442  double aileron_pos,
443  double elevator_pos,
444  double rudder_pos,
445  Eigen::Vector3d& Faero,
446  Eigen::Vector3d& Maero){
447  // 0. Common computation
448  double AoA_deg = boost::algorithm::clamp(AoA * 180 / 3.1415, -45.0, +45.0);
449  double AoS_deg = boost::algorithm::clamp(AoS * 180 / 3.1415, -90.0, +90.0);
450  double airspeedMod = airspeed.norm();
451  double dynamicPressure = calculateDynamicPressure(airspeedMod);
452  double airspeedModClamped = boost::algorithm::clamp(airspeed.norm(), 5, 40);
453 
454  // 1. Calculate aero force
455  Eigen::VectorXd polynomialCoeffs(7);
456  Eigen::Vector3d FL;
457  Eigen::Vector3d FS;
458  Eigen::Vector3d FD;
459 
460  calculateCLPolynomial(airspeedModClamped, polynomialCoeffs);
461  double CL = Math::polyval(polynomialCoeffs, AoA_deg);
462  FL = (Eigen::Vector3d(0, 1, 0).cross(airspeed.normalized())) * CL;
463 
464  calculateCSPolynomial(airspeedModClamped, polynomialCoeffs);
465  double CS = Math::polyval(polynomialCoeffs, AoA_deg);
466  double CS_rudder = calculateCSRudder(rudder_pos, airspeedModClamped);
467  double CS_beta = calculateCSBeta(AoS_deg, airspeedModClamped);
468  FS = airspeed.cross(Eigen::Vector3d(0, 1, 0).cross(airspeed.normalized())) * (CS + CS_rudder + CS_beta);
469 
470  calculateCDPolynomial(airspeedModClamped, polynomialCoeffs);
471  double CD = Math::polyval(polynomialCoeffs.block<5, 1>(0, 0), AoA_deg);
472  FD = (-1 * airspeed).normalized() * CD;
473 
474  Faero = 0.5 * dynamicPressure * (FL + FS + FD);
475 
476  // 2. Calculate aero moment
477  calculateCmxPolynomial(airspeedModClamped, polynomialCoeffs);
478  auto Cmx = Math::polyval(polynomialCoeffs, AoA_deg);
479 
480  calculateCmyPolynomial(airspeedModClamped, polynomialCoeffs);
481  auto Cmy = Math::polyval(polynomialCoeffs, AoA_deg);
482 
483  calculateCmzPolynomial(airspeedModClamped, polynomialCoeffs);
484  auto Cmz = -Math::polyval(polynomialCoeffs, AoA_deg);
485 
486  double Cmx_aileron = calculateCmxAileron(aileron_pos, airspeedModClamped);
493  double Cmy_elevator = calculateCmyElevator(abs(elevator_pos), airspeedModClamped);
494  double Cmz_rudder = calculateCmzRudder(rudder_pos, airspeedModClamped);
495 
496  auto Mx = Cmx + Cmx_aileron * aileron_pos;
497  auto My = Cmy + Cmy_elevator * elevator_pos;
498  auto Mz = Cmz + Cmz_rudder * rudder_pos;
499 
500  Maero = 0.5 * dynamicPressure * params_.characteristicLength * Eigen::Vector3d(Mx, My, Mz);
501 
502 
503  state_.forces.lift << 0.5 * dynamicPressure * params_.characteristicLength * FL;
504  state_.forces.drug << 0.5 * dynamicPressure * params_.characteristicLength * FD;
505  state_.forces.side << 0.5 * dynamicPressure * params_.characteristicLength * FS;
506  state_.moments.steer << Cmx_aileron * aileron_pos, Cmy_elevator * elevator_pos, Cmz_rudder * rudder_pos;
507  state_.moments.steer *= 0.5 * dynamicPressure * params_.characteristicLength;
508  state_.moments.airspeed << Cmx, Cmy, Cmz;
509  state_.moments.airspeed *= 0.5 * dynamicPressure * params_.characteristicLength;
510 }
511 
512 void InnoVtolDynamicsSim::thruster(double actuator,
513  double& thrust, double& torque, double& rpm) const{
514  constexpr size_t CONTROL_IDX = 0;
515  constexpr size_t THRUST_IDX = 1;
516  constexpr size_t TORQUE_IDX = 2;
517  constexpr size_t RPM_IDX = 4;
518 
519  size_t prev_idx = Math::findPrevRowIdxInMonotonicSequence(tables_.prop, actuator);
520  size_t next_idx = prev_idx + 1;
521  if(next_idx < tables_.prop.rows()){
522  auto prev_row = tables_.prop.row(prev_idx);
523  auto next_row = tables_.prop.row(next_idx);
524  auto t = (actuator - prev_row(CONTROL_IDX)) / (next_row(CONTROL_IDX) - prev_row(CONTROL_IDX));
525  thrust = Math::lerp(prev_row(THRUST_IDX), next_row(THRUST_IDX), t);
526  torque = Math::lerp(prev_row(TORQUE_IDX), next_row(TORQUE_IDX), t);
527  rpm = Math::lerp(prev_row(RPM_IDX), next_row(RPM_IDX), t);
528  }
529 }
530 
531 void InnoVtolDynamicsSim::calculateNewState(const Eigen::Vector3d& Maero,
532  const Eigen::Vector3d& Faero,
533  const std::vector<double>& actuator,
534  double dt_sec){
535  Eigen::VectorXd thrust(5);
536  Eigen::VectorXd torque(5);
537  for(size_t idx = 0; idx < 5; idx++){
538  thruster(actuator[idx], thrust[idx], torque[idx], state_.motorsRpm[idx]);
539  }
540 
541  for(size_t idx = 0; idx < 4; idx++){
542  state_.forces.motors[idx] << 0, 0, -thrust[idx];
543  }
544  state_.forces.motors[4] << thrust[4], 0, 0;
545 
546  std::array<Eigen::Vector3d, 5> motorTorquesInBodyCS;
547  motorTorquesInBodyCS[0] << 0, 0, torque[0];
548  motorTorquesInBodyCS[1] << 0, 0, torque[1];
549  motorTorquesInBodyCS[2] << 0, 0, -torque[2];
550  motorTorquesInBodyCS[3] << 0, 0, -torque[3];
551  motorTorquesInBodyCS[4] << -torque[4], 0, 0;
552  std::array<Eigen::Vector3d, 5> MdueToArmOfForceInBodyCS;
553  for(size_t idx = 0; idx < 5; idx++){
554  MdueToArmOfForceInBodyCS[idx] = params_.propellersLocation[idx].cross(state_.forces.motors[idx]);
555  state_.moments.motors[idx] = motorTorquesInBodyCS[idx] + MdueToArmOfForceInBodyCS[idx];
556  }
557 
558  auto MtotalInBodyCS = std::accumulate(&state_.moments.motors[0], &state_.moments.motors[5], Maero);
560  state_.angularVel += state_.angularAccel * dt_sec;
561  Eigen::Quaterniond quaternion(0, state_.angularVel(0), state_.angularVel(1), state_.angularVel(2));
562  Eigen::Quaterniond attitudeDelta = state_.attitude * quaternion;
563  state_.attitude.coeffs() += attitudeDelta.coeffs() * 0.5 * dt_sec;
564  state_.attitude.normalize();
565 
566  Eigen::Matrix3d rotationMatrix = calculateRotationMatrix();
567  auto& Fmotors = state_.forces.motors;
568  Eigen::Vector3d Fspecific = std::accumulate(&Fmotors[0], &Fmotors[5], Faero) / params_.mass;
569  Eigen::Vector3d Ftotal = (Fspecific + rotationMatrix * Eigen::Vector3d(0, 0, params_.gravity)) * params_.mass;
570 
571  state_.forces.total = Ftotal;
572  state_.moments.total = MtotalInBodyCS;
573 
574  state_.linearAccel = rotationMatrix.inverse() * Ftotal / params_.mass;
575  state_.linearVel += state_.linearAccel * dt_sec;
576  state_.position += state_.linearVel * dt_sec;
577 
578  if(state_.position[2] >= 0){
579  land();
580  }else{
581  state_.forces.specific = Fspecific;
582  }
583 
584  state_.bodylinearVel = rotationMatrix * state_.linearVel;
585 }
586 
588  Eigen::Matrix3d rotationMatrix = calculateRotationMatrix();
589  return rotationMatrix * Eigen::Vector3d(0, 0, -params_.gravity);
590 }
591 
593  Eigen::VectorXd& polynomialCoeffs) const{
594  Math::calculatePolynomial(tables_.CLPolynomial, airSpeedMod, polynomialCoeffs);
595 }
597  Eigen::VectorXd& polynomialCoeffs) const{
598  Math::calculatePolynomial(tables_.CSPolynomial, airSpeedMod, polynomialCoeffs);
599 }
601  Eigen::VectorXd& polynomialCoeffs) const{
602  Math::calculatePolynomial(tables_.CDPolynomial, airSpeedMod, polynomialCoeffs);
603 }
605  Eigen::VectorXd& polynomialCoeffs) const{
606  Math::calculatePolynomial(tables_.CmxPolynomial, airSpeedMod, polynomialCoeffs);
607 }
609  Eigen::VectorXd& polynomialCoeffs) const{
610  Math::calculatePolynomial(tables_.CmyPolynomial, airSpeedMod, polynomialCoeffs);
611 }
613  Eigen::VectorXd& polynomialCoeffs) const{
614  Math::calculatePolynomial(tables_.CmzPolynomial, airSpeedMod, polynomialCoeffs);
615 }
616 double InnoVtolDynamicsSim::calculateCSRudder(double rudder_pos, double airspeed) const{
617  return Math::griddata(-tables_.actuator, tables_.airspeed, tables_.CS_rudder, rudder_pos, airspeed);
618 }
619 double InnoVtolDynamicsSim::calculateCSBeta(double AoS_deg, double airspeed) const{
620  return Math::griddata(-tables_.AoS, tables_.airspeed, tables_.CS_beta, AoS_deg, airspeed);
621 }
622 double InnoVtolDynamicsSim::calculateCmxAileron(double aileron_pos, double airspeed) const{
623  return Math::griddata(tables_.actuator, tables_.airspeed, tables_.CmxAileron, aileron_pos, airspeed);
624 }
625 double InnoVtolDynamicsSim::calculateCmyElevator(double elevator_pos, double airspeed) const{
626  return Math::griddata(tables_.actuator, tables_.airspeed, tables_.CmyElevator, elevator_pos, airspeed);
627 }
628 double InnoVtolDynamicsSim::calculateCmzRudder(double rudder_pos, double airspeed) const{
629  return Math::griddata(tables_.actuator, tables_.airspeed, tables_.CmzRudder, rudder_pos, airspeed);
630 }
631 
632 // Motion dynamics equation
633 Eigen::Vector3d InnoVtolDynamicsSim::calculateAngularAccel(const Eigen::Matrix<double, 3, 3, Eigen::RowMajor>& inertia,
634  const Eigen::Vector3d& moment,
635  const Eigen::Vector3d& prevAngVel) const{
636  return inertia.inverse() * (moment - prevAngVel.cross(inertia * prevAngVel));
637 }
638 
643  return state_.position;
644 }
646  return state_.linearVel;
647 }
648 
652 Eigen::Quaterniond InnoVtolDynamicsSim::getVehicleAttitude() const{
653  return state_.attitude;
654 }
656  return state_.angularVel;
657 }
662 void InnoVtolDynamicsSim::getIMUMeasurement(Eigen::Vector3d& accOutFrd,
663  Eigen::Vector3d& gyroOutFrd){
664  Eigen::Vector3d accNoise(sqrt(params_.accVariance) * distribution_(generator_),
667  Eigen::Vector3d gyroNoise(sqrt(params_.gyroVariance) * distribution_(generator_),
670 
671  Eigen::Vector3d specificForce(state_.forces.specific);
672  Eigen::Vector3d angularVelocity(state_.angularVel);
673  Eigen::Quaterniond imuOrient(1, 0, 0, 0);
674  accOutFrd = imuOrient.inverse() * specificForce + params_.accelBias + accNoise;
675  gyroOutFrd = imuOrient.inverse() * angularVelocity + params_.gyroBias + gyroNoise;
676 }
677 
681 void InnoVtolDynamicsSim::setWindParameter(Eigen::Vector3d windMeanVelocity,
682  double windVariance){
683  environment_.windVelocity = windMeanVelocity;
684  environment_.windVariance = windVariance;
685 }
687  return state_.angularAccel;
688 }
690  return state_.linearAccel;
691 }
693  return state_.forces;
694 }
696  return state_.moments;
697 }
698 
700  return state_.bodylinearVel;
701 }
702 
703 bool InnoVtolDynamicsSim::getMotorsRpm(std::vector<double>& motorsRpm) {
704  motorsRpm.push_back(state_.motorsRpm[0]);
705  motorsRpm.push_back(state_.motorsRpm[1]);
706  motorsRpm.push_back(state_.motorsRpm[2]);
707  motorsRpm.push_back(state_.motorsRpm[3]);
708  motorsRpm.push_back(state_.motorsRpm[4]);
709  return true;
710 }
Moments moments
Eigen::Vector3d total
Eigen::Matrix< double, 3, 3, Eigen::RowMajor > inertia
double calculateCSRudder(double rudder_pos, double airspeed) const
const Forces & getForces() const
Eigen::Matrix< double, 8, 20, Eigen::RowMajor > CS_rudder
std::vector< double > mapCmdToActuatorStandardVTOL(const std::vector< double > &cmd) const
Eigen::Matrix< double, 8, 20, Eigen::RowMajor > CmzRudder
Eigen::Vector3d getBodyLinearVelocity() const
Eigen::Vector3d drug
void setInitialVelocity(const Eigen::Vector3d &linearVelocity, const Eigen::Vector3d &angularVelocity)
std::vector< double > mapCmdToActuatorInnoVTOL(const std::vector< double > &cmd) const
Eigen::Vector3d getAngularAcceleration() const
#define ROS_WARN_STREAM_THROTTLE(period, args)
double lerp(double a, double b, double f)
Definition: common_math.cpp:26
Eigen::Matrix< double, 8, 8, Eigen::RowMajor > CLPolynomial
int8_t init() override
Use rosparam here to initialize sim.
Eigen::MatrixXd getTableNew(const std::string &path, const char *name)
Eigen::Quaterniond initialAttitude
Eigen::Vector3d aero
Eigen::Vector3d specific
VtolParameters params_
void calculateCDPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
Eigen::Matrix< double, 8, 8, Eigen::RowMajor > CmxPolynomial
Eigen::Vector3d windVelocity
Eigen::Vector3d getVehicleVelocity() const override
void calculateCSPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
Eigen::Vector3d angularVel
void setWindParameter(Eigen::Vector3d windMeanVelocity, double wind_velocityVariance)
double calculateCmxAileron(double aileron_pos, double airspeed) const
Eigen::Vector3d linearVel
Eigen::Vector3d lift
Eigen::Quaterniond getVehicleAttitude() const override
Eigen::Vector3d gyroBias
void calculateCmxPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
double characteristicLength
Eigen::Matrix< double, 90, 1, Eigen::ColMajor > AoS
void updateActuators(std::vector< double > &cmd, double dtSecs)
size_t findPrevRowIdxInMonotonicSequence(const Eigen::MatrixXd &matrix, double key)
Given monotonic sequence (increasing or decreasing) and key, return the index of the previous element...
Definition: common_math.cpp:38
Eigen::Vector3d accelBias
void getIMUMeasurement(Eigen::Vector3d &accOut, Eigen::Vector3d &gyroOut) override
Eigen::Vector3d angularAccel
std::normal_distribution< double > distribution_
void loadTables(const std::string &path)
double calculateCSBeta(double AoS_deg, double airspeed) const
Eigen::Matrix< double, 8, 8, Eigen::RowMajor > CmzPolynomial
Eigen::Matrix< double, 8, 1, Eigen::ColMajor > airspeed
void thruster(double actuator, double &thrust, double &torque, double &rpm) const
double polyval(const Eigen::VectorXd &poly, double val)
Definition: common_math.cpp:30
std::array< double, 5 > motorsRpm
Eigen::Vector3d calculateWind()
Eigen::Matrix< double, 40, 5, Eigen::RowMajor > prop
Eigen::Vector3d calculateAirSpeed(const Eigen::Matrix3d &rotationMatrix, const Eigen::Vector3d &estimatedVelocity, const Eigen::Vector3d &windSpeed) const
std::vector< double > prevActuators
Eigen::Matrix< double, 1, 47, Eigen::RowMajor > AoA
double calculateAnglesOfSideslip(const Eigen::Vector3d &airSpeed) const
ROSCPP_DECL bool get(const std::string &key, std::string &s)
Eigen::Vector3d side
Forces forces
double calculateCmyElevator(double elevator_pos, double airspeed) const
const Moments & getMoments() const
double griddata(const Eigen::MatrixXd &x, const Eigen::MatrixXd &y, const Eigen::MatrixXd &z, double x_val, double y_val)
Definition: common_math.cpp:68
void calculateAerodynamics(const Eigen::Vector3d &airspeed, double AoA, double AoS, double aileron_pos, double elevator_pos, double rudder_pos, Eigen::Vector3d &Faero, Eigen::Vector3d &Maero)
Eigen::Matrix3d calculateRotationMatrix() const
Eigen::Vector3d position
std::array< Eigen::Vector3d, 5 > motors
Eigen::Vector3d getVehicleAngularVelocity() const override
Eigen::Quaterniond attitude
Eigen::Vector3d getVehiclePosition() const override
bool calculatePolynomial(const Eigen::MatrixXd &table, double airSpeedMod, Eigen::VectorXd &polynomialCoeffs)
Definition: common_math.cpp:87
Eigen::Matrix< double, 8, 20, Eigen::RowMajor > CmyElevator
void calculateNewState(const Eigen::Vector3d &Maero, const Eigen::Vector3d &Faero, const std::vector< double > &actuator, double dt_sec)
Eigen::Matrix< double, 8, 8, Eigen::RowMajor > CmyPolynomial
void calculateCLPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
Eigen::Matrix< double, 8, 6, Eigen::RowMajor > CDPolynomial
Eigen::Matrix< double, 8, 20, Eigen::RowMajor > CmxAileron
Eigen::Vector3d getLinearAcceleration() const
int8_t calibrate(SimMode_t calibrationType) override
Eigen::Vector3d steer
void land() override
Eigen::Vector3d initialPose
std::vector< double > actuatorMin
Eigen::Matrix< double, 20, 1, Eigen::ColMajor > actuator
double calculateCmzRudder(double rudder_pos, double airspeed) const
void calculateCmzPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
std::array< Eigen::Vector3d, 5 > motors
TablesWithCoeffs tables_
Eigen::Vector3d total
Eigen::Vector3d calculateAngularAccel(const Eigen::Matrix< double, 3, 3, Eigen::RowMajor > &inertia, const Eigen::Vector3d &moment, const Eigen::Vector3d &prevAngVel) const
Eigen::Vector3d airspeed
void calculateCmyPolynomial(double airSpeedMod, Eigen::VectorXd &polynomialCoeffs) const
void loadParams(const std::string &path)
Eigen::Matrix< double, 8, 90, Eigen::RowMajor > CS_beta
bool getMotorsRpm(std::vector< double > &motorsRpm) override
double calculateDynamicPressure(double airSpeedMod) const
std::vector< double > crntActuators
Eigen::Vector3d linearAccel
std::vector< double > actuatorTimeConstants
void process(double dt_secs, const std::vector< double > &motorSpeedCommandIn, bool isCmdPercent) override
Eigen::Vector3d calculateNormalForceWithoutMass() const
void setInitialPosition(const Eigen::Vector3d &position, const Eigen::Quaterniond &attitude) override
Eigen::Matrix< double, 8, 8, Eigen::RowMajor > CSPolynomial
Eigen::Vector3d bodylinearVel
std::array< Eigen::Vector3d, 5 > propellersLocation
std::vector< double > actuatorMax
std::default_random_engine generator_
Eigen::Vector3d aero
double calculateAnglesOfAtack(const Eigen::Vector3d &airSpeed) const


inno_vtol_dynamics
Author(s): Roman Fedorenko, Dmitry Ponomarev, Ezra Tal, Winter Guerra
autogenerated on Sat Jul 1 2023 02:13:44