Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
nps_fdm_fixedwing_sim.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Gautier Hattenberger <gautier.hattenberger@enac.fr>
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "nps_fdm.h"
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 
26 #include "std.h"
27 #include "math/pprz_geodetic.h"
30 #include "math/pprz_algebra.h"
32 #include "math/pprz_isa.h"
33 
34 #include "generated/airframe.h"
35 #include "generated/flight_plan.h"
36 
37 #include "state.h"
38 
39 // Check if rover firmware
40 #ifndef FIXEDWING_FIRMWARE
41 #error "The module nps_fdm_fixedwing_sim is a basic flight model for fixedwing only"
42 #endif
43 
44 #ifndef ROLL_RESPONSE_FACTOR
45 #define ROLL_RESPONSE_FACTOR 15.
46 #endif
47 
48 #ifndef PITCH_RESPONSE_FACTOR
49 #define PITCH_RESPONSE_FACTOR 1.
50 #endif
51 
52 #ifndef YAW_RESPONSE_FACTOR
53 #define YAW_RESPONSE_FACTOR 1.
54 #endif
55 
56 #ifndef WEIGHT
57 #define WEIGHT 1.
58 #endif
59 
60 #ifndef ROLL_MAX_SETPOINT
61 #define ROLL_MAX_SETPOINT RadOfDeg(40.)
62 #endif
63 
64 #ifndef ROLL_RATE_MAX_SETPOINT
65 #define ROLL_RATE_MAX_SETPOINT RadOfDeg(15.)
66 #endif
67 
68 #ifndef NOMINAL_AIRSPEED
69 #error "Please define NOMINAL_AIRSPEED in your airframe file"
70 #endif
71 
72 #ifndef MAXIMUM_AIRSPEED
73 #define MAXIMUM_AIRSPEED (NOMINAL_AIRSPEED * 1.5)
74 #endif
75 
76 #ifndef MAXIMUM_POWER
77 #define MAXIMUM_POWER (5. * MAXIMUM_AIRSPEED * WEIGHT)
78 #endif
79 
80 #ifndef AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE
81 #define AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE 0.45
82 #endif
83 
84 // NpsFdm structure
85 struct NpsFdm fdm;
86 
87 // Reference point
88 static struct LtpDef_d ltpdef;
89 
90 // Static functions declaration
91 static void init_ltp(void);
92 
94  struct EnuCoor_d pos;
95  struct EnuCoor_d speed;
96  struct DoubleEulers attitude;
97  struct DoubleEulers rates;
98  double airspeed;
99  double delta_roll;
100  double delta_pitch;
101  double delta_thrust;
102  struct EnuCoor_d wind;
103 };
104 
105 static struct fixedwing_sim_state sim_state;
106 
107 
109 void nps_fdm_init(double dt)
110 {
111  fdm.init_dt = dt; // (1 / simulation freq)
112  fdm.curr_dt = dt;
113  fdm.time = dt;
114 
115  fdm.on_ground = TRUE;
116 
117  fdm.nan_count = 0;
118  fdm.pressure = -1;
120  fdm.total_pressure = -1;
121  fdm.dynamic_pressure = -1;
122  fdm.temperature = -1;
123 
127 
128  VECT3_ASSIGN(sim_state.pos, 0., 0., 0.);
129  VECT3_ASSIGN(sim_state.speed, 0., 0., 0.);
130  EULERS_ASSIGN(sim_state.attitude, 0., 0., 0.);
131  EULERS_ASSIGN(sim_state.rates, 0., 0., 0.);
132  VECT3_ASSIGN(sim_state.wind, 0., 0., 0.);
133  sim_state.airspeed = 0.;
134  sim_state.delta_roll = 0.;
135  sim_state.delta_pitch = 0.;
136  sim_state.delta_thrust = 0.;
137 
138  init_ltp();
139 }
140 
141 
156 void nps_fdm_run_step(bool launch, double *commands, int commands_nb __attribute__((unused)))
157 {
158 
159  // commands
160  sim_state.delta_roll = commands[COMMAND_ROLL] * MAX_PPRZ;
161  sim_state.delta_pitch = -commands[COMMAND_PITCH] * MAX_PPRZ; // invert back to correct sign
162  sim_state.delta_thrust = commands[COMMAND_THROTTLE];
163 
164  static bool already_launched = false;
165  if (launch && !already_launched) {
166  sim_state.airspeed = NOMINAL_AIRSPEED;
167  already_launched = true;
168  }
169  if (sim_state.airspeed == 0. && sim_state.delta_thrust > 0.) {
170  sim_state.airspeed = NOMINAL_AIRSPEED;
171  }
172 
173  if (sim_state.pos.z >= -3. && sim_state.airspeed > 0.) {
175  double vn2 = NOMINAL_AIRSPEED * NOMINAL_AIRSPEED;
176 
177  // roll dynamic
178  double c_l = 4e-5 * sim_state.delta_roll;
179  double phi_dot_dot = ROLL_RESPONSE_FACTOR * c_l * v2 / vn2 - sim_state.rates.phi;
180  sim_state.rates.phi = sim_state.rates.phi + phi_dot_dot * fdm.curr_dt;
183  NormRadAngle(sim_state.attitude.phi);
185 
186  // yaw dynamic
189  NormRadAngle(sim_state.attitude.psi);
190 
191  // Aerodynamic pitching moment coeff, proportional to elevator
192  // No Thrust moment, so null (0) for steady flight
193  double c_m = 5e-7 * sim_state.delta_pitch;
194  double theta_dot_dot = PITCH_RESPONSE_FACTOR * c_m * v2 - sim_state.rates.theta;
195  sim_state.rates.theta = sim_state.rates.theta + theta_dot_dot * fdm.curr_dt;
197 
198  // Flight path angle
199  double gamma = atan2(sim_state.speed.z, sim_state.airspeed);
200 
201  // Cz proportional to angle of attack
202  double alpha = sim_state.attitude.theta - gamma;
203  double c_z = 0.2 * alpha + PPRZ_ISA_GRAVITY / vn2;
204 
205  // Lift
206  double lift = c_z * v2;
207  double z_dot_dot = lift / WEIGHT * cos(sim_state.attitude.theta) * cos(sim_state.attitude.phi) - PPRZ_ISA_GRAVITY;
208  sim_state.speed.z = sim_state.speed.z + z_dot_dot * fdm.curr_dt;
210 
211  // Constant Cx, drag to get expected cruise and maximum throttle
212  double cruise_th = AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE;
213  double drag = cruise_th + (v2 - vn2) * (1. - cruise_th) / (MAXIMUM_AIRSPEED*MAXIMUM_AIRSPEED - vn2);
214  double airspeed_dot = MAXIMUM_POWER / sim_state.airspeed * (sim_state.delta_thrust - drag) / WEIGHT - PPRZ_ISA_GRAVITY * sin(gamma);
215  sim_state.airspeed = sim_state.airspeed + airspeed_dot * fdm.curr_dt;
216  sim_state.airspeed = Max(sim_state.airspeed, 10.); // avoid stall
217 
218  // Wind effect (FIXME apply to forces ?)
224  }
225 
226  /****************************************************************************/
227  // Coordenates transformations |
228  // ----------------------------|
229 
230  /* in ECEF */
234  //ecef_of_enu_vect_d(&fdm.ecef_ecef_accel, &ltpdef, &rover_acc);
235 
236  /* in NED */
240  fdm.hmsl = -fdm.ltpprz_pos.z + NAV_ALT0 / 1000.;
241 
242  /* Eulers */
244  // Exporting Eulers to AHRS (in quaternions)
246 
247  // Angular vel & acc
251 }
252 
253 
254 /**************************
255  ** Generating LTP plane **
256  **************************/
257 
258 static void init_ltp(void)
259 {
260 
261  struct LlaCoor_d llh_nav0; /* Height above the ellipsoid */
262  llh_nav0.lat = RadOfDeg((double)NAV_LAT0 / 1e7);
263  llh_nav0.lon = RadOfDeg((double)NAV_LON0 / 1e7);
264  llh_nav0.alt = (double)(NAV_ALT0) / 1000.0;
265 
266  struct EcefCoor_d ecef_nav0;
267 
268  ecef_of_lla_d(&ecef_nav0, &llh_nav0);
269 
270  ltp_def_from_ecef_d(&ltpdef, &ecef_nav0);
271  fdm.ecef_pos = ecef_nav0;
272 
273  // accel and mag data should not be used
274  // AHRS and INS are bypassed
275  fdm.ltp_g.x = 0.;
276  fdm.ltp_g.y = 0.;
277  fdm.ltp_g.z = 0.;
278 
279  fdm.ltp_h.x = 1.;
280  fdm.ltp_h.y = 0.;
281  fdm.ltp_h.z = 0.;
282 
283 }
284 
285 
286 void nps_fdm_set_wind(double speed, double dir)
287 {
288  sim_state.wind.x = speed * sin(dir);
289  sim_state.wind.y = speed * cos(dir);
290  sim_state.wind.z = 0.;
291 }
292 
293 void nps_fdm_set_wind_ned(double wind_north, double wind_east, double wind_down)
294 {
295  sim_state.wind.x = wind_east;
296  sim_state.wind.y = wind_north;
297  sim_state.wind.z = -wind_down;
298 }
299 
300 void nps_fdm_set_turbulence(double wind_speed __attribute__((unused)),
301  int turbulence_severity __attribute__((unused)))
302 {
303 }
304 
305 void nps_fdm_set_temperature(double temp __attribute__((unused)),
306  double h __attribute__((unused)))
307 {
308 }
309 
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
pprz_t commands[COMMANDS_NB]
Definition: commands.c:30
double psi
in radians
double p
in rad/s^2
double theta
in radians
double q
in rad/s^2
double phi
in radians
double r
in rad/s^2
void double_quat_of_eulers(struct DoubleQuat *q, struct DoubleEulers *e)
euler angles
#define VECT3_ASSIGN(_a, _x, _y, _z)
Definition: pprz_algebra.h:125
#define EULERS_ASSIGN(_e, _phi, _theta, _psi)
Definition: pprz_algebra.h:274
double z
in meters
double z
in meters
double y
in meters
double x
in meters
double lat
in radians
double alt
in meters above WGS84 reference ellipsoid
double lon
in radians
void ltp_def_from_ecef_d(struct LtpDef_d *def, struct EcefCoor_d *ecef)
void ecef_of_enu_vect_d(struct EcefCoor_d *ecef, struct LtpDef_d *def, struct EnuCoor_d *enu)
void ned_of_ecef_vect_d(struct NedCoor_d *ned, struct LtpDef_d *def, struct EcefCoor_d *ecef)
void lla_of_ecef_d(struct LlaCoor_d *lla, struct EcefCoor_d *ecef)
void ned_of_ecef_point_d(struct NedCoor_d *ned, struct LtpDef_d *def, struct EcefCoor_d *ecef)
void ecef_of_lla_d(struct EcefCoor_d *ecef, struct LlaCoor_d *lla)
void ecef_of_enu_point_d(struct EcefCoor_d *ecef, struct LtpDef_d *def, struct EnuCoor_d *enu)
vector in EarthCenteredEarthFixed coordinates
vector in East North Up coordinates Units: meters
vector in Latitude, Longitude and Altitude
definition of the local (flat earth) coordinate system
#define PPRZ_ISA_GRAVITY
earth-surface gravitational acceleration in m/s^2
Definition: pprz_isa.h:56
#define PPRZ_ISA_SEA_LEVEL_PRESSURE
ISA sea level standard atmospheric pressure in Pascal.
Definition: pprz_isa.h:50
double time
Definition: nps_fdm.h:46
struct NedCoor_d ltpprz_ecef_vel
velocity in ltppprz frame, wrt ECEF frame
Definition: nps_fdm.h:79
struct DoubleVect3 ltp_g
Definition: nps_fdm.h:104
double pressure_sl
pressure at sea level in Pascal
Definition: nps_fdm.h:114
double init_dt
Definition: nps_fdm.h:47
double total_pressure
total atmospheric pressure in Pascal
Definition: nps_fdm.h:111
double hmsl
Definition: nps_fdm.h:56
struct EcefCoor_d ecef_pos
Definition: nps_fdm.h:53
struct NedCoor_d ltpprz_pos
Definition: nps_fdm.h:54
struct NedCoor_d ltpprz_ecef_accel
accel in ltppprz frame, wrt ECEF frame
Definition: nps_fdm.h:81
struct DoubleVect3 ltp_h
Definition: nps_fdm.h:105
double dynamic_pressure
dynamic pressure in Pascal
Definition: nps_fdm.h:112
struct DoubleEulers ltp_to_body_eulers
Definition: nps_fdm.h:92
struct EcefCoor_d ecef_ecef_accel
acceleration in ECEF frame, wrt ECEF frame
Definition: nps_fdm.h:66
double pressure
current (static) atmospheric pressure in Pascal
Definition: nps_fdm.h:110
double curr_dt
Definition: nps_fdm.h:48
struct DoubleQuat ltp_to_body_quat
Definition: nps_fdm.h:91
struct DoubleRates body_ecef_rotvel
Definition: nps_fdm.h:97
struct EcefCoor_d ecef_ecef_vel
velocity in ECEF frame, wrt ECEF frame
Definition: nps_fdm.h:64
double temperature
current temperature in degrees Celcius
Definition: nps_fdm.h:113
struct DoubleEulers ltpprz_to_body_eulers
Definition: nps_fdm.h:94
struct LlaCoor_d lla_pos
Definition: nps_fdm.h:55
bool on_ground
Definition: nps_fdm.h:49
int nan_count
Definition: nps_fdm.h:50
Definition: nps_fdm.h:44
void nps_fdm_set_wind_ned(double wind_north, double wind_east, double wind_down)
void nps_fdm_init(double dt)
NPS FDM rover init.
static void init_ltp(void)
struct DoubleEulers rates
void nps_fdm_run_step(bool launch, double *commands, int commands_nb)
Minimum complexity flight dynamic model In legacy Paparazzi simulator, was implemented in OCaml and c...
#define MAXIMUM_AIRSPEED
#define ROLL_RATE_MAX_SETPOINT
#define AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE
static struct fixedwing_sim_state sim_state
void nps_fdm_set_temperature(double temp, double h)
Set temperature in degrees Celcius at given height h above MSL.
#define MAXIMUM_POWER
#define ROLL_MAX_SETPOINT
struct DoubleEulers attitude
#define ROLL_RESPONSE_FACTOR
void nps_fdm_set_turbulence(double wind_speed, int turbulence_severity)
#define WEIGHT
#define YAW_RESPONSE_FACTOR
void nps_fdm_set_wind(double speed, double dir)
struct NpsFdm fdm
#define PITCH_RESPONSE_FACTOR
static struct LtpDef_d ltpdef
#define MAX_PPRZ
Definition: paparazzi.h:8
Paparazzi generic algebra macros.
Paparazzi floating point algebra.
Paparazzi generic macros for geodetic calculations.
Paparazzi double-precision floating point math for geodetic calculations.
Paparazzi floating point math for geodetic calculations.
Paparazzi atmospheric pressure conversion utilities.
static const float dir[]
API to get/set the generic vehicle states.
#define TRUE
Definition: std.h:4
float alpha
Definition: textons.c:133