3
\$\begingroup\$

How do I create an ideal spring that can oscillate indefinitely using Box2D?

A b2DistanceJoint works almost perfectly, but it eventually slows to a stop, even with damping set to 0. I think it is because b2DistanceJoint is not meant for creating springs, but for preserving the distance between two bodies by correction the violated distance with a spring like behaviour. Hence, it should have a damping to eventually bring back the bodies to initial state and stop at some point.

\$\endgroup\$
7
  • \$\begingroup\$ I saw a physics presentation by the author of box2d and his talk was specifically talking about how to make sure physics systems are convergent so they will slow down and come to a rest instead of gaining energy over time and things "exploding" mathematically. The talk showed that since physics simulations are just approximations, the methods either dampen or amplify. Because of this, I think it's possible there might not be an easy way to make this happen, and that its by design that things dampen over time, due to how box2d does integration. May be a way but I could see not being a way too \$\endgroup\$
    – Alan Wolfe
    Commented Apr 19, 2015 at 18:21
  • \$\begingroup\$ @AlanWolfe The integrator that uses Box2D (semi-implicit Euler) is Symplectic integrator. Semi-implicit Euler method almost conserves the energy. Hence, I think it is more about what is the task of the Distance Joint, rather than how the integration is being done, and does system loses energy because of the symulation. \$\endgroup\$
    – Narek
    Commented Apr 19, 2015 at 18:47
  • \$\begingroup\$ Isn't it possible to apply force at a fixed interval? \$\endgroup\$
    – William
    Commented Apr 19, 2015 at 18:59
  • \$\begingroup\$ Do the bodies have damping? \$\endgroup\$
    – akaltar
    Commented Apr 19, 2015 at 19:21
  • \$\begingroup\$ @akaltar bodies don't have damping. \$\endgroup\$
    – Narek
    Commented Apr 20, 2015 at 6:02

1 Answer 1

1
\$\begingroup\$

If you want well defined behavior, you should consider perpetuating the oscillations yourself. I will assume, for simplicity, that we are working with a simple spring-mass-damper system where the spring and damper behavior is encapsulated in a b2DistanceJoint.

The basic idea is to evaluate the total energy (kinetic + potential) of the system and apply a force if this is below a certain threshold. The total energy of the system at any instant is given by:

spring_mass_energy

spring_mass_energy2

where m is the mass of the body at the end of the spring, k is the spring coefficient, and x is the displacement from the rest length. k can be related to the frequency of the distance joint through the equation:

spring_coeff

Plugging this in and simplifying gives:

spring_mass_energy3

All of the variables on the right hand side can be evaluated (with the help of box2d). Once you have calculated the energy, compare it with a reasonable threshold value. If it exceeds that threshold, then your spring is under significant tension or compression and/or the mass has a high velocity; in this case we don't need to do anything. If the energy falls below the threshold, then apply some small force dF along the spring axis, in the direction that the mass is currently moving.

Here's how I might implement it (in c++)

/* ... */

b2Body springBody;
b2DistanceJoint spring;
double restLength;
double Ethresh;          //Threshold energy. Set to reasonable value.
double dFM;              //Small force. Set to reasonable value.

// in time loop

/* ... */

/* Assign spring body and distance joint */

double m = springBody.GetMass();
b2Vec2 vel = springBody.GetLinearVelocity();
double vmag = vel.Length();            //Assuming the body is traveling along the spring axis
double w = spring.GetFrequency();
double x = spring.GetLength() - restLength;
double E = 0.5*m*(vmag*vmag + w*w*x*x);

if(E < Ethresh){
    b2Vec2 dF = (vel/vmag)*dFM;
    springBody.applyForce(dF);
}

/* ... */

If you have a more complicated system (e.g. distance joints attached to bodies which are joined to tertiary bodies, etc...) this will of course invalidate the theory, but I believe this approach will produce visually believable results for many different setups.

\$\endgroup\$
2
  • \$\begingroup\$ I have thought about this but then figured out a better/easier solution. The omega0 is the resonant frequency. This means that the system loves to oscillate with that frequency, i.e. if you give enough strong impulse with that frequency, it will start to oscillate. \$\endgroup\$
    – Narek
    Commented Apr 20, 2015 at 6:08
  • 2
    \$\begingroup\$ @Narek Have you tested that solution? Does it work? If so, it would be helpful if you posted that answer with a little more detail and accepted it. \$\endgroup\$ Commented Apr 20, 2015 at 14:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .