[ODE] Bug either in ODE or in implementation (more likely?)

Sawyer sjlarkin at ouray.cudenver.edu
Thu Mar 17 03:06:10 MST 2005


I am trying to use the Gazebo Robot simulator which uses ODE.  For most 
situations this has worked very well but I am having problems getting 
reliable sensor returns from trimeshes.

This issue only occurs when using trimesh support.  The sensors are modeled as 
rays using ode.  The problem occurs when a ray has multiple collisions with a 
single (although large and complex) trimesh.  It seems to return the distance 
of a random collision, ie. not the closest one as would be the expected 
behavior, I have looked through the code of both packages but am getting lost 
in the details of collision_trimesh_ray.cpp and it's interaction with gazebo, 
below I have copied the code that is handling the collision detection within 
gazebo hoping that somebody more familiar with ode can spot a problem, also 
listed below are some screenshots highlighting the issue, as well as showing 
correct handling of other object types.

I have tried the versioned releases of both packages as well as the CVS 
downloads of both.  For ode this means ode-0.5, and the CVS branch downloaded 
on 3-17-05.

ode-0.5 + gazebo 0.5.x (including cvs)
http://mt-elbert.irgeek.com/~tobor/RayProximityBug1.jpg
http://mt-elbert.irgeek.com/~tobor/RayProximityBug2.jpg
http://mt-elbert.irgeek.com/~tobor/RayProximityBug3.jpg

ode-cvs 3-17-05 + gazebo 0.5.1
http://mt-elbert.irgeek.com/~tobor/RayProximityBugCVS.jpg

These are the only two functions that ask ode for collision information.  Also 
as far as I can tell gazebo is basically returning the depth of a random 
triangle collision depending on what order they are processed in.  I have not 
seen problems with any object type other than trimesh.  Any help is greatly 
appreciated.

Here is the code block from gazebo dealing with collisions:
in file: RayProximity.cc
//////////////////////////////////////////////////////////////////////////////
// Update the sensor information
void RayProximity::Update()
{
  int i;
  GzPose pose;
  RayGeom *ray;
  GzVector a, b;

  // Get the pose of the sensor body (global cs)
  pose = this->body->GetPose();

  // Reset the ray lengths and mark the geoms as dirty (so they get
  // redrawn)
  for (i = 0; i < this->rayCount; i++)
  {
    ray = this->rays[i];
    ray->dirty = true;
    ray->contactDepth = DBL_MAX;
    ray->contactRetro = 0.0;
    ray->contactFiducial = -1;

    // Update the ray endpoints (global cs)
    a = GzCoordPositionAdd(ray->pos_a, pose.pos, pose.rot);
    b = GzCoordPositionAdd(ray->pos_b, pose.pos, pose.rot);
    ray->Set(a, GzVectorUnit(GzVectorSub(b, a)));
  }

  // Do collision detection
  dSpaceCollide2( ( dGeomID ) ( this->superSpaceId ),
                  ( dGeomID ) ( this->world->GetSpaceId() ),
                  this, &UpdateCallback );

  return;
}

//////////////////////////////////////////////////////////////////////////////
// Callback for ray intersection test
void RayProximity::UpdateCallback( void *data, dGeomID o1, dGeomID o2 )
{
  int n;
  dContactGeom contact;
  Geom *geom1, *geom2;
  RayGeom *rayGeom;
  Geom *hitGeom;
  RayProximity *self;

  self = (RayProximity*) data;

  // Check space
  if ( dGeomIsSpace( o1 ) || dGeomIsSpace( o2 ) )
  {
    if (dGeomGetSpace(o1) == self->superSpaceId || dGeomGetSpace(o2) == 
self->superSpaceId)
    {
      dSpaceCollide2( o1, o2, self, &UpdateCallback );
    }
    if (dGeomGetSpace(o1) == self->raySpaceId || dGeomGetSpace(o2) == 
self->raySpaceId)
    {
      dSpaceCollide2( o1, o2, self, &UpdateCallback );
    }
  }
  else
  {
    geom1 = NULL;
    geom2 = NULL;

    // Get pointers to the underlying geoms
    if (dGeomGetClass(o1) == dGeomTransformClass)
      geom1 = (Geom*) dGeomGetData(dGeomTransformGetGeom(o1));
    else
      geom1 = (Geom*) dGeomGetData(o1);

    if (dGeomGetClass(o2) == dGeomTransformClass)
      geom2 = (Geom*) dGeomGetData(dGeomTransformGetGeom(o2));
    else
      geom2 = (Geom*) dGeomGetData(o2);

    assert(geom1 && geom2);

    rayGeom = NULL;
    hitGeom = NULL;

    // Figure out which one is a ray; note that this assumes
    // that the ODE dRayClass is used *soley* by the RayGeom.
    if (dGeomGetClass(o1) == dRayClass)
    {
      rayGeom = (RayGeom*) geom1;
      hitGeom = geom2;
    }

    if (dGeomGetClass(o2) == dRayClass)
    {
      assert(rayGeom == NULL);
      rayGeom = (RayGeom*) geom2;
      hitGeom = geom1;
    }

    // Check for ray/geom intersections
    if ( rayGeom && hitGeom )
    {
      n = dCollide(o1, o2, 1, &contact, sizeof(contact));
      if ( n > 0 )
      {
        if (contact.depth < rayGeom->contactDepth)
        {
          //printf("%p %p %f \n", o1, o2, contact.depth);
          rayGeom->contactDepth = contact.depth;
          rayGeom->contactRetro = hitGeom->GetRetro();
          rayGeom->contactFiducial = hitGeom->GetFiducial();
        }
      }
    }
  }
  return;
}

Thanks again,
Sawyer Larkin



More information about the ODE mailing list