[ODE] Ball joint vs universal joint
Brad
braddabug at comcast.net
Thu Aug 4 17:34:06 MST 2005
I made a simple demo of a user mode ball joint with stops. In the demo I
sat a simple system of two cubes connected via one of these ball joints
next to one connected via a universal joint. The axes and stops for
these joints are the same, so in theory the joints should behave the
same, right? But when the universal joint reaches a "corner" and comes
to rest, the ball joint bounces and just doesn't look as good.
Is there something wrong with my code? Or is this a "feature?"
// code uses the drawstuff thingy included with ODE
#define dSINGLE
#include <iostream>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#define GRAVITY -1
#define STEPSIZE 0.01
#define SIDE 0.5
//#define USE_EULER_AMOTOR
dWorldID myWorld;
dGeomID myFloor;
dBodyID myBase;
dBodyID myHead;
dBodyID myBase2;
dBodyID myHead2;
dJointID myBallJoint;
dJointID myFixedJoint;
dJointID myAngularMotor;
dJointID myFixedJoint2;
dJointID myUniJoint;
void setupTest()
{
myWorld = dWorldCreate();
dWorldSetERP(myWorld, 0.2f);
dWorldSetCFM(myWorld, 0.0001);
dWorldSetGravity(myWorld, 0, 0, GRAVITY);
// create the bodies
myBase = dBodyCreate(myWorld);
myHead = dBodyCreate(myWorld);
myBase2 = dBodyCreate(myWorld);
myHead2 = dBodyCreate(myWorld);
dBodySetPosition(myBase, 0, 0, 0.25);
dBodySetPosition(myHead, 0, 0, 3);
dBodySetPosition(myBase2, 2, 0, 0.25);
dBodySetPosition(myHead2, 2, 0, 3);
// create the joints
myBallJoint = dJointCreateBall(myWorld, 0);
myFixedJoint = dJointCreateFixed(myWorld, 0);
myAngularMotor = dJointCreateAMotor(myWorld, 0);
myUniJoint = dJointCreateUniversal(myWorld, 0);
myFixedJoint2 = dJointCreateFixed(myWorld, 0);
dJointAttach(myBallJoint, myBase, myHead);
dJointAttach(myFixedJoint, myBase, 0);
dJointAttach(myAngularMotor, myBase, myHead);
dJointAttach(myUniJoint, myBase2, myHead2);
dJointAttach(myFixedJoint2, myBase2, 0);
dJointSetBallAnchor(myBallJoint, 0, 0, 2);
dJointSetUniversalAnchor(myUniJoint, 2, 0, 2);
dJointSetFixed(myFixedJoint);
dJointSetFixed(myFixedJoint2);
dJointSetUniversalAxis1(myUniJoint, 1, 0, 0);
dJointSetUniversalAxis2(myUniJoint, 0, 1, 0);
dJointSetUniversalParam(myUniJoint, dParamHiStop, 1);
dJointSetUniversalParam(myUniJoint, dParamLoStop, -1);
dJointSetUniversalParam(myUniJoint, dParamHiStop2, 1);
dJointSetUniversalParam(myUniJoint, dParamLoStop2, -1);
// setup the angular motor
#ifdef USE_EULER_AMOTOR
dJointSetAMotorMode(myAngularMotor, dAMotorEuler);
dJointSetAMotorAxis(myAngularMotor, 0, 1, 1, 0, 0);
//dJointSetAMotorAxis(myAngularMotor, 1, 0, 0, 1, 0);
dJointSetAMotorAxis(myAngularMotor, 2, 2, 0, 0, 1);
#else
dJointSetAMotorNumAxes(myAngularMotor, 3);
dJointSetAMotorAxis(myAngularMotor, 0, 0, 1, 0, 0);
dJointSetAMotorAxis(myAngularMotor, 1, 0, 0, 1, 0);
dJointSetAMotorAxis(myAngularMotor, 2, 2, 0, 0, 1);
dJointSetAMotorAngle(myAngularMotor, 0, 0);
dJointSetAMotorAngle(myAngularMotor, 1, 0);
dJointSetAMotorAngle(myAngularMotor, 2, 0);
#endif
// create a stop
dJointSetAMotorParam(myAngularMotor, dParamHiStop, 1);
dJointSetAMotorParam(myAngularMotor, dParamLoStop, -1);
dJointSetAMotorParam(myAngularMotor, dParamHiStop, 1);
dJointSetAMotorParam(myAngularMotor, dParamLoStop, -1);
dJointSetAMotorParam(myAngularMotor, dParamHiStop2, 1);
dJointSetAMotorParam(myAngularMotor, dParamLoStop2, -1);
dJointSetAMotorParam(myAngularMotor, dParamHiStop2, 1);
dJointSetAMotorParam(myAngularMotor, dParamLoStop2, -1);
dJointSetAMotorParam(myAngularMotor, dParamHiStop3, 0);
dJointSetAMotorParam(myAngularMotor, dParamLoStop3, 0);
dJointSetAMotorParam(myAngularMotor, dParamHiStop3, 0);
dJointSetAMotorParam(myAngularMotor, dParamLoStop3, 0);
}
static void start()
{
static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
static void command (int cmd)
{
switch (cmd)
{
case 'a': case 'A':
dJointAddAMotorTorques(myAngularMotor, 10, 0, 0);
dJointAddUniversalTorques(myUniJoint, 10, 0);
break;
case 'd': case 'D':
dJointAddAMotorTorques(myAngularMotor, -10, 0, 0);
dJointAddUniversalTorques(myUniJoint, -10, 0);
break;
case 'w': case 'W':
dBodyAddRelTorque(myHead, 0, 0, 10);
break;
case 's': case 'S':
dBodyAddRelTorque(myHead, 0, 0, -10);
break;
case 'z': case 'Z':
dJointAddAMotorTorques(myAngularMotor, 0, 10, 0);
dJointAddUniversalTorques(myUniJoint, 0, 10);
break;
case 'x': case 'X':
dJointAddAMotorTorques(myAngularMotor, 0, -10, 0);
dJointAddUniversalTorques(myUniJoint, 0, -10);
}
}
static void simLoop (int pause)
{
// take a step
dWorldStep (myWorld,STEPSIZE);
// draw!
dsSetTexture(DS_WOOD);
dsSetColor(1,1,0);
dReal sides1[3] = {SIDE,SIDE,SIDE};
dsDrawBox(dBodyGetPosition(myBase), dBodyGetRotation(myBase), sides1);
dsDrawBox(dBodyGetPosition(myHead), dBodyGetRotation(myHead), sides1);
dsDrawBox(dBodyGetPosition(myBase2), dBodyGetRotation(myBase2), sides1);
dsDrawBox(dBodyGetPosition(myHead2), dBodyGetRotation(myHead2), sides1);
// draw the joints
dsSetTexture(DS_NONE);
dsSetColor(0, 0, 1);
float pos1[3] = {0,0,0};
float pos2[3] = {0, 0, 2};
const dReal *bpos = dBodyGetPosition(myHead);
float pos3[3];
pos3[0] = bpos[0]; pos3[1] = bpos[1]; pos3[2] = bpos[2];
dsDrawLine(pos1, pos2);
dsDrawLine(pos2, pos3);
// calculate the angles for the angular motor
const dReal * bpos1 = dBodyGetPosition(myHead);
// relative to the ball joint anchor
dVector3 bpos2;
bpos2[0] = 0;
bpos2[1] = 0;
bpos2[2] = 2;
// first axis (X)
float rx = bpos1[1] - bpos2[1];
float ry = bpos1[2] - bpos2[2];
float restx = 0;
float resty = 2;
float angle = atan(rx / ry);
dJointSetAMotorAngle(myAngularMotor, 0, angle);
// Y axis
rx = bpos1[0] - bpos2[0];
ry = bpos1[2] - bpos2[2];
angle = atan(rx / ry);
dJointSetAMotorAngle(myAngularMotor, 1, -angle);
}
void doTest (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = "./";
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dWorldDestroy (myWorld);
}
int main(int argc, char* argv[])
{
setupTest();
doTest(argc, argv);
return 0;
}
More information about the ODE
mailing list