Page 1 of 1

Chain of constraints is very unstable if masses differ

Posted: Thu Sep 05, 2019 10:33 am
by PetrD
Hello,
I am working on a pretty ambitious project that enables players to build their own worlds using generic shapes and constraints.

The physical simulation runs into problems when the player chains number (more than one) of dynamic bodies via constraints to a static body.
If the mass of the bodies varies greatly the constraints tend to become very "soft" or break completely.

What feels odd is that I can attach very heavy object to a static body with no problem. If there is another body between them though both constraints tend to break. I do not need constraints that never break. What I would like to have is some consistency in behaviour.

I have reproduced this issue in the bullet example browser using this code:

Code: Select all

	btCollisionShape* shape = new btBoxShape(btVector3(2, 2, 2));
	m_collisionShapes.push_back(shape);

	float mass = 1;

	btTransform tr;
	tr.setIdentity();
	tr.getBasis().setEulerZYX(0, 0, 0);

	tr.setOrigin(btVector3(btScalar(0.), btScalar(6), btScalar(0.)));
	btRigidBody* pBodyA = createRigidBody(0, tr, shape);
	pBodyA->setActivationState(DISABLE_DEACTIVATION);

	tr.setOrigin(btVector3(btScalar(10), btScalar(6), btScalar(0)));
	btRigidBody* pBodyB = createRigidBody(mass, tr, shape);
	pBodyB->setActivationState(DISABLE_DEACTIVATION);

	tr.setOrigin(btVector3(btScalar(20), btScalar(6), btScalar(0)));
	btRigidBody* pBodyC = createRigidBody(mass * 300, tr, shape);
	pBodyC->setActivationState(DISABLE_DEACTIVATION);

	btTransform frameInLeft, frameInRight;
	frameInLeft = btTransform::getIdentity();
	frameInLeft.setOrigin(btVector3(btScalar(5), btScalar(0), btScalar(0)));
	frameInRight = btTransform::getIdentity();
	frameInRight.setOrigin(btVector3(btScalar(-5), btScalar(0), btScalar(0)));

	{
		btGeneric6DofConstraint* pGen6DOF = new btGeneric6DofConstraint(*pBodyA, *pBodyB, frameInLeft, frameInRight, true);
		pGen6DOF->setAngularLowerLimit(btVector3(0, 0, 0));
		pGen6DOF->setAngularUpperLimit(btVector3(-1, 0, 0));
		m_dynamicsWorld->addConstraint(pGen6DOF, true);
	}

	{
		btGeneric6DofConstraint* pGen6DOF = new btGeneric6DofConstraint(*pBodyB, *pBodyC, frameInLeft, frameInRight, true);
		pGen6DOF->setAngularLowerLimit(btVector3(0, 0, 0));
		pGen6DOF->setAngularUpperLimit(btVector3(-1, 0, 0));
		m_dynamicsWorld->addConstraint(pGen6DOF, true);
	}
snippet.PNG
snippet.PNG (65.45 KiB) Viewed 153 times
Now I understand this might be a standard problem but I need to find a solution or workaround for it.

I tried to address such situations by increasing number of solver iterations and setting higher constraint ERP. That is however not enough in some cases (and I don't want to use extreme number of solver iterations anyway).

I have also limited the maximum mass for a body in the simulation and I scale down the inertia tensor calculated if it's too big. It helps but it's dirty and I would like to get rid of such a hack.

I will be thankful for any hint or advice,
Petr

Re: Chain of constraints is very unstable if masses differ

Posted: Thu Sep 05, 2019 2:34 pm
by Erwin Coumans
You can use btMultiBody instead, together with some velocity motors to model joint friction/damping.
It is easiest to prototype this directly in PyBullet first, see its quickstart guide.

For btRigidBody, using a smaller time step would help more than increasing the number of iterations, but btMultiBody is a better solution for this.

Re: Chain of constraints is very unstable if masses differ

Posted: Mon Sep 09, 2019 4:21 pm
by PetrD
Hi Erwin, thanks for your reply.
Unfortunately we cannot use btMultiBody because we let the player build the world himself. He has number of gadgets at his disposal representing joints of various types - some of them using limits, motors or springs. The player can combine any of these gadgets creating chains of different constraints. btMultiBody does not support these features atm.

Also as the game should handle big worlds with big number of dynamic objects and constraints we cannot afford to use extremely small step (atm we use 1/100 s).

Am I guessing correctly that the behaviour we are experiencing is to be expected from the algorithm used in btSequentialImpulseConstraintSolver? Can you think of any parameters to change or parts of the algorithm to rewrite to mitigate the issue?