Links: Hinges and Sliders

aboeing
Posts: 33
Joined: Tue Jul 26, 2005 2:28 pm

Links: Hinges and Sliders

Post by aboeing »

Hi,

Does someone have an example of how to use the btHingeConstraint?
Specifically, what should the axis values be?
(I would like to have a hing constrait like a door's: one pivot point for both bodies with one axis of rotation)

(ie: just like ODE's hinge: http://www.ode.org/ode-latest-userguide.html#sec_7_3_2)

Also, how does one set a prismatic links axis?
(ie: just like ODE's slider axis: http://www.ode.org/ode-latest-userguide.html#sec_7_3_3)
(I created the slider via the btGeneric6DofConstraint, and added setLinearLowerLimit/upper)

Thanks!
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Links: Hinges and Sliders

Post by Erwin Coumans »

aboeing wrote:Hi,

Does someone have an example of how to use the btHingeConstraint?
Specifically, what should the axis values be?
(I would like to have a hing constrait like a door's: one pivot point for both bodies with one axis of rotation)
(ie: just like ODE's hinge: http://www.ode.org/ode-latest-userguide.html#sec_7_3_2)
See Bullet/Demos/ConstraintDemo/ConstraintDemo.cpp, and add those 2 lines for a hinge:

Code: Select all

   {
                btRigidBody* body0 = localCreateRigidBody( mass,trans,shape);
                trans.setOrigin(btVector3(2*CUBE_HALF_EXTENTS,20,0));

                mass = 1.f;
                btRigidBody* body1 = localCreateRigidBody( mass,trans,shape);                 body1->setActivationState(DISABLE_DEACTIVATION);
                body1->setDamping(0.3,0.3);

                btVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS);
                btVector3 axisInA(0,0,1);

                btVector3 pivotInB = body1 ? body1->getCenterOfMassTransform().inverse()(body0->getCenterOfMassTransform()(pivotInA)) : pivotInA;
                btVector3 axisInB = body1?
                        (body1->getCenterOfMassTransform().getBasis().inverse()*(body1->getCenterOfMassTransform().getBasis() * axisInA)) :
                body0->getCenterOfMassTransform().getBasis() * axisInA;

                btTypedConstraint* p2p = new btPoint2PointConstraint(*body0,*body1,pivotInA,pivotInB);
                btTypedConstraint* hinge = new btHingeConstraint(*body0,*body1,pivotInA,pivotInB,axisInA,axisInB);

                m_dynamicsWorld->addConstraint(hinge);//p2p);

        }
Also, how does one set a prismatic links axis?
(ie: just like ODE's slider axis: http://www.ode.org/ode-latest-userguide.html#sec_7_3_3)
(I created the slider via the btGeneric6DofConstraint, and added setLinearLowerLimit/upper)
Thanks!
Which constraint do you want to build exactly? Ah, the slider in ConstraintDemo.cpp has been modified into a ragdoll rotational joint, for testing: using the btGeneric6DofConstraint, you can lock/free/limit the 3 linear and 3 angular axis independently.

To make it a slider with translation along the x-axis and rotation along the same x-axis, make following changes to the ConstraintDemo.cpp:

Code: Select all

btVector3 lowerSliderLimit = btVector3(-10,0,0);
btVector3 hiSliderLimit = btVector3(10,0,0);
and

Code: Select all

    //create a slider, using the generic D6 constraint
        {
                mass = 1.f;
                btVector3 sliderWorldPos(0,10,0);
                btVector3 sliderAxis(1,0,0);
                btScalar angle=0.f;//SIMD_RADS_PER_DEG * 10.f;
                btMatrix3x3 sliderOrientation(btQuaternion(sliderAxis ,angle));
                trans.setIdentity();
                trans.setOrigin(sliderWorldPos);
                //trans.setBasis(sliderOrientation);
                sliderTransform = trans;

                d6body0 = localCreateRigidBody( mass,trans,shape);
                d6body0->setActivationState(DISABLE_DEACTIVATION);
                btRigidBody* fixedBody1 = localCreateRigidBody(0,trans,0);

                btTransform frameInA, frameInB;
                frameInA = btTransform::getIdentity();
                frameInB = btTransform::getIdentity();

                btGeneric6DofConstraint* slider = new btGeneric6DofConstraint(*d6body0,*fixedBody1,frameInA,frameInB);
                slider->setLinearLowerLimit(lowerSliderLimit);
                slider->setLinearUpperLimit(hiSliderLimit);

                //range should be small, otherwise singularities will 'explode' the constraint
                slider->setAngularLowerLimit(btVector3(10,0,0));
                slider->setAngularUpperLimit(btVector3(0,0,0));

                m_dynamicsWorld->addConstraint(slider);

        }

This will all go into the Bullet manual at some stage.
Thanks,
Erwin
aboeing
Posts: 33
Joined: Tue Jul 26, 2005 2:28 pm

Post by aboeing »

Hi Erwin,
Thanks again for the fast replies!

I got the hinge working, but my question for the slider was how to set the axis along which the slider translates?
To make it a slider with translation along the x-axis and rotation along the same x-axis, make following changes to the ConstraintDemo.cpp:
I would like to make it slide along an arbitrary axis - is there a way to do this?

Edit: PS: I noticed some strange behaviour with the slider, if the two bodies of the slider have another body inbetween them (that does not belong to the set of constraints) they respond unpredictably.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Post by Erwin Coumans »

aboeing wrote:I would like to make it slide along an arbitrary axis - is there a way to do this?
Yes. Just choose a different local frame in A (and the appropriate local frame in B).
Edit: PS: I noticed some strange behaviour with the slider, if the two bodies of the slider have another body inbetween them (that does not belong to the set of constraints) they respond unpredictably.
Do you have some modified Bullet Demo that demonstrates this? Note that the current mouse picking in Bullet violates all constraints, it's too strong (a spring would be better).
Right now, the constraints are all solved before collision contacts. This means their effect is less then a collision. In a future version I will interleave regular joint constants with contact constraints, that should improve/fix this.

Erwin
aboeing
Posts: 33
Joined: Tue Jul 26, 2005 2:28 pm

Post by aboeing »

I'm not sure how to set the frame - I tried setting the bias via getBasis().setEulerYPR, but it didn't appear to rotate the link. What is the 'appropriate' local frame for the second link?

I PM'ed you with the download location for an example where you can reproduce the odd link behaviour.
par4
Posts: 2
Joined: Sat Dec 02, 2006 2:56 pm

Post by par4 »

Hi Erwin,

Bullet is a terrific library thanks for making it freely available.

Have you resolve the ?arbitrary axis? issue mentioned above and if so could you explain it here? I am currently trying to construct a ragdoll with btGeneric6DofConstraint (because of its rotational limits feature) and is experiencing a similar problem.

For example, the torso is represented by a big box and an upper left arm by a smaller box towards the top. I would want the pivot axis (where the 6 dof limits are referenced from) between these two to be the the shoulder bone (which is an arbitrary axis). However, my unsuccessful attempts had the pivot axis as the the segment between the pivot point and torso's center of mass.

Also a more general question is how to use the ?frameInA? and ?frameInB?variables in the btGeneric6DofConstraint constructor. I tried to set my own reference frames in my above attempts. For instance could you describe how to build a hinge from a btGeneric6DofConstraint that has an angle between the two attached bodies.

Thanks.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Post by Erwin Coumans »

I just upgraded the Bullet Physics integration in Blender 3D modeler to version 2.37, and added compound and generic D6 joint support. This way, I found out that indeed, there is some issue with using arbitrary joint frames for the generic D6 joint. I will look into it, and let you know when its fixed.

Thanks,
Erwin

par4 wrote:Hi Erwin,

Bullet is a terrific library thanks for making it freely available.

Have you resolve the ?arbitrary axis? issue mentioned above and if so could you explain it here? I am currently trying to construct a ragdoll with btGeneric6DofConstraint (because of its rotational limits feature) and is experiencing a similar problem.

For example, the torso is represented by a big box and an upper left arm by a smaller box towards the top. I would want the pivot axis (where the 6 dof limits are referenced from) between these two to be the the shoulder bone (which is an arbitrary axis). However, my unsuccessful attempts had the pivot axis as the the segment between the pivot point and torso's center of mass.

Also a more general question is how to use the ?frameInA? and ?frameInB?variables in the btGeneric6DofConstraint constructor. I tried to set my own reference frames in my above attempts. For instance could you describe how to build a hinge from a btGeneric6DofConstraint that has an angle between the two attached bodies.

Thanks.
par4
Posts: 2
Joined: Sat Dec 02, 2006 2:56 pm

Post by par4 »

Okay, thanks.
lolo
Posts: 4
Joined: Wed May 09, 2007 1:37 pm
Location: Brest, France

Post by lolo »

Hello,

I'm a newbie in Bullet.
I'm trying to create a slider joint between two objects along an arbitrary axis using a btGeneric6DofConstraint.
To do this, I saw the constraintDemo.cpp, the forum and also the blender source code.
When I create the slider, it is only along the X-axis of the object ....

Code: Select all

//create 2 rigid bodies : the parent and the child
//create the frame attached to the joint
btTransform  sliderFrame( 0.707,0.707,0,
                                             -0,707,0.707,0,
                                              0,0,1);
sliderFrame.setOrigin(btVector3(0,0,0));

btTransform sliderInParent = sliderFrame //the origin of the joint is the origin of the parent
                                                                            //the frame of the joint is the frame of the parent with a rotation of PI/4 around the Z-axis

btTransform sliderInWorld = parent.getCenterOfMassTransform()*sliderInParent;
btTransform sliderInChild = (child.getCenterOfmassTransform().inverse())*sliderInworld;

btGeneric6DofConstraint slider = new btGeneric6DofConstraint(parent, child, jointInParent, jointInChild);

//there is only one translation along the X-axis of joint frame
slider->setLinearLowerLimit(btVector3(1,0,0));
slider->setLinearUpperLimit(btVector3(0,0,0));

//there is no rotation
slider->setAngularLowerLimit(btVector3(0,0,0));
slider->setAngularUpperLimit(btVector3(0,0,0));

world->addConstraint(slider);
what I expect is that the child moves along the X-axis of the joint frame and not along its own X-Axis.

Can someone explain why it doesn't work :cry: ?
Is my interpretation of frameInA and frameInB or/and my interpretation of the axis which allow the degrees of freedom which are false?

Thanks for your help :)
Last edited by lolo on Sat May 12, 2007 9:45 pm, edited 1 time in total.
Rawsock
Posts: 3
Joined: Mon Apr 16, 2007 2:41 pm

Post by Rawsock »

Perhaps the linear constraints are specified in global space and need transforming first. I don't know if that's a bug or a feature but this code made joints work for me :

Code: Select all

// The linear limit desired
btVector3 old_limit;
// The frame of reference of the joint, in global space
btTransform jointFrame;

btTransform globaltransform;
globaltransform.setIdentity();
globaltransform.setOrigin(old_limit);

btVector3 new_limit = (jointframe.inverse() * globaltransform).getOrigin();
Use that snippet only with linear limits. Angular limits do not seem to be affected and work as expected.

PS: Sorry about my crappy english.
lolo
Posts: 4
Joined: Wed May 09, 2007 1:37 pm
Location: Brest, France

Post by lolo »

Hi Rawsock,


Thanks for answering so fast.
I try to integrate your code into mine, but it doesn't work.
When I execute the program, the slider joint is totally broken => translation along all the axis

So I modify it a bit :

Code: Select all



// The frame of reference of the joint, in global space
btTransform jointFrame; 

//I want the axis totally free, so in the local space attached to the joint
//I got : 
btVector3 lowerLimit=btVector3(1,0,0);
//and
btVector3 upperLimit=btVector3(0,0,0);

//so in global space all of this become
lowerLimit = jointFrame.inverse().getBasis().inverse() * lowerLimit;
// the upper limit is unchanged because it's a null vector
//and finally
sliderJoint.setLowerLimit(lowerLimit);
sliderJoint.setUpperLimit(upperLimit);
When you say that your snippet works, does it works in all cases? I mean does it work only when you have to create a limited translation or when you have to create an infinit translation(in this case what do you put in the upper and lower limits) ?

Thanks.
Rawsock
Posts: 3
Joined: Mon Apr 16, 2007 2:41 pm

Post by Rawsock »

Yes, i forgot to add that only works for partially locked linear limits. For infinite linear limits ( max < min ) it doesn't work. You could try simulating free limits with very big limits, but that seems very unstable.
lolo
Posts: 4
Joined: Wed May 09, 2007 1:37 pm
Location: Brest, France

Post by lolo »

Hi Rawsock,


I'm sorry to bother you one more time, but I try to do what you've said (big limit) and it doesn't work.
In my example, I want to compute a slider joint whose frame was turned PI/4 around Z-axis of the world frame. The slider is along the X-axis of the slider frame. The result is that my object can move along the X-axis and Y-axis of the world : it can move in a squared surface.

here is my code

Code: Select all


btTransform  sliderFrame( 0.707,0.707,0,
                                               -0,707,0.707,0,
                                                0,0,1);
sliderFrame.setOrigin(btVector3(0,0,0)); 

btTransform sliderInParent = sliderFrame //the origin of the joint is the origin of the parent
                                                                            //the frame of the joint is the frame of the parent with a rotation of PI/4 around the Z-axis

btTransform sliderInWorld = parent.getCenterOfMassTransform()*sliderInParent;
btTransform sliderInChild = (child.getCenterOfmassTransform().inverse())*sliderInworld; 

btGeneric6DofConstraint slider = new btGeneric6DofConstraint(parent, child, jointInParent, jointInChild); 
//I think this above part is good

btVector3 upperLimit(10,0,0);
btVector3 lowerLimit(-10,0,0);

upperLimit = sliderInWorld.getCenterOfMassTransform().getBasis()*upperLimit; // upperLimit = (0.707*10, 0.707*10,0);
lowerLimit = sliderInWorld.getCenterOfMassTransform().getBasis()*lowerLimit; // lowerLimit = (-0.707*10, -707*10,0);
//Is it what you explain in your last reply ?

Can tell me what's wrong into my code ?

Thanks a lot