00001
00031 #include <urdf_traverser/Helpers.h>
00032 #include <urdf_traverser/Functions.h>
00033 #include <urdf_traverser/UrdfTraverser.h>
00034 #include <urdf_traverser/PrintModel.h>
00035 #include <urdf_traverser/JointNames.h>
00036 #include <urdf_traverser/DependencyOrderedJoints.h>
00037
00038 #include <string>
00039 #include <ros/ros.h>
00040 #include <ros/package.h>
00041
00042 #include <map>
00043 #include <vector>
00044 #include <set>
00045 #include <fstream>
00046 #include <algorithm>
00047
00048 #define RAD_TO_DEG 180/M_PI
00049
00050 using urdf_traverser::UrdfTraverser;
00051
00052 std::string UrdfTraverser::getRootLinkName() const
00053 {
00054 LinkConstPtr root = this->model->getRoot();
00055 if (!root)
00056 {
00057 ROS_ERROR("Loaded model has no root");
00058 return "";
00059 }
00060 return root->name;
00061 }
00062
00063 bool UrdfTraverser::printModel(const std::string& fromLink, bool verbose)
00064 {
00065 return urdf_traverser::printModel(*this, fromLink, verbose);
00066 }
00067
00068 bool UrdfTraverser::printModel(bool verbose)
00069 {
00070 return urdf_traverser::printModel(*this, verbose);
00071 }
00072
00073
00074 bool UrdfTraverser::getDependencyOrderedJoints(std::vector<JointPtr>& result,
00075 const JointPtr& from_joint, bool allowSplits, bool onlyActive)
00076 {
00077 return urdf_traverser::getDependencyOrderedJoints(*this, result, from_joint, allowSplits, onlyActive);
00078 }
00079
00080 bool UrdfTraverser::getDependencyOrderedJoints(std::vector<JointPtr>& result, const LinkPtr& from_link,
00081 bool allowSplits, bool onlyActive)
00082 {
00083 return urdf_traverser::getDependencyOrderedJoints(*this, result, from_link->name, allowSplits, onlyActive);
00084 }
00085
00086
00087 bool UrdfTraverser::getJointNames(const std::string& fromLink,
00088 const bool skipFixed, std::vector<std::string>& result)
00089 {
00090 std::string rootLink = fromLink;
00091 if (rootLink.empty())
00092 {
00093 rootLink = getRootLinkName();
00094 }
00095
00096
00097 LinkPtr root_link;
00098 this->model->getLink(rootLink, root_link);
00099 if (!root_link)
00100 {
00101 ROS_ERROR("no root link %s", fromLink.c_str());
00102 return false;
00103 }
00104
00105 return urdf_traverser::getJointNames(*this, rootLink, skipFixed, result);
00106 }
00107
00108 int UrdfTraverser::getChildJoint(const JointPtr& joint, JointPtr& child)
00109 {
00110 LinkPtr childLink = getChildLink(joint);
00111 if (!childLink)
00112 {
00113 ROS_ERROR("Consistency: all joints must have child links");
00114 return -2;
00115 }
00116 if (childLink->child_joints.size() > 1)
00117 {
00118 return -1;
00119 }
00120 if (childLink->child_joints.empty())
00121 {
00122
00123
00124
00125 return 0;
00126 }
00127
00128 child = childLink->child_joints.front();
00129 return 1;
00130 }
00131
00132 urdf_traverser::LinkPtr UrdfTraverser::getChildLink(const JointConstPtr& joint)
00133 {
00134 LinkPtr childLink;
00135 model->getLink(joint->child_link_name, childLink);
00136 return childLink;
00137 }
00138
00139 urdf_traverser::LinkConstPtr UrdfTraverser::readChildLink(const JointConstPtr& joint) const
00140 {
00141 LinkPtr childLink;
00142 model->getLink(joint->child_link_name, childLink);
00143 return childLink;
00144 }
00145
00146 urdf_traverser::JointPtr UrdfTraverser::getParentJoint(const JointConstPtr& joint)
00147 {
00148 LinkConstPtr parentLink = model->getLink(joint->parent_link_name);
00149 if (!parentLink) return JointPtr();
00150 return parentLink->parent_joint;
00151 }
00152
00153 urdf_traverser::JointConstPtr UrdfTraverser::readParentJoint(const JointConstPtr& joint) const
00154 {
00155 LinkConstPtr parentLink = model->getLink(joint->parent_link_name);
00156 if (!parentLink) return JointPtr();
00157 return parentLink->parent_joint;
00158 }
00159
00160
00161
00162 bool UrdfTraverser::hasChildLink(const LinkConstPtr& link, const std::string& childName) const
00163 {
00164 for (unsigned int i = 0; i < link->child_links.size(); ++i)
00165 {
00166 LinkPtr childLink = link->child_links[i];
00167 if (childLink->name == childName) return true;
00168 }
00169 return false;
00170 }
00171
00172
00173 int UrdfTraverser::traverseTreeTopDown(const std::string& linkName, boost::function< int(RecursionParamsPtr&)> link_cb,
00174 RecursionParamsPtr& params, bool includeLink)
00175 {
00176 LinkPtr link = getLink(linkName);
00177 if (!link)
00178 {
00179 ROS_ERROR_STREAM("Could not get Link " << linkName);
00180 return -1;
00181 }
00182 return traverseTreeTopDown(link, link_cb, params, includeLink, 0);
00183 }
00184
00185 int UrdfTraverser::traverseTreeTopDown(const LinkPtr& link, boost::function< int(RecursionParamsPtr&)> link_cb,
00186 RecursionParamsPtr& params, bool includeLink, unsigned int level)
00187 {
00188 if (includeLink)
00189 {
00190 params->setParams(link, level);
00191 int link_ret = link_cb(params);
00192 if (link_ret <= 0)
00193 {
00194
00195 return link_ret;
00196 }
00197 }
00198
00199 level += 1;
00200 for (std::vector<LinkPtr>::const_iterator child = link->child_links.begin();
00201 child != link->child_links.end(); child++)
00202 {
00203 LinkPtr childLink = *child;
00204 if (childLink)
00205 {
00206 params->setParams(childLink, level);
00207 int link_ret = link_cb(params);
00208 if (link_ret <= 0)
00209 {
00210
00211 return link_ret;
00212 }
00213
00214
00215 int ret = traverseTreeTopDown(childLink, link_cb, params, false, level);
00216 if (ret < 0)
00217 {
00218 ROS_ERROR("Error parsing branch of %s", childLink->name.c_str());
00219 return -1;
00220 }
00221 }
00222 else
00223 {
00224 ROS_ERROR("root link: %s has a null child!", link->name.c_str());
00225 return false;
00226 }
00227 }
00228 return 1;
00229 };
00230
00231 int UrdfTraverser::traverseTreeBottomUp(const std::string& linkName, boost::function< int(RecursionParamsPtr&)> link_cb,
00232 RecursionParamsPtr& params, bool includeLink)
00233 {
00234 LinkPtr link = getLink(linkName);
00235 if (!link)
00236 {
00237 ROS_ERROR_STREAM("Could not get Link " << linkName);
00238 return -1;
00239 }
00240 return traverseTreeBottomUp(link, link_cb, params, includeLink, 0);
00241 }
00242
00243
00244
00245 int UrdfTraverser::traverseTreeBottomUp(const LinkPtr& link, boost::function<int(RecursionParamsPtr&)> link_cb,
00246 RecursionParamsPtr& params, bool includeLink, unsigned int level)
00247 {
00248 std::set<std::string> toTraverse;
00249 for (unsigned int i = 0; i < link->child_links.size(); ++i)
00250 {
00251 LinkPtr childLink = link->child_links[i];
00252 toTraverse.insert(childLink->name);
00253 }
00254
00255 for (std::set<std::string>::iterator it = toTraverse.begin(); it != toTraverse.end(); ++it)
00256 {
00257 if (!hasChildLink(link, *it))
00258 {
00259 ROS_ERROR_STREAM("Consistency: Link " << link->name << " does not have child " << *it << " any more.");
00260 return -1;
00261 }
00262
00263 LinkPtr childLink;
00264 this->model->getLink(*it, childLink);
00265
00266 if (childLink)
00267 {
00268
00269
00270 int travRes = traverseTreeBottomUp(childLink, link_cb, params, true, level + 1);
00271 if (travRes == 0)
00272 {
00273 ROS_INFO("Stopping traversal at %s", childLink->name.c_str());
00274 return 0;
00275 }
00276 else if (travRes < 0)
00277 {
00278 ROS_ERROR("Error parsing branch of %s", childLink->name.c_str());
00279 return -1;
00280 }
00281
00282 }
00283 else
00284 {
00285 ROS_ERROR("root link: %s has a null child!", link->name.c_str());
00286 return -1;
00287 }
00288 }
00289
00290 if (!includeLink)
00291 {
00292 return 1;
00293 }
00294
00295 params->setParams(link, level);
00296 int cbRet = link_cb(params);
00297 if (cbRet < 0)
00298 {
00299 ROS_ERROR("Error parsing branch of %s", link->name.c_str());
00300 return -1;
00301 }
00302 return cbRet;
00303 }
00304
00305
00306 urdf_traverser::LinkPtr UrdfTraverser::getLink(const std::string& name)
00307 {
00308 LinkPtr ptr;
00309 this->model->getLink(name, ptr);
00310 return ptr;
00311 }
00312
00313 urdf_traverser::LinkConstPtr UrdfTraverser::readLink(const std::string& name) const
00314 {
00315 LinkPtr ptr;
00316 this->model->getLink(name, ptr);
00317 return ptr;
00318 }
00319
00320 urdf_traverser::JointPtr UrdfTraverser::getJoint(const std::string& name)
00321 {
00322 JointPtr ptr;
00323 if (this->model->joints_.find(name) == this->model->joints_.end()) ptr.reset();
00324 else ptr = this->model->joints_.find(name)->second;
00325 return ptr;
00326 }
00327
00328 urdf_traverser::JointConstPtr UrdfTraverser::readJoint(const std::string& name) const
00329 {
00330 JointConstPtr ptr;
00331 if (this->model->joints_.find(name) == this->model->joints_.end()) ptr.reset();
00332 else ptr = this->model->joints_.find(name)->second;
00333 return ptr;
00334 }
00335
00336
00337 void UrdfTraverser::printJointNames(const std::string& fromLink)
00338 {
00339 std::vector<std::string> jointNames;
00340 if (!getJointNames(fromLink, false, jointNames))
00341 {
00342 ROS_WARN("Could not retrieve joint names to print on screen");
00343 }
00344 else
00345 {
00346 ROS_INFO_STREAM("Joint names starting from " << fromLink << ":");
00347 for (int i = 0; i < jointNames.size(); ++i) ROS_INFO_STREAM(jointNames[i]);
00348 ROS_INFO("---");
00349 }
00350 }
00351
00352 bool UrdfTraverser::loadModelFromFile(const std::string& urdfFilename)
00353 {
00354 std::string xml_file;
00355 if (!getModelFromFile(urdfFilename, xml_file))
00356 {
00357 ROS_ERROR("Could not load file");
00358 return false;
00359 }
00360
00361 boost::filesystem::path filePath(urdfFilename);
00362 setModelDirectory(filePath.parent_path().string());
00363 ROS_INFO_STREAM("Setting base model directory to " << modelDir);
00364
00365 if (!loadModelFromXMLString(xml_file))
00366 {
00367 ROS_ERROR("Could not load file");
00368 return false;
00369 }
00370 return true;
00371 }
00372
00373
00374
00375 bool UrdfTraverser::loadModelFromXMLString(const std::string& xmlString)
00376 {
00377 bool success = model->initString(xmlString);
00378 if (!success)
00379 {
00380 ROS_ERROR("Could not load model from XML string");
00381 return false;
00382 }
00383 return true;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 bool UrdfTraverser::getModelFromFile(const std::string& filename, std::string& xml_string) const
00395 {
00396 std::fstream xml_file(filename.c_str(), std::fstream::in);
00397 if (xml_file.is_open())
00398 {
00399 while (xml_file.good())
00400 {
00401 std::string line;
00402 std::getline(xml_file, line);
00403 xml_string += (line + "\n");
00404 }
00405 xml_file.close();
00406 return true;
00407 }
00408
00409 ROS_ERROR("Could not open file [%s] for parsing.", filename.c_str());
00410 return false;
00411 }
00412
00413 urdf_traverser::EigenTransform UrdfTraverser::getTransform(const LinkPtr& from_link, const JointPtr& to_joint)
00414 {
00415 LinkPtr link1 = from_link;
00416 LinkPtr link2;
00417 this->model->getLink(to_joint->child_link_name, link2);
00418 if (!link1 || !link2)
00419 {
00420 ROS_ERROR("Invalid joint specifications (%s, %s), first needs parent and second child",
00421 link1->name.c_str(), link2->name.c_str());
00422 }
00423 return urdf_traverser::getTransform(link1, link2);
00424 }