Oppose a force using a custom joint constraint

From Newton Wiki
Jump to: navigation, search

Template:Languages

Abstract

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

#ifndef SIMPLE_ACCELERATION_BASED_CONSTRAINT_H
#define SIMPLE_ACCELERATION_BASED_CONSTRAINT_H
#include "Ogre.h"
#include "OgreNewt.h" 

using namespace Ogre;
using namespace OgreNewt;

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

#endif

Source File

#ifndef SIMPLE_ACCELERATION_BASED_CONSTRAINT_CPP
#define SIMPLE_ACCELERATION_BASED_CONSTRAINT_CPP
#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 
	/**************************************/
bod->setCustomForceAndTorqueCallback<SimpleAccelerationBasedConstraint>(SimpleAccelerationBasedConstraint::ForceTorqueBodyCallback,this);

	/**************************************/
	//set up the user data so we can access this classes member variables from within the submitConstraint callback.
	/**************************************/
	this->setUserData(this);	 
}


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.
	/**************************************/
	bod->addForce(Vector3(100,0,0));
}

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
	setRowAcceleration(globalAccelerationAtCenterOfMass.x); 

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

#endif

Calling the Constraint

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

Results

You should see the box not moving on the screen.

Faq

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.