Constrained vehicle flips out when rotating >90 degrees

Orz
Posts: 2
Joined: Fri Apr 19, 2013 5:03 pm

Constrained vehicle flips out when rotating >90 degrees

Post by Orz »

I'm making a motorcycle racing game http://spaghettilogic.org/cafe_society and using Bullet for the vehicles. In order to keep them from tipping over, I apply a constraint that allows everything except rotation around the z axis. This worked fine when I was using the Panda3D engine. When I ported the project to C++ and linked in Bullet 2.77, I started having problems. The constraint works as expected when the vehicle is first added to the world, keeping it upright despite its two wheels. As soon as the vehicle turns over 90 degrees in either direction, it "explodes"; the vehicle spins and flies through the air. I suspect this is due to setting the angular limits without an epsilon "fudge factor", but I've spent all morning on it and I'm losing patience. If anyone can lend some insight it would be much appreciated.

Here's my code:

Code: Select all

		///Set above origin
		btTransform t;
		t.setIdentity();
		t.setOrigin(btVector3(0,5,0));
		rigidBody->setWorldTransform(t);
 		physics::world->addRigidBody(rigidBody);

		/** Force the bike to stay upright.  All movement is allowed except
		angular movement around the Z axis.  This would cause the bike to roll over.*/
//		rigidBody->setAngularFactor(btVector3(1,1,0));
		btTransform c;
		c.setIdentity();
		uprightConstraint = new btGeneric6DofConstraint(
			*rigidBody,
			btTransform::getIdentity(),
			false
		);

		uprightConstraint->setLimit(0, 1, 0);
		uprightConstraint->setLimit(1, 1, 0);
		uprightConstraint->setLimit(2, 1, 0);
		uprightConstraint->setLimit(3, 1, 0);
		uprightConstraint->setLimit(4, 1, 0);
		uprightConstraint->setLimit(5, 0, 0);

		physics::world->addConstraint(uprightConstraint);


		settings = new btRaycastVehicle::btVehicleTuning();
		raycaster = new btDefaultVehicleRaycaster(physics::world);

		bulletVehicle = new btRaycastVehicle(*settings, rigidBody, raycaster);
		bulletVehicle->setCoordinateSystem(0,1,2);	///Bike is sideways if this is set wrong
		physics::world->addVehicle(bulletVehicle);
norbie
Posts: 21
Joined: Mon Feb 11, 2013 1:57 pm

Re: Constrained vehicle flips out when rotating >90 degrees

Post by norbie »

I am not familiar with RaycastVehicle so my answer might not be 100% relevant but I know for sure that btGeneric6DofConstraint doesn't really like 90 degree rotation on its Y axis. Please see detailed description of btGeneric6DofConstraint in bullet online help:
Angulars limits have these possible ranges:
AXIS MIN ANGLE MAX ANGLE
X -PI PI
Y -PI/2 PI/2
Z -PI PI
So I guess you need to rotate the coordinate system of your constraint to be able to solve your problem e.g. you could try to rotate it by -90 degrees around the X axis. This way the X axis will stay, the "new" Z axis will point in the direction of the "old" Y and the "new" Y axis will point in the opposite direction as the "old" Z. So you will need to lock the Y axis in this coordinate system, and allow the rest to be free. Something like this:

Code: Select all

      btTransform c;
      c.setIdentity();
      c.getBasis().setEulerZYX( -SIMD_HALF_PI, 0, 0 );
...
     uprightConstraint->setLimit(0, 1, 0);
      uprightConstraint->setLimit(1, 1, 0);
      uprightConstraint->setLimit(2, 1, 0);
      uprightConstraint->setLimit(3, 1, 0);
      uprightConstraint->setLimit(4, 0, 0);
      uprightConstraint->setLimit(5, 1, 0);
Hope this helps.
Orz
Posts: 2
Joined: Fri Apr 19, 2013 5:03 pm

Re: Constrained vehicle flips out when rotating >90 degrees

Post by Orz »

That worked perfectly. Thank you very much. It also explains why I had no problems with Panda: that engine uses a coordinate system where Z is the up axis.

Just to clarify for anyone reading this thread in the future, you rotate an identity matrix 90 degrees around the X axis and pass it into the constructor of the btGeneric6dofConstraint:

Code: Select all

 		
btTransform c;
c.setIdentity();
c.getBasis().setEulerZYX( -SIMD_HALF_PI, 0, 0 );
uprightConstraint = new btGeneric6DofConstraint(*rigidBody, c, false);
uprightConstraint->setLimit(0, 1, 0);
uprightConstraint->setLimit(1, 1, 0);
uprightConstraint->setLimit(2, 1, 0);
uprightConstraint->setLimit(3, 1, 0);
uprightConstraint->setLimit(4, 0, 0);
uprightConstraint->setLimit(5, 1, 0);
physics::world->addConstraint(uprightConstraint);