ppovb5fc7/gazebo/plugins/ContainPlugin.cc

289 lines
7.8 KiB
C++
Raw Normal View History

2019-03-25 11:01:43 +08:00
/*
* Copyright (C) 2018 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 <string>
#include <ignition/math/OrientedBox.hh>
#include <ignition/math/Pose3.hh>
#include "gazebo/common/Events.hh"
#include "gazebo/common/UpdateInfo.hh"
#include "gazebo/physics/Entity.hh"
#include "gazebo/physics/World.hh"
#include "gazebo/transport/Node.hh"
#include "ContainPlugin.hh"
namespace gazebo
{
namespace physics
{
typedef boost::weak_ptr<physics::Entity> EntityWeakPtr;
}
/// \brief Private data class for the ContainPlugin class
class ContainPluginPrivate
{
/// \brief Connection to world update.
public: event::ConnectionPtr updateConnection;
/// \brief Pointer to the world.
public: physics::WorldPtr world;
/// \brief Scoped name of the entity we're checking.
public: std::string entityName;
/// \brief Pointer to the entity we're checking.
public: physics::EntityWeakPtr entity;
/// \brief Box representing the volume to check.
public: ignition::math::OrientedBoxd box;
/// \brief Gazebo transport node for communication.
public: transport::NodePtr gzNode;
/// \brief pointer to an entity whose pose the geometry will track
public: physics::EntityWeakPtr containerEntity;
/// \brief scoped name of entity to track
public: std::string containerEntityName;
/// \brief Publisher which publishes contain / doesn't contain messages.
public: transport::PublisherPtr containGzPub;
/// \brief Subscriber to enable messages.
public: transport::SubscriberPtr enableGzSub;
/// \brief Namespace for the topics:
/// /<ns>/contain
/// /<ns>/enable
public: std::string ns;
/// \brief 1 if contains, 0 if doesn't contain, -1 if unset
public: int contain = -1;
};
}
using namespace gazebo;
GZ_REGISTER_WORLD_PLUGIN(ContainPlugin)
/////////////////////////////////////////////////
ContainPlugin::ContainPlugin() : WorldPlugin(),
dataPtr(new ContainPluginPrivate)
{
}
/////////////////////////////////////////////////
void ContainPlugin::Load(physics::WorldPtr _world, sdf::ElementPtr _sdf)
{
// Entity name
if (!_sdf->HasElement("entity"))
{
gzerr << "Missing required parameter <entity>, plugin will not be "
<< "initialized." << std::endl;
return;
}
this->dataPtr->entityName = _sdf->Get<std::string>("entity");
// Namespace
if (!_sdf->HasElement("namespace"))
{
gzerr << "Missing required parameter <namespace>, plugin will not be "
<< "initialized." << std::endl;
return;
}
this->dataPtr->ns = _sdf->Get<std::string>("namespace");
// Pose
if (!_sdf->HasElement("pose"))
{
gzerr << "Missing required parameter <pose>, plugin will not be "
<< "initialized." << std::endl;
return;
}
auto pose = _sdf->Get<ignition::math::Pose3d>("pose");
sdf::ParamPtr frameParam = _sdf->GetElement("pose")->GetAttribute("frame");
if (frameParam)
{
this->dataPtr->containerEntityName = frameParam->GetAsString();
}
// Geometry
if (!_sdf->HasElement("geometry"))
{
gzerr << "Missing required parameter <geometry>, plugin will not be "
<< "initialized." << std::endl;
return;
}
auto geometryElem = _sdf->GetElement("geometry");
// Only box for now
if (!geometryElem->HasElement("box"))
{
gzerr << "Missing required parameter <box>, plugin will not be "
<< "initialized." << std::endl;
return;
}
auto boxElem = geometryElem->GetElement("box");
if (!boxElem->HasElement("size"))
{
gzerr << "Missing required parameter <size>, plugin will not be "
<< "initialized." << std::endl;
return;
}
auto size = boxElem->Get<ignition::math::Vector3d>("size");
this->dataPtr->box = ignition::math::OrientedBoxd(size, pose);
this->dataPtr->world = _world;
// Start/stop
this->dataPtr->gzNode = transport::NodePtr(new transport::Node());
this->dataPtr->gzNode->Init();
this->dataPtr->enableGzSub = this->dataPtr->gzNode->Subscribe("/" +
this->dataPtr->ns + "/enable", &ContainPlugin::Enable, this);
auto enabled = true;
if (_sdf->HasElement("enabled"))
enabled = _sdf->Get<bool>("enabled");
if (enabled)
{
boost::shared_ptr<msgs::Int> msg(new msgs::Int());
msg->set_data(1);
this->Enable(msg);
}
}
//////////////////////////////////////////////////
void ContainPlugin::Enable(ConstIntPtr &_msg)
{
auto enable = _msg->data() == 1;
// Already started
if (enable && this->dataPtr->updateConnection)
{
gzwarn << "Contain plugin is already enabled." << std::endl;
return;
}
// Already stopped
if (!enable && !this->dataPtr->updateConnection)
{
gzwarn << "Contain plugin is already disabled." << std::endl;
return;
}
// Start
if (enable)
{
// Start update
this->dataPtr->updateConnection = event::Events::ConnectWorldUpdateBegin(
std::bind(&ContainPlugin::OnUpdate, this, std::placeholders::_1));
this->dataPtr->containGzPub = this->dataPtr->gzNode->Advertise<msgs::Int>(
"/" + this->dataPtr->ns + "/contain");
gzmsg << "Started contain plugin [" << this->dataPtr->ns << "]"
<< std::endl;
return;
}
// Stop
{
this->dataPtr->updateConnection.reset();
this->dataPtr->containGzPub.reset();
this->dataPtr->contain = -1;
gzmsg << "Stopped contain plugin [" << this->dataPtr->ns << "]"
<< std::endl;
return;
}
}
/////////////////////////////////////////////////
void ContainPlugin::OnUpdate(const common::UpdateInfo &/*_info*/)
{
// Only get the entity once
physics::EntityPtr entity = this->dataPtr->entity.lock();
if (!entity)
{
this->dataPtr->entity = this->dataPtr->world->GetEntity(
this->dataPtr->entityName);
entity = this->dataPtr->entity.lock();
if (!entity)
{
// Could not find entity being tested
this->PublishContains(false);
return;
}
}
ignition::math::Vector3d entityInWorldFrame =
entity->GetWorldPose().Ign().Pos();
ignition::math::Vector3d entityInBoxFrame;
if (!this->dataPtr->containerEntityName.empty())
{
physics::EntityPtr referenceEntity = this->dataPtr->containerEntity.lock();
// box is in a potentially moving reference frame
if (!referenceEntity)
{
this->dataPtr->containerEntity = this->dataPtr->world->GetEntity(
this->dataPtr->containerEntityName);
referenceEntity = this->dataPtr->containerEntity.lock();
if (!referenceEntity)
{
// Could not find reference entity
this->PublishContains(false);
return;
}
}
auto worldToBox = referenceEntity->GetWorldPose().Ign();
auto boxToWorld = worldToBox.Inverse();
// Transform the entity vector from world frame to the frame the box is in
entityInBoxFrame = (boxToWorld.Rot() * entityInWorldFrame)
+ boxToWorld.Pos();
}
else
{
// box frame is world frame
entityInBoxFrame = entityInWorldFrame;
}
this->PublishContains(this->dataPtr->box.Contains(entityInBoxFrame));
}
//////////////////////////////////////////////////
void ContainPlugin::PublishContains(const bool _contains)
{
int containNow = _contains ? 1 : 0;
if (containNow != this->dataPtr->contain)
{
this->dataPtr->contain = containNow;
msgs::Int msg;
msg.set_data(this->dataPtr->contain);
this->dataPtr->containGzPub->Publish(msg);
}
}