00001 #include "r2_gazebo_gripper/GazeboGripper.h"
00002 #include <gazebo/physics/physics.hh>
00003 #include <gazebo/transport/transport.hh>
00004
00005 using namespace gazebo;
00006
00007 GazeboGripper::GazeboGripper()
00008 : ModelPlugin()
00009 , attached(false)
00010 , contactDuration(0.)
00011 , nonContactDuration(0.)
00012 {
00013 }
00014
00015 GazeboGripper::~GazeboGripper()
00016 {
00017 }
00018
00019 void GazeboGripper::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
00020 {
00021
00022 modelPtr = _model;
00023
00024 prevUpdateTime = _model->GetWorld()->GetSimTime();
00025 prevContactUpdateTime = prevUpdateTime;
00026
00027 if (!_sdf->HasAttribute("name"))
00028 {
00029 ROS_WARN("GazeboGripper: Plugin name missing");
00030 pluginName = "GazeboGripperPlugin";
00031 }
00032 else
00033 pluginName = _sdf->GetAttribute("name")->GetAsString().c_str();
00034 ROS_INFO("Loading GazeboGripper plugin '%s'", pluginName.c_str());
00035
00036
00037 if (!_sdf->HasElement("updateRate"))
00038 {
00039 ROS_INFO("%s: plugin missing <updateRate>, default to 1000", pluginName.c_str());
00040 updateTime = 1 / 1000;
00041 }
00042 else
00043 {
00044 updateTime = 1 / (_sdf->GetElement("updateRate")->Get<double>());
00045 }
00046
00047 if (!_sdf->HasElement("attachWait"))
00048 {
00049 ROS_FATAL("%s: plugin missing <attachWait>, cannot proceed", pluginName.c_str());
00050 return;
00051 }
00052 else
00053 {
00054 attachWait = _sdf->GetElement("attachWait")->Get<double>();
00055 }
00056
00057 if (!_sdf->HasElement("detachWait"))
00058 {
00059 ROS_FATAL("%s: plugin missing <detachWait>, cannot proceed", pluginName.c_str());
00060 return;
00061 }
00062 else
00063 {
00064 detachWait = _sdf->GetElement("detachWait")->Get<double>();
00065 }
00066
00067 if (!_sdf->HasElement("maxRelativeMotionRate"))
00068 {
00069 ROS_FATAL("%s: plugin missing <maxRelativeMotionRate>, cannot proceed", pluginName.c_str());
00070 return;
00071 }
00072 else
00073 {
00074 maxRelativeMotionRate = _sdf->GetElement("maxRelativeMotionRate")->Get<double>();
00075 }
00076
00077 if (!_sdf->HasElement("gripperAttachLink"))
00078 {
00079 ROS_FATAL("%s: plugin missing <gripperAttachLink>, cannot proceed", pluginName.c_str());
00080 return;
00081 }
00082 else
00083 {
00084 gripperAttachLink = _sdf->GetElement("gripperAttachLink")->Get<std::string>();
00085
00086 if (!modelPtr->GetLink(gripperAttachLink))
00087 {
00088 ROS_FATAL((std::string("%s: plugin couldn't find gripperAttachLink (%s) in model, cannot proceed.\n")
00089 + "\tLinks connected with static joints may be combined into one by the URDF parser.").c_str(),
00090 pluginName.c_str(), gripperAttachLink.c_str());
00091 return;
00092 }
00093
00094 ROS_INFO("%s: gripperAttachLink: %s", pluginName.c_str(), gripperAttachLink.c_str());
00095 }
00096
00097 if (!_sdf->HasElement("gripperLink"))
00098 {
00099 ROS_FATAL("%s: plugin missing <gripperLink>, cannot proceed", pluginName.c_str());
00100 return;
00101 }
00102
00103 std::vector<physics::LinkPtr> links;
00104 sdf::ElementPtr linkElem = _sdf->GetElement("gripperLink");
00105
00106 while (linkElem)
00107 {
00108 physics::LinkPtr link;
00109
00110 if (link = modelPtr->GetLink(linkElem->Get<std::string>()))
00111 {
00112 links.push_back(link);
00113 ROS_DEBUG("%s: added gripperLink: %s", linkElem->Get<std::string>().c_str(), pluginName.c_str());
00114 }
00115 else
00116 {
00117 ROS_FATAL((std::string("%s: plugin couldn't find gripperLink (%s) in model, cannot proceed.\n")
00118 + "\tLinks connected with static joints may be combined into one by the URDF parser.").c_str(),
00119 pluginName.c_str(), linkElem->Get<std::string>().c_str());
00120 return;
00121 }
00122
00123 linkElem = linkElem->GetNextElement("gripperLink");
00124 }
00125
00126 if (links.size() < 2)
00127 {
00128 ROS_FATAL("%s: plugin requires at least two gripperLinks, cannot proceed", pluginName.c_str());
00129 return;
00130 }
00131
00132 fixedJointPtr = modelPtr->GetWorld()->GetPhysicsEngine()->CreateJoint("revolute");
00133 fixedJointPtr->SetName(pluginName + "_joint");
00134
00135 collisionNames.clear();
00136
00137
00138 for (std::vector<physics::LinkPtr>::iterator linkIt = links.begin(); linkIt != links.end(); ++linkIt)
00139 {
00140 for (unsigned int j = 0; j < (*linkIt)->GetChildCount(); ++j)
00141 {
00142 physics::CollisionPtr collision = (*linkIt)->GetCollision(j);
00143 collisionNames.push_back(collision->GetScopedName());
00144 ROS_DEBUG("%s: Added collision '%s'", pluginName.c_str(), collision->GetScopedName().c_str());
00145 }
00146 }
00147
00148 if (collisionNames.size())
00149 {
00150
00151 physics::ContactManager *mgr = modelPtr->GetWorld()->GetPhysicsEngine()->GetContactManager();
00152
00153
00154 mgr->CreateFilter(pluginName, collisionNames);
00155 std::sort(collisionNames.begin(), collisionNames.end());
00156 }
00157
00158
00159 worldUpdateEvent = event::Events::ConnectWorldUpdateEnd(boost::bind(&GazeboGripper::onUpdate, this));
00160
00161 ROS_INFO("%s: plugin loaded", pluginName.c_str());
00162 }
00163
00164 void GazeboGripper::Init()
00165 {
00166 ROS_INFO("Gazebo Gripper plugin initialized");
00167 ModelPlugin::Init();
00168 }
00169
00170 void GazeboGripper::onUpdate()
00171 {
00172 physics::ContactManager *mgr = modelPtr->GetWorld()->GetPhysicsEngine()->GetContactManager();
00173
00174 common::Time currTime = modelPtr->GetWorld()->GetSimTime();
00175 if ((currTime - prevUpdateTime).Double() >= updateTime)
00176 {
00177 prevUpdateTime = currTime;
00178
00179 const std::vector<physics::Contact*>& contacts = mgr->GetContacts();
00180
00181 std::vector<physics::Contact*> myContacts;
00182 for (size_t i = 0; i < contacts.size(); ++i)
00183 {
00184
00185 std::string name1 = contacts[i]->collision1->GetScopedName();
00186 std::string name2 = contacts[i]->collision2->GetScopedName();
00187
00188 if (std::find(collisionNames.begin(), collisionNames.end(), name1) != collisionNames.end() ||
00189 std::find(collisionNames.begin(), collisionNames.end(), name2) != collisionNames.end())
00190 myContacts.push_back(contacts[i]);
00191 }
00192
00193 handleContacts(myContacts);
00194 mgr->Clear();
00195 }
00196 }
00197
00198 void GazeboGripper::handleContacts(const std::vector<physics::Contact*>& contacts)
00199 {
00200 common::Time currTime = modelPtr->GetWorld()->GetSimTime();
00201 double elapsedTime = (currTime - prevContactUpdateTime).Double();
00202 prevContactUpdateTime = currTime;
00203
00204
00205 int minContactCount = 1;
00206 if (contacts.size() >= minContactCount)
00207 {
00208 ROS_DEBUG("%s: Contacts: %d, duration: %f, attached? %s", pluginName.c_str(), (int)contacts.size(), contactDuration+elapsedTime, attached ? "YES":"NO");
00209
00210 nonContactDuration = 0;
00211 contactDuration += elapsedTime;
00212
00213
00214
00215 if (!attached)
00216 {
00217
00218 std::map<std::string, physics::Collision*> cc;
00219 std::map<std::string, int> contactCounts;
00220
00221
00222 for (unsigned int i = 0; i < contacts.size(); ++i)
00223 {
00224 std::string name1 = contacts[i]->collision1->GetScopedName();
00225 std::string name2 = contacts[i]->collision2->GetScopedName();
00226
00227
00228 std::vector<std::string>::iterator citer = std::find(collisionNames.begin(), collisionNames.end(), name1);
00229 if (citer == collisionNames.end())
00230 {
00231 cc[name1] = contacts[i]->collision1;
00232 contactCounts[name1] += 1;
00233 }
00234
00235 citer = std::find(collisionNames.begin(), collisionNames.end(), name2);
00236 if (citer == collisionNames.end())
00237 {
00238 cc[name2] = contacts[i]->collision2;
00239 contactCounts[name2] += 1;
00240 }
00241 }
00242
00243
00244
00245 for(std::map<std::string, int>::iterator iter = contactCounts.begin(); iter != contactCounts.end(); ++iter)
00246 {
00247
00248 if (iter->second < minContactCount)
00249 continue;
00250
00251
00252 double relMotionRate;
00253
00254 math::Pose diff = cc[iter->first]->GetLink()->GetWorldPose() - modelPtr->GetLink(gripperAttachLink)->GetWorldPose();
00255 if (contactDuration <= elapsedTime)
00256 relMotionRate = 0.0;
00257 else
00258 relMotionRate = (diff - prevDiff).pos.GetSquaredLength() / elapsedTime;
00259
00260 prevDiff = diff;
00261
00262
00263 if (relMotionRate > maxRelativeMotionRate)
00264 {
00265 ROS_DEBUG("%s: gripper contact relative motion too great (%f).", pluginName.c_str(), relMotionRate);
00266 contactDuration = 0;
00267 }
00268 else if (contactDuration >= attachWait)
00269 {
00270 handleAttach(cc[iter->first]->GetLink());
00271 break;
00272 }
00273 }
00274 }
00275 }
00276 else
00277 {
00278 contactDuration = 0;
00279
00280 if (attached)
00281 {
00282 nonContactDuration += elapsedTime;
00283 if (nonContactDuration >= detachWait)
00284 handleDetach();
00285 }
00286 }
00287 }
00288
00289 void GazeboGripper::handleAttach(physics::LinkPtr linkPtr)
00290 {
00291 attached = true;
00292
00293 fixedJointPtr->Load(modelPtr->GetLink(gripperAttachLink), linkPtr, math::Pose(0, 0, 0, 0, 0, 0));
00294 fixedJointPtr->Init();
00295 fixedJointPtr->SetHighStop(0, 0);
00296 fixedJointPtr->SetLowStop(0, 0);
00297
00298 ROS_INFO("%s: Gripper attached", pluginName.c_str());
00299 }
00300
00301 void GazeboGripper::handleDetach()
00302 {
00303 attached = false;
00304 fixedJointPtr->Detach();
00305 ROS_INFO("%s: Gripper detached", pluginName.c_str());
00306 }
00307
00308 GZ_REGISTER_MODEL_PLUGIN(GazeboGripper)