Posted by

herkules on September 23, 2007 at 10:09 AM PDT

Are you doing engineering using Java? Or even science? Than you sometimes might need to calculate how objects move under

the impression of forces and torques. The following might be for you then...

Are you doing engineering using Java? Or even science? Than you sometimes might need to calculate how objects move under

the impression of forces and torques. The following might be for you then...

Maybe somebody of you, dear reader, has already tried out my flight simulator

FlyingGuns which is part of the

Distributed RealTime Simulation project on SourceForge .

The flight model of motion is very simple.

I call it *physically motivated* instead of *physical* because it relies on some heuristics

that are not modeled using forces and torques. That is appropriate for a game but not for a true simulator.

There is no framework to plug in forces that are then correctly treated. This is the main reason why

the airplane cannot land, because there is just no mean to model the forces caused by the undercarriage on the ground.

In order to change this, I started to develop a simple dynamics framework.

It currently is located in the projects sandbox

because the API is not fully settled yet.

With this package, it is easy to define bodies that behave physically correct. This is a

piece of sample code to setup a 5kg body with gravity `G`

and a `Spring`

:

Body body = new Body();

body.setMass(5.0);

KinematicState state = new KinematicState();

state.attitude(QuatUtil.ONEd);

CompositeForce f = new CompositeForce();

f.addForce(new G(body));

Vector3d springcenter = new Vector3d(0,0,5);

Spring s = new Spring(springcenter, 5 );

f.addForce( s );

Dynamic dynbody = new Dynamic(body, state, f);

I call it *dynamics stack* to keep it apart from a *physics engine* like

ODEJava or JOODE .

A *physics engine* is a far more complex beast dealing a lot with collision detection

and - as a main task - computing the appropriate forces. But any *physics engine*

needs some kind of dynamics code under the hood.

There is no secret in how to do that. The math is known for hundreds of years meanwhile.

Yet some aspects, esp. those concerning rotational motion are highly unintuitive

(it took me 2 years to develop kind of mental image).

Having this thoroughly solved makes the value of this package.

## Stack

Why is it a stack? Because on each level of the stack there is a set of classes implementing the interface of the next lower level.

Each level of the stack can be used on its own, omitting higher levels as desired.

These are the stacked components:

- intergrator
- kinematics
- dynamics
- physics
- application, e.g. flight model

## Integration

Integration has the task to solve *ordinary differential equations* (ODE). It gets some initial

values and an object that can calculate the resp. derivatives in time d/dt. The integrator has no idea

what the values do mean - it has no notion of e.g. *position* or *speed*.

There are several well-known ways to do that with different quality and performance.

My package implements *Euler* and *RungeKutta*. While the algorithms are

not easy to understand, the resp. code is quite simple because the algorithms are very

well described in various textbooks

and there are many samples on the net.

*Cash-Karp* (see Numerical Recipes in C )

is currently under development.

The *Euler* integrator is the most simple one basically perfoming:

`x_new = x_old + v*dt`

Thats very fast, but only works if forces are small and do hardly ever change.

A common spring already may blow that approach.

*RungeKutta* is much more advanced but also takes (at least) four times more CPU power.

## Kinematics

Kinematics gives a meaning to terms like *position* or *speed* and can transform them to

the array of values needed by the integrator. It also respects that we are dealing with second

order differential equations (eg. position is order 0, velocity is order 1, acceleration is order 2)

and transforms them into a system of equations of first order:

One second order equation

position = f( velocity, acceleration )

makes 2x first order equation:

position = f(velocity)

velocity = f(acceleration)

On the kinematics level, the interface `Acceleration`

plays the key role. On this level,

there still is no notion of a phyical body having *mass* properties.

## Dynamics

Dynamics introduces the phyical body having *mass* and *inertia*. A class implementing

the kinematics interface `Acceleration`

converts forces and torques acting on a

physical body into acceleration. While this is trivial for translational properties (just divide

by mass - F=ma - remember?), the rotational parts needs some consideration concerning world-

and body-fixed coordinate systems and the transforms between them.

On the dynamics level, the interface `Force`

plays the key role.

## Physics

On this level, forces and torques are defined. It is not truely a level in the stack, but more

a collection of utilities. There are predefined forces like gravity *G* or a spring.

Conceptually harder is a class called `RotatingPart`

which allows to model parts

within a body that do rotate themselves. Think of propellers or turbines as an example.

Again, this rotational things are not easy to deal with on an intuitive level.

## Tests

Now how to test dynamics? I took two approaches. One is the classical unit test comparing the results of

the integration with a know analytical solution. Here is one taken from a textbook:

// problem 10-32 in my edition of Classical Dynamics by Marion+Thornton

@Test

public void spinningPlate()

{

Body b = new Body();

// I1 = 1, I2 = 2*I1, I3 = I1 + I2

b.setInertia(new Matrix3d(1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0));

KinematicState state = new KinematicState();

state.omega(new Vector3d(Math.sqrt(3), 0, 1));

// with no forces and torques, w_body_y(t) should be |w| cos(a) tanh(|w| t sin(a)).

// a = 30 degrees, so cos(a) = sqrt(3)/2 and sin(a) = 1/2. the expected result is

// thus sqrt(3) * tanh(t).

Dynamic d = new Dynamic(b, state, Force.NONE );

double dt = 1.0/1000.0;

double t = 0;

for( int i = 0; i < 300; i++ )

{

d.progress((long)t, dt);

t += dt;

// System.out.println(i + " " + Math.sqrt(3)*Math.tanh(t) + " " + state.omega().y);

assertEquals(Math.sqrt(3)*Math.tanh(t), state.omega().y, 0.05 );

}

}

The other approach is

*piecewise comparison* with a human judging from the visuals. E.g. assuming euler

integration works, I run the system with a RungeKutta integration. The results have to be

comparable. The same can be done to show that the calculation of acceleration from forces work correct

or that a rotating body behaves like one that does not rotate, but has a rotating part with same

inertia.

## Next

Things to come (besides an application for a new flight model for FlyingGuns) is some

kind of exception handling in case of overstress. Sometime, forces may go beyond their limits

that e.g. may destroy the structure. This could be implemented using exceptions.

## Links