542 lines
16 KiB
C++
542 lines
16 KiB
C++
/*
|
|
* Copyright (C) 2014 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 "gazebo/common/Assert.hh"
|
|
#include "gazebo/common/Console.hh"
|
|
#include "gazebo/common/Exception.hh"
|
|
#include "gazebo/math/Vector3.hh"
|
|
|
|
#include "gazebo/transport/Publisher.hh"
|
|
|
|
#include "gazebo/physics/Collision.hh"
|
|
#include "gazebo/physics/ContactManager.hh"
|
|
#include "gazebo/physics/Entity.hh"
|
|
#include "gazebo/physics/MapShape.hh"
|
|
#include "gazebo/physics/Model.hh"
|
|
#include "gazebo/physics/PhysicsTypes.hh"
|
|
#include "gazebo/physics/PhysicsFactory.hh"
|
|
#include "gazebo/physics/SurfaceParams.hh"
|
|
#include "gazebo/physics/World.hh"
|
|
|
|
#include "gazebo/physics/dart/DARTScrewJoint.hh"
|
|
#include "gazebo/physics/dart/DARTHingeJoint.hh"
|
|
#include "gazebo/physics/dart/DARTHinge2Joint.hh"
|
|
#include "gazebo/physics/dart/DARTSliderJoint.hh"
|
|
#include "gazebo/physics/dart/DARTBallJoint.hh"
|
|
#include "gazebo/physics/dart/DARTUniversalJoint.hh"
|
|
#include "gazebo/physics/dart/DARTFixedJoint.hh"
|
|
|
|
#include "gazebo/physics/dart/DARTRayShape.hh"
|
|
#include "gazebo/physics/dart/DARTBoxShape.hh"
|
|
#include "gazebo/physics/dart/DARTSphereShape.hh"
|
|
#include "gazebo/physics/dart/DARTCylinderShape.hh"
|
|
#include "gazebo/physics/dart/DARTPlaneShape.hh"
|
|
#include "gazebo/physics/dart/DARTMeshShape.hh"
|
|
#include "gazebo/physics/dart/DARTPolylineShape.hh"
|
|
#include "gazebo/physics/dart/DARTMultiRayShape.hh"
|
|
#include "gazebo/physics/dart/DARTHeightmapShape.hh"
|
|
|
|
#include "gazebo/physics/dart/DARTModel.hh"
|
|
#include "gazebo/physics/dart/DARTLink.hh"
|
|
|
|
#include "gazebo/physics/dart/DARTPhysics.hh"
|
|
|
|
#include "gazebo/physics/dart/DARTPhysicsPrivate.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace physics;
|
|
|
|
GZ_REGISTER_PHYSICS_ENGINE("dart", DARTPhysics)
|
|
|
|
//////////////////////////////////////////////////
|
|
DARTPhysics::DARTPhysics(WorldPtr _world)
|
|
: PhysicsEngine(_world), dataPtr(new DARTPhysicsPrivate())
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
DARTPhysics::~DARTPhysics()
|
|
{
|
|
delete this->dataPtr;
|
|
this->dataPtr = nullptr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::Load(sdf::ElementPtr _sdf)
|
|
{
|
|
PhysicsEngine::Load(_sdf);
|
|
|
|
// Gravity
|
|
auto g = this->world->Gravity();
|
|
// ODEPhysics checks this, so we will too.
|
|
if (g == ignition::math::Vector3d::Zero)
|
|
gzwarn << "Gravity vector is (0, 0, 0). Objects will float.\n";
|
|
this->dataPtr->dtWorld->setGravity(Eigen::Vector3d(g.X(), g.Y(), g.Z()));
|
|
|
|
// Time step
|
|
// double timeStep = this->sdf->GetValueDouble("time_step");
|
|
// this->dartWorld->setTimeStep(timeStep);
|
|
|
|
// TODO: Elements for dart settings
|
|
// sdf::ElementPtr dartElem = this->sdf->GetElement("dart");
|
|
// this->stepTimeDouble = dartElem->GetElement("dt")->GetValueDouble();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::Init()
|
|
{
|
|
// this->dartWorld->initialize();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::Fini()
|
|
{
|
|
PhysicsEngine::Fini();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::Reset()
|
|
{
|
|
boost::recursive_mutex::scoped_lock lock(*this->physicsUpdateMutex);
|
|
|
|
// Restore state all the models
|
|
unsigned int modelCount = this->world->GetModelCount();
|
|
DARTModelPtr dartModelIt;
|
|
|
|
for (unsigned int i = 0; i < modelCount; ++i)
|
|
{
|
|
dartModelIt =
|
|
boost::dynamic_pointer_cast<DARTModel>(this->world->GetModel(i));
|
|
GZ_ASSERT(dartModelIt.get(), "dartModelIt pointer is NULL");
|
|
|
|
dartModelIt->RestoreState();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::InitForThread()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::UpdateCollision()
|
|
{
|
|
this->contactManager->ResetCount();
|
|
|
|
dart::constraint::ConstraintSolver *dtConstraintSolver =
|
|
this->dataPtr->dtWorld->getConstraintSolver();
|
|
dart::collision::CollisionDetector *dtCollisionDetector =
|
|
dtConstraintSolver->getCollisionDetector();
|
|
int numContacts = dtCollisionDetector->getNumContacts();
|
|
|
|
for (int i = 0; i < numContacts; ++i)
|
|
{
|
|
const dart::collision::Contact &dtContact =
|
|
dtCollisionDetector->getContact(i);
|
|
dart::dynamics::BodyNode *dtBodyNode1 = dtContact.bodyNode1;
|
|
dart::dynamics::BodyNode *dtBodyNode2 = dtContact.bodyNode2;
|
|
|
|
DARTLinkPtr dartLink1 = this->FindDARTLink(dtBodyNode1);
|
|
DARTLinkPtr dartLink2 = this->FindDARTLink(dtBodyNode2);
|
|
|
|
GZ_ASSERT(dartLink1.get() != NULL, "dartLink1 in collision pare is NULL");
|
|
GZ_ASSERT(dartLink2.get() != NULL, "dartLink2 in collision pare is NULL");
|
|
|
|
unsigned int colIndex = 0;
|
|
CollisionPtr collisionPtr1 = dartLink1->GetCollision(colIndex);
|
|
CollisionPtr collisionPtr2 = dartLink2->GetCollision(colIndex);
|
|
|
|
// Add a new contact to the manager. This will return NULL if no one is
|
|
// listening for contact information.
|
|
Contact *contactFeedback = this->GetContactManager()->NewContact(
|
|
collisionPtr1.get(), collisionPtr2.get(),
|
|
this->world->GetSimTime());
|
|
|
|
if (!contactFeedback)
|
|
continue;
|
|
|
|
math::Pose body1Pose = dartLink1->GetWorldPose();
|
|
math::Pose body2Pose = dartLink2->GetWorldPose();
|
|
math::Vector3 localForce1;
|
|
math::Vector3 localForce2;
|
|
math::Vector3 localTorque1;
|
|
math::Vector3 localTorque2;
|
|
|
|
// calculate force in world frame
|
|
Eigen::Vector3d force = dtContact.force;
|
|
|
|
// calculate torque in world frame
|
|
Eigen::Vector3d torqueA =
|
|
(dtContact.point -
|
|
dtBodyNode1->getTransform().translation()).cross(force);
|
|
Eigen::Vector3d torqueB =
|
|
(dtContact.point -
|
|
dtBodyNode2->getTransform().translation()).cross(-force);
|
|
|
|
// Convert from world to link frame
|
|
localForce1 = body1Pose.rot.RotateVectorReverse(
|
|
DARTTypes::ConvVec3(force));
|
|
localForce2 = body2Pose.rot.RotateVectorReverse(
|
|
DARTTypes::ConvVec3(-force));
|
|
localTorque1 = body1Pose.rot.RotateVectorReverse(
|
|
DARTTypes::ConvVec3(torqueA));
|
|
localTorque2 = body2Pose.rot.RotateVectorReverse(
|
|
DARTTypes::ConvVec3(torqueB));
|
|
|
|
contactFeedback->positions[0] = DARTTypes::ConvVec3(dtContact.point);
|
|
contactFeedback->normals[0] = DARTTypes::ConvVec3(dtContact.normal);
|
|
contactFeedback->depths[0] = dtContact.penetrationDepth;
|
|
|
|
if (!dartLink1->IsStatic())
|
|
{
|
|
contactFeedback->wrench[0].body1Force = localForce1;
|
|
contactFeedback->wrench[0].body1Torque = localTorque1;
|
|
}
|
|
|
|
if (!dartLink2->IsStatic())
|
|
{
|
|
contactFeedback->wrench[0].body2Force = localForce2;
|
|
contactFeedback->wrench[0].body2Torque = localTorque2;
|
|
}
|
|
|
|
++contactFeedback->count;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::UpdatePhysics()
|
|
{
|
|
// need to lock, otherwise might conflict with world resetting
|
|
boost::recursive_mutex::scoped_lock lock(*this->physicsUpdateMutex);
|
|
|
|
// common::Time currTime = this->world->GetRealTime();
|
|
|
|
this->dataPtr->dtWorld->setTimeStep(this->maxStepSize);
|
|
this->dataPtr->dtWorld->step();
|
|
|
|
// Update all the transformation of DART's links to gazebo's links
|
|
// TODO: How to visit all the links in the world?
|
|
unsigned int modelCount = this->world->GetModelCount();
|
|
ModelPtr modelItr;
|
|
|
|
for (unsigned int i = 0; i < modelCount; ++i)
|
|
{
|
|
modelItr = this->world->GetModel(i);
|
|
// TODO: need to improve speed
|
|
Link_V links = modelItr->GetLinks();
|
|
unsigned int linkCount = links.size();
|
|
DARTLinkPtr dartLinkItr;
|
|
|
|
for (unsigned int j = 0; j < linkCount; ++j)
|
|
{
|
|
dartLinkItr
|
|
= boost::dynamic_pointer_cast<DARTLink>(links.at(j));
|
|
dartLinkItr->updateDirtyPoseFromDARTTransformation();
|
|
}
|
|
}
|
|
|
|
// this->lastUpdateTime = currTime;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
std::string DARTPhysics::GetType() const
|
|
{
|
|
return "dart";
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::SetSeed(uint32_t /*_seed*/)
|
|
{
|
|
gzwarn << "Not implemented yet in DART.\n";
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
ModelPtr DARTPhysics::CreateModel(BasePtr _parent)
|
|
{
|
|
DARTModelPtr model(new DARTModel(_parent));
|
|
|
|
return model;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
LinkPtr DARTPhysics::CreateLink(ModelPtr _parent)
|
|
{
|
|
if (_parent == NULL)
|
|
{
|
|
gzerr << "Link must have a parent in DART.\n";
|
|
return LinkPtr();
|
|
}
|
|
|
|
DARTLinkPtr link(new DARTLink(_parent));
|
|
link->SetWorld(_parent->GetWorld());
|
|
|
|
return link;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
CollisionPtr DARTPhysics::CreateCollision(const std::string &_type,
|
|
LinkPtr _body)
|
|
{
|
|
DARTCollisionPtr collision(new DARTCollision(_body));
|
|
ShapePtr shape = this->CreateShape(_type, collision);
|
|
collision->SetShape(shape);
|
|
shape->SetWorld(_body->GetWorld());
|
|
return collision;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
ShapePtr DARTPhysics::CreateShape(const std::string &_type,
|
|
CollisionPtr _collision)
|
|
{
|
|
ShapePtr shape;
|
|
DARTCollisionPtr collision =
|
|
boost::dynamic_pointer_cast<DARTCollision>(_collision);
|
|
|
|
if (_type == "sphere")
|
|
shape.reset(new DARTSphereShape(collision));
|
|
else if (_type == "plane")
|
|
shape.reset(new DARTPlaneShape(collision));
|
|
else if (_type == "box")
|
|
shape.reset(new DARTBoxShape(collision));
|
|
else if (_type == "cylinder")
|
|
shape.reset(new DARTCylinderShape(collision));
|
|
else if (_type == "multiray")
|
|
shape.reset(new DARTMultiRayShape(collision));
|
|
else if (_type == "mesh" || _type == "trimesh")
|
|
shape.reset(new DARTMeshShape(collision));
|
|
else if (_type == "polyline")
|
|
shape.reset(new DARTPolylineShape(collision));
|
|
else if (_type == "heightmap")
|
|
shape.reset(new DARTHeightmapShape(collision));
|
|
else if (_type == "map" || _type == "image")
|
|
shape.reset(new MapShape(collision));
|
|
else if (_type == "ray")
|
|
if (_collision)
|
|
shape.reset(new DARTRayShape(collision));
|
|
else
|
|
shape.reset(new DARTRayShape(this->world->GetPhysicsEngine()));
|
|
else
|
|
gzerr << "Unable to create collision of type[" << _type << "]\n";
|
|
|
|
return shape;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
JointPtr DARTPhysics::CreateJoint(const std::string &_type, ModelPtr _parent)
|
|
{
|
|
JointPtr joint;
|
|
|
|
if (_type == "prismatic")
|
|
joint.reset(new DARTSliderJoint(_parent));
|
|
else if (_type == "screw")
|
|
joint.reset(new DARTScrewJoint(_parent));
|
|
else if (_type == "revolute")
|
|
joint.reset(new DARTHingeJoint(_parent));
|
|
else if (_type == "revolute2")
|
|
joint.reset(new DARTHinge2Joint(_parent));
|
|
else if (_type == "ball")
|
|
joint.reset(new DARTBallJoint(_parent));
|
|
else if (_type == "universal")
|
|
joint.reset(new DARTUniversalJoint(_parent));
|
|
else if (_type == "fixed")
|
|
joint.reset(new DARTFixedJoint(_parent));
|
|
else
|
|
gzerr << "Unable to create joint of type[" << _type << "]";
|
|
|
|
return joint;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::SetGravity(const gazebo::math::Vector3 &_gravity)
|
|
{
|
|
this->world->SetGravitySDF(_gravity.Ign());
|
|
this->dataPtr->dtWorld->setGravity(
|
|
Eigen::Vector3d(_gravity.x, _gravity.y, _gravity.z));
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::DebugPrint() const
|
|
{
|
|
gzwarn << "Not implemented in DART.\n";
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
boost::any DARTPhysics::GetParam(const std::string &_key) const
|
|
{
|
|
boost::any value;
|
|
this->GetParam(_key, value);
|
|
return value;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
bool DARTPhysics::GetParam(const std::string &_key, boost::any &_value) const
|
|
{
|
|
if (!this->sdf->HasElement("dart"))
|
|
{
|
|
return PhysicsEngine::GetParam(_key, _value);
|
|
}
|
|
sdf::ElementPtr dartElem = this->sdf->GetElement("dart");
|
|
// physics dart element not yet added to sdformat
|
|
// GZ_ASSERT(dartElem != NULL, "DART SDF element does not exist");
|
|
|
|
if (_key == "max_contacts")
|
|
{
|
|
_value = dartElem->GetElement("max_contacts")->Get<int>();
|
|
}
|
|
else if (_key == "min_step_size")
|
|
{
|
|
_value = dartElem->GetElement("solver")->Get<double>("min_step_size");
|
|
}
|
|
else
|
|
{
|
|
return PhysicsEngine::GetParam(_key, _value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
bool DARTPhysics::SetParam(const std::string &_key, const boost::any &_value)
|
|
{
|
|
/// \TODO fill this out, see issue #1115
|
|
try
|
|
{
|
|
if (_key == "max_contacts")
|
|
{
|
|
int value = boost::any_cast<int>(_value);
|
|
gzerr << "Setting [" << _key << "] in DART to [" << value
|
|
<< "] not yet supported.\n";
|
|
}
|
|
else if (_key == "min_step_size")
|
|
{
|
|
double value = boost::any_cast<double>(_value);
|
|
gzerr << "Setting [" << _key << "] in DART to [" << value
|
|
<< "] not yet supported.\n";
|
|
}
|
|
else
|
|
{
|
|
if (_key == "max_step_size")
|
|
{
|
|
this->dataPtr->dtWorld->setTimeStep(boost::any_cast<double>(_value));
|
|
}
|
|
return PhysicsEngine::SetParam(_key, _value);
|
|
}
|
|
}
|
|
catch(boost::bad_any_cast &e)
|
|
{
|
|
gzerr << "DARTPhysics::SetParam(" << _key << ") boost::any_cast error: "
|
|
<< e.what() << std::endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
dart::simulation::World *DARTPhysics::GetDARTWorld()
|
|
{
|
|
return this->dataPtr->dtWorld;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::OnRequest(ConstRequestPtr &_msg)
|
|
{
|
|
msgs::Response response;
|
|
response.set_id(_msg->id());
|
|
response.set_request(_msg->request());
|
|
response.set_response("success");
|
|
std::string *serializedData = response.mutable_serialized_data();
|
|
|
|
if (_msg->request() == "physics_info")
|
|
{
|
|
msgs::Physics physicsMsg;
|
|
physicsMsg.set_type(msgs::Physics::DART);
|
|
physicsMsg.mutable_gravity()->CopyFrom(
|
|
msgs::Convert(this->world->Gravity()));
|
|
physicsMsg.mutable_magnetic_field()->CopyFrom(
|
|
msgs::Convert(this->MagneticField()));
|
|
physicsMsg.set_enable_physics(this->world->GetEnablePhysicsEngine());
|
|
physicsMsg.set_real_time_update_rate(this->realTimeUpdateRate);
|
|
physicsMsg.set_real_time_factor(this->targetRealTimeFactor);
|
|
physicsMsg.set_max_step_size(this->maxStepSize);
|
|
|
|
response.set_type(physicsMsg.GetTypeName());
|
|
physicsMsg.SerializeToString(serializedData);
|
|
this->responsePub->Publish(response);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void DARTPhysics::OnPhysicsMsg(ConstPhysicsPtr& _msg)
|
|
{
|
|
// Parent class handles many generic parameters
|
|
// This should be done first so that the profile settings
|
|
// can be over-ridden by other message parameters.
|
|
PhysicsEngine::OnPhysicsMsg(_msg);
|
|
|
|
if (_msg->has_enable_physics())
|
|
this->world->EnablePhysicsEngine(_msg->enable_physics());
|
|
|
|
if (_msg->has_gravity())
|
|
this->SetGravity(msgs::ConvertIgn(_msg->gravity()));
|
|
|
|
if (_msg->has_real_time_factor())
|
|
this->SetTargetRealTimeFactor(_msg->real_time_factor());
|
|
|
|
if (_msg->has_real_time_update_rate())
|
|
{
|
|
this->SetRealTimeUpdateRate(_msg->real_time_update_rate());
|
|
}
|
|
|
|
if (_msg->has_max_step_size())
|
|
{
|
|
this->SetMaxStepSize(_msg->max_step_size());
|
|
}
|
|
|
|
/// Make sure all models get at least on update cycle.
|
|
this->world->EnableAllModels();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
DARTLinkPtr DARTPhysics::FindDARTLink(
|
|
const dart::dynamics::BodyNode *_dtBodyNode)
|
|
{
|
|
DARTLinkPtr res;
|
|
|
|
const Model_V& models = this->world->GetModels();
|
|
|
|
for (Model_V::const_iterator itModel = models.begin();
|
|
itModel != models.end(); ++itModel)
|
|
{
|
|
const Link_V& links = (*itModel)->GetLinks();
|
|
|
|
for (Link_V::const_iterator itLink = links.begin();
|
|
itLink != links.end(); ++itLink)
|
|
{
|
|
DARTLinkPtr dartLink = boost::dynamic_pointer_cast<DARTLink>(*itLink);
|
|
|
|
if (dartLink->GetDARTBodyNode() == _dtBodyNode)
|
|
{
|
|
res = dartLink;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|