1618 lines
42 KiB
C++
1618 lines
42 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.
|
|
*
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
|
// pulled in by anybody (e.g., Boost).
|
|
#include <Winsock2.h>
|
|
#endif
|
|
|
|
#include <tbb/parallel_for.h>
|
|
#include <tbb/blocked_range.h>
|
|
#include <float.h>
|
|
|
|
#include <boost/bind.hpp>
|
|
#include <boost/function.hpp>
|
|
#include <boost/thread/recursive_mutex.hpp>
|
|
#include <sstream>
|
|
|
|
#include "gazebo/util/OpenAL.hh"
|
|
#include "gazebo/common/KeyFrame.hh"
|
|
#include "gazebo/common/Animation.hh"
|
|
#include "gazebo/common/Plugin.hh"
|
|
#include "gazebo/common/Events.hh"
|
|
#include "gazebo/common/Exception.hh"
|
|
#include "gazebo/common/Console.hh"
|
|
#include "gazebo/common/CommonTypes.hh"
|
|
|
|
#include "gazebo/physics/Gripper.hh"
|
|
#include "gazebo/physics/Joint.hh"
|
|
#include "gazebo/physics/JointController.hh"
|
|
#include "gazebo/physics/Link.hh"
|
|
#include "gazebo/physics/World.hh"
|
|
#include "gazebo/physics/PhysicsEngine.hh"
|
|
#include "gazebo/physics/Model.hh"
|
|
#include "gazebo/physics/Contact.hh"
|
|
|
|
#include "gazebo/transport/Node.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace physics;
|
|
|
|
//////////////////////////////////////////////////
|
|
Model::Model(BasePtr _parent)
|
|
: Entity(_parent)
|
|
{
|
|
this->AddType(MODEL);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
Model::~Model()
|
|
{
|
|
this->Fini();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::Load(sdf::ElementPtr _sdf)
|
|
{
|
|
Entity::Load(_sdf);
|
|
|
|
this->jointPub = this->node->Advertise<msgs::Joint>("~/joint");
|
|
|
|
this->SetStatic(this->sdf->Get<bool>("static"));
|
|
if (this->sdf->HasElement("static"))
|
|
{
|
|
this->sdf->GetElement("static")->GetValue()->SetUpdateFunc(
|
|
boost::bind(&Entity::IsStatic, this));
|
|
}
|
|
|
|
if (this->sdf->HasElement("self_collide"))
|
|
{
|
|
this->SetSelfCollide(this->sdf->Get<bool>("self_collide"));
|
|
}
|
|
|
|
if (this->sdf->HasElement("allow_auto_disable"))
|
|
this->SetAutoDisable(this->sdf->Get<bool>("allow_auto_disable"));
|
|
|
|
this->LoadLinks();
|
|
|
|
this->LoadModels();
|
|
|
|
// Load the joints if the world is already loaded. Otherwise, the World
|
|
// has some special logic to load models that takes into account state
|
|
// information.
|
|
if (this->world->IsLoaded())
|
|
this->LoadJoints();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadLinks()
|
|
{
|
|
/// \TODO: check for duplicate model, and raise an error
|
|
/// BasePtr dup = Base::GetByName(this->GetScopedName());
|
|
|
|
// Load the bodies
|
|
if (this->sdf->HasElement("link"))
|
|
{
|
|
sdf::ElementPtr linkElem = this->sdf->GetElement("link");
|
|
while (linkElem)
|
|
{
|
|
// Create a new link
|
|
LinkPtr link = this->GetWorld()->GetPhysicsEngine()->CreateLink(
|
|
boost::static_pointer_cast<Model>(shared_from_this()));
|
|
|
|
/// \TODO: canonical link is hardcoded to the first link.
|
|
/// warn users for now, need to add parsing of
|
|
/// the canonical tag in sdf
|
|
|
|
// find canonical link - there should only be one within a tree of models
|
|
if (!this->canonicalLink)
|
|
{
|
|
// Get the canonical link from parent, if not found then set the
|
|
// current link as the canonoical link.
|
|
LinkPtr cLink;
|
|
BasePtr entity = this->GetParent();
|
|
while (entity && entity->HasType(MODEL))
|
|
{
|
|
ModelPtr model = boost::static_pointer_cast<Model>(entity);
|
|
LinkPtr tmpLink = model->GetLink();
|
|
if (tmpLink)
|
|
{
|
|
cLink = tmpLink;
|
|
break;
|
|
}
|
|
entity = entity->GetParent();
|
|
}
|
|
|
|
if (cLink)
|
|
{
|
|
this->canonicalLink = cLink;
|
|
}
|
|
else
|
|
{
|
|
// first link found, set as canonical link
|
|
link->SetCanonicalLink(true);
|
|
this->canonicalLink = link;
|
|
|
|
// notify parent models of this canonical link
|
|
entity = this->GetParent();
|
|
while (entity && entity->HasType(MODEL))
|
|
{
|
|
ModelPtr model = boost::static_pointer_cast<Model>(entity);
|
|
model->canonicalLink = this->canonicalLink;
|
|
entity = entity->GetParent();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load the link using the config node. This also loads all of the
|
|
// bodies collisionetries
|
|
link->Load(linkElem);
|
|
linkElem = linkElem->GetNextElement("link");
|
|
this->links.push_back(link);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadModels()
|
|
{
|
|
// Load the models
|
|
if (this->sdf->HasElement("model"))
|
|
{
|
|
sdf::ElementPtr modelElem = this->sdf->GetElement("model");
|
|
while (modelElem)
|
|
{
|
|
// Create a new model
|
|
ModelPtr model = this->GetWorld()->GetPhysicsEngine()->CreateModel(
|
|
boost::static_pointer_cast<Model>(shared_from_this()));
|
|
model->SetWorld(this->GetWorld());
|
|
model->Load(modelElem);
|
|
this->models.push_back(model);
|
|
modelElem = modelElem->GetNextElement("model");
|
|
}
|
|
|
|
for (auto &model : this->models)
|
|
model->SetEnabled(true);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadJoints()
|
|
{
|
|
// Load the joints
|
|
if (this->sdf->HasElement("joint"))
|
|
{
|
|
sdf::ElementPtr jointElem = this->sdf->GetElement("joint");
|
|
while (jointElem)
|
|
{
|
|
try
|
|
{
|
|
this->LoadJoint(jointElem);
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "LoadJoint Failed\n";
|
|
}
|
|
jointElem = jointElem->GetNextElement("joint");
|
|
}
|
|
}
|
|
|
|
if (this->sdf->HasElement("gripper"))
|
|
{
|
|
sdf::ElementPtr gripperElem = this->sdf->GetElement("gripper");
|
|
while (gripperElem)
|
|
{
|
|
this->LoadGripper(gripperElem);
|
|
gripperElem = gripperElem->GetNextElement("gripper");
|
|
}
|
|
}
|
|
|
|
// Load nested model joints if the world is not already loaded. Otherwise,
|
|
// LoadJoints will be called from Model::Load.
|
|
if (!this->world->IsLoaded())
|
|
{
|
|
for (auto model : this->models)
|
|
model->LoadJoints();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::Init()
|
|
{
|
|
// Record the model's initial pose (for reseting)
|
|
math::Pose initPose = this->sdf->Get<math::Pose>("pose");
|
|
this->SetInitialRelativePose(initPose);
|
|
this->SetRelativePose(initPose);
|
|
|
|
// Initialize the bodies before the joints
|
|
for (Base_V::iterator iter = this->children.begin();
|
|
iter != this->children.end(); ++iter)
|
|
{
|
|
if ((*iter)->HasType(Base::LINK))
|
|
{
|
|
LinkPtr link = boost::static_pointer_cast<Link>(*iter);
|
|
if (link)
|
|
link->Init();
|
|
else
|
|
gzerr << "Child [" << (*iter)->GetName()
|
|
<< "] has type Base::LINK, but cannot be dynamically casted\n";
|
|
}
|
|
else if ((*iter)->HasType(Base::MODEL))
|
|
boost::static_pointer_cast<Model>(*iter)->Init();
|
|
}
|
|
|
|
// Initialize the joints last.
|
|
for (Joint_V::iterator iter = this->joints.begin();
|
|
iter != this->joints.end(); ++iter)
|
|
{
|
|
try
|
|
{
|
|
(*iter)->Init();
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "Init joint failed" << std::endl;
|
|
return;
|
|
}
|
|
// The following message used to be filled and sent in Model::LoadJoint
|
|
// It is moved here, after Joint::Init, so that the joint properties
|
|
// can be included in the message.
|
|
msgs::Joint msg;
|
|
(*iter)->FillMsg(msg);
|
|
this->jointPub->Publish(msg);
|
|
}
|
|
|
|
for (std::vector<GripperPtr>::iterator iter = this->grippers.begin();
|
|
iter != this->grippers.end(); ++iter)
|
|
{
|
|
(*iter)->Init();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::Update()
|
|
{
|
|
if (this->IsStatic())
|
|
return;
|
|
|
|
boost::recursive_mutex::scoped_lock lock(this->updateMutex);
|
|
|
|
for (Joint_V::iterator jiter = this->joints.begin();
|
|
jiter != this->joints.end(); ++jiter)
|
|
(*jiter)->Update();
|
|
|
|
if (this->jointController)
|
|
this->jointController->Update();
|
|
|
|
if (!this->jointAnimations.empty())
|
|
{
|
|
common::NumericKeyFrame kf(0);
|
|
std::map<std::string, double> jointPositions;
|
|
std::map<std::string, common::NumericAnimationPtr>::iterator iter;
|
|
iter = this->jointAnimations.begin();
|
|
while (iter != this->jointAnimations.end())
|
|
{
|
|
iter->second->GetInterpolatedKeyFrame(kf);
|
|
|
|
iter->second->AddTime(
|
|
(this->world->GetSimTime() - this->prevAnimationTime).Double());
|
|
|
|
if (iter->second->GetTime() < iter->second->GetLength())
|
|
{
|
|
iter->second->GetInterpolatedKeyFrame(kf);
|
|
jointPositions[iter->first] = kf.GetValue();
|
|
++iter;
|
|
}
|
|
else
|
|
{
|
|
this->jointAnimations.erase(iter++);
|
|
}
|
|
}
|
|
if (!jointPositions.empty())
|
|
{
|
|
this->jointController->SetJointPositions(jointPositions);
|
|
}
|
|
else
|
|
{
|
|
if (this->onJointAnimationComplete)
|
|
this->onJointAnimationComplete();
|
|
}
|
|
this->prevAnimationTime = this->world->GetSimTime();
|
|
}
|
|
|
|
for (auto &model : this->models)
|
|
model->Update();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetJointPosition(
|
|
const std::string &_jointName, double _position, int _index)
|
|
{
|
|
if (this->jointController)
|
|
this->jointController->SetJointPosition(_jointName, _position, _index);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetJointPositions(
|
|
const std::map<std::string, double> &_jointPositions)
|
|
{
|
|
if (this->jointController)
|
|
this->jointController->SetJointPositions(_jointPositions);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::RemoveChild(EntityPtr _child)
|
|
{
|
|
Joint_V::iterator jiter;
|
|
|
|
if (_child->HasType(LINK))
|
|
{
|
|
bool done = false;
|
|
|
|
while (!done)
|
|
{
|
|
done = true;
|
|
|
|
for (jiter = this->joints.begin(); jiter != this->joints.end(); ++jiter)
|
|
{
|
|
if (!(*jiter))
|
|
continue;
|
|
|
|
LinkPtr jlink0 = (*jiter)->GetJointLink(0);
|
|
LinkPtr jlink1 = (*jiter)->GetJointLink(1);
|
|
|
|
if (!jlink0 || !jlink1 || jlink0->GetName() == _child->GetName() ||
|
|
jlink1->GetName() == _child->GetName() ||
|
|
jlink0->GetName() == jlink1->GetName())
|
|
{
|
|
this->joints.erase(jiter);
|
|
done = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
this->RemoveLink(_child->GetScopedName());
|
|
}
|
|
|
|
Entity::RemoveChild(_child->GetId());
|
|
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
(*liter)->SetEnabled(true);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
boost::shared_ptr<Model> Model::shared_from_this()
|
|
{
|
|
return boost::static_pointer_cast<Model>(Entity::shared_from_this());
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::Fini()
|
|
{
|
|
// Destroy all attached models
|
|
for (auto &model : this->attachedModels)
|
|
{
|
|
if (model)
|
|
model->Fini();
|
|
}
|
|
this->attachedModels.clear();
|
|
|
|
// Destroy all models
|
|
for (auto &model : this->models)
|
|
{
|
|
if (model)
|
|
model->Fini();
|
|
}
|
|
this->models.clear();
|
|
|
|
// Destroy all joints
|
|
for (auto &joint : this->joints)
|
|
{
|
|
if (joint)
|
|
joint->Fini();
|
|
}
|
|
this->joints.clear();
|
|
this->jointController.reset();
|
|
|
|
// Destroy all links
|
|
for (auto &link : this->links)
|
|
{
|
|
if (link)
|
|
link->Fini();
|
|
}
|
|
this->canonicalLink.reset();
|
|
this->links.clear();
|
|
|
|
this->plugins.clear();
|
|
|
|
Entity::Fini();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::UpdateParameters(sdf::ElementPtr _sdf)
|
|
{
|
|
Entity::UpdateParameters(_sdf);
|
|
|
|
if (_sdf->HasElement("link"))
|
|
{
|
|
sdf::ElementPtr linkElem = _sdf->GetElement("link");
|
|
while (linkElem)
|
|
{
|
|
auto linkName = linkElem->Get<std::string>("name");
|
|
LinkPtr link = boost::dynamic_pointer_cast<Link>(
|
|
this->GetChild(linkName));
|
|
if (link)
|
|
link->UpdateParameters(linkElem);
|
|
else
|
|
{
|
|
gzwarn << "Model [" << this->GetName() <<
|
|
"] doesn't have a link called [" << linkName << "]" << std::endl;
|
|
}
|
|
linkElem = linkElem->GetNextElement("link");
|
|
}
|
|
}
|
|
|
|
if (_sdf->HasElement("joint"))
|
|
{
|
|
sdf::ElementPtr jointElem = _sdf->GetElement("joint");
|
|
while (jointElem)
|
|
{
|
|
auto jointName = jointElem->Get<std::string>("name");
|
|
JointPtr joint = boost::dynamic_pointer_cast<Joint>(
|
|
this->GetChild(jointName));
|
|
if (joint)
|
|
joint->UpdateParameters(jointElem);
|
|
else
|
|
{
|
|
gzwarn << "Model [" << this->GetName() <<
|
|
"] doesn't have a joint called [" << jointName << "]" << std::endl;
|
|
}
|
|
jointElem = jointElem->GetNextElement("joint");
|
|
}
|
|
}
|
|
|
|
if (_sdf->HasElement("model"))
|
|
{
|
|
sdf::ElementPtr modelElem = _sdf->GetElement("model");
|
|
while (modelElem)
|
|
{
|
|
auto modelName = modelElem->Get<std::string>("name");
|
|
ModelPtr model = boost::dynamic_pointer_cast<Model>(
|
|
this->GetChild(modelName));
|
|
if (model)
|
|
model->UpdateParameters(modelElem);
|
|
else
|
|
{
|
|
gzwarn << "Model [" << this->GetName() <<
|
|
"] doesn't have a nested model called [" << modelName << "]"
|
|
<< std::endl;
|
|
}
|
|
modelElem = modelElem->GetNextElement("model");
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
const sdf::ElementPtr Model::GetSDF()
|
|
{
|
|
return Entity::GetSDF();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
const sdf::ElementPtr Model::UnscaledSDF()
|
|
{
|
|
GZ_ASSERT(this->sdf != NULL, "Model sdf member is NULL");
|
|
this->sdf->Update();
|
|
|
|
sdf::ElementPtr unscaledSdf(this->sdf);
|
|
|
|
// Go through all collisions and visuals and divide size by scale
|
|
// See Link::UpdateVisualGeomSDF
|
|
if (!this->sdf->HasElement("link"))
|
|
return unscaledSdf;
|
|
|
|
auto linkElem = this->sdf->GetElement("link");
|
|
while (linkElem)
|
|
{
|
|
// Visuals
|
|
if (linkElem->HasElement("visual"))
|
|
{
|
|
auto visualElem = linkElem->GetElement("visual");
|
|
while (visualElem)
|
|
{
|
|
auto geomElem = visualElem->GetElement("geometry");
|
|
|
|
if (geomElem->HasElement("box"))
|
|
{
|
|
auto size = geomElem->GetElement("box")->
|
|
Get<ignition::math::Vector3d>("size");
|
|
geomElem->GetElement("box")->GetElement("size")->Set(
|
|
size / this->scale);
|
|
}
|
|
else if (geomElem->HasElement("sphere"))
|
|
{
|
|
double radius = geomElem->GetElement("sphere")->Get<double>("radius");
|
|
geomElem->GetElement("sphere")->GetElement("radius")->Set(
|
|
radius/this->scale.Max());
|
|
}
|
|
else if (geomElem->HasElement("cylinder"))
|
|
{
|
|
double radius =
|
|
geomElem->GetElement("cylinder")->Get<double>("radius");
|
|
double length =
|
|
geomElem->GetElement("cylinder")->Get<double>("length");
|
|
double radiusScale = std::max(this->scale.X(), this->scale.Y());
|
|
|
|
geomElem->GetElement("cylinder")->GetElement("radius")->Set(
|
|
radius/radiusScale);
|
|
geomElem->GetElement("cylinder")->GetElement("length")->Set(
|
|
length/this->scale.Z());
|
|
}
|
|
else if (geomElem->HasElement("mesh"))
|
|
{
|
|
// Keep mesh scale because meshes can't be scaled yet (issue #1473)
|
|
}
|
|
|
|
visualElem = visualElem->GetNextElement("visual");
|
|
}
|
|
}
|
|
|
|
// Collisions
|
|
if (linkElem->HasElement("collision"))
|
|
{
|
|
auto collisionElem = linkElem->GetElement("collision");
|
|
while (collisionElem)
|
|
{
|
|
auto geomElem = collisionElem->GetElement("geometry");
|
|
|
|
if (geomElem->HasElement("box"))
|
|
{
|
|
auto size = geomElem->GetElement("box")->
|
|
Get<ignition::math::Vector3d>("size");
|
|
geomElem->GetElement("box")->GetElement("size")->Set(
|
|
size / this->scale);
|
|
}
|
|
else if (geomElem->HasElement("sphere"))
|
|
{
|
|
double radius = geomElem->GetElement("sphere")->Get<double>("radius");
|
|
geomElem->GetElement("sphere")->GetElement("radius")->Set(
|
|
radius/this->scale.Max());
|
|
}
|
|
else if (geomElem->HasElement("cylinder"))
|
|
{
|
|
double radius =
|
|
geomElem->GetElement("cylinder")->Get<double>("radius");
|
|
double length =
|
|
geomElem->GetElement("cylinder")->Get<double>("length");
|
|
double radiusScale = std::max(this->scale.X(), this->scale.Y());
|
|
|
|
geomElem->GetElement("cylinder")->GetElement("radius")->Set(
|
|
radius/radiusScale);
|
|
geomElem->GetElement("cylinder")->GetElement("length")->Set(
|
|
length/this->scale.Z());
|
|
}
|
|
else if (geomElem->HasElement("mesh"))
|
|
{
|
|
// Keep mesh scale because meshes can't be scaled yet (issue #1473)
|
|
}
|
|
|
|
collisionElem = collisionElem->GetNextElement("collision");
|
|
}
|
|
}
|
|
|
|
linkElem = linkElem->GetNextElement("link");
|
|
}
|
|
|
|
return unscaledSdf;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::Reset()
|
|
{
|
|
Entity::Reset();
|
|
|
|
this->ResetPhysicsStates();
|
|
|
|
for (Joint_V::iterator jiter = this->joints.begin();
|
|
jiter != this->joints.end(); ++jiter)
|
|
{
|
|
(*jiter)->Reset();
|
|
}
|
|
|
|
// Reset plugins after links and joints,
|
|
// so that plugins can restore initial conditions
|
|
for (std::vector<ModelPluginPtr>::iterator iter = this->plugins.begin();
|
|
iter != this->plugins.end(); ++iter)
|
|
{
|
|
(*iter)->Reset();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::ResetPhysicsStates()
|
|
{
|
|
// reset link velocities when resetting model
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
(*liter)->ResetPhysicsStates();
|
|
}
|
|
|
|
// reset nested model physics states
|
|
for (auto &m : this->models)
|
|
m->ResetPhysicsStates();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetLinearVel(const math::Vector3 &_vel)
|
|
{
|
|
for (Link_V::iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if (*iter)
|
|
{
|
|
(*iter)->SetEnabled(true);
|
|
(*iter)->SetLinearVel(_vel);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetAngularVel(const math::Vector3 &_vel)
|
|
{
|
|
for (Link_V::iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if (*iter)
|
|
{
|
|
(*iter)->SetEnabled(true);
|
|
(*iter)->SetAngularVel(_vel);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetLinearAccel(const math::Vector3 &_accel)
|
|
{
|
|
for (Link_V::iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if (*iter)
|
|
{
|
|
(*iter)->SetEnabled(true);
|
|
(*iter)->SetLinearAccel(_accel);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetAngularAccel(const math::Vector3 &_accel)
|
|
{
|
|
for (Link_V::iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if (*iter)
|
|
{
|
|
(*iter)->SetEnabled(true);
|
|
(*iter)->SetAngularAccel(_accel);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetRelativeLinearVel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetRelativeLinearVel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetWorldLinearVel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetWorldLinearVel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetRelativeAngularVel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetRelativeAngularVel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetWorldAngularVel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetWorldAngularVel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetRelativeLinearAccel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetRelativeLinearAccel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetWorldLinearAccel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetWorldLinearAccel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetRelativeAngularAccel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetRelativeAngularAccel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Vector3 Model::GetWorldAngularAccel() const
|
|
{
|
|
if (this->GetLink("canonical"))
|
|
return this->GetLink("canonical")->GetWorldAngularAccel();
|
|
else
|
|
return math::Vector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
math::Box Model::GetBoundingBox() const
|
|
{
|
|
math::Box box;
|
|
|
|
box.min.Set(FLT_MAX, FLT_MAX, FLT_MAX);
|
|
box.max.Set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
|
|
for (Link_V::const_iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if (*iter)
|
|
{
|
|
math::Box linkBox;
|
|
linkBox = (*iter)->GetBoundingBox();
|
|
box += linkBox;
|
|
}
|
|
}
|
|
|
|
return box;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
unsigned int Model::GetJointCount() const
|
|
{
|
|
return this->joints.size();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
const Joint_V &Model::GetJoints() const
|
|
{
|
|
return this->joints;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
JointPtr Model::GetJoint(const std::string &_name)
|
|
{
|
|
JointPtr result;
|
|
Joint_V::iterator iter;
|
|
|
|
for (iter = this->joints.begin(); iter != this->joints.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetScopedName() == _name || (*iter)->GetName() == _name)
|
|
{
|
|
result = (*iter);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
const Model_V &Model::NestedModels() const
|
|
{
|
|
return this->models;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
ModelPtr Model::NestedModel(const std::string &_name) const
|
|
{
|
|
ModelPtr result;
|
|
|
|
for (auto &m : this->models)
|
|
{
|
|
if ((m->GetScopedName() == _name) || (m->GetName() == _name))
|
|
{
|
|
result = m;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
LinkPtr Model::GetLinkById(unsigned int _id) const
|
|
{
|
|
return boost::dynamic_pointer_cast<Link>(this->GetById(_id));
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
const Link_V &Model::GetLinks() const
|
|
{
|
|
return this->links;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
LinkPtr Model::GetLink(const std::string &_name) const
|
|
{
|
|
Link_V::const_iterator iter;
|
|
LinkPtr result;
|
|
|
|
if (_name == "canonical")
|
|
{
|
|
result = this->canonicalLink;
|
|
}
|
|
else
|
|
{
|
|
for (iter = this->links.begin(); iter != this->links.end(); ++iter)
|
|
{
|
|
if (((*iter)->GetScopedName() == _name) || ((*iter)->GetName() == _name))
|
|
{
|
|
result = *iter;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadJoint(sdf::ElementPtr _sdf)
|
|
{
|
|
JointPtr joint;
|
|
|
|
std::string stype = _sdf->Get<std::string>("type");
|
|
|
|
joint = this->GetWorld()->GetPhysicsEngine()->CreateJoint(stype,
|
|
boost::static_pointer_cast<Model>(shared_from_this()));
|
|
if (!joint)
|
|
{
|
|
gzerr << "Unable to create joint of type[" << stype << "]\n";
|
|
// gzthrow("Unable to create joint of type[" + stype + "]\n");
|
|
return;
|
|
}
|
|
|
|
joint->SetModel(boost::static_pointer_cast<Model>(shared_from_this()));
|
|
|
|
// Load the joint
|
|
joint->Load(_sdf);
|
|
|
|
if (this->GetJoint(joint->GetScopedName()) != NULL)
|
|
{
|
|
gzerr << "can't have two joint with the same name\n";
|
|
gzthrow("can't have two joints with the same name ["+
|
|
joint->GetScopedName() + "]\n");
|
|
}
|
|
|
|
this->joints.push_back(joint);
|
|
|
|
if (!this->jointController)
|
|
this->jointController.reset(new JointController(
|
|
boost::dynamic_pointer_cast<Model>(shared_from_this())));
|
|
this->jointController->AddJoint(joint);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadGripper(sdf::ElementPtr _sdf)
|
|
{
|
|
GripperPtr gripper(new Gripper(
|
|
boost::static_pointer_cast<Model>(shared_from_this())));
|
|
gripper->Load(_sdf);
|
|
this->grippers.push_back(gripper);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
std::vector<std::string> Model::SensorScopedName(
|
|
const std::string &_name) const
|
|
{
|
|
std::vector<std::string> names;
|
|
for (Link_V::const_iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
for (unsigned int j = 0; j < (*iter)->GetSensorCount(); ++j)
|
|
{
|
|
const auto sensorName = (*iter)->GetSensorName(j);
|
|
if (sensorName.size() < _name.size())
|
|
{
|
|
continue;
|
|
}
|
|
if (sensorName.substr(sensorName.size() - _name.size(), _name.size()) ==
|
|
_name)
|
|
{
|
|
names.push_back(sensorName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return names;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadPlugins()
|
|
{
|
|
// Check to see if we need to load any model plugins
|
|
if (this->GetPluginCount() > 0)
|
|
{
|
|
int iterations = 0;
|
|
|
|
// Wait for the sensors to be initialized before loading
|
|
// plugins, if there are any sensors
|
|
while (this->GetSensorCount() > 0 && !this->world->SensorsInitialized() &&
|
|
iterations < 50)
|
|
{
|
|
common::Time::MSleep(100);
|
|
iterations++;
|
|
}
|
|
|
|
// Load the plugins if the sensors have been loaded, or if there
|
|
// are no sensors attached to the model.
|
|
if (iterations < 50)
|
|
{
|
|
// Load the plugins
|
|
sdf::ElementPtr pluginElem = this->sdf->GetElement("plugin");
|
|
while (pluginElem)
|
|
{
|
|
this->LoadPlugin(pluginElem);
|
|
pluginElem = pluginElem->GetNextElement("plugin");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gzerr << "Sensors failed to initialize when loading model["
|
|
<< this->GetName() << "] via the factory mechanism."
|
|
<< "Plugins for the model will not be loaded.\n";
|
|
}
|
|
}
|
|
|
|
for (auto &model : this->models)
|
|
model->LoadPlugins();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
unsigned int Model::GetPluginCount() const
|
|
{
|
|
unsigned int result = 0;
|
|
|
|
// Count all the plugins specified in SDF
|
|
if (this->sdf->HasElement("plugin"))
|
|
{
|
|
sdf::ElementPtr pluginElem = this->sdf->GetElement("plugin");
|
|
while (pluginElem)
|
|
{
|
|
result++;
|
|
pluginElem = pluginElem->GetNextElement("plugin");
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
unsigned int Model::GetSensorCount() const
|
|
{
|
|
unsigned int result = 0;
|
|
|
|
// Count all the sensors on all the links
|
|
for (Link_V::const_iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
result += (*iter)->GetSensorCount();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::LoadPlugin(sdf::ElementPtr _sdf)
|
|
{
|
|
std::string pluginName = _sdf->Get<std::string>("name");
|
|
std::string filename = _sdf->Get<std::string>("filename");
|
|
|
|
gazebo::ModelPluginPtr plugin;
|
|
|
|
try
|
|
{
|
|
plugin = gazebo::ModelPlugin::Create(filename, pluginName);
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "Exception occured in the constructor of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run.\n";
|
|
|
|
// Log the message. gzerr has problems with this in 1.9. Remove the
|
|
// gzlog command in gazebo2.
|
|
gzlog << "Exception occured in the constructor of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run." << std::endl;
|
|
return;
|
|
}
|
|
|
|
if (plugin)
|
|
{
|
|
if (plugin->GetType() != MODEL_PLUGIN)
|
|
{
|
|
gzerr << "Model[" << this->GetName() << "] is attempting to load "
|
|
<< "a plugin, but detected an incorrect plugin type. "
|
|
<< "Plugin filename[" << filename << "] name["
|
|
<< pluginName << "]\n";
|
|
return;
|
|
}
|
|
|
|
ModelPtr myself = boost::static_pointer_cast<Model>(shared_from_this());
|
|
|
|
try
|
|
{
|
|
plugin->Load(myself, _sdf);
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "Exception occured in the Load function of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run.\n";
|
|
|
|
// Log the message. gzerr has problems with this in 1.9. Remove the
|
|
// gzlog command in gazebo2.
|
|
gzlog << "Exception occured in the Load function of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run." << std::endl;
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
plugin->Init();
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "Exception occured in the Init function of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run\n";
|
|
|
|
// Log the message. gzerr has problems with this in 1.9. Remove the
|
|
// gzlog command in gazebo2.
|
|
gzlog << "Exception occured in the Init function of plugin with name["
|
|
<< pluginName << "] and filename[" << filename << "]. "
|
|
<< "This plugin will not run." << std::endl;
|
|
return;
|
|
}
|
|
|
|
this->plugins.push_back(plugin);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetGravityMode(const bool &_v)
|
|
{
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
if (*liter)
|
|
{
|
|
(*liter)->SetGravityMode(_v);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetCollideMode(const std::string &_m)
|
|
{
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
if (*liter)
|
|
{
|
|
(*liter)->SetCollideMode(_m);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetLaserRetro(const float _retro)
|
|
{
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
if (*liter)
|
|
{
|
|
(*liter)->SetLaserRetro(_retro);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::FillMsg(msgs::Model &_msg)
|
|
{
|
|
ignition::math::Pose3d relPose = this->GetRelativePose().Ign();
|
|
|
|
_msg.set_name(this->GetScopedName());
|
|
_msg.set_is_static(this->IsStatic());
|
|
_msg.set_self_collide(this->GetSelfCollide());
|
|
msgs::Set(_msg.mutable_pose(), relPose);
|
|
_msg.set_id(this->GetId());
|
|
msgs::Set(_msg.mutable_scale(), this->scale);
|
|
|
|
msgs::Set(this->visualMsg->mutable_pose(), relPose);
|
|
_msg.add_visual()->CopyFrom(*this->visualMsg);
|
|
|
|
for (const auto &link : this->links)
|
|
{
|
|
link->FillMsg(*_msg.add_link());
|
|
}
|
|
|
|
for (const auto &joint : this->joints)
|
|
{
|
|
joint->FillMsg(*_msg.add_joint());
|
|
}
|
|
for (const auto &model : this->models)
|
|
{
|
|
model->FillMsg(*_msg.add_model());
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::ProcessMsg(const msgs::Model &_msg)
|
|
{
|
|
if (_msg.has_id() && _msg.id() != this->GetId())
|
|
{
|
|
gzerr << "Incorrect ID[" << _msg.id() << " != " << this->GetId() << "]\n";
|
|
return;
|
|
}
|
|
else if ((_msg.has_id() && _msg.id() != this->GetId()) &&
|
|
_msg.name() != this->GetScopedName())
|
|
{
|
|
gzerr << "Incorrect name[" << _msg.name() << " != " << this->GetName()
|
|
<< "]\n";
|
|
return;
|
|
}
|
|
|
|
this->SetName(this->world->StripWorldName(_msg.name()));
|
|
if (_msg.has_pose())
|
|
this->SetWorldPose(msgs::ConvertIgn(_msg.pose()));
|
|
for (int i = 0; i < _msg.link_size(); i++)
|
|
{
|
|
LinkPtr link = this->GetLinkById(_msg.link(i).id());
|
|
if (link)
|
|
link->ProcessMsg(_msg.link(i));
|
|
}
|
|
|
|
if (_msg.has_is_static())
|
|
this->SetStatic(_msg.is_static());
|
|
|
|
if (_msg.has_scale())
|
|
this->SetScale(msgs::ConvertIgn(_msg.scale()));
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetJointAnimation(
|
|
const std::map<std::string, common::NumericAnimationPtr> &_anims,
|
|
boost::function<void()> _onComplete)
|
|
{
|
|
boost::recursive_mutex::scoped_lock lock(this->updateMutex);
|
|
std::map<std::string, common::NumericAnimationPtr>::const_iterator iter;
|
|
for (iter = _anims.begin(); iter != _anims.end(); ++iter)
|
|
{
|
|
this->jointAnimations[iter->first] = iter->second;
|
|
}
|
|
this->onJointAnimationComplete = _onComplete;
|
|
this->prevAnimationTime = this->world->GetSimTime();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::StopAnimation()
|
|
{
|
|
boost::recursive_mutex::scoped_lock lock(this->updateMutex);
|
|
Entity::StopAnimation();
|
|
this->onJointAnimationComplete.clear();
|
|
this->jointAnimations.clear();
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::AttachStaticModel(ModelPtr &_model, math::Pose _offset)
|
|
{
|
|
if (!_model->IsStatic())
|
|
{
|
|
gzerr << "AttachStaticModel requires a static model\n";
|
|
return;
|
|
}
|
|
|
|
this->attachedModels.push_back(_model);
|
|
this->attachedModelsOffset.push_back(_offset);
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::DetachStaticModel(const std::string &_modelName)
|
|
{
|
|
for (unsigned int i = 0; i < this->attachedModels.size(); i++)
|
|
{
|
|
if (this->attachedModels[i]->GetName() == _modelName)
|
|
{
|
|
this->attachedModels.erase(this->attachedModels.begin()+i);
|
|
this->attachedModelsOffset.erase(this->attachedModelsOffset.begin()+i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::OnPoseChange()
|
|
{
|
|
math::Pose p;
|
|
for (unsigned int i = 0; i < this->attachedModels.size(); i++)
|
|
{
|
|
p = this->GetWorldPose();
|
|
p += this->attachedModelsOffset[i];
|
|
this->attachedModels[i]->SetWorldPose(p, true);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::SetState(const ModelState &_state)
|
|
{
|
|
this->SetWorldPose(_state.GetPose(), true);
|
|
this->SetScale(_state.Scale(), true);
|
|
|
|
LinkState_M linkStates = _state.GetLinkStates();
|
|
for (LinkState_M::iterator iter = linkStates.begin();
|
|
iter != linkStates.end(); ++iter)
|
|
{
|
|
LinkPtr link = this->GetLink(iter->first);
|
|
if (link)
|
|
link->SetState(iter->second);
|
|
else
|
|
gzerr << "Unable to find link[" << iter->first << "]\n";
|
|
}
|
|
|
|
for (const auto &ms : _state.NestedModelStates())
|
|
{
|
|
ModelPtr model = this->NestedModel(ms.first);
|
|
if (model)
|
|
model->SetState(ms.second);
|
|
else
|
|
gzerr << "Unable to find model[" << ms.first << "]\n";
|
|
}
|
|
|
|
// For now we don't use the joint state values to set the state of
|
|
// simulation.
|
|
// for (unsigned int i = 0; i < _state.GetJointStateCount(); ++i)
|
|
// {
|
|
// JointState jointState = _state.GetJointState(i);
|
|
// this->SetJointPosition(this->GetName() + "::" + jointState.GetName(),
|
|
// jointState.GetAngle(0).Radian());
|
|
// }
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetScale(const math::Vector3 &_scale)
|
|
{
|
|
this->SetScale(_scale.Ign());
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetScale(const ignition::math::Vector3d &_scale,
|
|
const bool _publish)
|
|
{
|
|
if (this->scale == _scale)
|
|
return;
|
|
|
|
this->scale = _scale;
|
|
|
|
Base_V::iterator iter;
|
|
for (iter = this->children.begin(); iter != this->children.end(); ++iter)
|
|
{
|
|
if (*iter && (*iter)->HasType(LINK))
|
|
{
|
|
boost::static_pointer_cast<Link>(*iter)->SetScale(_scale);
|
|
}
|
|
}
|
|
|
|
if (_publish)
|
|
this->PublishScale();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
ignition::math::Vector3d Model::Scale() const
|
|
{
|
|
return this->scale;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
void Model::PublishScale()
|
|
{
|
|
GZ_ASSERT(this->GetParentModel() != NULL,
|
|
"A model without a parent model should not happen");
|
|
|
|
this->world->PublishModelScale(this->GetParentModel());
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetEnabled(bool _enabled)
|
|
{
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
if (*liter)
|
|
(*liter)->SetEnabled(_enabled);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetLinkWorldPose(const math::Pose &_pose, std::string _linkName)
|
|
{
|
|
// look for link matching link name
|
|
LinkPtr link = this->GetLink(_linkName);
|
|
if (link)
|
|
this->SetLinkWorldPose(_pose, link);
|
|
else
|
|
gzerr << "Setting Model Pose by specifying Link failed:"
|
|
<< " Link[" << _linkName << "] not found.\n";
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetLinkWorldPose(const math::Pose &_pose, const LinkPtr &_link)
|
|
{
|
|
math::Pose linkPose = _link->GetWorldPose();
|
|
math::Pose currentModelPose = this->GetWorldPose();
|
|
math::Pose linkRelPose = currentModelPose - linkPose;
|
|
math::Pose targetModelPose = linkRelPose * _pose;
|
|
this->SetWorldPose(targetModelPose);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetAutoDisable(bool _auto)
|
|
{
|
|
if (!this->joints.empty())
|
|
return;
|
|
|
|
for (Link_V::iterator liter = this->links.begin();
|
|
liter != this->links.end(); ++liter)
|
|
{
|
|
if (*liter)
|
|
{
|
|
(*liter)->SetAutoDisable(_auto);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool Model::GetAutoDisable() const
|
|
{
|
|
return this->sdf->Get<bool>("allow_auto_disable");
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::SetSelfCollide(bool _self_collide)
|
|
{
|
|
this->sdf->GetElement("self_collide")->Set(_self_collide);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool Model::GetSelfCollide() const
|
|
{
|
|
return this->sdf->Get<bool>("self_collide");
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void Model::RemoveLink(const std::string &_name)
|
|
{
|
|
for (Link_V::iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetName() == _name || (*iter)->GetScopedName() == _name)
|
|
{
|
|
this->links.erase(iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/////////////////////////////////////////////////
|
|
JointControllerPtr Model::GetJointController()
|
|
{
|
|
return this->jointController;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
GripperPtr Model::GetGripper(size_t _index) const
|
|
{
|
|
if (_index < this->grippers.size())
|
|
return this->grippers[_index];
|
|
else
|
|
return GripperPtr();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
size_t Model::GetGripperCount() const
|
|
{
|
|
return this->grippers.size();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
double Model::GetWorldEnergyPotential() const
|
|
{
|
|
double e = 0;
|
|
for (Link_V::const_iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
e += (*iter)->GetWorldEnergyPotential();
|
|
}
|
|
for (Joint_V::const_iterator iter = this->joints.begin();
|
|
iter != this->joints.end(); ++iter)
|
|
{
|
|
for (unsigned int j = 0; j < (*iter)->GetAngleCount(); ++j)
|
|
{
|
|
e += (*iter)->GetWorldEnergyPotentialSpring(j);
|
|
}
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
double Model::GetWorldEnergyKinetic() const
|
|
{
|
|
double e = 0;
|
|
for (Link_V::const_iterator iter = this->links.begin();
|
|
iter != this->links.end(); ++iter)
|
|
{
|
|
e += (*iter)->GetWorldEnergyKinetic();
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
double Model::GetWorldEnergy() const
|
|
{
|
|
return this->GetWorldEnergyPotential() + this->GetWorldEnergyKinetic();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
gazebo::physics::JointPtr Model::CreateJoint(
|
|
const std::string &_name, const std::string &_type,
|
|
physics::LinkPtr _parent, physics::LinkPtr _child)
|
|
{
|
|
gazebo::physics::JointPtr joint;
|
|
if (this->GetJoint(_name))
|
|
{
|
|
gzwarn << "Model [" << this->GetName()
|
|
<< "] already has a joint named [" << _name
|
|
<< "], skipping creating joint.\n";
|
|
return joint;
|
|
}
|
|
joint =
|
|
this->world->GetPhysicsEngine()->CreateJoint(_type, shared_from_this());
|
|
joint->SetName(_name);
|
|
joint->Attach(_parent, _child);
|
|
// need to call Joint::Load to clone Joint::sdfJoint into Joint::sdf
|
|
joint->Load(_parent, _child, gazebo::math::Pose());
|
|
this->joints.push_back(joint);
|
|
return joint;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
gazebo::physics::JointPtr Model::CreateJoint(sdf::ElementPtr _sdf)
|
|
{
|
|
if (_sdf->GetName() != "joint" ||
|
|
!_sdf->HasAttribute("name") ||
|
|
!_sdf->HasAttribute("type"))
|
|
{
|
|
gzerr << "Invalid _sdf passed to Model::CreateJoint" << std::endl;
|
|
return physics::JointPtr();
|
|
}
|
|
|
|
std::string jointName(_sdf->Get<std::string>("name"));
|
|
if (this->GetJoint(jointName))
|
|
{
|
|
gzwarn << "Model [" << this->GetName()
|
|
<< "] already has a joint named [" << jointName
|
|
<< "], skipping creating joint.\n";
|
|
return physics::JointPtr();
|
|
}
|
|
|
|
try
|
|
{
|
|
// LoadJoint can throw if the scoped name of the joint already exists.
|
|
this->LoadJoint(_sdf);
|
|
}
|
|
catch(...)
|
|
{
|
|
gzerr << "LoadJoint Failed" << std::endl;
|
|
}
|
|
return this->GetJoint(jointName);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool Model::RemoveJoint(const std::string &_name)
|
|
{
|
|
bool paused = this->world->IsPaused();
|
|
gazebo::physics::JointPtr joint = this->GetJoint(_name);
|
|
if (joint)
|
|
{
|
|
this->world->SetPaused(true);
|
|
if (this->jointController)
|
|
{
|
|
this->jointController->RemoveJoint(joint.get());
|
|
}
|
|
joint->Detach();
|
|
joint->Fini();
|
|
|
|
this->joints.erase(
|
|
std::remove(this->joints.begin(), this->joints.end(), joint),
|
|
this->joints.end());
|
|
this->world->SetPaused(paused);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
gzwarn << "Joint [" << _name
|
|
<< "] does not exist in model [" << this->GetName()
|
|
<< "], not removed.\n";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
LinkPtr Model::CreateLink(const std::string &_name)
|
|
{
|
|
LinkPtr link;
|
|
if (this->GetLink(_name))
|
|
{
|
|
gzwarn << "Model [" << this->GetName()
|
|
<< "] already has a link named [" << _name
|
|
<< "], skipping creating link.\n";
|
|
return link;
|
|
}
|
|
|
|
link = this->world->GetPhysicsEngine()->CreateLink(shared_from_this());
|
|
|
|
link->SetName(_name);
|
|
this->links.push_back(link);
|
|
|
|
return link;
|
|
}
|