1 /***************************************************************************
5 ----------------------------------------------------------------------------
7 FUNCTION: Integration routine for equations of motion
10 ----------------------------------------------------------------------------
12 MODULE STATUS: developmental
14 ----------------------------------------------------------------------------
16 GENEALOGY: Written 920802 by Bruce Jackson. Based upon equations
17 given in reference [1] and a Matrix-X/System Build block
18 diagram model of equations of motion coded by David Raney
19 at NASA-Langley in June of 1992.
21 ----------------------------------------------------------------------------
23 DESIGNED BY: Bruce Jackson
25 CODED BY: Bruce Jackson
29 ----------------------------------------------------------------------------
35 921223 Modified calculation of Phi and Psi to use the "atan2" routine
36 rather than the "atan" to allow full circular angles.
37 "atan" limits to +/- pi/2. EBJ
39 940111 Changed from oldstyle include file ls_eom.h; also changed
40 from DATA to SCALAR type. EBJ
42 950207 Initialized Alpha_dot and Beta_dot to zero on first pass; calculated
45 950224 Added logic to avoid adding additional increment to V_east
46 in case V_east already accounts for rotating earth.
53 Revision 1.3 2000/10/23 22:34:55 curt
55 LaRCsim c172 on-ground and in-air starts, reset: all work
56 UIUC Cessna172 on-ground and in-air starts work as expected, reset
57 results in an aircraft that is upside down but does not crash FG. I
58 don't know what it was like before, so it may well be no change.
59 JSBSim c172 and X15 in-air starts work fine, resets now work (and are
60 trimmed), on-ground starts do not -- the c172 ends up on its back. I
61 suspect this is no worse than before.
64 Balloon (the weather code returns nan's for the atmosphere data --this
65 is in the weather module and apparently is a linux only bug)
67 MagicCarpet (needs work yet)
68 External (don't know how)
71 LaRCsim c172 on-ground starts with a negative terrain altitude (this
72 happens at KPAO when the scenery is not present). The FDM inits to
73 about 50 feet AGL and the model falls to the ground. It does stay
74 upright, however, and seems to be fine once it settles out, FWIW.
77 --implement set_Model on the bus
78 --bring Christian's weather data into JSBSim
79 -- add default method to bus for updating things like the sin and cos of
80 latitude (for Balloon, MagicCarpet)
86 -- all data members now declared protected instead of private.
87 -- eliminated all but a small set of 'setters', no change to getters.
88 -- that small set is declared virtual, the default implementation
89 provided preserves the old behavior
90 -- all of the vector data members are now initialized.
91 -- added busdump() method -- FG_LOG's all the bus data when called,
92 useful for diagnostics.
95 -- bus data members now directly assigned to
98 -- bus data members now directly assigned to
99 -- changed V_equiv_kts to V_calibrated_kts
103 -- bus data members now directly assigned to
104 -- implemented the FGInterface virtual setters with JSBSim specific
106 -- changed the static FDMExec to a dynamic fdmex (needed so that the
107 JSBSim object can be deleted when a model change is called for)
108 -- implemented constructor and destructor, moved some of the logic
109 formerly in init() to constructor
110 -- added logic to bring up FGEngInterface objects and set the RPM and
115 -- bus data members now directly assigned to
116 -- implemented the FGInterface virtual setters with LaRCsim specific
117 logic, uses LaRCsimIC
118 -- implemented constructor and destructor, moved some of the logic
119 formerly in init() to constructor
120 -- moved default inertias to here from fg_init.cxx
121 -- eliminated the climb rate calculation. The equivalent, climb_rate =
122 -1*vdown, is now in copy_from_LaRCsim().
124 src/FDM/LaRCsimIC.cxx
125 src/FDM/LaRCsimIC.hxx
126 -- similar to FGInitialCondition, this class has all the logic needed to
127 turn data like Vc and Mach into the more fundamental quantities LaRCsim
129 -- put it in src/FDM since it is a class
131 src/FDM/MagicCarpet.cxx
132 -- bus data members now directly assigned to
135 -- adds LaRCsimIC.hxx and cxx
137 src/FDM/JSBSim/FGAtmosphere.h
138 src/FDM/JSBSim/FGDefs.h
139 src/FDM/JSBSim/FGInitialCondition.cpp
140 src/FDM/JSBSim/FGInitialCondition.h
141 src/FDM/JSBSim/JSBSim.cpp
142 -- changes to accomodate the new bus
144 src/FDM/LaRCsim/atmos_62.h
145 src/FDM/LaRCsim/ls_geodesy.h
146 -- surrounded prototypes with #ifdef __cplusplus ... #endif , functions
147 here are needed in LaRCsimIC
149 src/FDM/LaRCsim/c172_main.c
150 src/FDM/LaRCsim/cherokee_aero.c
151 src/FDM/LaRCsim/ls_aux.c
152 src/FDM/LaRCsim/ls_constants.h
153 src/FDM/LaRCsim/ls_geodesy.c
154 src/FDM/LaRCsim/ls_geodesy.h
155 src/FDM/LaRCsim/ls_step.c
156 src/FDM/UIUCModel/uiuc_betaprobe.cpp
157 -- changed PI to LS_PI, eliminates preprocessor naming conflict with
160 src/FDM/LaRCsim/ls_interface.c
161 src/FDM/LaRCsim/ls_interface.h
162 -- added function ls_set_model_dt()
165 -- eliminated calls that set the NED speeds to body components. They
166 are no longer needed and confuse the new bus.
169 -- eliminated calls that just brought the bus data up-to-date (e.g.
170 set_sin_cos_latitude). or set default values. The bus now handles the
171 defaults and updates itself when the setters are called (for LaRCsim and
172 JSBSim). A default method for doing this needs to be added to the bus.
173 -- added fgVelocityInit() to set the speed the user asked for. Both
174 JSBSim and LaRCsim can now be initialized using any of:
175 vc,mach, NED components, UVW components.
178 --eliminated call to fgFDMSetGroundElevation, this data is now 'pulled'
179 onto the bus every update()
183 -- added enum to keep track of the speed requested by the user
184 -- eliminated calls to set NED velocity properties to body speeds, they
185 are no longer needed.
186 -- added options for the NED components.
188 src/Network/garmin.cxx
190 --eliminated calls that just brought the bus data up-to-date (e.g.
191 set_sin_cos_latitude). The bus now updates itself when the setters are
192 called (for LaRCsim and JSBSim). A default method for doing this needs
193 to be added to the bus.
194 -- changed set_V_equiv_kts to set_V_calibrated_kts. set_V_equiv_kts no
195 longer exists ( get_V_equiv_kts still does, though)
197 src/WeatherCM/FGLocalWeatherDatabase.cpp
198 -- commented out the code to put the weather data on the bus, a
199 different scheme for this is needed.
201 Revision 1.2 1999/10/29 16:08:33 curt
202 Added flaps support to c172 model.
204 Revision 1.1.1.1 1999/06/17 18:07:33 curt
205 Start of 0.7.x branch
207 Revision 1.1.1.1 1999/04/05 21:32:45 curt
208 Start of 0.6.x branch.
210 Revision 1.4 1998/08/24 20:09:27 curt
211 Code optimization tweaks from Norman Vine.
213 Revision 1.3 1998/07/12 03:11:04 curt
214 Removed some printf()'s.
215 Fixed the autopilot integration so it should be able to update it's control
216 positions every time the internal flight model loop is run, and not just
217 once per rendered frame.
218 Added a routine to do the necessary stuff to force an arbitrary altitude
220 Gave the Navion engine just a tad more power.
222 Revision 1.2 1998/01/19 18:40:28 curt
223 Tons of little changes to clean up the code and to remove fatal errors
224 when building with the c++ compiler.
226 Revision 1.1 1997/05/29 00:09:59 curt
227 Initial Flight Gear revision.
229 * Revision 1.5 1995/03/02 20:24:13 bjax
230 * Added logic to avoid adding additional increment to V_east
231 * in case V_east already accounts for rotating earth. EBJ
233 * Revision 1.4 1995/02/07 20:52:21 bjax
234 * Added initialization of Alpha_dot and Beta_dot to zero on first
235 * pass; they get calculated by ls_aux on next pass... EBJ
237 * Revision 1.3 1994/01/11 19:01:12 bjax
238 * Changed from DATA to SCALAR type; also fixed header files (was ls_eom.h)
240 * Revision 1.2 1993/06/02 15:03:09 bjax
241 * Moved initialization of geocentric position to subroutine ls_geod_to_geoc.
243 * Revision 1.1 92/12/30 13:16:11 bjax
247 ----------------------------------------------------------------------------
251 [ 1] McFarland, Richard E.: "A Standard Kinematic Model
252 for Flight Simulation at NASA-Ames", NASA CR-2497,
255 [ 2] ANSI/AIAA R-004-1992 "Recommended Practice: Atmos-
256 pheric and Space Flight Vehicle Coordinate Systems",
260 ----------------------------------------------------------------------------
264 ----------------------------------------------------------------------------
268 ----------------------------------------------------------------------------
270 INPUTS: State derivatives
272 ----------------------------------------------------------------------------
276 --------------------------------------------------------------------------*/
278 #include "ls_types.h"
279 #include "ls_constants.h"
280 #include "ls_generic.h"
281 #include "ls_accel.h"
283 #include "ls_model.h"
285 #include "ls_geodesy.h"
286 #include "ls_gravity.h"
287 /* #include "ls_sim_control.h" */
290 extern SCALAR Simtime; /* defined in ls_main.c */
292 void ls_step( SCALAR dt, int Initialize ) {
293 static int inited = 0;
295 static SCALAR v_dot_north_past, v_dot_east_past, v_dot_down_past;
296 static SCALAR latitude_dot_past, longitude_dot_past, radius_dot_past;
297 static SCALAR p_dot_body_past, q_dot_body_past, r_dot_body_past;
298 SCALAR p_local_in_body, q_local_in_body, r_local_in_body;
299 SCALAR epsilon, inv_eps, local_gnd_veast;
300 SCALAR e_dot_0, e_dot_1, e_dot_2, e_dot_3;
301 static SCALAR e_0, e_1, e_2, e_3;
302 static SCALAR e_dot_0_past, e_dot_1_past, e_dot_2_past, e_dot_3_past;
303 SCALAR cos_Lat_geocentric, inv_Radius_to_vehicle;
305 /* I N I T I A L I Z A T I O N */
308 if ( (inited == 0) || (Initialize != 0) )
310 /* Set past values to zero */
311 v_dot_north_past = v_dot_east_past = v_dot_down_past = 0;
312 latitude_dot_past = longitude_dot_past = radius_dot_past = 0;
313 p_dot_body_past = q_dot_body_past = r_dot_body_past = 0;
314 e_dot_0_past = e_dot_1_past = e_dot_2_past = e_dot_3_past = 0;
316 /* Initialize geocentric position from geodetic latitude and altitude */
318 ls_geod_to_geoc( Latitude, Altitude, &Sea_level_radius, &Lat_geocentric);
319 Earth_position_angle = 0;
320 Lon_geocentric = Longitude;
321 Radius_to_vehicle = Altitude + Sea_level_radius;
323 /* Correct eastward velocity to account for earths' rotation, if necessary */
325 local_gnd_veast = OMEGA_EARTH*Sea_level_radius*cos(Lat_geocentric);
326 if( fabs(V_east - V_east_rel_ground) < 0.8*local_gnd_veast )
327 V_east = V_east + local_gnd_veast;
329 /* Initialize quaternions and transformation matrix from Euler angles */
331 e_0 = cos(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5)
332 + sin(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5);
333 e_1 = cos(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5)
334 - sin(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5);
335 e_2 = cos(Psi*0.5)*sin(Theta*0.5)*cos(Phi*0.5)
336 + sin(Psi*0.5)*cos(Theta*0.5)*sin(Phi*0.5);
337 e_3 =-cos(Psi*0.5)*sin(Theta*0.5)*sin(Phi*0.5)
338 + sin(Psi*0.5)*cos(Theta*0.5)*cos(Phi*0.5);
339 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
340 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
341 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
342 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
343 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
344 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
345 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
346 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
347 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
349 /* Calculate local gravitation acceleration */
351 ls_gravity( Radius_to_vehicle, Lat_geocentric, &Gravity );
353 /* Initialize vehicle model */
358 /* Calculate initial accelerations */
362 /* Initialize auxiliary variables */
368 /* set flag; disable integrators */
378 Simtime = Simtime + dt;
380 /* L I N E A R V E L O C I T I E S */
382 /* Integrate linear accelerations to get velocities */
383 /* Using predictive Adams-Bashford algorithm */
385 V_north = V_north + dth*(3*V_dot_north - v_dot_north_past);
386 V_east = V_east + dth*(3*V_dot_east - v_dot_east_past );
387 V_down = V_down + dth*(3*V_dot_down - v_dot_down_past );
389 /* record past states */
391 v_dot_north_past = V_dot_north;
392 v_dot_east_past = V_dot_east;
393 v_dot_down_past = V_dot_down;
395 /* Calculate trajectory rate (geocentric coordinates) */
397 inv_Radius_to_vehicle = 1.0/Radius_to_vehicle;
398 cos_Lat_geocentric = cos(Lat_geocentric);
400 if ( cos_Lat_geocentric != 0) {
401 Longitude_dot = V_east/(Radius_to_vehicle*cos_Lat_geocentric);
404 Latitude_dot = V_north*inv_Radius_to_vehicle;
405 Radius_dot = -V_down;
407 /* A N G U L A R V E L O C I T I E S A N D P O S I T I O N S */
409 /* Integrate rotational accelerations to get velocities */
411 P_body = P_body + dth*(3*P_dot_body - p_dot_body_past);
412 Q_body = Q_body + dth*(3*Q_dot_body - q_dot_body_past);
413 R_body = R_body + dth*(3*R_dot_body - r_dot_body_past);
415 /* Save past states */
417 p_dot_body_past = P_dot_body;
418 q_dot_body_past = Q_dot_body;
419 r_dot_body_past = R_dot_body;
421 /* Calculate local axis frame rates due to travel over curved earth */
423 P_local = V_east*inv_Radius_to_vehicle;
424 Q_local = -V_north*inv_Radius_to_vehicle;
425 R_local = -V_east*tan(Lat_geocentric)*inv_Radius_to_vehicle;
427 /* Transform local axis frame rates to body axis rates */
429 p_local_in_body = T_local_to_body_11*P_local + T_local_to_body_12*Q_local + T_local_to_body_13*R_local;
430 q_local_in_body = T_local_to_body_21*P_local + T_local_to_body_22*Q_local + T_local_to_body_23*R_local;
431 r_local_in_body = T_local_to_body_31*P_local + T_local_to_body_32*Q_local + T_local_to_body_33*R_local;
433 /* Calculate total angular rates in body axis */
435 P_total = P_body - p_local_in_body;
436 Q_total = Q_body - q_local_in_body;
437 R_total = R_body - r_local_in_body;
439 /* Transform to quaternion rates (see Appendix E in [2]) */
441 e_dot_0 = 0.5*( -P_total*e_1 - Q_total*e_2 - R_total*e_3 );
442 e_dot_1 = 0.5*( P_total*e_0 - Q_total*e_3 + R_total*e_2 );
443 e_dot_2 = 0.5*( P_total*e_3 + Q_total*e_0 - R_total*e_1 );
444 e_dot_3 = 0.5*( -P_total*e_2 + Q_total*e_1 + R_total*e_0 );
446 /* Integrate using trapezoidal as before */
448 e_0 = e_0 + dth*(e_dot_0 + e_dot_0_past);
449 e_1 = e_1 + dth*(e_dot_1 + e_dot_1_past);
450 e_2 = e_2 + dth*(e_dot_2 + e_dot_2_past);
451 e_3 = e_3 + dth*(e_dot_3 + e_dot_3_past);
453 /* calculate orthagonality correction - scale quaternion to unity length */
455 epsilon = sqrt(e_0*e_0 + e_1*e_1 + e_2*e_2 + e_3*e_3);
463 /* Save past values */
465 e_dot_0_past = e_dot_0;
466 e_dot_1_past = e_dot_1;
467 e_dot_2_past = e_dot_2;
468 e_dot_3_past = e_dot_3;
470 /* Update local to body transformation matrix */
472 T_local_to_body_11 = e_0*e_0 + e_1*e_1 - e_2*e_2 - e_3*e_3;
473 T_local_to_body_12 = 2*(e_1*e_2 + e_0*e_3);
474 T_local_to_body_13 = 2*(e_1*e_3 - e_0*e_2);
475 T_local_to_body_21 = 2*(e_1*e_2 - e_0*e_3);
476 T_local_to_body_22 = e_0*e_0 - e_1*e_1 + e_2*e_2 - e_3*e_3;
477 T_local_to_body_23 = 2*(e_2*e_3 + e_0*e_1);
478 T_local_to_body_31 = 2*(e_1*e_3 + e_0*e_2);
479 T_local_to_body_32 = 2*(e_2*e_3 - e_0*e_1);
480 T_local_to_body_33 = e_0*e_0 - e_1*e_1 - e_2*e_2 + e_3*e_3;
482 /* Calculate Euler angles */
484 Theta = asin( -T_local_to_body_13 );
486 if( T_local_to_body_11 == 0 )
489 Psi = atan2( T_local_to_body_12, T_local_to_body_11 );
491 if( T_local_to_body_33 == 0 )
494 Phi = atan2( T_local_to_body_23, T_local_to_body_33 );
496 /* Resolve Psi to 0 - 359.9999 */
498 if (Psi < 0 ) Psi = Psi + 2*LS_PI;
500 /* L I N E A R P O S I T I O N S */
502 /* Trapezoidal acceleration for position */
504 Lat_geocentric = Lat_geocentric + dth*(Latitude_dot + latitude_dot_past );
505 Lon_geocentric = Lon_geocentric + dth*(Longitude_dot + longitude_dot_past);
506 Radius_to_vehicle = Radius_to_vehicle + dth*(Radius_dot + radius_dot_past );
507 Earth_position_angle = Earth_position_angle + dt*OMEGA_EARTH;
509 /* Save past values */
511 latitude_dot_past = Latitude_dot;
512 longitude_dot_past = Longitude_dot;
513 radius_dot_past = Radius_dot;
517 /*************************************************************************/