[ODE] simulator behaviour problem

Gildas Bayard gildas.bayard at mail.com
Tue Dec 11 06:59:02 2001


This is a multi-part message in MIME format.

------=_NextPart_000_003E_01C18253.14EFC980
Content-Type: multipart/alternative;
	boundary="----=_NextPart_001_003F_01C18253.14EFC980"


------=_NextPart_001_003F_01C18253.14EFC980
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable


Hi everybody,

I'm about to use ODE for my PhD stuff. My goal is to design adaptive
controllers based on new types of neural network which include adaptive
synapses and simulation of neuromodulators behaviour.

To obtain a good controller through artificial evolution, I need to
perform thousands of virtual test in the same simulator with
successively different animats. That's where I get into a problem with =
ODE.

I try the following:
1) I create a world and a space.
2) I add bodies and joints for my first hexapod and run the
simulation. After a certain amount of time I want to test an other
one. So I destroy all the bodies and joints of the first hexapod and
add all the bodies and joints of the second one.
3) When I've tested enough hexapods I destroy the world and space.

The exact problem is the following: right after the morphology has
been re-created again I got an "ODE Message 3: LCP internal error,=20
s <=3D 0" error and the hexapod performs a bad move.

Even if I recreate world and space each time I want to test a new
hexapod (in addition to the morphology), I got the same problem.
I probably need to initialize something each time I test a new agent
but I don't know what...

Gildas Bayard

AnimatLab
Laboratoire d'Informatique de Paris 6

NB: In the example file I've attached the morphology is always the same =
so
it doesn't seem useful to destroy the hexapod to create it again right
away. The idea is that in my application the morphology might vary
from an animat to another one.

------=_NextPart_001_003F_01C18253.14EFC980
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2600.0" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff><FONT face=3DArial size=3D2>
<DIV><BR>Hi everybody,</DIV>
<DIV>&nbsp;</DIV>
<DIV>I'm about to use ODE for my PhD stuff. My goal is to design=20
adaptive<BR>controllers based on new types of neural network which =
include=20
adaptive<BR>synapses and simulation of neuromodulators behaviour.</DIV>
<DIV>&nbsp;</DIV>
<DIV>To obtain a good controller through artificial evolution, I need=20
to<BR>perform thousands of virtual test in the same simulator=20
with<BR>successively different animats. That's where I get into a =
problem with=20
ODE.</DIV>
<DIV>&nbsp;</DIV>
<DIV>I try the following:<BR>1) I create a world and a space.<BR>2) I =
add bodies=20
and joints for my first hexapod and run the<BR>simulation. After a =
certain=20
amount of time I want to test an other<BR>one. So I destroy all the =
bodies and=20
joints of the first hexapod and<BR>add all the bodies and joints of the =
second=20
one.<BR>3) When I've tested enough hexapods I destroy the world and =
space.</DIV>
<DIV>&nbsp;</DIV>
<DIV>The exact problem is the following: right after the morphology =
has<BR>been=20
re-created again I got an "ODE Message 3: LCP internal error, <BR>s =
&lt;=3D 0"=20
error and the hexapod performs a bad move.</DIV>
<DIV>&nbsp;</DIV>
<DIV>Even if I recreate world and space each time I want to test a=20
new<BR>hexapod (in addition to the morphology), I got the same =
problem.<BR>I=20
probably need to initialize something each time I test a new =
agent<BR>but I=20
don't know what...</DIV>
<DIV>&nbsp;</DIV>
<DIV>Gildas Bayard</DIV>
<DIV>&nbsp;</DIV>
<DIV>AnimatLab<BR>Laboratoire d'Informatique de Paris 6</DIV>
<DIV>&nbsp;</DIV>
<DIV>NB: In the example file I've attached the morphology is always the =
same=20
so<BR>it doesn't seem useful to destroy the hexapod to create it again=20
right<BR>away. The idea is that in my application the morphology might=20
vary<BR>from an animat to another one.</FONT></DIV></BODY></HTML>

------=_NextPart_001_003F_01C18253.14EFC980--

------=_NextPart_000_003E_01C18253.14EFC980
Content-Type: application/octet-stream;
	name="hexapod.cpp"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="hexapod.cpp"

/******************=0A=
 *                *=0A=
 *     hexapod    *=0A=
 *                *=0A=
 ******************=0A=
=0A=
bodies are enclosed by [], joints are enclosed by ()=0A=
=0A=
FRONT=0A=
=0A=
        LEFT            RIGHT=0A=
=0A=
    (13)    (07)    (06)    (12)=0A=
[14]----[08]----[02]----[07]----[13]=0A=
                 |=0A=
                 | (01)=0A=
                 |=0A=
    (11)    (05) |  (04)    (10)=0A=
[12]----[06]----[01]----[05]----[11]=0A=
                 |=0A=
                 | (00)=0A=
                 |=0A=
    (09)    (03) |  (02)    (08)=0A=
[10]----[04]----[00]----[03]----[09]=0A=
=0A=
BACK=0A=
=0A=
*/=0A=
=0A=
#include <iostream>=0A=
#include <string>=0A=
#include <stdio.h>=0A=
#include "ode/ode.h"=0A=
=0A=
#include "../drawstuff/src/drawstuff.cpp"=0A=
#include "../drawstuff/src/x11.cpp"=0A=
=0A=
// select correct drawing functions=0A=
=0A=
#ifdef dDOUBLE=0A=
#define dsDrawBox dsDrawBoxD=0A=
#define dsDrawSphere dsDrawSphereD=0A=
#define dsDrawCylinder dsDrawCylinderD=0A=
#define dsDrawCappedCylinder dsDrawCappedCylinderD=0A=
#endif=0A=
=0A=
// some constants=0A=
#define FOREARMLENGTH 0.05 // forearm length=0A=
#define FOREARMWIDTH 0.05  // forearm width (also forearm height)=0A=
#define FOREARMMASS 0.1    // forearm mass=0A=
=0A=
#define ARMLENGTH 0.2   // arm length=0A=
#define ARMWIDTH 0.05	// arm width (also arm height)=0A=
#define ARMMASS 0.2     // arm mass=0A=
=0A=
#define BODYRADIUS 0.1	// body radius=0A=
#define BODYMASS 0.5	// body mass=0A=
=0A=
#define STARTX 0    // hexapod start position along x=0A=
#define STARTY 0    // hexapod start position along y=0A=
#define STARTZ 0.2  // hexapod start position along z=0A=
=0A=
#define STEPSIZE 0.01 // integrator step size in seconds=0A=
#define MAXFORCE 3=0A=
#define GRAPHICS 1=0A=
  =0A=
dWorld *world;=0A=
dSpace *space;=0A=
dJointGroup *contactgroup;=0A=
dGeom *ground;=0A=
dGeom *ground_box;=0A=
dBody *body[15];=0A=
dJoint *joint[14];=0A=
dGeom *box[12];=0A=
dGeom *sphere[3];=0A=
dContact contact;=0A=
=0A=
// this is called by dSpaceCollide when two objects in space are=0A=
// potentially colliding.=0A=
void nearCallback (void *data, dGeomID o1, dGeomID o2) {=0A=
  =0A=
  // if both objects are static -> return=0A=
  if ((dGeomGetBody(o1) =3D=3D NULL) && (dGeomGetBody(o2) =3D=3D NULL)) {=0A=
    return;=0A=
  }=0A=
=0A=
  // if both objects are dynamic -> test if they are connected, if they =
are -> return=0A=
  if ((dGeomGetBody(o1) !=3D NULL) && (dGeomGetBody(o2) !=3D NULL)) {=0A=
    if (dAreConnected(dGeomGetBody(o1), dGeomGetBody(o2))) {=0A=
      return;=0A=
    }=0A=
  }=0A=
=0A=
  if (dCollide (o1,o2,0,&contact.geom,sizeof(dContactGeom))) {=0A=
    dJoint *joint =3D new dJoint();=0A=
    joint->createContact (*world, contactgroup, &contact);=0A=
    dJointAttach (joint->id(), dGeomGetBody(o1), dGeomGetBody(o2));=0A=
  }=0A=
}=0A=
=0A=
int gaitPart;=0A=
int secondElapsed;=0A=
dReal timeElapsed;=0A=
=0A=
void control() {=0A=
  // implement bugs tripod gait=0A=
  =0A=
  dReal bodyForearmGroup1;  // group 1 is two arms on the right (joints =
2 and 6), one on the left (joint 5)=0A=
  dReal bodyForearmGroup2;  // group 2 is two arms on the left (joints 3 =
and 7), one on the right (joint 4)=0A=
  dReal forearmArmGroup1;=0A=
  dReal forearmArmGroup2;=0A=
=0A=
  timeElapsed +=3D STEPSIZE;=0A=
=0A=
  if ((int)timeElapsed - secondElapsed >=3D 1)=0A=
    cerr << "second elapsed =3D " << ++secondElapsed << endl;=0A=
  =0A=
  // target orientations, determine gait=0A=
  if ((int)timeElapsed % 2 < 1) {=0A=
    if (gaitPart !=3D 1) {=0A=
      gaitPart =3D 1;=0A=
      //	cout << "gait part 1" << endl;=0A=
    }=0A=
    bodyForearmGroup1 =3D M_PI /16;=0A=
    bodyForearmGroup2 =3D - M_PI / 16;=0A=
    forearmArmGroup1 =3D 0;=0A=
    forearmArmGroup2 =3D - M_PI / 4;=0A=
  }=0A=
  else {=0A=
    if (gaitPart !=3D 2) {=0A=
      gaitPart =3D 2;=0A=
      //	cout << "gait part 2" << endl;=0A=
    }=0A=
    bodyForearmGroup1 =3D - M_PI / 16;=0A=
    bodyForearmGroup2 =3D M_PI / 16;=0A=
    forearmArmGroup1 =3D - M_PI / 4;=0A=
    forearmArmGroup2 =3D 0;=0A=
  }=0A=
=0A=
  dReal targetSpeed;=0A=
  dReal maxSpeed =3D 0;=0A=
=0A=
  for (int i =3D 0; i < 14; i++) {=0A=
    // body/body joint should remain around zero orientation=0A=
    if (i < 2) {=0A=
      targetSpeed =3D - 10 * dJointGetHingeAngle(joint[i]->id());=0A=
      maxSpeed =3D 2;=0A=
    }=0A=
=0A=
    // body/forearm orientation=0A=
    else if (i < 8) {=0A=
      if ((i =3D=3D 2) || (i =3D=3D 5) || (i=3D=3D 6)) // group 1=0A=
	if (i % 2 =3D=3D 0) // i even=0A=
	  targetSpeed =3D 10 * (bodyForearmGroup1 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
	else // i odd=0A=
	  targetSpeed =3D 10 * (- bodyForearmGroup1 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
      else // group 2=0A=
	if (i % 2 =3D=3D 0) // i even=0A=
	  targetSpeed =3D 10 * (bodyForearmGroup2 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
	else // i odd=0A=
	  targetSpeed =3D 10 * (- bodyForearmGroup2 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
      //      cerr << "Body/Forearm target speed: " << targetSpeed << =
endl;=0A=
      maxSpeed =3D 1;=0A=
    }=0A=
=0A=
    // forearm/arm orientation=0A=
    else if (i < 14) {=0A=
      if ((i =3D=3D 8) || (i =3D=3D 11) || (i=3D=3D 12)) { // group 1=0A=
	if (i % 2 =3D=3D 0) // i even=0A=
	  targetSpeed =3D 10 * (forearmArmGroup1 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
	else // i odd=0A=
	  targetSpeed =3D 10 * (- forearmArmGroup1 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
      }=0A=
      else { // group 2=0A=
	if (i % 2 =3D=3D 0) // i even=0A=
	  targetSpeed =3D 10 * (forearmArmGroup2 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
	else // i odd=0A=
	  targetSpeed =3D 10 * (- forearmArmGroup2 - =
dJointGetHingeAngle(joint[i]->id()));=0A=
      }=0A=
      //      cerr << "Forearm/Arm target speed: " << targetSpeed << =
endl;=0A=
      maxSpeed =3D 1;=0A=
    }=0A=
=0A=
    if (targetSpeed > maxSpeed) targetSpeed =3D maxSpeed;=0A=
    if (targetSpeed < -maxSpeed) targetSpeed =3D -maxSpeed;=0A=
=0A=
    if (i < 14) {=0A=
      //	cerr << "archi output value: " <<  targetSpeed << endl;=0A=
      dJointSetHingeParam(joint[i]->id(), dParamVel, targetSpeed);=0A=
    }=0A=
    else {=0A=
      dJointSetHingeParam(joint[i]->id(), dParamVel, 0);=0A=
    }=0A=
    //      dJointSetHingeParam(joint[i], dParamVel, targetSpeed);=0A=
  }=0A=
}=0A=
=0A=
void start3dDisplay(int window_width, int window_height) {=0A=
  current_state =3D 1;=0A=
  use_textures =3D 0;=0A=
  initMotionModel();=0A=
  createMainWindow (window_width, window_height);=0A=
  glXMakeCurrent (display,win,glx_context);=0A=
=0A=
  char *prefix =3D "../drawstuff/textures";=0A=
  char *s =3D (char*) alloca (strlen(prefix) + 20);=0A=
=0A=
  strcpy (s,prefix);=0A=
  strcat (s,"/sky.ppm");=0A=
  sky_texture =3D new Texture (s);=0A=
=0A=
  strcpy (s,prefix);=0A=
  strcat (s,"/ground.ppm");=0A=
  ground_texture =3D new Texture (s);=0A=
=0A=
  strcpy (s,prefix);=0A=
  strcat (s,"/wood.ppm");=0A=
  wood_texture =3D new Texture (s);=0A=
}=0A=
=0A=
void initFrame (int width, int height) {=0A=
  if (current_state < 1) dsDebug ("internal error");=0A=
  current_state =3D 2;=0A=
=0A=
  // setup stuff=0A=
  glEnable (GL_LIGHTING);=0A=
  glEnable (GL_LIGHT0);=0A=
  glDisable (GL_TEXTURE_2D);=0A=
  glDisable (GL_TEXTURE_GEN_S);=0A=
  glDisable (GL_TEXTURE_GEN_T);=0A=
  glShadeModel (GL_FLAT);=0A=
  glEnable (GL_DEPTH_TEST);=0A=
  glDepthFunc (GL_LESS);=0A=
  glEnable (GL_CULL_FACE);=0A=
  glCullFace (GL_BACK);=0A=
  glFrontFace (GL_CCW);=0A=
=0A=
  // setup viewport=0A=
  glViewport (0,0,width,height);=0A=
  glMatrixMode (GL_PROJECTION);=0A=
  glLoadIdentity();=0A=
  const float vnear =3D 0.1f;=0A=
  const float vfar =3D 100.0f;=0A=
  const float k =3D 0.8f;     // view scale, 1 =3D +/- 45 degrees=0A=
  if (width >=3D height) {=0A=
    float k2 =3D float(height)/float(width);=0A=
    glFrustum (-vnear*k,vnear*k,-vnear*k*k2,vnear*k*k2,vnear,vfar);=0A=
  }=0A=
  else {=0A=
    float k2 =3D float(width)/float(height);=0A=
    glFrustum (-vnear*k*k2,vnear*k*k2,-vnear*k,vnear*k,vnear,vfar);=0A=
  }=0A=
=0A=
  // setup lights. it makes a difference whether this is done in the=0A=
  // GL_PROJECTION matrix mode (lights are scene relative) or the=0A=
  // GL_MODELVIEW matrix mode (lights are camera relative, bad!).=0A=
  static GLfloat light_ambient[] =3D { 0.5, 0.5, 0.5, 1.0 };=0A=
  static GLfloat light_diffuse[] =3D { 1.0, 1.0, 1.0, 1.0 };=0A=
  static GLfloat light_specular[] =3D { 1.0, 1.0, 1.0, 1.0 };=0A=
  glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient);=0A=
  glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse);=0A=
  glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular);=0A=
  glColor3f (1.0, 1.0, 1.0);=0A=
=0A=
  // clear the window=0A=
  glClearColor (0.5,0.5,0.5,0);=0A=
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);=0A=
=0A=
  // snapshot camera position (in MS Windows it is changed by the GUI =
thread)=0A=
  float view2_xyz[3];=0A=
  float view2_hpr[3];=0A=
  memcpy (view2_xyz,view_xyz,sizeof(float)*3);=0A=
  memcpy (view2_hpr,view_hpr,sizeof(float)*3);=0A=
=0A=
  // go to GL_MODELVIEW matrix mode and set the camera=0A=
  glMatrixMode (GL_MODELVIEW);=0A=
  glLoadIdentity();=0A=
  setCamera (view2_xyz[0],view2_xyz[1],view2_xyz[2],=0A=
	     view2_hpr[0],view2_hpr[1],view2_hpr[2]);=0A=
=0A=
  // set the light position (for some reason we have to do this in model =
view.=0A=
  static GLfloat light_position[] =3D { LIGHTX, LIGHTY, 1.0, 0.0 };=0A=
  glLightfv (GL_LIGHT0, GL_POSITION, light_position);=0A=
=0A=
  // draw the background (ground, sky etc)=0A=
  drawSky (view2_xyz);=0A=
  drawGround();=0A=
=0A=
  // draw the little markers on the ground=0A=
  drawPyramidGrid();=0A=
=0A=
  // leave openGL in a known state - flat shaded white, no textures=0A=
  glEnable (GL_LIGHTING);=0A=
  glDisable (GL_TEXTURE_2D);=0A=
  glShadeModel (GL_FLAT);=0A=
  glEnable (GL_DEPTH_TEST);=0A=
  glDepthFunc (GL_LESS);=0A=
  glColor3f (1,1,1);=0A=
  setColor (1,1,1,1);=0A=
=0A=
  // draw the rest of the objects. set drawing state first.=0A=
  color[0] =3D 1;=0A=
  color[0] =3D 1;=0A=
  color[0] =3D 1;=0A=
  tnum =3D 0;=0A=
}=0A=
=0A=
void drawObjects(void) {=0A=
  for (int i =3D 0; i < 3; i++) {=0A=
    dsDrawSphere (dGeomGetPosition(sphere[i]->id()), =
dGeomGetRotation(sphere[i]->id()), BODYRADIUS);=0A=
  }=0A=
  dReal forearmSides[3] =3D {FOREARMLENGTH, FOREARMWIDTH, FOREARMWIDTH};=0A=
  for (int i =3D 0; i < 6; i++) {=0A=
    dsDrawBox (dGeomGetPosition(box[i]->id()), =
dGeomGetRotation(box[i]->id()), forearmSides);=0A=
  }=0A=
  dReal armSides[3] =3D {ARMLENGTH, ARMWIDTH, ARMWIDTH};=0A=
  for (int i =3D 6; i < 12; i++) {=0A=
    dsDrawBox (dGeomGetPosition(box[i]->id()), =
dGeomGetRotation(box[i]->id()), armSides);=0A=
  }=0A=
  =0A=
  dVector3 ss;=0A=
  dGeomBoxGetLengths (ground_box->id(),ss);=0A=
  dsDrawBox =
(dGeomGetPosition(ground_box->id()),dGeomGetRotation(ground_box->id()),ss=
);=0A=
}=0A=
=0A=
void createHexapod(dWorld *world, dSpace *space) {=0A=
  int i;=0A=
  dMass *mass =3D new dMass();=0A=
=0A=
  // bodies=0A=
  for (i =3D 0; i < 3; i++) {=0A=
    body[i] =3D new dBody(*world);=0A=
    //    cerr << "position body " << i << "=3D " << STARTX << ", " << =
STARTY + i * 2 * BODYRADIUS << ", " << STARTZ << endl;=0A=
=0A=
    body[i]->setPosition(STARTX, STARTY + (i - 1) * 2 * BODYRADIUS, =
STARTZ);=0A=
    mass->setSphere(1, BODYRADIUS);=0A=
    mass->adjust(BODYMASS);=0A=
    body[i]->setMass(mass);=0A=
    sphere[i] =3D new dGeom();=0A=
    sphere[i]->createSphere (*space, BODYRADIUS);=0A=
    sphere[i]->setBody(*body[i]);=0A=
  }=0A=
=0A=
  // forearms=0A=
  for (i =3D 3; i < 9; i++) {=0A=
    body[i] =3D new dBody(*world);=0A=
    //    cerr << "position body " << i << "=3D " << (i%2 =3D=3D 0 ? =
STARTX - FOREARMLENGTH / 2.0 - BODYRADIUS : STARTX + FOREARMLENGTH / 2.0 =
+ BODYRADIUS) << ", " << STARTY + (i - 3)/2 * 2 *BODYRADIUS << ", " << =
STARTZ << endl;=0A=
=0A=
    body[i]->setPosition(i%2 =3D=3D 0 ? STARTX - BODYRADIUS - =
FOREARMLENGTH / 2.0: STARTX +  BODYRADIUS + FOREARMLENGTH / 2.0, \=0A=
		     STARTY + ((i - 3)/2 - 1) * 2 *BODYRADIUS, \=0A=
		     STARTZ);=0A=
    mass->setBox(1, FOREARMLENGTH, FOREARMWIDTH, FOREARMWIDTH);=0A=
    mass->adjust(FOREARMMASS);=0A=
    body[i]->setMass(mass);=0A=
    box[i - 3] =3D new dGeom();=0A=
    box[i - 3]->createBox(*space, FOREARMLENGTH, FOREARMWIDTH, =
FOREARMWIDTH);=0A=
    box[i - 3]->setBody(*body[i]);=0A=
  }=0A=
=0A=
  // arms=0A=
  for (i =3D 9; i < 15; i++) {=0A=
    body[i] =3D new dBody(*world);=0A=
    //    cerr << "position body " << i << "=3D " << (i%2 =3D=3D 0 ? =
STARTX - FOREARMLENGTH - ARMLENGTH / 2.0 - BODYRADIUS : STARTX + =
FOREARMLENGTH + ARMLENGTH / 2.0 + BODYRADIUS) << ", " << STARTY + (i - =
9)/2 * 2 *BODYRADIUS << ", " << STARTZ << endl;=0A=
    body[i]->setPosition(i%2 =3D=3D 0 ? STARTX - BODYRADIUS - =
FOREARMLENGTH - ARMLENGTH / 2.0 : STARTX + BODYRADIUS + FOREARMLENGTH + =
ARMLENGTH / 2.0, \=0A=
		     STARTY + ((i - 9)/2 - 1) * 2 *BODYRADIUS, \=0A=
		     STARTZ);=0A=
    mass->setBox(1, ARMLENGTH, ARMWIDTH, ARMWIDTH);=0A=
    mass->adjust(ARMMASS);=0A=
    body[i]->setMass(mass);=0A=
    box[i - 3] =3D new dGeom();=0A=
    box[i - 3]->createBox(*space, ARMLENGTH, ARMWIDTH, ARMWIDTH);=0A=
    box[i - 3]->setBody(*body[i]);=0A=
  }=0A=
=0A=
  // links body/body (number 0 and 1)=0A=
  for (i =3D 0; i < 2; i++) {=0A=
    joint[i] =3D new dJoint();=0A=
    joint[i]->createHinge(*world, 0);=0A=
    joint[i]->attach(*body[i], *body[i + 1]);=0A=
    //    cerr << "anchor joint " << i << "=3D " << STARTX << ", " << =
STARTY + (2 * i + 1) / 2.0 * BODYRADIUS << ", " << STARTZ << " | axis =
joint " << i << "=3D 0, 1, 0" << endl;=0A=
    joint[i]->setHingeAnchor(STARTX, STARTY + (2 * i - 1) * BODYRADIUS , =
STARTZ); // i / 2 * 2.0 !=3D i=0A=
    joint[i]->setHingeAxis(0, 1, 0);=0A=
    joint[i]->setHingeParam(dParamFMax, MAXFORCE);=0A=
  }=0A=
  =0A=
  // links body/forearm allowing front/back moves (number 2 to 7)=0A=
  for (i =3D 2; i < 8; i++) {=0A=
    joint[i] =3D new dJoint();=0A=
    joint[i]->createHinge(*world, 0);=0A=
    joint[i]->attach(*body[(i - 2) / 2], *body[i + 1]);=0A=
    //    cerr << "anchor joint " << i << "=3D " << (i%2 =3D=3D 0 ? =
STARTX - BODYRADIUS : STARTX + BODYRADIUS) << ", " << STARTY + (i - 2)/2 =
* 2.0 * BODYRADIUS << ", " << STARTZ << " | axis joint " << i << "=3D 0, =
0, 1" << endl;=0A=
    joint[i]->setHingeAnchor(i%2 =3D=3D 0 ? STARTX - BODYRADIUS : STARTX =
+ BODYRADIUS , \=0A=
		     STARTY + ((i - 2)/2 - 1) * 2.0 * BODYRADIUS, \=0A=
		     STARTZ);=0A=
    joint[i]->setHingeAxis(0, 0, 1);=0A=
    joint[i]->setHingeParam(dParamFMax, MAXFORCE);=0A=
  }=0A=
=0A=
  // links forearm/arm allowing up/down moves (number 8 to 13)=0A=
  for (i =3D 8; i < 14; i++) {=0A=
    joint[i] =3D new dJoint();=0A=
    joint[i]->createHinge(*world, 0);=0A=
    joint[i]->attach(*body[i - 5], *body[i + 1]);=0A=
    //    cerr << "anchor joint " << i << "=3D " << (i%2 =3D=3D 0 ? =
STARTX + BODYRADIUS + FOREARMLENGTH: STARTX - BODYRADIUS - =
FOREARMLENGTH) << ", " << STARTY + (i - 8)/2 * 2.0 * BODYRADIUS << ", " =
<< STARTZ << " | axis joint " << i << "=3D 0, 1, 0" << endl;=0A=
    joint[i]->setHingeAnchor(i%2 =3D=3D 0 ? STARTX + BODYRADIUS + =
FOREARMLENGTH: STARTX - BODYRADIUS - FOREARMLENGTH, \=0A=
		     STARTY + ((i - 8)/2 - 1) * 2.0 * BODYRADIUS, STARTZ);=0A=
    joint[i]->setHingeAxis(0, 1, 0);=0A=
    joint[i]->setHingeParam(dParamFMax, MAXFORCE);=0A=
  }=0A=
}=0A=
=0A=
void destroyHexapod() {=0A=
  int i;=0A=
  =0A=
  for (i =3D 0; i < 12; i++)=0A=
    delete box[i];=0A=
  for (i =3D 0; i < 3; i++)=0A=
    delete sphere[i];=0A=
  for (i =3D 0; i < 15; i++)=0A=
    delete body[i];=0A=
  for (i =3D 0; i < 14; i++)=0A=
    delete joint[i];=0A=
}=0A=
=0A=
void createEnvironement(dWorld *world, dSpace *space) {=0A=
  ground =3D new dGeom();=0A=
  ground->createPlane (*space,0,0,1,0);=0A=
  ground_box =3D new dGeom();=0A=
  ground_box->createBox (*space, 2, 1.5, 1);=0A=
  dMatrix3 R;=0A=
  dRFromAxisAndAngle (R, 1, 0, 0, 0.15);=0A=
  ground_box->setPosition(0, 2, -0.4);=0A=
  ground_box->setRotation(R);=0A=
}=0A=
=0A=
void destroyEnvironement() {=0A=
  delete ground;=0A=
  delete ground_box;=0A=
}=0A=
=0A=
int main (int argc, char **argv) {=0A=
  contact.surface.mode =3D dContactSlip1 | dContactSlip2 | =
dContactBounce;=0A=
  contact.surface.mu =3D dInfinity;=0A=
  contact.surface.slip1 =3D 0.05;=0A=
  contact.surface.slip2 =3D 0.05;=0A=
  contact.surface.bounce =3D 0.5;=0A=
  contact.surface.bounce_vel =3D 0.01;=0A=
  contact.surface.soft_erp =3D 0.9;=0A=
  contact.surface.soft_cfm =3D 0.05;=0A=
=0A=
  // create virtual world=0A=
  world =3D new dWorld();=0A=
  space =3D new dSpace();=0A=
  contactgroup =3D new dJointGroup(1000);=0A=
  world->setGravity (0, 0, -9.81);=0A=
    =0A=
  createEnvironement(world, space);=0A=
=0A=
  // run graphical simulation=0A=
  start3dDisplay(352, 288);=0A=
  for (int nbExec =3D 0; nbExec < 4; nbExec++) {=0A=
    createHexapod(world, space);=0A=
    =0A=
    // reset controler=0A=
    gaitPart =3D 0;=0A=
    secondElapsed =3D 0;=0A=
    timeElapsed =3D 0;=0A=
    =0A=
    for (int i =3D 0; i < 100; i++) {=0A=
      // drive the hexapod=0A=
      control();=0A=
      =0A=
      // make a step forward=0A=
      space->collide(NULL, &nearCallback);=0A=
      world->step(STEPSIZE);=0A=
=0A=
      // remove all contact joints=0A=
      contactgroup->empty();=0A=
      cerr << "#";=0A=
=0A=
      // draw the scene=0A=
      initFrame(352, 288);=0A=
      drawObjects();=0A=
      glFlush();=0A=
      glXSwapBuffers (display,win);=0A=
      XSync (display,0);=0A=
    }=0A=
    destroyHexapod();=0A=
  }=0A=
  dsStopGraphics();=0A=
  destroyMainWindow();=0A=
=0A=
  destroyEnvironement();=0A=
  =0A=
  delete contactgroup;=0A=
  delete world;=0A=
  delete space;=0A=
=0A=
  return 0;=0A=
}=0A=

------=_NextPart_000_003E_01C18253.14EFC980
Content-Type: application/octet-stream;
	name="Makefile"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="Makefile"

#########################################################################=0A=
#                                                                       #=0A=
# Open Dynamics Engine, Copyright (C) 2001 Russell L. Smith.            #=0A=
#   Email: russ@q12.org   Web: www.q12.org                              #=0A=
#                                                                       #=0A=
# This library is free software; you can redistribute it and/or         #=0A=
# modify it under the terms of the GNU Lesser General Public            #=0A=
# License as published by the Free Software Foundation; either          #=0A=
# version 2.1 of the License, or (at your option) any later version.    #=0A=
#                                                                       #=0A=
# This library is distributed in the hope that it will be useful,       #=0A=
# but WITHOUT ANY WARRANTY; without even the implied warranty of        #=0A=
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      #=0A=
# Lesser General Public License for more details.                       #=0A=
#                                                                       #=0A=
# You should have received a copy of the GNU Lesser General Public      #=0A=
# License along with this library (see the file LICENSE.TXT); if not,   #=0A=
# write to the Free Software Foundation, Inc., 59 Temple Place,         #=0A=
# Suite 330, Boston, MA 02111-1307 USA.                                 #=0A=
#                                                                       #=0A=
#########################################################################=0A=
=0A=
MAKEFILE_INC=3D../build/Makefile.inc=0A=
include $(MAKEFILE_INC)=0A=
=0A=
APPNAMES =3D $(call fEXENAME,hexapod)=0A=
=0A=
INCLUDE_PATHS =3D ../include=0A=
LIB_PATHS =3D ../lib=0A=
EXTRA_CLEAN =3D $(APPNAMES)=0A=
DEFINES=3Dd$(DREAL)=0A=
=0A=
ifeq ($(PLATFORM_IS_WINDOWS),1)=0A=
  RSRC=3D../lib/drawstuff.res=0A=
endif=0A=
=0A=
all: $(APPNAMES)=0A=
=0A=
$(call fEXENAME,hexapod): $(call fTARGETS,hexapod.cpp)=0A=
	$(call fLINK,$@,$(call fTARGETS,hexapod.cpp) $(call fLIB,ode) $(call =
fLIB,drawstuff) $(LINKOPENGL) $(LINKWIN) $(LINKMATH) $(RSRC))=0A=
=0A=
$(call fEXENAME,test): $(call fTARGETS,test.cpp)=0A=
	$(call fLINK,$@,$(call fTARGETS,test.cpp) $(call fLIB,ode) $(call =
fLIB,drawstuff) $(LINKOPENGL) $(LINKWIN) $(LINKMATH) $(RSRC))=0A=

------=_NextPart_000_003E_01C18253.14EFC980
Content-Type: image/jpeg;
	name="snapshot.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
	filename="snapshot.jpg"

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAE+AWADASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDh4I9c
1rxLJpWlSTy3UssgihWfYDt3MeSQBgA9+1dB/wAK4+JP/Phc/wDgwi/+OVh+GWuv+E8u/sHm/bDB
qHkeRnzPM+zzbduOd2cYxzmug8MH4k/8JZo328eLPsf26Dz/AD/tPl+XvXduzxtxnOeMV7NSrNP3
WvmZpHBR6jdzapbeZdTPsjnZdzk4PlNyPelOrX/a9uT/ANtm/wAapWrf8TKIn/njP/6Kao9+OKuM
tX/XRCNH+1tQ/wCf25/7/N/jSDV78DAvbjn/AKaN/jWcXANBfJzVcwGj/a1+P+X24z/11b/Gj+1r
8D/j8uP+/rVm7+fWgueO1HMBo/2tqB/5frjPb96f8aP7Wv8AP/H9cf8Af1uf1rO3+4pC5o5gNH+1
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
zmT/ABr0iij+xqP80vw/yD+28R/LH8f8zzf/AIRrXP8AoH/+Rk/xo/4RrXP+gf8A+Rk/xr0iij+x
qP8ANL8P8g/tvEfyx/H/ADPNv+EZ1z/oH/8AkZP8aP8AhGtc/wCgf/5GT/GvSaKX9jUf5pfh/kH9
t4j+WP4/5nmv/CM65/z4f+Rk/wAaP+EY1zPNh/5GT/GvSqKP7Fo/zS/D/IP7bxH8sfx/zPNf+EY1
z/nw/wDIyf40f8IxruMfYP8AyKn+NelUUf2LR/ml+H+Qf23iP5Y/j/meanwxrvH+g/X98n+NB8Ma
4f8Alx/8jJ/jXpVFH9i0f5pfh/kH9t4j+WP4/wCZ5p/wi+ubs/YP/Iqf41KfDet/ZI4BYcrI7k+a
n8QUev8As16NRS/sSh/NL8P8g/tzEfyx/H/M80PhbXP+fD/yMn+NJ/wi2uEY+wgD/rqn+NemUUf2
LQ/ml+H+Qf23iP5Y/j/mFFFFeyeMFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUA
FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU
UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR
RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUA
FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU
UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR
RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUA
FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU
UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR
RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFj7L/t/pR9l/wBv9Kt0V+d/6x43
+b8F/kfa/wBkYP8Ak/F/5lT7L/t/pR9l/wBv9Kt0Uf6x43+b8F/kH9kYP+T8X/mVPsv+3+lH2X/b
/SrdFH+seN/m/Bf5B/ZGD/k/F/5lT7L/ALf6UfZf9v8ASrdFH+seN/m/Bf5B/ZGD/k/F/wCZU+y/
7f6UfZf9v9Kt0Uf6x43+b8F/kH9kYP8Ak/F/5lT7L/t/pR9l/wBv9Kt0Uf6x43+b8F/kH9kYP+T8
X/mVPsv+3+lH2X/b/SrdFH+seN/m/Bf5B/ZGD/k/F/5lT7L/ALf6UfZf9v8ASrdFH+seN/m/Bf5B
/ZGD/k/F/wCZU+y/7f6UfZf9v9Kt0Uf6x43+b8F/kH9kYP8Ak/F/5lT7L/t/pR9l/wBv9Kt0Uf6x
43+b8F/kH9kYP+T8X/mVPsv+3+lH2X/b/SrdFH+seN/m/Bf5B/ZGD/k/F/5lT7L/ALf6UfZf9v8A
SrdFH+seN/m/Bf5B/ZGD/k/F/wCZU+y/7f6UfZf9v9Kt0Uf6x43+b8F/kH9kYP8Ak/F/5lT7L/t/
pR9l/wBv9Kt0Uf6x43+b8F/kH9kYP+T8X/mVPsv+3+lH2X/b/SrdFH+seN/m/Bf5B/ZGD/k/F/5l
T7L/ALf6UfZf9v8ASrdFH+seN/m/Bf5B/ZGD/k/F/wCZU+y/7f6UfZf9v9Kt0Uf6x43+b8F/kH9k
YP8Ak/F/5lT7L/t/pR9l/wBv9Kt0Uf6x43+b8F/kH9kYP+T8X/mVPsv+3+lH2X/b/SrdFH+seN/m
/Bf5B/ZGD/k/F/5lT7L/ALf6UfZf9v8ASrdFH+seN/m/Bf5B/ZGD/k/F/wCZU+y/7f6UfZf9v9Kt
0Uf6x43+b8F/kH9kYP8Ak/F/5lT7L/t/pR9l/wBv9Kt0Uf6x43+b8F/kH9kYP+T8X/mFFFFeAemF
FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUU
UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRR
QAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA
BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAF
FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUV
c07S7vVJJEtYt/lqWYngD0GfU9B/+uq0sbwyvFINroxVh6EdahVYObgnqt0FnuMoooqwCiiigAoo
ooAKKKkt7ea6nSCCNpJXOFVe/wDn1pSkopyk7JAR0VPe2c1heS2s4AkjODg5B7g/lUFEZKcVKLum
AUUUUwCiiigAooooAKKDwM1bvtNutOMX2mJkEqB0JBGcjkexGcEVLqQUlBvV7ILFSiimvIkYy7qo
6ZY4qwHUVTm1awgGZLuLrjCncc/QVUm8S6dHt2NJLnrsTGPzxSOing8RU+GDfyNeiuck8WIHIjtG
ZOxZ9p/LBqpJ4pvW3hI4UBztOCSv64z+FFzshk+LlvG3q0ddRXCya5qUqFGumAP91Qp/MDNVZbu5
nULNcSyKDkB3JGfxpXOuGQVX8c0vS7/yO+lu7aBgs1xFGxGcO4Bx+NVZNc02JyjXSkj+6pYfmBiu
FooudUMgpL45t+ll/mda3iqzCnbDOWxwCAAT9c1Vk8WSFCI7RVfsWfcPywK5yii52QyfCR+zf5s9
KooopnxQUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUVnXGuafbSmJpw8gIDL
GN23nByegxzkdeOlMunTnUfLBNvyNGiq1rqFreki3mV2HVeQfrg84560l1qNlZEi5uoYmC79jONx
HsOp6HpRuEqc4y5ZJp9i1RWOPEti0u1FnZMgeYEwv15OePpWlbXUN3D5sEgdM4zjGD9DSNKmFr0o
qc4NJ+RNRWdqWtWmltGk295X5EcYBYD1OSMD/PY1Vt/EsEkaGa3ljcn5tuGVefXgn8qHpuXSwWIr
R56cG0bdFIrK6hlIKkZBB4IpaDl2CiiigArNv9M85jLAAHP3lPAb/wCvWlRTTsBxlzaLLkEbJAeu
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

------=_NextPart_000_003E_01C18253.14EFC980--