pxmlw6n2f/Gazebo_Distributed_TCP/gazebo/physics/ode/ODELink.cc

774 lines
22 KiB
C++

/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <math.h>
#include <sstream>
#include "gazebo/common/Assert.hh"
#include "gazebo/common/Console.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/physics/Collision.hh"
#include "gazebo/physics/World.hh"
#include "gazebo/physics/WorldPrivate.hh"
#include "gazebo/physics/Model.hh"
#include "gazebo/physics/ode/ODECollision.hh"
#include "gazebo/physics/ode/ODESurfaceParams.hh"
#include "gazebo/physics/ode/ODEPhysics.hh"
#include "gazebo/physics/ode/ODELink.hh"
using namespace gazebo;
using namespace physics;
//////////////////////////////////////////////////
ODELink::ODELink(EntityPtr _parent)
: Link(_parent)
{
this->linkId = NULL;
}
//////////////////////////////////////////////////
ODELink::~ODELink()
{
this->Fini();
}
//////////////////////////////////////////////////
void ODELink::Load(sdf::ElementPtr _sdf)
{
this->odePhysics = boost::dynamic_pointer_cast<ODEPhysics>(
this->GetWorld()->GetPhysicsEngine());
if (this->odePhysics == NULL)
gzthrow("Not using the ode physics engine");
Link::Load(_sdf);
}
//////////////////////////////////////////////////
void ODELink::Init()
{
if (!this->IsStatic())
{
this->linkId = dBodyCreate(this->odePhysics->GetWorldId());
dBodySetData(this->linkId, this);
// Only use auto disable if no joints and no sensors are present
if (this->GetModel()->GetAutoDisable() &&
this->GetModel()->GetJointCount() == 0 &&
this->GetSensorCount() == 0)
{
dBodySetAutoDisableDefaults(this->linkId);
dBodySetAutoDisableFlag(this->linkId, 1);
}
else
{
dBodySetAutoDisableFlag(this->linkId, 0);
}
}
GZ_ASSERT(this->sdf != NULL, "Unable to initialize link, SDF is NULL");
this->SetKinematic(this->sdf->Get<bool>("kinematic"));
this->SetGravityMode(this->sdf->Get<bool>("gravity"));
this->SetLinearDamping(this->GetLinearDamping());
this->SetAngularDamping(this->GetAngularDamping());
Link::Init();
if (this->linkId)
{
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 cogVec = this->inertial->GetCoG();
for (auto const &child : this->children)
{
if (child->HasType(Base::COLLISION))
{
ODECollisionPtr g = boost::static_pointer_cast<ODECollision>(child);
if (g->IsPlaceable() && g->GetCollisionId())
{
dGeomSetBody(g->GetCollisionId(), this->linkId);
}
}
}
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to place collision bodies"
<< " in ODELink::Init" << std::endl;
}
// Update the Collision Offsets, Surface, and Center of Mass.
this->UpdateCollisionOffsets();
this->UpdateSurface();
// Only update the Center of Mass if object is dynamic
if (!this->GetKinematic())
this->UpdateMass();
if (this->linkId)
{
dBodySetMovedCallback(this->linkId, MoveCallback);
dBodySetDisabledCallback(this->linkId, DisabledCallback);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to set callbacks in ODELink::Init"
<< std::endl;
}
}
//////////////////////////////////////////////////
void ODELink::DisabledCallback(dBodyID /*_id*/)
{
}
//////////////////////////////////////////////////
void ODELink::MoveCallback(dBodyID _id)
{
const dReal *p;
const dReal *r;
ODELink *self = static_cast<ODELink*>(dBodyGetData(_id));
// self->poseMutex->lock();
p = dBodyGetPosition(_id);
r = dBodyGetQuaternion(_id);
self->dirtyPose.pos.Set(p[0], p[1], p[2]);
self->dirtyPose.rot.Set(r[0], r[1], r[2], r[3]);
// subtracting cog location from ode pose
GZ_ASSERT(self->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 cog = self->dirtyPose.rot.RotateVector(
self->inertial->GetCoG());
self->dirtyPose.pos -= cog;
// Tell the world that our pose has changed.
self->world->_AddDirty(self);
// self->poseMutex->unlock();
// get force and applied to this body
if (_id)
{
const dReal *dforce = dBodyGetForce(_id);
self->force.Set(dforce[0], dforce[1], dforce[2]);
const dReal *dtorque = dBodyGetTorque(_id);
self->torque.Set(dtorque[0], dtorque[1], dtorque[2]);
}
}
//////////////////////////////////////////////////
void ODELink::Fini()
{
if (this->linkId)
dBodyDestroy(this->linkId);
this->linkId = NULL;
this->odePhysics.reset();
Link::Fini();
}
//////////////////////////////////////////////////
void ODELink::SetGravityMode(bool _mode)
{
if (this->sdf->HasElement("gravity"))
this->sdf->GetElement("gravity")->Set(_mode);
if (this->linkId)
{
dBodySetGravityMode(this->linkId, _mode ? 1: 0);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetGravityMode" << std::endl;
}
}
//////////////////////////////////////////////////
bool ODELink::GetGravityMode() const
{
int mode = 0;
if (this->linkId)
{
mode = dBodyGetGravityMode(this->linkId);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetGravityMode returns default of "
<< mode << std::endl;
}
return mode;
}
//////////////////////////////////////////////////
void ODELink::SetSelfCollide(bool _collide)
{
this->sdf->GetElement("self_collide")->Set(_collide);
if (_collide)
this->spaceId = dSimpleSpaceCreate(this->odePhysics->GetSpaceId());
}
//////////////////////////////////////////////////
void ODELink::OnPoseChange()
{
Link::OnPoseChange();
if (!this->linkId)
{
if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to respond to OnPoseChange"
<< std::endl;
return;
}
this->SetEnabled(true);
const math::Pose myPose = this->GetWorldPose();
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 cog = myPose.rot.RotateVector(this->inertial->GetCoG());
// adding cog location for ode pose
dBodySetPosition(this->linkId,
myPose.pos.x + cog.x,
myPose.pos.y + cog.y,
myPose.pos.z + cog.z);
dQuaternion q;
q[0] = myPose.rot.w;
q[1] = myPose.rot.x;
q[2] = myPose.rot.y;
q[3] = myPose.rot.z;
// Set the rotation of the ODE link
dBodySetQuaternion(this->linkId, q);
}
//////////////////////////////////////////////////
dBodyID ODELink::GetODEId() const
{
return this->linkId;
}
//////////////////////////////////////////////////
void ODELink::SetEnabled(bool _enable) const
{
if (!this->linkId)
{
if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetEnabled" << std::endl;
return;
}
if (_enable)
dBodyEnable(this->linkId);
else
dBodyDisable(this->linkId);
}
/////////////////////////////////////////////////////////////////////
bool ODELink::GetEnabled() const
{
bool result = true;
if (this->linkId)
result = dBodyIsEnabled(this->linkId);
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetEnabled returns default of "
<< result << std::endl;
}
return result;
}
/////////////////////////////////////////////////////////////////////
void ODELink::UpdateCollisionOffsets()
{
if (this->linkId)
{
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 cogVec = this->inertial->GetCoG();
for (auto const &child : this->children)
{
if (child->HasType(Base::COLLISION))
{
ODECollisionPtr g = boost::static_pointer_cast<ODECollision>(child);
if (g->IsPlaceable() && g->GetCollisionId())
{
// update pose immediately
math::Pose localPose = g->GetRelativePose();
localPose.pos -= cogVec;
dQuaternion q;
q[0] = localPose.rot.w;
q[1] = localPose.rot.x;
q[2] = localPose.rot.y;
q[3] = localPose.rot.z;
// Set the pose of the encapsulated collision; this is always relative
// to the CoM
dGeomSetOffsetPosition(g->GetCollisionId(), localPose.pos.x,
localPose.pos.y, localPose.pos.z);
dGeomSetOffsetQuaternion(g->GetCollisionId(), q);
}
}
}
}
}
/////////////////////////////////////////////////////////////////////
void ODELink::UpdateSurface()
{
if (!this->linkId)
{
return;
}
for (auto const &child : this->children)
{
if (child->HasType(Base::COLLISION))
{
ODECollisionPtr g = boost::static_pointer_cast<ODECollision>(child);
if (g->IsPlaceable() && g->GetCollisionId())
{
// Set max_vel and min_depth
boost::any value;
if (g->GetODESurface()->maxVel < 0 && this->GetWorld()->
GetPhysicsEngine()->GetParam("contact_max_correcting_vel", value))
{
try
{
g->GetODESurface()->maxVel = boost::any_cast<double>(value);
}
catch(boost::bad_any_cast &_e)
{
gzerr << "Failed boost::any_cast in ODELink.cc: " << _e.what();
}
}
// Set surface properties max_vel and min_depth
dBodySetMaxVel(this->linkId, g->GetODESurface()->maxVel);
dBodySetMinDepth(this->linkId, g->GetODESurface()->minDepth);
}
}
}
}
/////////////////////////////////////////////////////////////////////
void ODELink::UpdateMass()
{
if (!this->linkId)
{
if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to UpdateMass" << std::endl;
return;
}
dMass odeMass;
dMassSetZero(&odeMass);
// The CoG must always be (0, 0, 0)
math::Vector3 cog(0, 0, 0);
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
// give ODE un-rotated inertia
math::Matrix3 moi = this->inertial->GetMOI(
math::Pose(this->inertial->GetCoG(), math::Quaternion()));
math::Vector3 principals(moi[0][0], moi[1][1], moi[2][2]);
math::Vector3 products(moi[0][1], moi[0][2], moi[1][2]);
dMassSetParameters(&odeMass, this->inertial->GetMass(),
cog.x, cog.y, cog.z,
principals.x, principals.y, principals.z,
products.x, products.y, products.z);
if (this->inertial->GetMass() > 0)
dBodySetMass(this->linkId, &odeMass);
else
gzthrow("Setting custom link " + this->GetScopedName() + "mass to zero!");
// In case the center of mass changed:
this->UpdateCollisionOffsets();
this->OnPoseChange();
}
//////////////////////////////////////////////////
void ODELink::SetLinearVel(const math::Vector3 &_vel)
{
if (this->linkId)
{
dBodySetLinearVel(this->linkId, _vel.x, _vel.y, _vel.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetLinearVel" << std::endl;
}
//////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldLinearVel(const math::Vector3 &_offset) const
{
math::Vector3 vel;
if (this->linkId)
{
dVector3 dvel;
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 offsetFromCoG = _offset - this->inertial->GetCoG();
dBodyGetRelPointVel(this->linkId, offsetFromCoG.x, offsetFromCoG.y,
offsetFromCoG.z, dvel);
vel.Set(dvel[0], dvel[1], dvel[2]);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetWorldLinearVel returns default of "
<< vel << std::endl;
}
return vel;
}
//////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldLinearVel(const math::Vector3 &_offset,
const math::Quaternion &_q) const
{
math::Vector3 vel;
if (this->linkId)
{
dVector3 dvel;
math::Pose wPose = this->GetWorldPose();
GZ_ASSERT(this->inertial != NULL, "Inertial pointer is NULL");
math::Vector3 offsetFromCoG =
wPose.rot.RotateVectorReverse(_q * _offset)
- this->inertial->GetCoG();
dBodyGetRelPointVel(this->linkId, offsetFromCoG.x, offsetFromCoG.y,
offsetFromCoG.z, dvel);
vel.Set(dvel[0], dvel[1], dvel[2]);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetWorldLinearVel returns default of "
<< vel << std::endl;
}
return vel;
}
//////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldCoGLinearVel() const
{
math::Vector3 vel;
if (this->linkId)
{
const dReal *dvel;
dvel = dBodyGetLinearVel(this->linkId);
vel.Set(dvel[0], dvel[1], dvel[2]);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetWorldCoGLinearVel returns default of "
<< vel << std::endl;
}
return vel;
}
//////////////////////////////////////////////////
void ODELink::SetAngularVel(const math::Vector3 &_vel)
{
if (this->linkId)
{
dBodySetAngularVel(this->linkId, _vel.x, _vel.y, _vel.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetAngularVel" << std::endl;
}
//////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldAngularVel() const
{
math::Vector3 vel;
if (this->linkId)
{
const dReal *dvel;
dvel = dBodyGetAngularVel(this->linkId);
vel.Set(dvel[0], dvel[1], dvel[2]);
}
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetWorldAngularVel returns default of "
<< vel << std::endl;
}
return vel;
}
//////////////////////////////////////////////////
void ODELink::SetForce(const math::Vector3 &_force)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodySetForce(this->linkId, _force.x, _force.y, _force.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetForce" << std::endl;
}
//////////////////////////////////////////////////
void ODELink::SetTorque(const math::Vector3 &_torque)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodySetTorque(this->linkId, _torque.x, _torque.y, _torque.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetTorque" << std::endl;
}
//////////////////////////////////////////////////
void ODELink::AddForce(const math::Vector3 &_force)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddForce(this->linkId, _force.x, _force.y, _force.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddForce" << std::endl;
}
/////////////////////////////////////////////////
void ODELink::AddRelativeForce(const math::Vector3 &_force)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddRelForce(this->linkId, _force.x, _force.y, _force.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddRelativeForce" << std::endl;
}
/////////////////////////////////////////////////
void ODELink::AddForceAtRelativePosition(const math::Vector3 &_force,
const math::Vector3 &_relpos)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddForceAtRelPos(this->linkId, _force.x, _force.y, _force.z,
_relpos.x, _relpos.y, _relpos.z);
}
else if (!this->IsStatic())
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddForceAtRelativePosition"
<< std::endl;
}
}
/////////////////////////////////////////////////
void ODELink::AddForceAtWorldPosition(const math::Vector3 &_force,
const math::Vector3 &_pos)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddForceAtPos(this->linkId, _force.x, _force.y, _force.z,
_pos.x, _pos.y, _pos.z);
}
else if (!this->IsStatic())
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddForceAtWorldPosition"
<< std::endl;
}
}
//////////////////////////////////////////////////
void ODELink::AddLinkForce(const math::Vector3 &_force,
const math::Vector3 &_offset)
{
if (this->linkId)
{
// Force vector represents a direction only, so it should be rotated but
// not translated
math::Vector3 forceWorld = this->GetWorldPose().rot.RotateVector(_force);
// Does this need to be rotated?
math::Vector3 offsetCoG = _offset - this->inertial->GetCoG();
this->SetEnabled(true);
dBodyAddForceAtRelPos(this->linkId,
forceWorld.x, forceWorld.y, forceWorld.z,
offsetCoG.x, offsetCoG.y, offsetCoG.z);
}
else if (!this->IsStatic())
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddLinkForce"
<< std::endl;
}
}
/////////////////////////////////////////////////
void ODELink::AddTorque(const math::Vector3 &_torque)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddTorque(this->linkId, _torque.x, _torque.y, _torque.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddTorque" << std::endl;
}
/////////////////////////////////////////////////
void ODELink::AddRelativeTorque(const math::Vector3 &_torque)
{
if (this->linkId)
{
this->SetEnabled(true);
dBodyAddRelTorque(this->linkId, _torque.x, _torque.y, _torque.z);
}
else if (!this->IsStatic())
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to AddRelativeTorque" << std::endl;
}
/////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldForce() const
{
return this->force;
}
//////////////////////////////////////////////////
math::Vector3 ODELink::GetWorldTorque() const
{
return this->torque;
}
//////////////////////////////////////////////////
dSpaceID ODELink::GetSpaceId() const
{
return this->spaceId;
}
//////////////////////////////////////////////////
void ODELink::SetSpaceId(dSpaceID _spaceid)
{
this->spaceId = _spaceid;
}
//////////////////////////////////////////////////
void ODELink::SetLinearDamping(double _damping)
{
if (this->GetODEId())
dBodySetLinearDamping(this->GetODEId(), _damping);
else if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetLinearDamping" << std::endl;
}
//////////////////////////////////////////////////
void ODELink::SetAngularDamping(double _damping)
{
if (this->GetODEId())
dBodySetAngularDamping(this->GetODEId(), _damping);
else if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetAngularDamping" << std::endl;
}
//////////////////////////////////////////////////
void ODELink::SetKinematic(const bool &_state)
{
this->sdf->GetElement("kinematic")->Set(_state);
if (this->linkId)
{
if (_state && !dBodyIsKinematic(this->linkId))
dBodySetKinematic(this->linkId);
else if (dBodyIsKinematic(this->linkId))
dBodySetDynamic(this->linkId);
}
else if (!this->IsStatic() && this->initialized)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetKinematic" << std::endl;
}
//////////////////////////////////////////////////
bool ODELink::GetKinematic() const
{
bool result = false;
if (this->linkId)
result = dBodyIsKinematic(this->linkId);
else if (!this->IsStatic() && this->initialized)
{
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, GetKinematic returns default of "
<< result << std::endl;
}
return result;
}
//////////////////////////////////////////////////
void ODELink::SetAutoDisable(bool _disable)
{
if (this->GetModel()->GetJointCount() == 0 && this->linkId)
{
dBodySetAutoDisableFlag(this->linkId, _disable);
}
else if (!this->linkId)
gzlog << "ODE body for link [" << this->GetScopedName() << "]"
<< " does not exist, unable to SetAutoDisable" << std::endl;
else
gzlog << "ODE model has joints, unable to SetAutoDisable" << std::endl;
}
//////////////////////////////////////////////////
void ODELink::SetLinkStatic(bool /*_static*/)
{
gzlog << "To be implemented\n";
}