$search
00001 /********************************************************************* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2008, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of the Willow Garage nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *********************************************************************/ 00034 00035 #include <gazebo/urdf2gazebo.h> 00036 #include "ros/ros.h" 00037 #include "ros/package.h" 00038 #include <fstream> 00039 #include <sstream> 00040 00041 using namespace urdf2gazebo; 00042 00043 URDF2Gazebo::URDF2Gazebo() 00044 { 00045 } 00046 00047 URDF2Gazebo::~URDF2Gazebo() 00048 { 00049 } 00050 00051 00052 std::string URDF2Gazebo::vector32str(const urdf::Vector3 vector, double (*conv)(double) = NULL) 00053 { 00054 std::stringstream ss; 00055 ss << (conv ? conv(vector.x) : vector.x); 00056 ss << " "; 00057 ss << (conv ? conv(vector.y) : vector.y); 00058 ss << " "; 00059 ss << (conv ? conv(vector.z) : vector.z); 00060 return ss.str(); 00061 } 00062 00063 std::string URDF2Gazebo::values2str(unsigned int count, const double *values, double (*conv)(double) = NULL) 00064 { 00065 std::stringstream ss; 00066 for (unsigned int i = 0 ; i < count ; i++) 00067 { 00068 if (i > 0) 00069 ss << " "; 00070 ss << (conv ? conv(values[i]) : values[i]); 00071 } 00072 return ss.str(); 00073 } 00074 00075 void URDF2Gazebo::setupTransform(btTransform &transform, urdf::Pose pose) 00076 { 00077 btMatrix3x3 mat; 00078 mat.setRotation(btQuaternion(pose.rotation.x,pose.rotation.y,pose.rotation.z,pose.rotation.w)); 00079 transform = btTransform(mat,btVector3(pose.position.x,pose.position.y,pose.position.z)); 00080 } 00081 00082 void URDF2Gazebo::setupTransform(urdf::Pose &pose, btTransform transform) 00083 { 00084 btVector3 pz = transform.getOrigin(); 00085 pose.position = urdf::Vector3(pz.x(), pz.y(), pz.z()); 00086 00087 btMatrix3x3 mat = transform.getBasis(); 00088 btQuaternion btq; 00089 mat.getRotation(btq); 00090 pose.rotation = urdf::Rotation(btq.x(),btq.y(),btq.z(),btq.w()); 00091 } 00092 00093 void URDF2Gazebo::addKeyValue(TiXmlElement *elem, const std::string& key, const std::string &value) 00094 { 00095 TiXmlElement* child_elem = elem->FirstChildElement(key); 00096 if (child_elem) 00097 { 00098 std::string old_value = getGazeboValue(child_elem); 00099 if (old_value != value) 00100 ROS_WARN("multiple inconsistent <%s> exists due to fixed joint reduction, overwriting previous value [%s] with [%s].",key.c_str(),old_value.c_str(),value.c_str()); 00101 else 00102 ROS_DEBUG("multiple <%s> exists due to fixed joint reduction, overwriting previous value.",key.c_str()); 00103 elem->RemoveChild(child_elem); // remove if one already exists 00104 } 00105 00106 TiXmlElement *ekey = new TiXmlElement(key); 00107 TiXmlText *text_ekey = new TiXmlText(value); 00108 ekey->LinkEndChild(text_ekey); 00109 elem->LinkEndChild(ekey); 00110 } 00111 00112 void URDF2Gazebo::addTransform(TiXmlElement *elem, const::btTransform& transform) 00113 { 00114 btVector3 pz = transform.getOrigin(); 00115 double cpos[3] = { pz.x(), pz.y(), pz.z() }; 00116 00117 btMatrix3x3 mat = transform.getBasis(); 00118 // mat.getRPY is broken, get back quaternion, use urdf::Rotation to get from quaternion to rpy 00119 btQuaternion btq; 00120 mat.getRotation(btq); 00121 urdf::Rotation q(btq.x(),btq.y(),btq.z(),btq.w()); 00122 00123 double crot[3]; 00124 q.getRPY(crot[0],crot[1],crot[2]); 00125 //mat.getEulerYPR(crot[2],crot[1],crot[0]); // equivalent to below // bug with gimbal lock 00126 //mat.getRPY(crot[0],crot[1],crot[2]); // bug with gimbal lock 00127 00128 /* set geometry transform */ 00129 addKeyValue(elem, "xyz", values2str(3, cpos)); 00130 addKeyValue(elem, "rpy", values2str(3, crot, rad2deg)); 00131 } 00132 00133 std::string URDF2Gazebo::getGazeboValue(TiXmlElement* elem) 00134 { 00135 std::string value_str; 00136 if (elem->Attribute("value")) 00137 { 00138 value_str = elem->Attribute("value"); 00139 } 00140 else if(elem->FirstChild()) // FIXME: comment out check for now, as ros and system tinyxml does not match. elem->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT 00141 { 00142 value_str = elem->FirstChild()->ValueStr(); 00143 } 00144 return value_str; 00145 } 00146 00147 void URDF2Gazebo::parseGazeboExtension(TiXmlDocument &urdf_in) 00148 { 00149 ROS_DEBUG("parsing gazebo extension"); 00150 TiXmlElement* robot_xml = urdf_in.FirstChildElement("robot"); 00151 00152 // Get all Gazebo extension elements, put everything in this->gazebo_extensions_ map, containing a key string (link/joint name) and values 00153 for (TiXmlElement* gazebo_xml = robot_xml->FirstChildElement("gazebo"); gazebo_xml; gazebo_xml = gazebo_xml->NextSiblingElement("gazebo")) 00154 { 00155 const char* ref = gazebo_xml->Attribute("reference"); 00156 std::string ref_str; 00157 if (!ref) 00158 { 00159 ROS_DEBUG("parsing gazebo extension for robot, reference is not specified"); 00160 // copy extensions for robot (outside of link/joint) 00161 ref_str.clear(); 00162 } 00163 else 00164 { 00165 ROS_DEBUG("parsing gazebo extension for %s",ref); 00166 // copy extensions for link/joint 00167 ref_str = std::string(ref); 00168 } 00169 00170 if (this->gazebo_extensions_.find(ref_str) == this->gazebo_extensions_.end()) 00171 { 00172 std::vector<GazeboExtension*> extensions; 00173 ROS_DEBUG("extension map for reference [%s] does not exist yet, creating new extension map",ref); 00174 this->gazebo_extensions_.insert(std::make_pair( ref_str, extensions ) ); 00175 } 00176 00177 // create and insert a new GazeboExtension into the map 00178 GazeboExtension* gazebo = new GazeboExtension(); 00179 00180 00181 // begin parsing xml node 00182 for (TiXmlElement *child_elem = gazebo_xml->FirstChildElement(); child_elem; child_elem = child_elem->NextSiblingElement()) 00183 { 00184 ROS_DEBUG("child element : %s ", child_elem->ValueStr().c_str()); 00185 00186 gazebo->original_reference = ref_str; 00187 00188 // go through all elements of the extension, extract what we know, and save the rest in blobs 00189 00190 // material 00191 if (child_elem->ValueStr() == "material") 00192 { 00193 gazebo->material = getGazeboValue(child_elem); 00194 ROS_DEBUG(" material %s",gazebo->material.c_str()); 00195 } 00196 else if (child_elem->ValueStr() == "static") 00197 { 00198 std::string value_str = getGazeboValue(child_elem); 00199 00200 // default of setting static flag is false 00201 if (value_str == "true" || value_str == "True" || value_str == "TRUE" || value_str == "yes" || value_str == "1") 00202 gazebo->setStaticFlag = true; 00203 else 00204 gazebo->setStaticFlag = false; 00205 00206 ROS_DEBUG(" setStaticFlag %d",gazebo->setStaticFlag); 00207 00208 } 00209 else if (child_elem->ValueStr() == "turnGravityOff") 00210 { 00211 std::string value_str = getGazeboValue(child_elem); 00212 00213 // default of turnGravityOff is false 00214 if (value_str == "true" || value_str == "True" || value_str == "TRUE" || value_str == "yes" || value_str == "1") 00215 gazebo->turnGravityOff = true; 00216 else 00217 gazebo->turnGravityOff = false; 00218 00219 ROS_DEBUG(" turnGravityOff %d",gazebo->turnGravityOff); 00220 00221 } 00222 else if (child_elem->ValueStr() == "dampingFactor") 00223 { 00224 gazebo->is_dampingFactor = true; 00225 gazebo->dampingFactor = atof(getGazeboValue(child_elem).c_str()); 00226 ROS_DEBUG(" dampingFactor %f",gazebo->dampingFactor); 00227 } 00228 else if (child_elem->ValueStr() == "maxVel") 00229 { 00230 gazebo->is_maxVel = true; 00231 gazebo->maxVel = atof(getGazeboValue(child_elem).c_str()); 00232 ROS_DEBUG(" maxVel %f",gazebo->maxVel); 00233 } 00234 else if (child_elem->ValueStr() == "minDepth") 00235 { 00236 gazebo->is_minDepth = true; 00237 gazebo->minDepth = atof(getGazeboValue(child_elem).c_str()); 00238 ROS_DEBUG(" minDepth %f",gazebo->minDepth); 00239 } 00240 else if (child_elem->ValueStr() == "mu1") 00241 { 00242 gazebo->is_mu1 = true; 00243 gazebo->mu1 = atof(getGazeboValue(child_elem).c_str()); 00244 ROS_DEBUG(" mu1 %f",gazebo->mu1); 00245 } 00246 else if (child_elem->ValueStr() == "mu2") 00247 { 00248 gazebo->is_mu2 = true; 00249 gazebo->mu2 = atof(getGazeboValue(child_elem).c_str()); 00250 ROS_DEBUG(" mu2 %f",gazebo->mu2); 00251 } 00252 else if (child_elem->ValueStr() == "fdir1") 00253 { 00254 gazebo->fdir1 = getGazeboValue(child_elem); 00255 ROS_DEBUG(" fdir1 %s",gazebo->fdir1.c_str()); 00256 } 00257 else if (child_elem->ValueStr() == "kp") 00258 { 00259 gazebo->is_kp = true; 00260 gazebo->kp = atof(getGazeboValue(child_elem).c_str()); 00261 ROS_DEBUG(" kp %f",gazebo->kp); 00262 } 00263 else if (child_elem->ValueStr() == "kd") 00264 { 00265 gazebo->is_kd = true; 00266 gazebo->kd = atof(getGazeboValue(child_elem).c_str()); 00267 ROS_DEBUG(" kd %f",gazebo->kd); 00268 } 00269 else if (child_elem->ValueStr() == "genTexCoord") 00270 { 00271 std::string value_str = getGazeboValue(child_elem); 00272 00273 // default of genTexCoord is false 00274 if (value_str == "true" || value_str == "True" || value_str == "TRUE" || value_str == "yes" || value_str == "1") 00275 gazebo->genTexCoord = true; 00276 else 00277 gazebo->genTexCoord = false; 00278 00279 ROS_DEBUG(" genTexCoord %d",gazebo->genTexCoord); 00280 00281 } 00282 else if (child_elem->ValueStr() == "selfCollide") 00283 { 00284 std::string value_str = getGazeboValue(child_elem); 00285 00286 // default of selfCollide is false 00287 if (value_str == "true" || value_str == "True" || value_str == "TRUE" || value_str == "yes" || value_str == "1") 00288 gazebo->selfCollide = true; 00289 else 00290 gazebo->selfCollide = false; 00291 00292 ROS_DEBUG(" selfCollide %d",gazebo->selfCollide); 00293 00294 } 00295 else if (child_elem->ValueStr() == "laserRetro") 00296 { 00297 gazebo->is_laserRetro = true; 00298 gazebo->laserRetro = atof(getGazeboValue(child_elem).c_str()); 00299 ROS_DEBUG(" laserRetro %f",gazebo->laserRetro); 00300 } 00301 else if (child_elem->ValueStr() == "stopKp") 00302 { 00303 gazebo->is_stopKp = true; 00304 gazebo->stopKp = atof(getGazeboValue(child_elem).c_str()); 00305 ROS_DEBUG(" stopKp %f",gazebo->stopKp); 00306 } 00307 else if (child_elem->ValueStr() == "stopKd") 00308 { 00309 gazebo->is_stopKd = true; 00310 gazebo->stopKd = atof(getGazeboValue(child_elem).c_str()); 00311 ROS_DEBUG(" stopKd %f",gazebo->stopKd); 00312 } 00313 else if (child_elem->ValueStr() == "initial_joint_position") 00314 { 00315 gazebo->is_initial_joint_position = true; 00316 gazebo->initial_joint_position = atof(getGazeboValue(child_elem).c_str()); 00317 ROS_DEBUG(" initial_joint_position %f",gazebo->initial_joint_position); 00318 } 00319 else if (child_elem->ValueStr() == "fudgeFactor") 00320 { 00321 gazebo->is_fudgeFactor = true; 00322 gazebo->fudgeFactor = atof(getGazeboValue(child_elem).c_str()); 00323 ROS_DEBUG(" fudgeFactor %f",gazebo->fudgeFactor); 00324 } 00325 else if (child_elem->ValueStr() == "provideFeedback") 00326 { 00327 std::string value_str = getGazeboValue(child_elem); 00328 00329 if (value_str == "true" || value_str == "True" || value_str == "TRUE" || value_str == "yes" || value_str == "1") 00330 gazebo->provideFeedback = true; 00331 else 00332 gazebo->provideFeedback = false; 00333 00334 ROS_DEBUG(" provideFeedback %d",(int)gazebo->provideFeedback); 00335 } 00336 else 00337 { 00338 std::ostringstream stream; 00339 stream << *child_elem; 00340 // save all unknown stuff in a vector of blobs 00341 TiXmlElement *blob = new TiXmlElement(*child_elem); 00342 gazebo->blobs.push_back(blob); 00343 ROS_DEBUG(" blobs %s",stream.str().c_str()); 00344 } 00345 } 00346 00347 // insert into my map 00348 (this->gazebo_extensions_.find(ref_str))->second.push_back(gazebo); 00349 } 00350 } 00351 00352 void URDF2Gazebo::insertGazeboExtensionGeom(TiXmlElement *elem,std::string link_name) 00353 { 00354 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00355 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00356 { 00357 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00358 { 00359 if ((*ge)->original_reference == link_name) 00360 { 00361 // insert mu1, mu2, kp, kd for geom 00362 if ((*ge)->is_mu1) 00363 addKeyValue(elem, "mu1", values2str(1, &(*ge)->mu1) ); 00364 if ((*ge)->is_mu2) 00365 addKeyValue(elem, "mu2", values2str(1, &(*ge)->mu2) ); 00366 if (!(*ge)->fdir1.empty()) 00367 addKeyValue(elem, "fdir1", (*ge)->fdir1); 00368 if ((*ge)->is_kp) 00369 addKeyValue(elem, "kp", values2str(1, &(*ge)->kp) ); 00370 if ((*ge)->is_kd) 00371 addKeyValue(elem, "kd", values2str(1, &(*ge)->kd) ); 00372 if ((*ge)->genTexCoord) 00373 addKeyValue(elem, "genTexCoord", "true"); 00374 else 00375 addKeyValue(elem, "genTexCoord", "false"); 00376 if ((*ge)->is_laserRetro) 00377 addKeyValue(elem, "laserRetro", values2str(1, &(*ge)->laserRetro) ); 00378 } 00379 } 00380 } 00381 } 00382 00383 void URDF2Gazebo::insertGazeboExtensionVisual(TiXmlElement *elem,std::string link_name) 00384 { 00385 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00386 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00387 { 00388 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00389 { 00390 if ((*ge)->original_reference == link_name) 00391 { 00392 // insert material block 00393 if (!(*ge)->material.empty()) 00394 addKeyValue(elem, "material", (*ge)->material); 00395 } 00396 } 00397 } 00398 } 00399 00400 void URDF2Gazebo::insertGazeboExtensionBody(TiXmlElement *elem,std::string link_name) 00401 { 00402 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00403 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00404 { 00405 if (gazebo_it->first == link_name) 00406 { 00407 ROS_DEBUG("body: reference %s link name %s",gazebo_it->first.c_str(),link_name.c_str()); 00408 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00409 { 00410 // insert turnGravityOff 00411 if ((*ge)->turnGravityOff) 00412 addKeyValue(elem, "turnGravityOff", "true"); 00413 else 00414 addKeyValue(elem, "turnGravityOff", "false"); 00415 00416 // damping factor 00417 if ((*ge)->is_dampingFactor) 00418 addKeyValue(elem, "dampingFactor", values2str(1, &(*ge)->dampingFactor) ); 00419 // max contact interpenetration correction velocity 00420 if ((*ge)->is_maxVel) 00421 addKeyValue(elem, "maxVel", values2str(1, &(*ge)->maxVel) ); 00422 // contact interpenetration margin tolerance 00423 if ((*ge)->is_minDepth) 00424 addKeyValue(elem, "minDepth", values2str(1, &(*ge)->minDepth) ); 00425 // selfCollide tag 00426 if ((*ge)->selfCollide) 00427 addKeyValue(elem, "selfCollide", "true"); 00428 else 00429 addKeyValue(elem, "selfCollide", "false"); 00430 // insert blobs into body 00431 for (std::vector<TiXmlElement*>::iterator blob_it = (*ge)->blobs.begin(); 00432 blob_it != (*ge)->blobs.end(); blob_it++) 00433 { 00434 elem->LinkEndChild((*blob_it)->Clone()); 00435 } 00436 } 00437 } 00438 } 00439 } 00440 void URDF2Gazebo::insertGazeboExtensionJoint(TiXmlElement *elem,std::string joint_name) 00441 { 00442 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00443 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00444 { 00445 if (gazebo_it->first == joint_name) 00446 { 00447 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00448 { 00449 ROS_DEBUG("geom: reference %s joint name %s, stopKp %f",gazebo_it->first.c_str(),joint_name.c_str(),(*ge)->stopKp); 00450 // insert stopKp, stopKd, fudgeFactor 00451 if ((*ge)->is_stopKp) 00452 addKeyValue(elem, "stopKp", values2str(1, &(*ge)->stopKp) ); 00453 if ((*ge)->is_stopKd) 00454 addKeyValue(elem, "stopKd", values2str(1, &(*ge)->stopKd) ); 00455 if ((*ge)->is_initial_joint_position) 00456 addKeyValue(elem, "initial_joint_position", values2str(1, &(*ge)->initial_joint_position) ); 00457 if ((*ge)->is_fudgeFactor) 00458 addKeyValue(elem, "fudgeFactor", values2str(1, &(*ge)->fudgeFactor) ); 00459 00460 // insert provideFeedback 00461 if ((*ge)->provideFeedback) 00462 addKeyValue(elem, "provideFeedback", "true"); 00463 else 00464 addKeyValue(elem, "provideFeedback", "false"); 00465 } 00466 } 00467 } 00468 } 00469 void URDF2Gazebo::insertGazeboExtensionRobot(TiXmlElement *elem) 00470 { 00471 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00472 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00473 { 00474 if (gazebo_it->first.empty()) // no reference 00475 { 00476 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00477 { 00478 // insert static flag 00479 if ((*ge)->setStaticFlag) 00480 addKeyValue(elem, "static", "true"); 00481 else 00482 addKeyValue(elem, "static", "false"); 00483 // insert blobs into robot 00484 for (std::vector<TiXmlElement*>::iterator blob_it = (*ge)->blobs.begin(); 00485 blob_it != (*ge)->blobs.end(); blob_it++) 00486 { 00487 std::ostringstream stream_in; 00488 stream_in << *(*blob_it); 00489 ROS_DEBUG("robot: reference empty, blobs for robot\n%s",stream_in.str().c_str()); 00490 elem->LinkEndChild((*blob_it)->Clone()); 00491 } 00492 } 00493 } 00494 } 00495 } 00496 00497 std::string URDF2Gazebo::getGeometrySize(boost::shared_ptr<urdf::Geometry> geometry, int *sizeCount, double *sizeVals) 00498 { 00499 std::string type("empty"); 00500 00501 switch (geometry->type) 00502 { 00503 case urdf::Geometry::BOX: 00504 type = "box"; 00505 *sizeCount = 3; 00506 { 00507 boost::shared_ptr<const urdf::Box> box; 00508 box = boost::dynamic_pointer_cast< const urdf::Box >(geometry); 00509 sizeVals[0] = box->dim.x; 00510 sizeVals[1] = box->dim.y; 00511 sizeVals[2] = box->dim.z; 00512 } 00513 break; 00514 case urdf::Geometry::CYLINDER: 00515 type = "cylinder"; 00516 *sizeCount = 2; 00517 { 00518 boost::shared_ptr<const urdf::Cylinder> cylinder; 00519 cylinder = boost::dynamic_pointer_cast<const urdf::Cylinder >(geometry); 00520 sizeVals[0] = cylinder->radius; 00521 sizeVals[1] = cylinder->length; 00522 } 00523 break; 00524 case urdf::Geometry::SPHERE: 00525 type = "sphere"; 00526 *sizeCount = 1; 00527 { 00528 boost::shared_ptr<const urdf::Sphere> sphere; 00529 sphere = boost::dynamic_pointer_cast<const urdf::Sphere >(geometry); 00530 sizeVals[0] = sphere->radius; 00531 } 00532 break; 00533 case urdf::Geometry::MESH: 00534 type = "trimesh"; 00535 *sizeCount = 3; 00536 { 00537 boost::shared_ptr<const urdf::Mesh> mesh; 00538 mesh = boost::dynamic_pointer_cast<const urdf::Mesh >(geometry); 00539 sizeVals[0] = mesh->scale.x; 00540 sizeVals[1] = mesh->scale.y; 00541 sizeVals[2] = mesh->scale.z; 00542 } 00543 break; 00544 default: 00545 *sizeCount = 0; 00546 printf("Unknown body type: %d in geometry\n", geometry->type); 00547 break; 00548 } 00549 00550 return type; 00551 } 00552 00553 std::string URDF2Gazebo::getGeometryBoundingBox(boost::shared_ptr<urdf::Geometry> geometry, double *sizeVals) 00554 { 00555 std::string type; 00556 00557 switch (geometry->type) 00558 { 00559 case urdf::Geometry::BOX: 00560 type = "box"; 00561 { 00562 boost::shared_ptr<const urdf::Box> box; 00563 box = boost::dynamic_pointer_cast<const urdf::Box >(geometry); 00564 sizeVals[0] = box->dim.x; 00565 sizeVals[1] = box->dim.y; 00566 sizeVals[2] = box->dim.z; 00567 } 00568 break; 00569 case urdf::Geometry::CYLINDER: 00570 type = "cylinder"; 00571 { 00572 boost::shared_ptr<const urdf::Cylinder> cylinder; 00573 cylinder = boost::dynamic_pointer_cast<const urdf::Cylinder >(geometry); 00574 sizeVals[0] = cylinder->radius * 2; 00575 sizeVals[1] = cylinder->radius * 2; 00576 sizeVals[2] = cylinder->length; 00577 } 00578 break; 00579 case urdf::Geometry::SPHERE: 00580 type = "sphere"; 00581 { 00582 boost::shared_ptr<const urdf::Sphere> sphere; 00583 sphere = boost::dynamic_pointer_cast<const urdf::Sphere >(geometry); 00584 sizeVals[0] = sizeVals[1] = sizeVals[2] = sphere->radius; 00585 } 00586 break; 00587 case urdf::Geometry::MESH: 00588 type = "trimesh"; 00589 { 00590 boost::shared_ptr<const urdf::Mesh> mesh; 00591 mesh = boost::dynamic_pointer_cast<const urdf::Mesh >(geometry); 00592 sizeVals[0] = mesh->scale.x; 00593 sizeVals[1] = mesh->scale.y; 00594 sizeVals[2] = mesh->scale.z; 00595 } 00596 break; 00597 default: 00598 sizeVals[0] = sizeVals[1] = sizeVals[2] = 0; 00599 printf("Unknown body type: %d in geometry\n", geometry->type); 00600 break; 00601 } 00602 00603 return type; 00604 } 00605 00606 void URDF2Gazebo::printMass(std::string link_name, dMass mass) 00607 { 00608 ROS_DEBUG("LINK NAME: [%s] from dMass",link_name.c_str()); 00609 ROS_DEBUG(" MASS: [%f]",mass.mass); 00610 ROS_DEBUG(" CG: [%f %f %f]",mass.c[0],mass.c[1],mass.c[2]); 00611 ROS_DEBUG(" I: [%f %f %f]",mass.I[0],mass.I[1],mass.I[2]); 00612 ROS_DEBUG(" [%f %f %f]",mass.I[4],mass.I[5],mass.I[6]); 00613 ROS_DEBUG(" [%f %f %f]",mass.I[8],mass.I[9],mass.I[10]); 00614 } 00615 00616 void URDF2Gazebo::printMass(boost::shared_ptr<urdf::Link> link) 00617 { 00618 ROS_DEBUG("LINK NAME: [%s] from urdf::Link",link->name.c_str()); 00619 ROS_DEBUG(" MASS: [%f]",link->inertial->mass); 00620 ROS_DEBUG(" CG: [%f %f %f]",link->inertial->origin.position.x,link->inertial->origin.position.y,link->inertial->origin.position.z); 00621 ROS_DEBUG(" I: [%f %f %f]",link->inertial->ixx,link->inertial->ixy,link->inertial->ixz); 00622 ROS_DEBUG(" [%f %f %f]",link->inertial->ixy,link->inertial->iyy,link->inertial->iyz); 00623 ROS_DEBUG(" [%f %f %f]",link->inertial->ixz,link->inertial->iyz,link->inertial->izz); 00624 } 00625 00626 00627 #ifdef ROBOT_MODEL_MULTI_VISUAL_COLLISION 00628 void URDF2Gazebo::reduceFixedJoints(TiXmlElement *root, boost::shared_ptr<urdf::Link> link) 00629 { 00630 00631 ROS_DEBUG("TREE: at [%s]",link->name.c_str()); 00632 00633 // if child is attached to self by fixed link first go up the tree, check it's children recursively 00634 for (unsigned int i = 0 ; i < link->child_links.size() ; ++i) 00635 if (link->child_links[i]->parent_joint->type == urdf::Joint::FIXED) 00636 reduceFixedJoints(root, link->child_links[i]); 00637 00638 // reduce this link's stuff up the tree to parent but skip first joint if it's the world 00639 if (link->getParent() && link->getParent()->name != "world" && link->parent_joint && link->parent_joint->type == urdf::Joint::FIXED) 00640 { 00641 ROS_DEBUG("TREE: extension lumping from [%s] to [%s]",link->name.c_str(),link->getParent()->name.c_str()); 00642 00643 // lump gazebo extensions to parent, (give them new reference link names) 00644 reduceGazeboExtensionToParent(link); 00645 00646 ROS_DEBUG("TREE: mass lumping from [%s] to [%s]",link->name.c_str(),link->getParent()->name.c_str()); 00647 /* now lump all contents of this link to parent */ 00648 if (link->inertial) 00649 { 00650 // get parent mass (in parent link frame) 00651 dMass parent_mass; 00652 dMassSetParameters(&parent_mass, link->getParent()->inertial->mass, 00653 link->getParent()->inertial->origin.position.x, link->getParent()->inertial->origin.position.y, link->getParent()->inertial->origin.position.z, 00654 link->getParent()->inertial->ixx, link->getParent()->inertial->iyy, link->getParent()->inertial->izz, 00655 link->getParent()->inertial->ixy, link->getParent()->inertial->ixz, link->getParent()->inertial->iyz); 00656 printMass(link->getParent()->name,parent_mass); 00657 printMass(link->getParent()); 00658 // set link mass (in link frame) 00659 dMass link_mass; 00660 dMassSetParameters(&link_mass, link->inertial->mass, 00661 link->inertial->origin.position.x, link->inertial->origin.position.y, link->inertial->origin.position.z, 00662 link->inertial->ixx, link->inertial->iyy, link->inertial->izz, 00663 link->inertial->ixy, link->inertial->ixz, link->inertial->iyz); 00664 printMass(link->name,link_mass); 00665 printMass(link); 00666 // un-rotate link mass into parent link frame 00667 dMatrix3 R; 00668 double phi, theta, psi; 00669 ROS_DEBUG("debug: %f %f %f",phi,theta,psi); 00670 link->parent_joint->parent_to_joint_origin_transform.rotation.getRPY(phi,theta,psi); 00671 dRFromEulerAngles(R, phi, theta, psi); 00672 dMassRotate(&link_mass, R); 00673 printMass(link->name,link_mass); 00674 // un-translate link mass into parent link frame 00675 dMassTranslate(&link_mass, link->parent_joint->parent_to_joint_origin_transform.position.x 00676 , link->parent_joint->parent_to_joint_origin_transform.position.y 00677 , link->parent_joint->parent_to_joint_origin_transform.position.z); 00678 printMass(link->name,link_mass); 00679 // now link_mass is in the parent frame, add link_mass to parent_mass 00680 dMassAdd(&parent_mass,&link_mass); // now parent_mass contains link_mass in parent frame 00681 printMass(link->getParent()->name,parent_mass); 00682 // update parent mass 00683 link->getParent()->inertial->mass = parent_mass.mass; 00684 link->getParent()->inertial->ixx = parent_mass.I[0+4*0]; 00685 link->getParent()->inertial->iyy = parent_mass.I[1+4*1]; 00686 link->getParent()->inertial->izz = parent_mass.I[2+4*2]; 00687 link->getParent()->inertial->ixy = parent_mass.I[0+4*1]; 00688 link->getParent()->inertial->ixz = parent_mass.I[0+4*2]; 00689 link->getParent()->inertial->iyz = parent_mass.I[1+4*2]; 00690 link->getParent()->inertial->origin.position.x = parent_mass.c[0]; 00691 link->getParent()->inertial->origin.position.y = parent_mass.c[1]; 00692 link->getParent()->inertial->origin.position.z = parent_mass.c[2]; 00693 printMass(link->getParent()); 00694 } 00695 00696 // lump visual to parent 00697 // lump all visual to parent, assign group name "lump::"+group name+"::'+link name 00698 // lump but keep the link name in(/as) the group name, so we can correlate visuals to visuals somehow. 00699 for (std::map<std::string, boost::shared_ptr<std::vector<boost::shared_ptr<urdf::Visual> > > >::iterator visuals_it = link->visual_groups.begin(); 00700 visuals_it != link->visual_groups.end(); visuals_it++) 00701 { 00702 // if it's a "default" mesh, it should be added under "lump:"+link name 00703 if (visuals_it->first == "default") 00704 { 00705 std::string lump_group_name = std::string("lump::")+link->name; 00706 ROS_DEBUG("adding modified lump group name [%s] to link [%s]",lump_group_name.c_str(),link->getParent()->name.c_str()); 00707 for (std::vector<boost::shared_ptr<urdf::Visual> >::iterator visual_it = visuals_it->second->begin(); visual_it != visuals_it->second->end(); visual_it++) 00708 { 00709 // transform visual origin from link frame to parent link frame before adding to parent 00710 (*visual_it)->origin = transformToParentFrame((*visual_it)->origin, link->parent_joint->parent_to_joint_origin_transform); 00711 // add the modified visual to parent 00712 link->getParent()->addVisual(lump_group_name,*visual_it); 00713 } 00714 } 00715 else if (visuals_it->first.find(std::string("lump::")) == 0) // starts with "lump::" 00716 { 00717 // if it's a previously lumped mesh, relump under same group_name 00718 std::string lump_group_name = visuals_it->first; 00719 ROS_DEBUG("re-lumping group name [%s] to link [%s]",lump_group_name.c_str(),link->getParent()->name.c_str()); 00720 for (std::vector<boost::shared_ptr<urdf::Visual> >::iterator visual_it = visuals_it->second->begin(); visual_it != visuals_it->second->end(); visual_it++) 00721 { 00722 // transform visual origin from link frame to parent link frame before adding to parent 00723 (*visual_it)->origin = transformToParentFrame((*visual_it)->origin, link->parent_joint->parent_to_joint_origin_transform); 00724 // add the modified visual to parent 00725 link->getParent()->addVisual(lump_group_name,*visual_it); 00726 } 00727 } 00728 } 00729 00730 // lump collision parent 00731 // lump all collision to parent, assign group name "lump::"+group name+"::'+link name 00732 // lump but keep the link name in(/as) the group name, so we can correlate visuals to collisions somehow. 00733 for (std::map<std::string, boost::shared_ptr<std::vector<boost::shared_ptr<urdf::Collision> > > >::iterator collisions_it = link->collision_groups.begin(); 00734 collisions_it != link->collision_groups.end(); collisions_it++) 00735 { 00736 // if it's a "default" mesh, it should be added under "lump:"+link name 00737 if (collisions_it->first == "default") 00738 { 00739 std::string lump_group_name = std::string("lump::")+link->name; 00740 ROS_DEBUG("adding modified lump group name [%s] to link [%s]",lump_group_name.c_str(),link->getParent()->name.c_str()); 00741 for (std::vector<boost::shared_ptr<urdf::Collision> >::iterator collision_it = collisions_it->second->begin(); collision_it != collisions_it->second->end(); collision_it++) 00742 { 00743 // transform collision origin from link frame to parent link frame before adding to parent 00744 (*collision_it)->origin = transformToParentFrame((*collision_it)->origin, link->parent_joint->parent_to_joint_origin_transform); 00745 // add the modified collision to parent 00746 link->getParent()->addCollision(lump_group_name,*collision_it); 00747 } 00748 } 00749 else if (collisions_it->first.find(std::string("lump::")) == 0) // starts with "lump::" 00750 { 00751 // if it's a previously lumped mesh, relump under same group_name 00752 std::string lump_group_name = collisions_it->first; 00753 ROS_DEBUG("re-lumping group name [%s] to link [%s]",lump_group_name.c_str(),link->getParent()->name.c_str()); 00754 for (std::vector<boost::shared_ptr<urdf::Collision> >::iterator collision_it = collisions_it->second->begin(); collision_it != collisions_it->second->end(); collision_it++) 00755 { 00756 // transform collision origin from link frame to parent link frame before adding to parent 00757 (*collision_it)->origin = transformToParentFrame((*collision_it)->origin, link->parent_joint->parent_to_joint_origin_transform); 00758 // add the modified collision to parent 00759 link->getParent()->addCollision(lump_group_name,*collision_it); 00760 } 00761 } 00762 } 00763 printCollisionGroups(link->getParent()); 00764 00765 // STRATEGY: later when extracting visuals and collision pairs to construct <geom> for gazebo, given that geom(coillision) wraps visual, 00766 // loop through lumped collisions, for each collision, 00767 // call createGeom() using visual_groups.find(lump group name) to find potential visuals to create the <geom> tag for the body. 00768 // This way, <geom> is created only if collision exists in first place, and if matching visual exists it is used, other a sphere default 00769 // is created 00770 00771 00772 ROS_DEBUG("BEGIN JOINT LUMPING"); 00773 // set child link's parent_joint's parent link to a parent link up stream that does not have a fixed parent_joint 00774 for (unsigned int i = 0 ; i < link->child_links.size() ; ++i) { 00775 boost::shared_ptr<urdf::Joint> parent_joint = link->child_links[i]->parent_joint; 00776 if (parent_joint->type != urdf::Joint::FIXED) { 00777 // go down the tree until we hit a parent joint that is not fixed 00778 boost::shared_ptr<urdf::Link> new_parent_link = link; 00779 btTransform joint_anchor_transform; // set to identity first 00780 while(new_parent_link->parent_joint && new_parent_link->parent_joint->type == urdf::Joint::FIXED) { 00781 ROS_DEBUG(" ...JOINT: searching: at [%s] checking if parent [%s] is attachable",new_parent_link->name.c_str(),new_parent_link->getParent()->name.c_str()); 00782 joint_anchor_transform *= joint_anchor_transform; 00783 parent_joint->parent_to_joint_origin_transform = transformToParentFrame(parent_joint->parent_to_joint_origin_transform, 00784 new_parent_link->parent_joint->parent_to_joint_origin_transform); 00785 new_parent_link = new_parent_link->getParent(); 00786 } 00787 // now set the link->child_links[i]->parent_joint's parent link to the new_parent_link 00788 link->child_links[i]->setParent(new_parent_link); 00789 parent_joint->parent_link_name = new_parent_link->name; 00790 ROS_DEBUG(" JOINT: reparenting for link %s joint %s from %s to %s",link->child_links[i]->name.c_str(),link->child_links[i]->parent_joint->name.c_str(),link->name.c_str(),new_parent_link->name.c_str()); 00791 // and set the link->child_links[i]->parent_joint's parent_to_joint_orogin_transform as the aggregated 00792 // anchor transform? 00793 } 00794 } 00795 } 00796 00797 // continue down the tree for non-fixed joints 00798 for (unsigned int i = 0 ; i < link->child_links.size() ; ++i) 00799 if (link->child_links[i]->parent_joint->type != urdf::Joint::FIXED) 00800 reduceFixedJoints(root, link->child_links[i]); 00801 } 00802 00803 void URDF2Gazebo::printCollisionGroups(boost::shared_ptr<urdf::Link> link) 00804 { 00805 ROS_DEBUG("COLLISION LUMPING: link: [%s] contains [%d] collisions",link->name.c_str(),(int)link->collision_groups.size()); 00806 for (std::map<std::string, boost::shared_ptr<std::vector<boost::shared_ptr<urdf::Collision> > > >::iterator cols_it = link->collision_groups.begin(); 00807 cols_it != link->collision_groups.end(); cols_it++) 00808 { 00809 ROS_DEBUG(" collision_groups: [%s] has [%d] Collision objects",cols_it->first.c_str(),(int)cols_it->second->size()); 00810 //for (std::vector<boost::shared_ptr<urdf::Collision> >::iterator collision_it = cols_it->second->begin(); collision_it != cols_it->second->end(); collision_it++) 00811 // ROS_DEBUG(" origins for debugging: [%s]",...cols_it->first.c_str()); 00812 } 00813 } 00814 #endif 00815 00817 urdf::Pose URDF2Gazebo::transformToParentFrame(urdf::Pose transform_in_link_frame, urdf::Pose parent_to_link_transform) 00818 { 00819 urdf::Pose transform_in_parent_link_frame; 00820 #ifdef ROBOT_MODEL_MULTI_VISUAL_COLLISION 00821 // in the new revision, urdf::Pose has some transform operator overrides 00822 // rotate link pose to parent_link frame 00823 transform_in_parent_link_frame.position = parent_to_link_transform.rotation * transform_in_link_frame.position; 00824 transform_in_parent_link_frame.rotation = parent_to_link_transform.rotation * transform_in_link_frame.rotation; 00825 // translate link to parent_link frame 00826 transform_in_parent_link_frame.position = parent_to_link_transform.position + transform_in_parent_link_frame.position; 00827 #else 00828 // copy transforms to btTransform 00829 btTransform bt_transform_in_link_frame; 00830 setupTransform(bt_transform_in_link_frame, transform_in_link_frame); 00831 btTransform bt_parent_to_link_transform; 00832 setupTransform(bt_parent_to_link_transform, parent_to_link_transform); 00833 00834 // rotate link pose to parent_link frame 00835 btVector3 bt_transform_in_parent_link_frame_pos = bt_parent_to_link_transform.getBasis() * bt_transform_in_link_frame.getOrigin(); 00836 btMatrix3x3 bt_transform_in_parent_link_frame_rot = bt_parent_to_link_transform.getBasis() * bt_transform_in_link_frame.getBasis(); 00837 // translate link to parent_link frame 00838 bt_transform_in_parent_link_frame_pos = bt_parent_to_link_transform.getOrigin() + bt_transform_in_parent_link_frame_pos; 00839 btTransform bt_transform_in_parent_link_frame = btTransform(bt_transform_in_parent_link_frame_rot, bt_transform_in_parent_link_frame_pos); 00840 00841 // copy transform back to urdf::Pose 00842 setupTransform(transform_in_parent_link_frame, bt_transform_in_parent_link_frame); 00843 #endif 00844 return transform_in_parent_link_frame; 00845 } 00846 00847 void URDF2Gazebo::reduceGazeboExtensionToParent(boost::shared_ptr<urdf::Link> link) 00848 { 00849 std::string link_name = link->name; 00850 std::string new_link_name = link->getParent()->name; 00851 00852 ROS_DEBUG(" EXTENSION: Reference lumping from [%s] to [%s]",link_name.c_str(), new_link_name.c_str()); 00853 00854 // update extension map with references to link_name 00855 listGazeboExtensions(); 00856 00857 std::map<std::string,std::vector<GazeboExtension*> >::iterator ext = this->gazebo_extensions_.find(link_name); 00858 if (ext != this->gazebo_extensions_.end()) 00859 { 00860 00861 // update reduction transform (for rays, cameras for now). FIXME: contact frames too? 00862 for (std::vector<GazeboExtension*>::iterator ge = ext->second.begin(); ge != ext->second.end(); ge++) 00863 (*ge)->reduction_transform = transformToParentFrame((*ge)->reduction_transform, link->parent_joint->parent_to_joint_origin_transform); 00864 00865 // FIXME: if the sensor block has sensor:ray or sensor:camera or sensor:stereo_camera, look for/replace/insert reduction transform into xml block 00866 for (std::vector<GazeboExtension*>::iterator ge = ext->second.begin(); ge != ext->second.end(); ge++) 00867 updateGazeboExtensionBlobsReductionTransform((*ge)); 00868 00869 // replace all instances of the link_name string in blobs with new_link_name 00870 for (std::vector<GazeboExtension*>::iterator ge = ext->second.begin(); ge != ext->second.end(); ge++) 00871 updateGazeboExtensionFrameReplace((*ge)->blobs, link_name, new_link_name); 00872 00873 00874 // find existing extension with the new link reference 00875 std::map<std::string,std::vector<GazeboExtension*> >::iterator new_ext = this->gazebo_extensions_.find(new_link_name); 00876 // create new_extension if none exists 00877 if (new_ext == this->gazebo_extensions_.end()) 00878 { 00879 std::vector<GazeboExtension*> extensions; 00880 this->gazebo_extensions_.insert(std::make_pair( new_link_name, extensions ) ); 00881 new_ext = this->gazebo_extensions_.find(new_link_name); 00882 } 00883 00884 // pop extensions from link's vector and push them into the new link's vector 00885 for (std::vector<GazeboExtension*>::iterator ge = ext->second.begin(); ge != ext->second.end(); ge++) 00886 { 00887 new_ext->second.push_back(*ge); 00888 } 00889 ext->second.clear(); 00890 } 00891 00892 listGazeboExtensions(); 00893 00894 // for empty extensions, search and replace link name patterns with new link name 00895 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); 00896 gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 00897 if (gazebo_it->first.empty()) 00898 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 00899 updateGazeboExtensionFrameReplace((*ge)->blobs, link_name, new_link_name); 00900 00901 listGazeboExtensions(); 00902 } 00903 00904 void URDF2Gazebo::updateGazeboExtensionFrameReplace(std::vector<TiXmlElement*> &blobs, std::string link_name, std::string new_link_name) 00905 { 00906 // HACK: need to do this more generally, but we also need to replace all instances of link name with new link name 00907 // e.g. contact sensor refers to <geom>base_link_geom</geom> and it needs to be reparented to <geom>base_footprint_geom</geom> 00908 ROS_DEBUG(" STRING REPLACE: instances of link name [%s] with new link name [%s]",link_name.c_str(),new_link_name.c_str()); 00909 for (std::vector<TiXmlElement*>::iterator blob_it = blobs.begin(); blob_it != blobs.end(); blob_it++) 00910 { 00911 00912 00913 std::ostringstream stream_in; 00914 stream_in << *(*blob_it); 00915 std::string blob = stream_in.str(); 00916 ROS_DEBUG(" INITIAL STRING [%s-->%s]: %s",link_name.c_str(),new_link_name.c_str(),blob.c_str()); 00917 00918 if ((*blob_it)->ValueStr() == "sensor:contact") 00919 { 00920 // parse it and add/replace the reduction transform 00921 // find first instance of xyz and rpy, replace with reduction transform 00922 TiXmlNode* geomName = (*blob_it)->FirstChild("geom"); 00923 if (geomName) 00924 { 00925 ROS_DEBUG(" <geom>%s</geom> : %s --> %s",getGazeboValue(geomName->ToElement()).c_str(),link_name.c_str(),new_link_name.c_str()); 00926 if (getGazeboValue(geomName->ToElement()) == link_name + std::string("_geom")) 00927 { 00928 (*blob_it)->RemoveChild(geomName); 00929 TiXmlElement* geom_name_key = new TiXmlElement("geom"); 00930 std::ostringstream geom_name_stream; 00931 geom_name_stream << new_link_name << "_geom_" << link_name; 00932 TiXmlText* geom_name_txt = new TiXmlText(geom_name_stream.str()); 00933 geom_name_key->LinkEndChild(geom_name_txt); 00934 (*blob_it)->LinkEndChild(geom_name_key); 00935 } 00936 } 00937 } 00938 if ((*blob_it)->ValueStr() == "controller:gazebo_ros_p3d" || 00939 (*blob_it)->ValueStr() == "controller:gazebo_ros_imu" || 00940 (*blob_it)->ValueStr() == "controller:gazebo_ros_projector") 00941 { 00942 // parse it and add/replace the reduction transform 00943 // find first instance of xyz and rpy, replace with reduction transform 00944 TiXmlNode* bodyName = (*blob_it)->FirstChild("bodyName"); 00945 if (bodyName) 00946 { 00947 if (getGazeboValue(bodyName->ToElement()) == link_name) 00948 { 00949 ROS_DEBUG(" <bodyName>%s</bodyName> : %s --> %s",getGazeboValue(bodyName->ToElement()).c_str(),link_name.c_str(),new_link_name.c_str()); 00950 (*blob_it)->RemoveChild(bodyName); 00951 TiXmlElement* body_name_key = new TiXmlElement("bodyName"); 00952 std::ostringstream body_name_stream; 00953 body_name_stream << new_link_name; 00954 TiXmlText* body_name_txt = new TiXmlText(body_name_stream.str()); 00955 body_name_key->LinkEndChild(body_name_txt); 00956 (*blob_it)->LinkEndChild(body_name_key); 00957 ROS_DEBUG("Re-parenting extension [%s] from [%s] to [%s] is broken, needs the transform to be complete",(*blob_it)->ValueStr().c_str(),link_name.c_str(),new_link_name.c_str()); 00958 } 00959 } 00960 } 00961 if ((*blob_it)->ValueStr() == "joint:hinge") 00962 { 00963 // parse it and add/replace the reduction transform 00964 // find first instance of xyz and rpy, replace with reduction transform 00965 TiXmlNode* body1 = (*blob_it)->FirstChild("body1"); 00966 if (body1) 00967 { 00968 if (getGazeboValue(body1->ToElement()) == link_name) 00969 { 00970 ROS_DEBUG(" <body1>%s</body1> : %s --> %s",getGazeboValue(body1->ToElement()).c_str(),link_name.c_str(),new_link_name.c_str()); 00971 (*blob_it)->RemoveChild(body1); 00972 TiXmlElement* body1_name_key = new TiXmlElement("body1"); 00973 std::ostringstream body1_name_stream; 00974 body1_name_stream << new_link_name; 00975 TiXmlText* body1_name_txt = new TiXmlText(body1_name_stream.str()); 00976 body1_name_key->LinkEndChild(body1_name_txt); 00977 (*blob_it)->LinkEndChild(body1_name_key); 00978 } 00979 } 00980 TiXmlNode* body2 = (*blob_it)->FirstChild("body2"); 00981 if (body2) 00982 { 00983 if (getGazeboValue(body2->ToElement()) == link_name) 00984 { 00985 ROS_DEBUG(" <body2>%s</body2> : %s --> %s",getGazeboValue(body2->ToElement()).c_str(),link_name.c_str(),new_link_name.c_str()); 00986 (*blob_it)->RemoveChild(body2); 00987 TiXmlElement* body2_name_key = new TiXmlElement("body2"); 00988 std::ostringstream body2_name_stream; 00989 body2_name_stream << new_link_name; 00990 TiXmlText* body2_name_txt = new TiXmlText(body2_name_stream.str()); 00991 body2_name_key->LinkEndChild(body2_name_txt); 00992 (*blob_it)->LinkEndChild(body2_name_key); 00993 } 00994 } 00995 TiXmlNode* anchor = (*blob_it)->FirstChild("anchor"); 00996 if (anchor) 00997 { 00998 if (getGazeboValue(anchor->ToElement()) == link_name) 00999 { 01000 ROS_DEBUG(" <anchor>%s</anchor> : %s --> %s",getGazeboValue(anchor->ToElement()).c_str(),link_name.c_str(),new_link_name.c_str()); 01001 (*blob_it)->RemoveChild(anchor); 01002 TiXmlElement* anchor_name_key = new TiXmlElement("anchor"); 01003 std::ostringstream anchor_name_stream; 01004 anchor_name_stream << new_link_name; 01005 TiXmlText* anchor_name_txt = new TiXmlText(anchor_name_stream.str()); 01006 anchor_name_key->LinkEndChild(anchor_name_txt); 01007 (*blob_it)->LinkEndChild(anchor_name_key); 01008 } 01009 } 01010 } 01011 01012 01013 std::ostringstream stream_out; 01014 stream_out << *(*blob_it); 01015 ROS_DEBUG(" STRING REPLACED: %s",stream_out.str().c_str()); 01016 } 01017 } 01018 01019 void URDF2Gazebo::updateGazeboExtensionBlobsReductionTransform(GazeboExtension* ext) 01020 { 01021 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 01022 { 01023 if (gazebo_it->second.size() > 0) 01024 { 01025 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 01026 { 01027 for (std::vector<TiXmlElement*>::iterator blob_it = (*ge)->blobs.begin(); blob_it != (*ge)->blobs.end(); blob_it++) 01028 { 01029 // overwrite <xyz> and <rpy> if they exist 01030 if ((*blob_it)->ValueStr() == "sensor:ray" || (*blob_it)->ValueStr() == "sensor:camera" || 01031 (*blob_it)->ValueStr() == "controller:gazebo_ros_p3d" || 01032 (*blob_it)->ValueStr() == "controller:gazebo_ros_imu" || 01033 (*blob_it)->ValueStr() == "controller:gazebo_ros_projector") 01034 { 01035 // parse it and add/replace the reduction transform 01036 // find first instance of xyz and rpy, replace with reduction transform 01037 ROS_DEBUG("testing reduction transform for [%s]",(*blob_it)->ValueStr().c_str()); 01038 for (TiXmlNode* el_it = (*blob_it)->FirstChild(); el_it; el_it = el_it->NextSibling()) 01039 { 01040 std::ostringstream stream_in; 01041 stream_in << *el_it; 01042 ROS_DEBUG(" %s",stream_in.str().c_str()); 01043 } 01044 01045 TiXmlNode* xyz_key = (*blob_it)->FirstChild("xyz"); 01046 if (xyz_key) 01047 (*blob_it)->RemoveChild(xyz_key); 01048 TiXmlNode* rpy_key = (*blob_it)->FirstChild("rpy"); 01049 if (rpy_key) 01050 (*blob_it)->RemoveChild(rpy_key); 01051 01052 xyz_key = new TiXmlElement("xyz"); 01053 rpy_key = new TiXmlElement("rpy"); 01054 01055 urdf::Vector3 reduction_xyz((*ge)->reduction_transform.position.x,(*ge)->reduction_transform.position.y,(*ge)->reduction_transform.position.z); 01056 urdf::Rotation reduction_q((*ge)->reduction_transform.rotation.x,(*ge)->reduction_transform.rotation.y,(*ge)->reduction_transform.rotation.z,(*ge)->reduction_transform.rotation.w); 01057 01058 std::ostringstream xyz_stream, rpy_stream; 01059 xyz_stream << reduction_xyz.x << " " << reduction_xyz.y << " " << reduction_xyz.z; 01060 urdf::Vector3 reduction_rpy; 01061 reduction_q.getRPY(reduction_rpy.x,reduction_rpy.y,reduction_rpy.z); // convert to Euler angles for Gazebo XML 01062 rpy_stream << reduction_rpy.x*180./M_PI << " " << reduction_rpy.y*180./M_PI << " " << reduction_rpy.z*180./M_PI; // convert to degrees for Gazebo (though ROS is in Radians) 01063 01064 TiXmlText* xyz_txt = new TiXmlText(xyz_stream.str()); 01065 TiXmlText* rpy_txt = new TiXmlText(rpy_stream.str()); 01066 01067 xyz_key->LinkEndChild(xyz_txt); 01068 rpy_key->LinkEndChild(rpy_txt); 01069 01070 (*blob_it)->LinkEndChild(xyz_key); 01071 (*blob_it)->LinkEndChild(rpy_key); 01072 } 01073 } 01074 } 01075 } 01076 } 01077 } 01078 01079 void URDF2Gazebo::listGazeboExtensions() 01080 { 01081 ROS_DEBUG("===================================================================="); 01082 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 01083 { 01084 int ext_count = 0; 01085 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 01086 { 01087 if ((*ge)->blobs.size() > 0) 01088 { 01089 ROS_DEBUG(" PRINTING [%d] BLOBS for extension [%d] referencing [%s]",(int)(*ge)->blobs.size(),ext_count++,gazebo_it->first.c_str()); 01090 for (std::vector<TiXmlElement*>::iterator blob_it = (*ge)->blobs.begin(); blob_it != (*ge)->blobs.end(); blob_it++) 01091 { 01092 std::ostringstream stream_in; 01093 stream_in << *(*blob_it); 01094 ROS_DEBUG(" BLOB: %s",stream_in.str().c_str()); 01095 } 01096 } 01097 } 01098 } 01099 ROS_DEBUG("===================================================================="); 01100 } 01101 01102 void URDF2Gazebo::listGazeboExtensions(std::string reference) 01103 { 01104 ROS_DEBUG("--------------------------------------------------------------------"); 01105 for (std::map<std::string,std::vector<GazeboExtension*> >::iterator gazebo_it = this->gazebo_extensions_.begin(); gazebo_it != this->gazebo_extensions_.end(); gazebo_it++) 01106 { 01107 if (gazebo_it->first == reference) 01108 { 01109 ROS_DEBUG(" PRINTING [%d] EXTENSIONS referencing [%s]",(int)gazebo_it->second.size(),reference.c_str()); 01110 for (std::vector<GazeboExtension*>::iterator ge = gazebo_it->second.begin(); ge != gazebo_it->second.end(); ge++) 01111 { 01112 for (std::vector<TiXmlElement*>::iterator blob_it = (*ge)->blobs.begin(); blob_it != (*ge)->blobs.end(); blob_it++) 01113 { 01114 std::ostringstream stream_in; 01115 stream_in << *(*blob_it); 01116 ROS_DEBUG(" BLOB: %s",stream_in.str().c_str()); 01117 } 01118 } 01119 } 01120 } 01121 ROS_DEBUG("--------------------------------------------------------------------"); 01122 } 01123 01124 void URDF2Gazebo::convertLink(TiXmlElement *root, boost::shared_ptr<const urdf::Link> link, const btTransform &transform, bool enforce_limits,bool reduce_fixed_joints) 01125 { 01126 btTransform currentTransform = transform; 01127 01128 // must have an <inertial> block and cannot have zero mass. allow det(I) == zero, such as in the case of point mass geoms. 01129 if (link->name != "world" && ((!link->inertial) || (link->inertial->mass == 0.0))) 01130 { 01131 if(!link->child_links.empty()) 01132 ROS_WARN("urdf2gazebo: link(%s) has no inertia, %d children link ignored.", link->name.c_str(),(int)link->child_links.size()); 01133 01134 if(!link->child_joints.empty()) 01135 ROS_WARN("urdf2gazebo: link(%s) has no inertia, %d children joint ignored.", link->name.c_str(),(int)link->child_joints.size()); 01136 01137 if(link->parent_joint) 01138 ROS_WARN("urdf2gazebo: link(%s) has no inertia, parent joint(%s) is ignored.",link->name.c_str(), link->parent_joint->name.c_str()); 01139 01140 ROS_WARN("urdf2gazebo: link(%s) has no inertia, not modeled in gazebo.", link->name.c_str()); 01141 return; 01142 } 01143 01144 /* create <body:...> block for non fixed joint attached bodies */ 01145 if ((link->getParent() && link->getParent()->name == "world") || 01146 !reduce_fixed_joints || (!link->parent_joint || link->parent_joint->type != urdf::Joint::FIXED)) 01147 createBody(root, link, transform, currentTransform, enforce_limits, reduce_fixed_joints); 01148 01149 // recurse into children 01150 for (unsigned int i = 0 ; i < link->child_links.size() ; ++i) 01151 convertLink(root, link->child_links[i], currentTransform, enforce_limits, reduce_fixed_joints); 01152 } 01153 01154 void URDF2Gazebo::createBody(TiXmlElement *root, boost::shared_ptr<const urdf::Link> link, const btTransform &transform, btTransform ¤tTransform, bool enforce_limits, bool reduce_fixed_joints) 01155 { 01156 int linkGeomSize; 01157 double linkSize[3]; 01158 01159 /* create new body */ 01160 TiXmlElement *elem = new TiXmlElement("body:empty"); // FIXME: does it matter what the collision type of the body is? 01161 01162 /* set body name */ 01163 elem->SetAttribute("name", link->name); 01164 01165 /* set mass properties */ 01166 addKeyValue(elem, "massMatrix", "true"); 01167 addKeyValue(elem, "mass", values2str(1, &link->inertial->mass)); 01168 01169 addKeyValue(elem, "ixx", values2str(1, &link->inertial->ixx)); 01170 addKeyValue(elem, "ixy", values2str(1, &link->inertial->ixy)); 01171 addKeyValue(elem, "ixz", values2str(1, &link->inertial->ixz)); 01172 addKeyValue(elem, "iyy", values2str(1, &link->inertial->iyy)); 01173 addKeyValue(elem, "iyz", values2str(1, &link->inertial->iyz)); 01174 addKeyValue(elem, "izz", values2str(1, &link->inertial->izz)); 01175 01176 addKeyValue(elem, "cx", values2str(1, &link->inertial->origin.position.x)); 01177 addKeyValue(elem, "cy", values2str(1, &link->inertial->origin.position.y)); 01178 addKeyValue(elem, "cz", values2str(1, &link->inertial->origin.position.z)); 01179 01180 double roll,pitch,yaw; 01181 link->inertial->origin.rotation.getRPY(roll,pitch,yaw); 01182 if (roll != 0 || pitch != 0 || yaw != 0) 01183 ROS_ERROR("rotation of inertial frame is not supported\n"); 01184 01185 /* compute global transform */ 01186 btTransform localTransform; 01187 // this is the transform from parent link to current link 01188 // this transform does not exist for the root link 01189 if (link->parent_joint) 01190 { 01191 ROS_DEBUG("%s has a parent joint",link->name.c_str()); 01192 setupTransform(localTransform, link->parent_joint->parent_to_joint_origin_transform); 01193 currentTransform *= localTransform; 01194 } 01195 else 01196 ROS_DEBUG("%s has no parent joint",link->name.c_str()); 01197 01198 01199 // create origin tag for this element 01200 addTransform(elem, currentTransform); 01201 01202 // make additional geoms using the lumped stuff 01203 // FIXME: what's the pairing strategy between visuals and collisions? 01204 // when only visuals exists? 01205 // when only collisions exists? 01206 // originally, there's one visual and one collision per link, which maps nicely to <body><geom><visual> heirarchy 01207 // now we have multiple visuals and collisions... how do we map? 01208 // loop through all default visuals and lump visuals 01209 #ifdef ROBOT_MODEL_MULTI_VISUAL_COLLISION 01210 for (std::map<std::string, boost::shared_ptr<std::vector<boost::shared_ptr<urdf::Collision> > > >::const_iterator collisions_it = link->collision_groups.begin(); 01211 collisions_it != link->collision_groups.end(); collisions_it++) 01212 { 01213 if (collisions_it->first == "default") 01214 { 01215 ROS_DEBUG("creating default geom for link [%s]",link->name.c_str()); 01216 boost::shared_ptr<urdf::Collision> collision = *(collisions_it->second->begin()); 01217 boost::shared_ptr<urdf::Visual> visual = *(link->visual_groups.find(collisions_it->first)->second->begin()); 01218 01219 std::string collision_type = "empty"; 01220 if (!collision || !collision->geometry) 01221 ROS_DEBUG("urdf2gazebo: link(%s) does not have a collision or geometry tag. No <geometry> will be assigned.", link->name.c_str()); 01222 else 01223 collision_type = getGeometrySize(collision->geometry, &linkGeomSize, linkSize); // add collision information 01224 01225 /* make a <geom:...> block */ 01226 createGeom(root, elem, link, transform, currentTransform, collision_type, collision, visual, linkGeomSize, linkSize, link->name); 01227 } 01228 else if (collisions_it->first.find(std::string("lump::")) == 0) // starts with "lump::" 01229 { 01230 ROS_DEBUG("creating lump geom [%s] for link [%s]",collisions_it->first.c_str(),link->name.c_str()); 01231 boost::shared_ptr<urdf::Collision> collision = *(collisions_it->second->begin()); 01232 boost::shared_ptr<urdf::Visual> visual = *(link->visual_groups.find(collisions_it->first)->second->begin()); 01233 01234 std::string collision_type = "empty"; 01235 if (!collision || !collision->geometry) 01236 ROS_DEBUG("urdf2gazebo: link(%s) does not have a collision or geometry tag. No <geometry> will be assigned.", link->name.c_str()); 01237 else 01238 collision_type = getGeometrySize(collision->geometry, &linkGeomSize, linkSize); // add collision information 01239 01240 std::string original_reference = collisions_it->first.substr(6); 01241 /* make a <geom:...> block */ 01242 createGeom(root, elem, link, transform, currentTransform, collision_type, collision, visual, linkGeomSize, linkSize, original_reference); 01243 } 01244 } 01245 #else 01246 { 01247 ROS_DEBUG("creating default geom for link [%s]",link->name.c_str()); 01248 std::string collision_type = "empty"; 01249 if (!link->collision || !link->collision->geometry) 01250 ROS_DEBUG("urdf2gazebo: link(%s) does not have a collision or geometry tag. No <geometry> will be assigned.", link->name.c_str()); 01251 else 01252 collision_type = getGeometrySize(link->collision->geometry, &linkGeomSize, linkSize); // add collision information 01253 01254 /* make a <geom:...> block */ 01255 createGeom(root, elem, link, transform, currentTransform, collision_type, link->collision, link->visual, linkGeomSize, linkSize, link->name); 01256 } 01257 #endif 01258 01259 /* copy gazebo extensions data */ 01260 insertGazeboExtensionBody(elem,link->name); 01261 01262 /* add body to document */ 01263 root->LinkEndChild(elem); 01264 01265 /* make a <joint:...> block */ 01266 createJoint(root, link, currentTransform, enforce_limits, reduce_fixed_joints); 01267 01268 } 01269 01270 01271 void URDF2Gazebo::createJoint(TiXmlElement *root, boost::shared_ptr<const urdf::Link> link, btTransform ¤tTransform, bool enforce_limits,bool reduce_fixed_joints) 01272 { 01273 /* compute the joint tag */ 01274 std::string jtype; 01275 jtype.clear(); 01276 if (link->parent_joint != NULL) 01277 { 01278 switch (link->parent_joint->type) 01279 { 01280 case urdf::Joint::CONTINUOUS: 01281 case urdf::Joint::REVOLUTE: 01282 jtype = "hinge"; 01283 break; 01284 case urdf::Joint::PRISMATIC: 01285 jtype = "slider"; 01286 break; 01287 case urdf::Joint::FLOATING: 01288 case urdf::Joint::PLANAR: 01289 break; 01290 case urdf::Joint::FIXED: 01291 jtype = "fixed"; 01292 break; 01293 default: 01294 printf("Unknown joint type: %d in link '%s'\n", link->parent_joint->type, link->name.c_str()); 01295 break; 01296 } 01297 } 01298 01299 // skip if joint type is fixed and we are not faking it with a hinge, skip/return 01300 // with the exception of root link being world, because there's no lumping there 01301 if (link->getParent() && link->getParent()->name != "world" && jtype == "fixed" && reduce_fixed_joints) return; 01302 01303 if (!jtype.empty()) 01304 { 01305 TiXmlElement *joint; 01306 if (jtype == "fixed") joint = new TiXmlElement("joint:hinge"); 01307 else joint = new TiXmlElement("joint:" + jtype); 01308 joint->SetAttribute("name", link->parent_joint->name); 01309 addKeyValue(joint, "body1", link->name); 01310 addKeyValue(joint, "body2", link->getParent()->name); 01311 addKeyValue(joint, "anchor", link->name); 01312 01313 if (jtype == "fixed") 01314 { 01315 addKeyValue(joint, "lowStop", "0"); 01316 addKeyValue(joint, "highStop", "0"); 01317 addKeyValue(joint, "axis", "0 0 1"); 01318 addKeyValue(joint, "damping", "0"); 01319 } 01320 else 01321 { 01322 btTransform currentTransformCopy( currentTransform ); 01323 currentTransformCopy.setOrigin( btVector3(0, 0, 0) ); 01324 btVector3 rotatedJointAxis = currentTransformCopy * btVector3( link->parent_joint->axis.x, 01325 link->parent_joint->axis.y, 01326 link->parent_joint->axis.z ); 01327 double rotatedJointAxisArray[3] = { rotatedJointAxis.x(), rotatedJointAxis.y(), rotatedJointAxis.z() }; 01328 addKeyValue(joint, "axis", values2str(3, rotatedJointAxisArray)); 01329 if (link->parent_joint->dynamics) 01330 addKeyValue(joint, "damping", values2str(1, &link->parent_joint->dynamics->damping )); 01331 01332 // Joint Anchor is deprecated 01333 // btTransform currentAnchorTransform( currentTransform ); 01334 // currentAnchorTransform.setOrigin( btVector3(0, 0, 0) ); 01335 // btVector3 jointAnchor = currentAnchorTransform * btVector3( link->parent_joint->anchor.x, 01336 // link->parent_joint->anchor.y, 01337 // link->parent_joint->anchor.z ); 01338 // double tmpAnchor[3] = { jointAnchor.x(), jointAnchor.y(), jointAnchor.z() }; 01339 // addKeyValue(joint, "anchorOffset", values2str(3, tmpAnchor)); 01340 01341 if (enforce_limits && link->parent_joint->limits) 01342 { 01343 if (jtype == "slider") 01344 { 01345 addKeyValue(joint, "lowStop", values2str(1, &link->parent_joint->limits->lower )); 01346 addKeyValue(joint, "highStop", values2str(1, &link->parent_joint->limits->upper )); 01347 } 01348 else if (link->parent_joint->type != urdf::Joint::CONTINUOUS) 01349 { 01350 double *lowstop = &link->parent_joint->limits->lower; 01351 double *highstop = &link->parent_joint->limits->upper; 01352 // enforce ode bounds, this will need to be fixed 01353 if (*lowstop > *highstop) 01354 { 01355 ROS_WARN("urdf2gazebo: hinge joint limits: lowStop > highStop, setting lowStop to highStop."); 01356 *lowstop = *highstop; 01357 } 01358 addKeyValue(joint, "lowStop", values2str(1, &link->parent_joint->limits->lower, rad2deg)); 01359 addKeyValue(joint, "highStop", values2str(1, &link->parent_joint->limits->upper, rad2deg)); 01360 } 01361 } 01362 } 01363 /* copy gazebo extensions data */ 01364 insertGazeboExtensionJoint(joint,link->parent_joint->name); 01365 01366 /* add joint to document */ 01367 root->LinkEndChild(joint); 01368 } 01369 } 01370 01371 01372 void URDF2Gazebo::createGeom(TiXmlElement *root, TiXmlElement* elem, boost::shared_ptr<const urdf::Link> link, const btTransform &transform, btTransform ¤tTransform,std::string collision_type, boost::shared_ptr<urdf::Collision> collision, boost::shared_ptr<urdf::Visual> visual, int linkGeomSize, double* linkSize, std::string original_reference) 01373 { 01374 /* begin create geometry node, skip if no collision specified */ 01375 if (collision_type != "empty") 01376 { 01377 TiXmlElement *geom = new TiXmlElement("geom:" + collision_type); 01378 /* set its name */ 01379 if (original_reference == link->name) 01380 geom->SetAttribute("name", link->name + std::string("_geom")); 01381 else 01382 geom->SetAttribute("name", link->name + std::string("_geom_")+original_reference); 01383 01384 /* set transform */ 01385 addKeyValue(geom, "xyz", vector32str(collision->origin.position)); 01386 double rpy[3]; 01387 collision->origin.rotation.getRPY(rpy[0],rpy[1],rpy[2]); 01388 addKeyValue(geom, "rpy", values2str(3, rpy, rad2deg)); 01389 01390 if (collision->geometry->type == urdf::Geometry::MESH) 01391 { 01392 boost::shared_ptr<const urdf::Mesh> mesh; 01393 mesh = boost::dynamic_pointer_cast<const urdf::Mesh >(collision->geometry); 01394 /* set mesh size or scale */ 01395 addKeyValue(geom, "scale", vector32str(mesh->scale)); 01396 01397 /* set mesh file */ 01398 /* expand to get absolute mesh filename */ 01399 std::string fullname = mesh->filename; 01400 if (fullname.find("package://") == 0) 01401 { 01402 fullname.erase(0, strlen("package://")); 01403 size_t pos = fullname.find("/"); 01404 if (pos == std::string::npos) 01405 { 01406 ROS_FATAL("Could not parse package:// format for [%s]",mesh->filename.c_str()); 01407 } 01408 01409 std::string package = fullname.substr(0, pos); 01410 fullname.erase(0, pos); 01411 std::string package_path = ros::package::getPath(package); 01412 01413 if (package_path.empty()) 01414 { 01415 ROS_FATAL("%s Package[%s] does not exist",mesh->filename.c_str(),package.c_str()); 01416 } 01417 01418 fullname = package_path + fullname; 01419 } 01420 01421 // give some warning if file does not exist. 01422 std::ifstream fin; fin.open(fullname.c_str(), std::ios::in); fin.close(); 01423 if (fin.fail()) 01424 ROS_ERROR("filename referred by mesh [%s] does not appear to exist.",mesh->filename.c_str()); 01425 01426 // add mesh filename 01427 addKeyValue(geom, "mesh", fullname); 01428 01429 } 01430 else 01431 { 01432 /* set geometry size */ 01433 addKeyValue(geom, "size", values2str(linkGeomSize, linkSize)); 01434 } 01435 01436 /* set additional data from extensions */ 01437 insertGazeboExtensionGeom(geom,original_reference); 01438 01439 // FIXME: unfortunately, visual is not created if collision is missing!!! 01440 createVisual(root, geom, link, transform, currentTransform, collision_type, collision, visual,original_reference); 01441 01442 /* add geometry to body */ 01443 elem->LinkEndChild(geom); 01444 } 01445 } 01446 01447 void URDF2Gazebo::createVisual(TiXmlElement *root, TiXmlElement *geom, boost::shared_ptr<const urdf::Link> link, const btTransform &transform, btTransform ¤tTransform, std::string collision_type, boost::shared_ptr<urdf::Collision> collision, boost::shared_ptr<urdf::Visual> visual,std::string original_reference) 01448 { 01449 /* begin create gazebo visual node */ 01450 TiXmlElement *gazebo_visual = new TiXmlElement("visual"); 01451 /* compute the visualisation transfrom */ 01452 btTransform coll; 01453 01454 setupTransform(coll, collision->origin); 01455 coll.inverse(); 01456 01457 btTransform vis; 01458 if(!visual) 01459 { 01460 ROS_WARN("urdf2gazebo: link(%s) does not have a visual tag, using zero transform.", link->name.c_str()); 01461 setupTransform(vis, urdf::Pose()); 01462 } 01463 else 01464 setupTransform(vis, visual->origin); 01465 coll = coll.inverseTimes(vis); 01466 01467 addTransform(gazebo_visual, coll); 01468 01469 /* set geometry size */ 01470 01471 if (!visual || !visual->geometry) 01472 { 01473 ROS_WARN("urdf2gazebo: link(%s) does not have a visual->geometry tag, using default SPHERE with 1mm radius.", link->name.c_str()); 01474 double visualSize[3]; 01475 visualSize[0]=visualSize[1]=visualSize[2]=0.002; 01476 addKeyValue(gazebo_visual, "scale", values2str(3, visualSize)); 01477 addKeyValue(gazebo_visual, "mesh", "unit_sphere"); 01478 } 01479 else if (visual->geometry->type == urdf::Geometry::MESH) 01480 { 01481 boost::shared_ptr<const urdf::Mesh> mesh; 01482 mesh = boost::dynamic_pointer_cast<const urdf::Mesh >(visual->geometry); 01483 /* set mesh size or scale */ 01484 /* 01485 if (visual->geometry->isSet["size"]) 01486 addKeyValue(gazebo_visual, "size", values2str(3, mesh->size)); 01487 else 01488 addKeyValue(gazebo_visual, "scale", values2str(3, mesh->scale)); 01489 */ 01490 addKeyValue(gazebo_visual, "scale", vector32str(mesh->scale)); 01491 01492 /* set mesh file */ 01493 if (mesh->filename.empty()) 01494 { 01495 ROS_ERROR("urdf2gazebo: mesh geometry (%s) was specified but no filename given? using collision type.",link->name.c_str()); 01496 addKeyValue(gazebo_visual, "mesh", "unit_" + collision_type); // reuse collision type if mesh does not specify filename 01497 } 01498 else 01499 { 01500 /* set mesh file */ 01501 /* expand to get absolute mesh filename */ 01502 std::string fullname = mesh->filename; 01503 if (fullname.find("package://") == 0) 01504 { 01505 fullname.erase(0, strlen("package://")); 01506 size_t pos = fullname.find("/"); 01507 if (pos == std::string::npos) 01508 { 01509 ROS_FATAL("Could not parse package:// format for [%s]",mesh->filename.c_str()); 01510 } 01511 01512 std::string package = fullname.substr(0, pos); 01513 fullname.erase(0, pos); 01514 std::string package_path = ros::package::getPath(package); 01515 01516 if (package_path.empty()) 01517 { 01518 ROS_FATAL("%s Package[%s] does not exist",mesh->filename.c_str(),package.c_str()); 01519 } 01520 01521 fullname = package_path + fullname; 01522 } 01523 01524 // add mesh filename 01525 addKeyValue(gazebo_visual, "mesh", fullname); 01526 } 01527 01528 } 01529 else 01530 { 01531 double visualSize[3]; 01532 std::string visual_geom_type = getGeometryBoundingBox(visual->geometry, visualSize); 01533 addKeyValue(gazebo_visual, "scale", values2str(3, visualSize)); 01534 addKeyValue(gazebo_visual, "mesh", "unit_" + visual_geom_type); 01535 } 01536 01537 /* set additional data from extensions */ 01538 insertGazeboExtensionVisual(gazebo_visual,original_reference); 01539 01540 /* end create visual node */ 01541 geom->LinkEndChild(gazebo_visual); 01542 } 01543 01544 01545 void URDF2Gazebo::walkChildAddNamespace(TiXmlNode* robot_xml,std::string robot_namespace) 01546 { 01547 TiXmlNode* child = 0; 01548 child = robot_xml->IterateChildren(child); 01549 while (child != NULL) 01550 { 01551 ROS_DEBUG("recursively walking gazebo extension for %s --> %d",child->ValueStr().c_str(),(int)child->ValueStr().find(std::string("controller"))); 01552 if (child->ValueStr().find(std::string("controller")) == 0 && child->ValueStr().find(std::string("controller")) != std::string::npos) 01553 { 01554 if (child->FirstChildElement("robotNamespace") == NULL) 01555 { 01556 ROS_DEBUG(" adding robotNamespace for %s",child->ValueStr().c_str()); 01557 addKeyValue(child->ToElement(), "robotNamespace", robot_namespace); 01558 } 01559 else 01560 { 01561 ROS_DEBUG(" robotNamespace already exists for %s",child->ValueStr().c_str()); 01562 } 01563 } 01564 this->walkChildAddNamespace(child,robot_namespace); 01565 child = robot_xml->IterateChildren(child); 01566 } 01567 } 01568 01569 void URDF2Gazebo::convert(TiXmlDocument &urdf_in, TiXmlDocument &gazebo_xml_out, bool enforce_limits, urdf::Vector3 initial_xyz, urdf::Vector3 initial_rpy,std::string model_name , std::string robot_namespace, bool xml_declaration) 01570 { 01571 01572 // copy model to a string 01573 std::ostringstream stream_in; 01574 stream_in << urdf_in; 01575 01576 /* Create a RobotModel from string */ 01577 urdf::Model robot_model; 01578 01579 if (!robot_model.initString(stream_in.str().c_str())) 01580 { 01581 ROS_ERROR("Unable to load robot model from param server robot_description\n"); 01582 exit(2); 01583 } 01584 01585 01586 // add xml declaration if needed 01587 if (xml_declaration) 01588 { 01589 TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", ""); 01590 gazebo_xml_out.LinkEndChild(decl); 01591 } 01592 01593 /* create root element and define needed namespaces */ 01594 TiXmlElement *robot = new TiXmlElement("model:physical"); 01595 robot->SetAttribute("xmlns:gazebo", "http://playerstage.sourceforge.net/gazebo/xmlschema/#gz"); 01596 robot->SetAttribute("xmlns:model", "http://playerstage.sourceforge.net/gazebo/xmlschema/#model"); 01597 robot->SetAttribute("xmlns:sensor", "http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"); 01598 robot->SetAttribute("xmlns:body", "http://playerstage.sourceforge.net/gazebo/xmlschema/#body"); 01599 robot->SetAttribute("xmlns:geom", "http://playerstage.sourceforge.net/gazebo/xmlschema/#geom"); 01600 robot->SetAttribute("xmlns:joint", "http://playerstage.sourceforge.net/gazebo/xmlschema/#joint"); 01601 robot->SetAttribute("xmlns:controller", "http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"); 01602 robot->SetAttribute("xmlns:interface", "http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"); 01603 robot->SetAttribute("xmlns:rendering", "http://playerstage.sourceforge.net/gazebo/xmlschema/#rendering"); 01604 robot->SetAttribute("xmlns:physics", "http://playerstage.sourceforge.net/gazebo/xmlschema/#physics"); 01605 01606 // set model name to urdf robot name if not specified 01607 if (model_name.empty()) 01608 robot->SetAttribute("name", robot_model.getName()); 01609 else 01610 robot->SetAttribute("name", model_name); 01611 01612 /* set the transform for the whole model to identity */ 01613 addKeyValue(robot, "xyz", vector32str(initial_xyz)); 01614 addKeyValue(robot, "rpy", vector32str(initial_rpy)); 01615 btTransform transform; 01616 transform.setIdentity(); 01617 01618 /* parse gazebo extension */ 01619 parseGazeboExtension( urdf_in ); 01620 01621 /* start conversion */ 01622 01623 boost::shared_ptr<const urdf::Link> root_link = robot_model.getRoot(); 01624 /* if link connects to parent via fixed joint, lump down and remove link */ 01625 // set reduce_fixed_joints to true will use hinge joints replacements, otherwise, we reduce it down to its parent link recursively 01626 #ifdef ROBOT_MODEL_MULTI_VISUAL_COLLISION 01627 bool reduce_fixed_joints = true; 01628 if (reduce_fixed_joints) 01629 reduceFixedJoints(robot, (boost::const_pointer_cast< urdf::Link >(root_link))); // uncomment to test reduction 01630 #else 01631 bool reduce_fixed_joints = false; 01632 #endif 01633 01634 if (root_link->name == "world") 01635 { 01636 /* convert all children link */ 01637 for (std::vector<boost::shared_ptr<urdf::Link> >::const_iterator child = root_link->child_links.begin(); child != root_link->child_links.end(); child++) 01638 convertLink(robot, (*child), transform, enforce_limits, reduce_fixed_joints); 01639 } 01640 else 01641 { 01642 /* convert, starting from root link */ 01643 convertLink(robot, root_link, transform, enforce_limits, reduce_fixed_joints); 01644 } 01645 01646 /* find all data item types */ 01647 insertGazeboExtensionRobot(robot); 01648 01649 if (!robot_namespace.empty()) 01650 { 01651 // traverse all of the: controller::*, add robotNamespace if does not exist already 01652 ROS_DEBUG("walking gazebo extension for %s",robot->ValueStr().c_str()); 01653 this->walkChildAddNamespace(robot,robot_namespace); 01654 } 01655 01656 std::ostringstream stream_robot; 01657 stream_robot << *(robot); 01658 ROS_DEBUG("\n\n\nentire robot:\n%s",stream_robot.str().c_str()); 01659 gazebo_xml_out.LinkEndChild(robot); 01660 } 01661 01662 01663 01664 01665 01666 01667 01668 01669 01670