SideContactPlugin.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2016 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
18 #include <boost/algorithm/string/replace.hpp>
19 #include <string>
20 
21 #include "SideContactPlugin.hh"
22 #include <ignition/math/Vector3.hh>
23 
24 using namespace gazebo;
26 
27 SideContactPlugin::SideContactPlugin() : ModelPlugin()
29 {
30 }
31 
34 {
35  event::Events::DisconnectWorldUpdateBegin(this->updateConnection);
36  this->parentSensor.reset();
37  this->world.reset();
38 }
39 
41 void SideContactPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
42 {
43  GZ_ASSERT(_model, "Model pointer is null");
44 
45  if (!_sdf->HasElement("contact_sensor_name"))
46  {
47  gzerr << "'contact_sensor_name' not specified in SDF\n";
48  }
49  this->model = _model;
50  this->world = this->model->GetWorld();
51  this->node = transport::NodePtr(new transport::Node());
52  this->node->Init(this->world->GetName());
53 
54  this->contactSensorName = _sdf->Get<std::string>("contact_sensor_name");
55  bool sensorFound = this->FindContactSensor();
56  if (!sensorFound || !this->parentSensor)
57  {
58  gzerr << "Contact sensor not found: " << this->contactSensorName << "\n";
59  }
60 
61  std::string parentLinkName = this->parentLink->GetScopedName();
62  std::string defaultCollisionName = parentLinkName + "::__default__";
63  if (this->parentSensor->GetCollisionCount() != 1)
64  {
65  gzerr << "SideContactPlugin requires a single collision to observe contacts for\n";
66  return;
67  }
68 
69  this->collisionName = this->parentSensor->GetCollisionName(0);
70  if (this->collisionName == defaultCollisionName)
71  {
72  // Use the first collision of the parent link by default
73  if (this->parentLink->GetCollisions().empty())
74  {
75  gzerr << "Couldn't find any collisions for the contact sensor.";
76  return;
77  }
78  unsigned int index = 0;
79  this->collisionName = this->parentLink->GetCollision(index)->GetScopedName();
80  }
81  gzdbg << "[" << this->model->GetName() << "] Watching collisions on: " << this->collisionName << "\n";
82 
83  if (_sdf->HasElement("contact_side_normal"))
84  {
85  this->sideNormal = _sdf->Get<ignition::math::Vector3d>("contact_side_normal");
86  }
87  else
88  {
89  this->sideNormal = ignition::math::Vector3d(0, 0, 1);
90  }
91 
92 
93  // FIXME: how to not hard-code this gazebo prefix?
94  std::string contactTopic = "/gazebo/" + this->scopedContactSensorName;
95  boost::replace_all(contactTopic, "::", "/");
96  this->contactSub =
97  this->node->Subscribe(contactTopic, &SideContactPlugin::OnContactsReceived, this);
98 
99  // Listen to the update event. This event is broadcast every
100  // simulation iteration.
101  this->updateConnection = event::Events::ConnectWorldUpdateBegin(
102  boost::bind(&SideContactPlugin::OnUpdate, this, _1));
103 }
104 
107 {
108  auto sensorManager = sensors::SensorManager::Instance();
109  auto links = this->model->GetLinks();
110  for (const auto &link : links)
111  {
112  std::string scopedContactSensorName =
113  this->world->GetName() + "::" + link->GetScopedName() + "::" + this->contactSensorName;
114  for (unsigned int i = 0; i < link->GetSensorCount(); ++i)
115  {
116  if (link->GetSensorName(i) == scopedContactSensorName)
117  {
118  this->parentLink = link;
119  this->scopedContactSensorName = scopedContactSensorName;
120  this->parentSensor =
121  std::static_pointer_cast<sensors::ContactSensor>(
122  sensorManager->GetSensor(scopedContactSensorName));
123  return this->parentSensor != 0;
124  }
125  }
126  }
127  return false;
128 }
129 
131 void SideContactPlugin::OnContactsReceived(ConstContactsPtr& _msg)
132 {
133  boost::mutex::scoped_lock lock(this->mutex);
134  this->newestContactsMsg = *_msg;
135  this->newMsg = true;
136 }
137 
139 void SideContactPlugin::OnUpdate(const common::UpdateInfo &/*_info*/)
140 {
142 }
143 
146 {
147  if (!this->newMsg)
148  {
149  return;
150  }
151 
152  auto parentLinkPose = this->parentLink->GetWorldPose().Ign();
153  math::Vector3 parentLinkTopNormal = parentLinkPose.Rot().RotateVector(this->sideNormal);
154 
155  // Get all the contacts
156  boost::mutex::scoped_lock lock(this->mutex);
157  msgs::Contacts contacts = this->newestContactsMsg;
158  this->contactingLinks.clear();
159  double factor = 1.0;
160 
161  for (int i = 0; i < contacts.contact_size(); ++i)
162  {
163  // Get the collision that's not the parent link
164  std::string collision = contacts.contact(i).collision1();
165  if (this->collisionName == contacts.contact(i).collision1()) {
166  collision = contacts.contact(i).collision2();
167  factor = -1.0; // the frames are reversed for the alignment check
168  }
169 
170  // Only consider links with collision normals aligned with the normal of the link's side
171  for (int j = 0; j < contacts.contact(i).position_size(); ++j)
172  {
173  ignition::math::Vector3d contactNormal = msgs::ConvertIgn(contacts.contact(i).normal(j));
174  double alignment = factor * parentLinkTopNormal.Dot(contactNormal);
175  if (alignment > 0.0) {
176  physics::CollisionPtr collisionPtr =
177  boost::dynamic_pointer_cast<physics::Collision>(this->world->GetEntity(collision));
178  if (collisionPtr) { // ensure the collision hasn't been deleted
179  physics::LinkPtr link = collisionPtr->GetLink();
180  this->contactingLinks.insert(link);
181  }
182  }
183  }
184  }
185  this->newMsg = false;
186 }
187 
190 {
191  this->CalculateContactingLinks();
192  this->contactingModels.clear();
193  for (auto link : this->contactingLinks)
194  {
195  physics::ModelPtr model = link->GetModel();
196  this->contactingModels.insert(model);
197  }
198 }
boost::mutex mutex
Mutex for protecting contacts msg.
physics::WorldPtr world
Pointer to the world.
bool newMsg
Flag for new contacts message.
virtual void CalculateContactingModels()
Determine which models are in contact with the side of the parent link.
virtual void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
Load the sensor plugin.
std::string collisionName
Name of the collision of the parent&#39;s link.
virtual ~SideContactPlugin()
Destructor.
std::string contactSensorName
Name of the contact sensor.
std::set< physics::ModelPtr > contactingModels
Set of pointers to models that have collisions with the parent link&#39;s side.
transport::NodePtr node
Pointer to this node for publishing/subscribing.
A plugin for a model with a contact sensor that only monitors collisions on one of its sides...
std::set< physics::LinkPtr > contactingLinks
Set of pointers to links that have collisions with the parent link&#39;s side.
sensors::ContactSensorPtr parentSensor
Pointer to the contact sensor.
transport::SubscriberPtr contactSub
Subscriber for the contact topic.
event::ConnectionPtr updateConnection
Pointer to the update event connection.
physics::LinkPtr parentLink
Pointer to the sensor&#39;s parent&#39;s link.
virtual void OnUpdate(const common::UpdateInfo &_info)
Called when world update events are received.
physics::ModelPtr model
Pointer to the model.
std::string scopedContactSensorName
Scoped name of the contact sensor.
msgs::Contacts newestContactsMsg
Contacts msg received.
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
virtual void CalculateContactingLinks()
Determine which links are in contact with the side of the parent link.
bool FindContactSensor()
Iterate through links of model to find sensor with the specified name.
virtual void OnContactsReceived(ConstContactsPtr &_msg)
Callback that recieves the contact sensor&#39;s messages.
ignition::math::Vector3d sideNormal
The normal, in local frame, to the side that is to have contacts monitored (default (0...


osrf_gear
Author(s):
autogenerated on Wed Sep 7 2016 03:48:12