Baumgarte and Softness for 2D Joints

 Posts: 41
 Joined: Sat Apr 08, 2006 11:20 am
Baumgarte and Softness for 2D Joints
On Erin's blog, in a comment is the following statement:
"Relaxation is an indirect way to soften the joints. In the GDC07 version of the bridge I directly use softness and the Baumgarte parameter to achieve a specified joint stiffness and damping. Unlike a true spring and damper, the SI algorithm can handle large stiffness and damping values."
What is the relationship between the Baumgarte Factor/Softness and Spring Constant/Dampning Constant.
Also, what is the general method for adding "softness" to other constraints. I have a 2D pin joint (keeps the anchors of two bodies at a constant distance) and a 2D slider joint that I'd like to add softness to.
Jeff
"Relaxation is an indirect way to soften the joints. In the GDC07 version of the bridge I directly use softness and the Baumgarte parameter to achieve a specified joint stiffness and damping. Unlike a true spring and damper, the SI algorithm can handle large stiffness and damping values."
What is the relationship between the Baumgarte Factor/Softness and Spring Constant/Dampning Constant.
Also, what is the general method for adding "softness" to other constraints. I have a 2D pin joint (keeps the anchors of two bodies at a constant distance) and a 2D slider joint that I'd like to add softness to.
Jeff

 Posts: 324
 Joined: Fri Jul 01, 2005 5:29 am
 Location: Irvine
 Contact:
You can find a reference for this technique here:
http://ode.org/ode0.5userguide.html#sec_3_8_2
I have implemented this in the current version of Box2D:
http://www.gphysics.com/files/Box2D_Lite.zip
In particular, look at the suspension bridge demo.
You should be able to use the same technique for any joint. Coming up with stiffness and damping coefficients for rotational constraints may be a little tricky. You'll need to consider the length scale of your objects.
http://ode.org/ode0.5userguide.html#sec_3_8_2
I have implemented this in the current version of Box2D:
http://www.gphysics.com/files/Box2D_Lite.zip
In particular, look at the suspension bridge demo.
You should be able to use the same technique for any joint. Coming up with stiffness and damping coefficients for rotational constraints may be a little tricky. You'll need to consider the length scale of your objects.

 Posts: 41
 Joined: Sat Apr 08, 2006 11:20 am
I'm still trying to get my head around the implementation of softeness.
In particular, I have a 2D Angle Joint with upper and lower limits. I used Erin's description here http://www.continuousphysics.com/Bullet ... .php?t=517 to create the joint. The joint works fine and I mostly understand the physics behind it.
However, now I'm trying to add a softness parameter to soften the joint correction at the limits.
I read the description in the ODE paper and I've looked at the softness implementation in Box2D_Lite, but I still can't seem to translate that into something that works for my angle limits.
In the Box2D_Lite, you apply the softness in the PreStep by adding it to a couple elements of the big K matrix:
K.col1.x += softness;
K.col2.y += softness;
I assume this is related to the following statment in the ode paper: "Thus CFM simply adds to the diagonal of the original system matrix"
And you apply the softness further in the ApplyImpulse by subtracting softness*P from the dv:
impulse = M * (bias  dv  softness * P);
I assume this is due to the function from the ODE docs: J * v = c + CFM * lambda
I'm just not sure how to apply it to my Angle joint. There is still just a little to much MathFog in the way.
Anybody care to break the math down a little bit more for me.
In particular, I have a 2D Angle Joint with upper and lower limits. I used Erin's description here http://www.continuousphysics.com/Bullet ... .php?t=517 to create the joint. The joint works fine and I mostly understand the physics behind it.
However, now I'm trying to add a softness parameter to soften the joint correction at the limits.
I read the description in the ODE paper and I've looked at the softness implementation in Box2D_Lite, but I still can't seem to translate that into something that works for my angle limits.
In the Box2D_Lite, you apply the softness in the PreStep by adding it to a couple elements of the big K matrix:
K.col1.x += softness;
K.col2.y += softness;
I assume this is related to the following statment in the ode paper: "Thus CFM simply adds to the diagonal of the original system matrix"
And you apply the softness further in the ApplyImpulse by subtracting softness*P from the dv:
impulse = M * (bias  dv  softness * P);
I assume this is due to the function from the ODE docs: J * v = c + CFM * lambda
I'm just not sure how to apply it to my Angle joint. There is still just a little to much MathFog in the way.
Anybody care to break the math down a little bit more for me.

 Posts: 874
 Joined: Sun Jul 03, 2005 4:06 pm
 Location: Kirkland, WA
You basically want to weaken the constraint force:
The usual formulation is:
J*W*JT*lambda = = K * lambda = 0.1 * C / dt  J * v
> lambda =  (ERP * C / dt  J * v ) / K
If we now add CFM to K lambda get smaller while if we would subtract from K lambda would get stronger. So if I remember correctly you should do:
lambda =  (ERP * C / dt  J * v ) / ( K + CFM )
So I suggest you try someting like ERP = 0.001 and CFM = 0.005 (or vice versa  I don't remember). If you want to use ODE values I mean to remember that you need to scale or divide by dt...
HTH,
Dirk
The usual formulation is:
J*W*JT*lambda = = K * lambda = 0.1 * C / dt  J * v
> lambda =  (ERP * C / dt  J * v ) / K
If we now add CFM to K lambda get smaller while if we would subtract from K lambda would get stronger. So if I remember correctly you should do:
lambda =  (ERP * C / dt  J * v ) / ( K + CFM )
So I suggest you try someting like ERP = 0.001 and CFM = 0.005 (or vice versa  I don't remember). If you want to use ODE values I mean to remember that you need to scale or divide by dt...
HTH,
Dirk

 Posts: 41
 Joined: Sat Apr 08, 2006 11:20 am
Thanks Dirk.
I'm not really concerned with the values of ERP and CFM (BiasFactor and Softness)
I'm just interested in implementing softness into my angle joint class. (I'll worry about good values later)
What you show helps me alot. My only question now I guess is the specifics of how to apply this in practice given my prestep and iteration steps.
In my prestep I calculate a K and the biasVelocity
In my iteration step (ApplyImpulses) I calculate my impulse, accumulate impulses, then apply the clamped impulse.
Do I simply need to modify my K calculation in the prestep to include the CFM (softness) factor?
Going from memory (as I'm at work) I think my mass factor (Inv K?) is:
massFactor = 1/(invI1 + InvI2) //calculated in the prestep
and my impulse calc is:
impulse = (biasVelocty  angularVelocity1 + angularVelocity2)*massFactor //might not have remembered all the signs correctly
do i just need to make massFactor;
massFactor = 1/(invI1 + InvI2 + CFM)
I'm not really concerned with the values of ERP and CFM (BiasFactor and Softness)
I'm just interested in implementing softness into my angle joint class. (I'll worry about good values later)
What you show helps me alot. My only question now I guess is the specifics of how to apply this in practice given my prestep and iteration steps.
In my prestep I calculate a K and the biasVelocity
In my iteration step (ApplyImpulses) I calculate my impulse, accumulate impulses, then apply the clamped impulse.
Do I simply need to modify my K calculation in the prestep to include the CFM (softness) factor?
Going from memory (as I'm at work) I think my mass factor (Inv K?) is:
massFactor = 1/(invI1 + InvI2) //calculated in the prestep
and my impulse calc is:
impulse = (biasVelocty  angularVelocity1 + angularVelocity2)*massFactor //might not have remembered all the signs correctly
do i just need to make massFactor;
massFactor = 1/(invI1 + InvI2 + CFM)

 Posts: 324
 Joined: Fri Jul 01, 2005 5:29 am
 Location: Irvine
 Contact:
You really should go through the entire derivation if you really want to understand softness.
We start with:
Newton's Law:
M * (v2  v1) = JT * lambda
Velocity constraint with softness and Baumgarte:
J * v2 + softness * lambda + bias = 0
where bias = biasFactor * C / dt
We know everything except v2 and lambda.
First solve Newton's law for v2 in terms of lambda:
v2 = v1 + invM * JT * lambda
Substitute this expression into the velocity constraint:
J * (v1 + invM * JT * lambda) + softness * lambda + bias = 0
Now collect coefficients of lambda:
(J * invM * JT + softness) * lambda =  J * v1  bias
Now we define:
K = J * invM * JT + softness
and Meff = invK is the effective mass.
Now keep in mind that v1 contains the velocities for both bodies:
v1 = column_vector(vb1, omegab1, vb2, omegab2)
Now here is where things get a bit hairy. Each iteration we are not computing the whole impulse, we are computing an increment to the impulse and we are updating the velocity. Also, as we solve each constraint we get a perfect v2, but then some other constraint will come along and mess it up. So we want to patch up the constraint while acknowledging the accumulated impulse and the damaged velocity. To help with that we use P for the accumulated impulse and dP as the update. Mathematically we have:
M * (v2new  v2damaged) = JT * dP
J * v2new + softness * (P + dP) + bias = 0
If we solve this we get:
v2new = v2damaged + invM * JT * dP
J * (v2damaged + invM * JT * dP) + softness * P + softness * dP + bias = 0
(J * invM * JT + softness) * dP = (J * v2damaged + softness * P + bias)
Note how the accumulated impulse comes into the righthand side. We can solve this for dP and then accumulate and clamp the impulse.
So you can see that understanding softness is a bit tricky. I recommend going over this with a 1D test case and implementing it and making sure you understand it. Try a 1D particle that can only move up and down. Then try to constrain the motion completely with a soft constraint.
We start with:
Newton's Law:
M * (v2  v1) = JT * lambda
Velocity constraint with softness and Baumgarte:
J * v2 + softness * lambda + bias = 0
where bias = biasFactor * C / dt
We know everything except v2 and lambda.
First solve Newton's law for v2 in terms of lambda:
v2 = v1 + invM * JT * lambda
Substitute this expression into the velocity constraint:
J * (v1 + invM * JT * lambda) + softness * lambda + bias = 0
Now collect coefficients of lambda:
(J * invM * JT + softness) * lambda =  J * v1  bias
Now we define:
K = J * invM * JT + softness
and Meff = invK is the effective mass.
Now keep in mind that v1 contains the velocities for both bodies:
v1 = column_vector(vb1, omegab1, vb2, omegab2)
Now here is where things get a bit hairy. Each iteration we are not computing the whole impulse, we are computing an increment to the impulse and we are updating the velocity. Also, as we solve each constraint we get a perfect v2, but then some other constraint will come along and mess it up. So we want to patch up the constraint while acknowledging the accumulated impulse and the damaged velocity. To help with that we use P for the accumulated impulse and dP as the update. Mathematically we have:
M * (v2new  v2damaged) = JT * dP
J * v2new + softness * (P + dP) + bias = 0
If we solve this we get:
v2new = v2damaged + invM * JT * dP
J * (v2damaged + invM * JT * dP) + softness * P + softness * dP + bias = 0
(J * invM * JT + softness) * dP = (J * v2damaged + softness * P + bias)
Note how the accumulated impulse comes into the righthand side. We can solve this for dP and then accumulate and clamp the impulse.
So you can see that understanding softness is a bit tricky. I recommend going over this with a 1D test case and implementing it and making sure you understand it. Try a 1D particle that can only move up and down. Then try to constrain the motion completely with a soft constraint.

 Posts: 41
 Joined: Sat Apr 08, 2006 11:20 am