Crash when using 6DOF constraint in a redundant setup

aspfreakout
Posts: 6
Joined: Mon Jan 24, 2011 10:15 am

Crash when using 6DOF constraint in a redundant setup

Post by aspfreakout »

admin renamed buggyworld.zip -> buggyworld.bullet

Hi,

I was trying simulate a highly redundant spring-mass system using Bullet in combination with GameKit.
The simulation (see the code below) contains a number of spheres (about 50) with a mass of 0.1(kg) at random locations.
Between some pairs of spheres I want to put springs, so I'm using the 6dof spring constraint (so I don't have to change my code to allow more movements) with only one unconstrained axis (the first linear one).
The pairs are a subset of a Delaunay triangulation of the spheres' locations (i.e. so that only pairs of nearby spheres are selected).

Of course the resulting system is highly redundant most of the time, but this is exactly the goal of the experiment, so reducing the number of springs is not an option (I'd rather prefer to add some more...).

So to setup the simulation, I first create a set of spheres, and then I start adding constraints between pairs (A,B) of spheres.
For the transform in frame A, I take the offset (B.getPosition()-A.getPosition()) divided by two as the origin and use projection of the vector from A to B on A's original x-axis to compute a rotation matrix.
I reduced the internal time step to 1ms and set the solver's number of iterations to 20 to increase the accuracy.

If I run this, the simulation crashes after a few frames with the following exception:
gamekit-read-only/OgreLite/OgreMain/src/OgreNode.cpp:393: virtual void Ogre::Node::setOrientation(const Ogre::Quaternion&): Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
The error is generated by gkPhysicsController::setTransform() at gkPhysicsController.cpp:601 0xb07a8d, trying to update position of the objects in Ogre (using NaN for the rotation).
Basically my simulation exploded, because if I run the simulation in slow-motion, I can see the objects drift away into infinity before crashing.

I don't see why this happens, but I guess something's wrong with the transforms for the constraints?

So here's the code with the necessary comments:

Code: Select all

	unsigned num_points = 50;
	float sparseness = 0.3;
	gkVector3 center(0,0,1);
	for(unsigned i=0;i<num_points;++i){
		gkVector3 point;
		//generate random points (locations)
		point.x = center.x+(float)rand()/(float)RAND_MAX-0.5;
		point.y = center.y+(float)rand()/(float)RAND_MAX-0.5;
		point.z = center.z+(float)rand()/(float)RAND_MAX-0.5;
		input.push_back(point);

		gkString new_name = "Ball_";char buff[10];	sprintf(buff,"%u",i);
		new_name.append(buff);
		//create a new ball
		gkGameObject* newball = scene->getObject("Sphere")->clone(new_name);

		//add it to the scene
		newball->setOwner(0);
		newball->setActiveLayer(true);
		engine.getActiveScene()->addObject(newball);
		newball->createInstance();
		newball->setPosition(point);
		newball->getAttachedBody()->getBody()->setActivationState(DISABLE_DEACTIVATION);

		newball->setOrientation(gkEuler(0,0,0));
		balls.push_back(newball);
	}
	d.triangulate(input,output); //delaunay triangulation

	for(unsigned i=0;i<output.size();++i){
		gkVector3 pa = input[output[i].first];
		gkGameObject* ba = balls[output[i].first];// A
		gkVector3 pb = input[output[i].second];
		gkGameObject* bb = balls[output[i].second]; //B
		if(((float)rand()/(float)RAND_MAX)>sparseness){
			joints.push_back(std::pair<size_type,size_type>(output[i].first,output[i].second));
			btTransform ta,tb; //transforms in A and B's frames
			ta.setIdentity();
			gkVector3 offset = bb->getPosition()-ba->getPosition(); //vector from A to B
			btVector3 offset_b(offset.x,offset.y,offset.z); //in Bullet
			btVector3 noffset_b = offset_b.normalized(); //normalize the vector (not strictly necessary)
			noffset_b/=noffset_b.x(); //assures that we have a valid rotation matrix
			ta.setOrigin(offset_b/2); //place the joint in the middle of A and B
			//create the rotation matrix (the x-axis is projected onto the vector from A to B)
			btMatrix3x3 rotmat = btMatrix3x3(noffset_b.x(),noffset_b.y(),noffset_b.z(),0,1,0,0,0,1).transpose();
			btScalar det = rotmat.determinant();
			ta.setBasis(rotmat);
			//just a check, but it is always equal to one
			gkPrintf("det %f\n ",ta.getBasis().determinant());
			//the same for B
			tb.setIdentity();
			tb.setOrigin(-offset_b/2);
			tb.setBasis(rotmat);
			//Create the constraint
			btGeneric6DofSpringConstraint * constraint = new btGeneric6DofSpringConstraint(*ba->getAttachedBody()->getBody(),*bb->getAttachedBody()->getBody(),ta,tb,true);
			//Fix every direction except for the first (x)
			constraint->setLinearLowerLimit(btVector3(1,0,0));
			constraint->setLinearUpperLimit(btVector3(-1,0,0));
			constraint->setAngularLowerLimit(btVector3(0,0,0));
			constraint->setAngularUpperLimit(btVector3(0,0,0));

			constraint->enableSpring(0,true); //enable the internal spring for the first direction
			constraint->setStiffness(0, 10); //spring constant
			constraint->setDamping(0,0.8);
			constraint->setEquilibriumPoint();
			
			//add the constraint to the physics engine
			engine.getActiveScene()->getDynamicsWorld()->getBulletWorld()->addConstraint(constraint);
		}
Of course I can provide additional information if required, it's just a bit hard to extract a complete example.
Instead I exported the Bullet world through: engine.getActiveScene()->getDynamicsWorld()->exportBullet("buggyworld.zip"); which you can find attached to this post.

Any ideas on how to fix this would be appreciated!
Thanks
You do not have the required permissions to view the files attached to this post.