Oppose a force using a custom joint constraint

From Newton Wiki
Jump to: navigation, search



I've been struggling trying to make a raycast car and understand Newton. An important part of this is preventing the car from sliding. In order to do this the lateral forces need to be canceled. (A tire rolls easily in one direction, but is quite difficult to push it orthogonal to it's normal axis of rotation). These lateral forces are a function of the normal force at the tire contact point and the coefficient of friction between the tire and the terrain.

Techniques to cancel lateral forces

Since I'm new to this I can really only comment on the method I've been exploring, which is using a custom joint to cancel the lateral forces.

First steps

Originally I just went for it, but I got confused and was never able to make it work. I backed up to the simplest case I could make that would cancel the lateral forces on an object. To further simplify it I applied and tried to cancel the force at the center of mass. I've created a class that demonstrates this using OgreNewt and Ogre. I apply a force in the Positive x direction. This force is canceled by the custom joint constraint.

Header File

#include "Ogre.h"
#include "OgreNewt.h" 

using namespace Ogre;
using namespace OgreNewt;

class SimpleAccelerationBasedConstraint : public OgreNewt::CustomJoint
	SimpleAccelerationBasedConstraint(SceneManager *mgr, World *world, Body *bod);
	void ForceTorqueBodyCallback(OgreNewt::Body *bod);
	void submitConstraint();
	Vector3 previousTimestepVelocity;
	Body *bod;


Source File

#include "SimpleAccelerationBasedConstraint.h"

SimpleAccelerationBasedConstraint::SimpleAccelerationBasedConstraint(SceneManager *mgr, World *world, Body *body) :   CustomJoint(1,body,NULL)
	previousTimestepVelocity = 0;
	float KgFrameMass = 100;//100kg
	Entity *ent = mgr->createEntity("boxEntity", "box.mesh" );
       SceneNode *sn = mgr->getRootSceneNode()->createChildSceneNode("box");
	sn->scale(0.02f,0.02f,0.02f); //scale the scene node because the box.mesh is bigger than I want.
       sn->attachObject( ent );
	bod = body;

	//create an interia matrix.
	Ogre::Vector3 inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( KgFrameMass, Ogre::Vector3(2,.5,2) );
	bod->setMassMatrix( KgFrameMass, inertia );

	//attach the Ogre scene node to the body
	bod->attachToNode( sn );

	//set the position and orientation of the body 
	bod->setPositionOrientation(Vector3(0,10,0) , Quaternion(Quaternion::IDENTITY)); //position the object 10 meters above 0,0,0
	bod->setAutoFreeze(0);//keep it active all the time..this may be unecessary

	//set up the force/torque callback 

	//set up the user data so we can access this classes member variables from within the submitConstraint callback.

void SimpleAccelerationBasedConstraint::ForceTorqueBodyCallback(OgreNewt::Body *bod)
	//apply a force for the contraint to oppose
	//for this example it must be only in the x direction due to the way we calcualted the velocity and acceleration below.

void SimpleAccelerationBasedConstraint::submitConstraint()
	SimpleAccelerationBasedConstraint *me = (SimpleAccelerationBasedConstraint*)this->getUserData();
	//get the chassis pos and velocity
	Vector3 globalPos;
	Quaternion globalOrient;
	me->bod->getPositionOrientation(globalPos, globalOrient);
	Vector3 globalLinearVelocity = me->bod->getVelocity();

	//calculate the acceleration at the center of mass.
	Vector3 globalAccelerationAtCenterOfMass  = (globalLinearVelocity-me->previousTimestepVelocity)/bod->getWorld()->getTimeStep();

	//add the linear constraint to prevent movement along the + x direction at the center of mass of the object.
	addLinearRow(globalPos+Vector3(1,0,0), globalPos,Vector3(1,0,0));
	//in this staged example, I'm only applying a force in the positive x direction so I know the acceleration
	//can only be in the +x direction

	//save the current velocity for next time.
	me->previousTimestepVelocity = globalLinearVelocity;


Calling the Constraint

//create the body and set the mass matrix
Body *bod = new OgreNewt::Body(mWorld, col );
simple = new SimpleAccelerationBasedConstraint(mPLSMSceneMgr,mWorld, bod);


You should see the box not moving on the screen.


The box.mesh is there just so I can visually see the object, feel free to drop in any other mesh you have available to you.