The Orbiter example makes use of a generalized six degree of freedom (6DOF) rigid body model built into the VSE library. A wide variety of platforms can be modeled by implementing an abstract method that computes influences acting on the vehicle. These influences include forces, accelerations, and torques the vehicle is subjected to given its state. The use of this library class results in the Orbiter simulation requiring only three classes external to the VSE. One defines the models taking part in the simulation - a rotating central body and a vehicle orbiting about that body. The second class extends the 6DOF library class, fulfilling the abstract method by defining gravitational potential, propulsion forces, and attitude control torques acting on this vehicle. The third class connects the model (math) to the visualization environment (graphics) and user inputs (keyboard controls).

A quick note on the nomenclature "six degree of freedom", or 6DOF, as used in this project. The term 6DOF is not meant to be the formal definition encountered in academics. It simply means that in addition to using accelerations along the X, Y, and Z axes to compute translational position and velocity, angular accelerations about the these axes are also used to compute attitude and angular velocity. For a rigid body, translational motion is fairly simple to model because movement along each axis can be treated independently when all forces are resolved about the body's center of gravity. This process involves translating each force acting on the body to be through its center of gravity and then computing the resulting torques induced by those forces before integration of the equations of motion. This simplification does not exist for rotational motion. A lack of symmetry in the vehicle's mass distribution results in a torque about one axis inducing accelerations about other axes. In addition, even for a completely symmetric body (say, a sphere), gyroscopic coupling results in accelerations about a third axis due to angular rates about two other axes! The math is not difficult - just a bit more involved.

In applied engineering, the terms 6DOF and 3DOF are often used to distinguish between simulations modeling rotational dynamics vs. kinematics. The models often have many more degrees of freedom. Because so many degrees of freedom may exist in a complicated model, describing that model by listing the total number of degrees of freedom becomes a bit nonsensical.

Within the VSE, models, along with classes used to run them in a
simulation, are packaged individually as libraries. The actual model
typically consists of two core classes. The most basic represents a
system of differential equations doing nothing more than taking the
current time and state vector as inputs, outputting the corresponding
derivatives to that state vector. See *intxm.IDiffQ.getXDot()* for
the basic interface. The class **msd3D.MassSpDpDQ** is an example of
the equations of motion for a mass, spring, damper. The class
**trmtm.Simple6DOFdq**, also implementing **IDiffQ** is used by
**orbiter.Orbiter**. It is instantiated within the
**trmtm.Simple6DOFSys** abstract class - the 6DOF library model
previously alluded to. **Simple6DOFSys** implements
**intxm.ISysEqns**, which guarantees functionality related to the
State-Space and propagation of a dynamic model.

*Simple6DOFSys.finishModel()* is an abstract method allowing the
user to add forces acting through the modeled body's center of gravity,
field forces, accelerations, and torques. This class offers a great
deal of flexibility with respect to modeling without further knowledge
of rigid body dynamics. The body force input may be thrusts due to a
propulsion system, environmental influences, etc.... Field forces could
be the result of something such as a magnetic field. Gravitational
potential is a common acceleration. Control surfaces and attitude
control systems may impart torques about the body. All of these inputs
can be computed external to these library classes based on the model's
current state. The differential equations class, **Simple6DOFdq**,
queries the system for these inputs during the integration process. The
integrator used within the **Simple6DOFSys** class is currently
hard-coded to be **intxm.RK4** (implementing
**intxm.IIntegrator**). **Simple6DOFdq** and **Simple6DOFSys**
are aware of each other.

The remaining classes in each model package define the simulation
environment and usually contain objects that generate the GUI, set up
the 3D environment, select the solid model, and connect the 3D
environment to the simulated model (**orbiter.OrbiterVisModel**).
User input controls (keyboard, mouse, etc...) are configured in one of
these classes as well. The primary class in each model implements an
interface needed to start the simulation (**orbiter.Orbiter**). This
class either needs to be instantiated within an application to run, or
launched directly with the **RunVSE** application. The JAR file
containing the supplied launcher is called RunVSE.jar.

The VSE supports this central model paradigm. However, the method employed by the Orbiter simulation propagates the rotating central body and vehicle states independently. The following lengthy outline of the Orbiter model includes a description of the classes built to handle all the time synchronization issues that arise when propagating each model independently.

Everything starts with the **orbiter.Orbiter** class. It implements
the **servm.ISimModel**, which guarantees a *public void run()*
method. This method is used by an application that will instantiate the
**Orbiter** class and then launch it.

**Orbiter** creates a **j3d.SimV3Dcfg** object containing
simulation configuration options. A display refresh rate obtained from
the **SimV3Dcfg** object is used to initialize a
**j3d.ModelTimeBehavior** object. This important extension of the
Java3D **Behavior** controls the overall progression of time. There
are two versions of time within the simulation. The first is computer,
or clock time. It advances at the output rate plus the time it takes to
perform all computations related to propagating each model and updating
the display (the output rate is not the underlying graphics refresh
rate). In contrast, simulation time marks the progression of time
within the simulation. If the simulation time is set to progress at 60
times that of the clock, then only one minute of clock time would pass
for an hour of simulation time (ignoring lag time due to computations).
For a computationally intensive simulation, it may not be possible to
have simulation time out-pace, or even equal, clock time.

Once initialized (during the instantiation of **j3d.SimV3D**,
occurring at the end of *Orbiter.run()*) , the Behavior's
*wakupon()* method is called with a Java3D **WakeupCondition**
that will cause the simulation to sleep for the duration of the
configured output rate. Upon waking up, the *"processStimulus()"*
method is called which updates the simulation time. Each model has a
**j3d.IVisualModel** object associated with it that then triggers
an *IVisualModel.update()* method. As previously mentioned,
implementation of an **IVisualModel** is what ties the mathematical
model to the visualization environment.

After the **ModelTimeBehavior** is instantiated, A
**cycxm.ModelStepper** object is created and initialized with an
integration step and output step size. This class manages timing
related bookkeeping for a model relying on some form of numeric
integration (or propagation by sequential discrete step sizes). It
determines how many integration steps are needed to meet a larger output
step size. For non-graphic output, the output rate could be the
frequency at which numeric data should be written to a file. For this
scenario, it is the length of time between updates to the Java3D display
(most likely larger than the Java3D refresh rate). The
*ModelStepper.stepper()* method documentation describes what
happens when the output rate is not a multiple of the integration step
size. Multiple **ModelStepper** objects can be created to manage
models requiring different integration step sizes.

Models for the central body (**trmtm.RotatingBodySys**) and orbiting
vehicle (**orbiter.OrbiterSys**) are then created and their states
initialized. Both of these objects implement **intxm.ISysEqns**. A
two element array of **IVisualModel** objects is then created. The
first is **j3d.RotatingBodyVisModel** for the central body and
**orbiter.OrbiterVisModel** for the orbiter. As stated before, these
classes link the math models to the visualization environment. For
example, **orbiter.OrbiterVisModel** defines how the orbiter model
reacts to keyboard inputs.

The constructors for both **IVisualModel** objects make use of Java3D
**TransformGroup** objects containing the solid model. As described
by the Java3D documentation, a "...TransformGroup node specifies a
single spatial transformation, via a Transform3D object, that can
position, orient, and scale all of its children." What this means is
the TransformGroup is the object that is modified to
change the graphic representation of the model state.

The array of **IVisualModel** objects is then registered with the
**ModelTimeBehavior** object allowing it to manage the process of
updating the state of each model from one output interval to the next.
All models will output at the same rate. However, not all models will
need to use the same integration step size. The order in which each
**IVisualModel** appears in the array is the order in which each
model will be updated. For maximum accuracy, the state of independent
models should be updated before that of dependent ones. For example,
with the orbiter simulation, the orientation of the central body must
first be computed to determine the gravitational potential exerted on
the vehicle. The twist is most integration methods, such as the RK4
one, require the state of influences acting on the model at intermediate
points between between not only each output, but between each
integration step. The Orbiter example is easy to handle because the
central body model is a simple analytic function - the total rotation
angle is equal to the initial angle plus the angular velocity multiplied
by the total time. When the **ModelTimeBehavior** tells the
**OrbiterVisModel** to update, the **ModelStepper** integrates the
orbiter's equations of motion, propagating its state forward by the
integration step size. This causes the integrator to call the
*Simple6DOFdq.getXDot()* method, which in turn calls the
*OrbiterSys.finishModel()* method. This method requests the state
of the central body at multiple intermediate points between the
integration time step. Being a simple analytic model, the central body
recomputes its attitude for each requested time.

If the central body dynamics were based on a more complicated model, then a decision would need to be made regarding how to handle retrieving its state. One option is to simply use the latest central body state for all calls by the orbiter's integrator (no change in influences for each time step during the integration period). This is the most efficient method and may be accurate enough for many simulations. An alternate method would be for the central body model to continuously recompute its state on each call from some previous time to the time requested - this could be costly in terms of computational burden but simple to implement. Yet another option would be for the central body to internally buffer a set of state vectors spanning the output step size, allowing for quick interpolation of the central body's state at intermediate times. A forth method would be to make use of a simplified linear model for short term propagation of the central body's state (similar to a state-transition matrix). The final decision rests with the designer of the model. The goal here is to simply bring light to this potential problem.

After initializing the array of **IVisualModel** objects, a Java3D
**BranchGroup** is created for each model with the
**j3d.SimpleBGModel** class. A **BranchGroup** can be thought of
as a basic self contained unit that can be inserted independently into
the Java3D virtual universe. It contains the visual representation of
the model along with the logic needed to update itself and react to
outside stimuli. This is where keyboard controls are connected using
the **j3d.KeyBehavior** class. In addition to keyboard controls, the
**SimpleBGModel** class can also create its own
**ModelTimeBehavior** for simulations based around a central model,
alleviating the need for the user to create them outside of this class.
The SimpleBGModel could just a well be passed to any external Java3D
application requiring a BranchGroup object. Note that the VSE uses a
"Z-axis up" reference frame, where a rotation of -90 deg about the
X-axis is made from the Java3D "Y-axis up" reference frame.

The final step is to instantiate a **j3d.SimV3D** object with the
**SimV3Dcfg** object and the array of **BranchGroup** models.
From here, *SimV3D.init()* creates the basic GUI interface.
Instantiation of **j3d.SimV3DJPanel** completes the GUI and fires up
the simulation with the creation of a Java3D **SimpleUniverse**.

Back to Homepage