From 34ebae277f08227d8482c9b5908fd7234e79d299 Mon Sep 17 00:00:00 2001 From: Joseph Mirabel <jmirabel@laas.fr> Date: Thu, 28 Sep 2017 15:55:47 +0200 Subject: [PATCH] [SRDF] Support SRDF as XML string and split declaration and definition --- src/CMakeLists.txt | 1 + src/parsers/srdf.cpp | 217 +++++++++++++++++++++++++++++++++++++++++++ src/parsers/srdf.hpp | 176 ++++------------------------------- 3 files changed, 238 insertions(+), 156 deletions(-) create mode 100644 src/parsers/srdf.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1893de70b..68e287994 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,7 @@ SET(${PROJECT_NAME}_MULTIBODY_SOURCES SET(${PROJECT_NAME}_PARSERS_SOURCES parsers/sample-models.cpp + parsers/srdf.cpp ) IF(URDFDOM_FOUND) diff --git a/src/parsers/srdf.cpp b/src/parsers/srdf.cpp new file mode 100644 index 000000000..56abb5c16 --- /dev/null +++ b/src/parsers/srdf.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2017 CNRS +// +// This file is part of Pinocchio +// Pinocchio is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation, either version +// 3 of the License, or (at your option) any later version. +// +// Pinocchio is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. You should have +// received a copy of the GNU Lesser General Public License along with +// Pinocchio If not, see +// <http://www.gnu.org/licenses/>. + +#ifndef __se3_parser_srdf_hxx__ +#define __se3_parser_srdf_hxx__ + +#include "pinocchio/parsers/srdf.hpp" + +#include "pinocchio/multibody/model.hpp" +#include "pinocchio/multibody/geometry.hpp" +#include <iostream> + +// Read XML file with boost +#include <boost/property_tree/xml_parser.hpp> +#include <boost/property_tree/ptree.hpp> +#include <fstream> +#include <sstream> +#include <boost/foreach.hpp> + + +namespace se3 +{ + namespace srdf + { + +#ifdef WITH_HPP_FCL + namespace details + { + inline void removeCollisionPairs(const Model& model, + GeometryModel & geomModel, + std::istream & stream, + const bool verbose = false) + { + // Read xml stream + using boost::property_tree::ptree; + ptree pt; + read_xml(stream, pt); + + // Iterate over collision pairs + BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot")) + { + if (v.first == "disable_collisions") + { + const std::string link1 = v.second.get<std::string>("<xmlattr>.link1"); + const std::string link2 = v.second.get<std::string>("<xmlattr>.link2"); + + // Check first if the two bodies exist in model + if (!model.existBodyName(link1) || !model.existBodyName(link2)) + { + if (verbose) + std::cout << "It seems that " << link1 << " or " << link2 << " do not exist in model. Skip." << std::endl; + continue; + } + + const Model::JointIndex frame_id1 = model.getBodyId(link1); + const Model::JointIndex frame_id2 = model.getBodyId(link2); + + // Malformed SRDF + if (frame_id1 == frame_id2) + { + if (verbose) + std::cout << "Cannot disable collision between " << link1 << " and " << link2 << std::endl; + continue; + } + + typedef std::vector<CollisionPair> CollisionPairs_t; + bool didRemove = false; + for(CollisionPairs_t::iterator _colPair = geomModel.collisionPairs.begin(); + _colPair != geomModel.collisionPairs.end(); ) { + const CollisionPair& colPair (*_colPair); + bool remove = + ( + (geomModel.geometryObjects[colPair.first ].parentFrame == frame_id1) + && (geomModel.geometryObjects[colPair.second].parentFrame == frame_id2) + ) || ( + (geomModel.geometryObjects[colPair.second].parentFrame == frame_id1) + && (geomModel.geometryObjects[colPair.first ].parentFrame == frame_id2) + ); + + if (remove) { + _colPair = geomModel.collisionPairs.erase(_colPair); + didRemove = true; + } else { + ++_colPair; + } + } + if(didRemove && verbose) + std::cout << "Remove collision pair (" << link1 << "," << link2 << ")" << std::endl; + + } + } // BOOST_FOREACH + } + } // namespace details + + void removeCollisionPairsFromSrdf(const Model& model, + GeometryModel & geomModel, + const std::string & filename, + const bool verbose) throw (std::invalid_argument) + { + // Check extension + const std::string extension = filename.substr(filename.find_last_of('.')+1); + if (extension != "srdf") + { + const std::string exception_message (filename + " does not have the right extension."); + throw std::invalid_argument(exception_message); + } + + // Open file + std::ifstream srdf_stream(filename.c_str()); + if (! srdf_stream.is_open()) + { + const std::string exception_message (filename + " does not seem to be a valid file."); + throw std::invalid_argument(exception_message); + } + + details::removeCollisionPairs(model, geomModel, srdf_stream, verbose); + } + + void removeCollisionPairsFromSrdfString( + const Model& model, + GeometryModel & geomModel, + const std::string & xmlString, + const bool verbose) + { + std::istringstream srdf_stream(xmlString); + details::removeCollisionPairs(model, geomModel, srdf_stream, verbose); + } + +#endif // ifdef WITH_HPP_FCL + + Eigen::VectorXd getNeutralConfigurationFromSrdf(Model & model, + const std::string & filename, + const bool verbose) throw (std::invalid_argument) + { + // Check extension + const std::string extension = filename.substr(filename.find_last_of('.')+1); + if (extension != "srdf") + { + const std::string exception_message (filename + " does not have the right extension."); + throw std::invalid_argument(exception_message); + } + + // Open file + std::ifstream srdf_stream(filename.c_str()); + if (! srdf_stream.is_open()) + { + const std::string exception_message (filename + " does not seem to be a valid file."); + throw std::invalid_argument(exception_message); + } + + // Read xml stream + using boost::property_tree::ptree; + ptree pt; + read_xml(srdf_stream, pt); + + // Iterate over all tags directly children of robot + BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot")) + { + // if we encounter a tag group_state + if (v.first == "group_state") + { + const std::string name = v.second.get<std::string>("<xmlattr>.name"); + // Ensure that it is the half_sitting tag + if( name == "half_sitting") + { + // Iterate over all the joint tags + BOOST_FOREACH(const ptree::value_type & joint, v.second) + { + if (joint.first == "joint") + { + std::string joint_name = joint.second.get<std::string>("<xmlattr>.name"); + double joint_config = joint.second.get<double>("<xmlattr>.value"); + if (verbose) + { + std::cout << "(" << joint_name << " , " << joint_config << ")" << std::endl; + } + // Search in model the joint and its config id + Model::JointIndex joint_id = model.getJointId(joint_name); + + if (joint_id != model.joints.size()) // != model.njoints + { + const JointModel & joint = model.joints[joint_id]; + model.neutralConfiguration(joint.idx_q()) = joint_config; // joint with 1 dof + // model.neutralConfiguration.segment(joint.idx_q(),joint.nq()) = joint_config; // joint with more than 1 dof + } + else + { + if (verbose) std::cout << "The Joint " << joint_name << " was not found in model" << std::endl; + } + } + } + return model.neutralConfiguration; + } + + } + } // BOOST_FOREACH + assert(false && "no half_sitting configuration found in the srdf file"); // Should we throw something here ? + return Eigen::VectorXd::Constant(model.nq,NAN); // warning : uninitialized vector is returned + } + } +} // namespace se3 + +#endif // ifndef __se3_parser_srdf_hxx__ diff --git a/src/parsers/srdf.hpp b/src/parsers/srdf.hpp index 34b2af4fc..51a3d2426 100644 --- a/src/parsers/srdf.hpp +++ b/src/parsers/srdf.hpp @@ -20,13 +20,6 @@ #include "pinocchio/multibody/model.hpp" #include "pinocchio/multibody/geometry.hpp" -#include <iostream> - -// Read XML file with boost -#include <boost/property_tree/xml_parser.hpp> -#include <boost/property_tree/ptree.hpp> -#include <fstream> -#include <boost/foreach.hpp> namespace se3 @@ -45,86 +38,23 @@ namespace se3 /// \param[in] filename The complete path to the SRDF file. /// \param[in] verbose Verbosity mode (print removed collision pairs and undefined link inside the model). /// - inline void removeCollisionPairsFromSrdf(const Model& model, - GeometryModel & geomModel, - const std::string & filename, - const bool verbose = false) throw (std::invalid_argument) - { - // Check extension - const std::string extension = filename.substr(filename.find_last_of('.')+1); - if (extension != "srdf") - { - const std::string exception_message (filename + " does not have the right extension."); - throw std::invalid_argument(exception_message); - } - - // Open file - std::ifstream srdf_stream(filename.c_str()); - if (! srdf_stream.is_open()) - { - const std::string exception_message (filename + " does not seem to be a valid file."); - throw std::invalid_argument(exception_message); - } - - // Read xml stream - using boost::property_tree::ptree; - ptree pt; - read_xml(srdf_stream, pt); - - // Iterate over collision pairs - BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot")) - { - if (v.first == "disable_collisions") - { - const std::string link1 = v.second.get<std::string>("<xmlattr>.link1"); - const std::string link2 = v.second.get<std::string>("<xmlattr>.link2"); - - // Check first if the two bodies exist in model - if (!model.existBodyName(link1) || !model.existBodyName(link2)) - { - if (verbose) - std::cout << "It seems that " << link1 << " or " << link2 << " do not exist in model. Skip." << std::endl; - continue; - } - - const Model::JointIndex frame_id1 = model.getBodyId(link1); - const Model::JointIndex frame_id2 = model.getBodyId(link2); - - // Malformed SRDF - if (frame_id1 == frame_id2) - { - if (verbose) - std::cout << "Cannot disable collision between " << link1 << " and " << link2 << std::endl; - continue; - } - - typedef std::vector<CollisionPair> CollisionPairs_t; - bool didRemove = false; - for(CollisionPairs_t::iterator _colPair = geomModel.collisionPairs.begin(); - _colPair != geomModel.collisionPairs.end(); ) { - const CollisionPair& colPair (*_colPair); - bool remove = - ( - (geomModel.geometryObjects[colPair.first ].parentFrame == frame_id1) - && (geomModel.geometryObjects[colPair.second].parentFrame == frame_id2) - ) || ( - (geomModel.geometryObjects[colPair.second].parentFrame == frame_id1) - && (geomModel.geometryObjects[colPair.first ].parentFrame == frame_id2) - ); - - if (remove) { - _colPair = geomModel.collisionPairs.erase(_colPair); - didRemove = true; - } else { - ++_colPair; - } - } - if(didRemove && verbose) - std::cout << "Remove collision pair (" << link1 << "," << link2 << ")" << std::endl; - - } - } // BOOST_FOREACH - } + void removeCollisionPairsFromSrdf(const Model& model, + GeometryModel & geomModel, + const std::string & filename, + const bool verbose = false) throw (std::invalid_argument); + /// + /// \brief Deactive all possible collision pairs mentioned in the SRDF file. + /// + /// \param[in] model Model of the kinematic tree. + /// \param[in] geomModel Model of the geometries. + /// \param[out] data_geom Data containing the active collision pairs. + /// \param[in] xmlString the SRDF string. + /// \param[in] verbose Verbosity mode (print removed collision pairs and undefined link inside the model). + /// + void removeCollisionPairsFromSrdfString(const Model& model, + GeometryModel & geomModel, + const std::string & xmlString, + const bool verbose = false); #endif // ifdef WITH_HPP_FCL @@ -138,75 +68,9 @@ namespace se3 /// \param[in] verbose Verbosity mode. /// /// \return The neutral configuration as an eigen vector - inline Eigen::VectorXd getNeutralConfigurationFromSrdf(Model & model, - const std::string & filename, - const bool verbose = false) throw (std::invalid_argument) - { - // Check extension - const std::string extension = filename.substr(filename.find_last_of('.')+1); - if (extension != "srdf") - { - const std::string exception_message (filename + " does not have the right extension."); - throw std::invalid_argument(exception_message); - } - - // Open file - std::ifstream srdf_stream(filename.c_str()); - if (! srdf_stream.is_open()) - { - const std::string exception_message (filename + " does not seem to be a valid file."); - throw std::invalid_argument(exception_message); - } - - // Read xml stream - using boost::property_tree::ptree; - ptree pt; - read_xml(srdf_stream, pt); - - // Iterate over all tags directly children of robot - BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot")) - { - // if we encounter a tag group_state - if (v.first == "group_state") - { - const std::string name = v.second.get<std::string>("<xmlattr>.name"); - // Ensure that it is the half_sitting tag - if( name == "half_sitting") - { - // Iterate over all the joint tags - BOOST_FOREACH(const ptree::value_type & joint, v.second) - { - if (joint.first == "joint") - { - std::string joint_name = joint.second.get<std::string>("<xmlattr>.name"); - double joint_config = joint.second.get<double>("<xmlattr>.value"); - if (verbose) - { - std::cout << "(" << joint_name << " , " << joint_config << ")" << std::endl; - } - // Search in model the joint and its config id - Model::JointIndex joint_id = model.getJointId(joint_name); - - if (joint_id != model.joints.size()) // != model.njoints - { - const JointModel & joint = model.joints[joint_id]; - model.neutralConfiguration(joint.idx_q()) = joint_config; // joint with 1 dof - // model.neutralConfiguration.segment(joint.idx_q(),joint.nq()) = joint_config; // joint with more than 1 dof - } - else - { - if (verbose) std::cout << "The Joint " << joint_name << " was not found in model" << std::endl; - } - } - } - return model.neutralConfiguration; - } - - } - } // BOOST_FOREACH - assert(false && "no half_sitting configuration found in the srdf file"); // Should we throw something here ? - return Eigen::VectorXd::Constant(model.nq,NAN); // warning : uninitialized vector is returned - } + Eigen::VectorXd getNeutralConfigurationFromSrdf(Model & model, + const std::string & filename, + const bool verbose = false) throw (std::invalid_argument); } } // namespace se3 -- GitLab