The Source for Java Technology Collaboration
User: Password:



Joerg Plewe

Joerg Plewe's Blog

A simple physics/dynamics stack

Posted by herkules on September 23, 2007 at 10:09 AM | Comments (12)

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
dynamics_overview.jpg

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.

screenshot_DynamicSample.jpg

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


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • This looks very interesting and pretty simple to use. Could I use your library for something simple like the inertial dragging on the iPhone or a fountain/volcano particle simulator?

    Posted by: joshy on September 24, 2007 at 09:44 AM

  • Yes, you can use it. But I wouldn't. For 2D as well as for particles the rotational parts are quite easy. And for particles, running 1000s of integrators might kill performance. I assume you'd be better of with a formula like that:

    s_new = s_old + v*t + 1/2*a*t²

    Posted by: herkules on September 24, 2007 at 02:26 PM

  • Yes, you can use it. But I wouldn't. For 2D as well as for particles the rotational parts are quite easy. And for particles, running 1000s of integrators might kill performance. I assume you'd be better of with a formula like that:

    s_new = s_old + v*t + 1/2*a*t²

    Posted by: herkules on September 24, 2007 at 02:27 PM

  • Very cool Joerg!

    Posted by: johnreynolds on September 25, 2007 at 06:55 AM

  • I love this stuff :-)

    Posted by: fabriziogiudici on September 25, 2007 at 07:50 AM

  • Do you have any additional examples to help get a better understanding of how to use it - i.e. a set of masses connected by a set of springs, with damping?

    Posted by: andyroberts007 on September 25, 2007 at 08:39 AM

  • No, currently not, I'm sorry. Having connected masses also is not well covered by the package so far. This is where true physics engines like ODEJava or JOODE come into play, bc. forces on a body depend on other bodies. I assume this requires a somewhat different approach for integration. Currently integration is done per object, which might not be good enough for multi-body problems.

    Posted by: herkules on September 25, 2007 at 08:49 AM

  • My current goal is to create a flight model ... and thats a single-body problem :)

    But I already thought about that ... maybe I'll attack that later.

    Posted by: herkules on September 25, 2007 at 08:53 AM

  • Doh! Now you tell me this, after I've built my own library! Actually, building my own library (incomplete though it remains) was quite fun in its own right. There's more I'd like to toy with in the area of units (and I think there are existing libraries for that) and generics.

    Posted by: trinition on September 25, 2007 at 05:25 PM

  • I'm sorry :)

    Work together to make it better?

    plewe at hardcode dot de

    Posted by: herkules on September 26, 2007 at 11:57 AM

  • I quite liked this.
    Would be interested to see how far the physics model evolved. Have always been a fan of WW1 flight combat games, especially ones which aimed to offer realistic physics. Few are attempting this commercially now.

    I never got to see a realistically modelled Sopwith Camel with engine torque (rotary engine) and vicious spin characteristics. Some got close but the Holy Grail was never reached.

    From the overview, it does not seem you are going that far with WW1 flight models.

    Posted by: pbalmforth on October 01, 2007 at 12:04 PM

  • pbalmforth, for now I just have the framework. Although the class RotatingPart is a hint on what it could get used for.

    Now creating a flight model can start. Making a high-fidelity flight model will be quite difficult, for it iss hard to find reliable data about the original planes. You can just guess about mass properties like CG or inertia, not even talking about aerodynamical features.

    You can find windtunnel data for F16 on the net, but unfortunately not for Fokker DR1 :(

    Finding a true DR1 pilot who finally can judge how good the model is another problem.

    The intention of the framework was that it should be possible to model forces piece by piece. This can be helpful to improve a given model over time by taking more and more forces into account.

    If there is anybody out there with knowlegde and motivation to build a high-fidelity model ... lets do that!

    Posted by: herkules on October 02, 2007 at 03:24 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds