LCOV - code coverage report
Current view: top level - src - Parser.cpp (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 118 170 69.4 %
Date: 2022-06-06 13:34:00 Functions: 15 22 68.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2019 IIT-HHCM
       3             :  * Author: Luca Muratore
       4             :  * email:  luca.muratore@iit.it
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  * http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             : */
      17             : 
      18             : #include <end_effector/Parser.h>
      19             : 
      20             : #define CHAIN_PER_GROUP 1
      21             : 
      22          72 : ROSEE::Parser::Parser ( const rclcpp::Node::SharedPtr node ) :
      23          72 :     _node ( node ) {
      24             : 
      25          72 : }
      26             : 
      27             : 
      28          72 : ROSEE::Parser::~Parser() {
      29             : 
      30          72 : }
      31             : 
      32         190 : bool ROSEE::Parser::getJointsInFinger ( std::string base_link,
      33             :                                         std::string tip_link,
      34             :                                         std::string finger_name
      35             :                                       ) {
      36             : 
      37             :     //we add here the finger to the map because later is added only if the joint is actuated.
      38             :     //Instead we want in the map all the fingers, even if they have no actuated joint in.
      39             :     //this is necessary to not cause later problem due to have the right number of finger
      40         190 :     _finger_joint_map.insert(std::make_pair(finger_name, std::vector<std::string>())); 
      41             :     
      42             :     
      43         380 :     KDL::Chain actual_chain;
      44         190 :     if ( _robot_tree.getChain ( base_link, tip_link, actual_chain ) ) {
      45             : 
      46         190 :         int segments_num = actual_chain.getNrOfSegments();
      47         609 :         for ( int i = 0; i < segments_num; i++ ) {
      48             : 
      49         838 :             KDL::Segment actual_segment = actual_chain.getSegment ( i );
      50         838 :             KDL::Joint actual_joint = actual_segment.getJoint();
      51             : 
      52         419 :             bool is_valid_joint = false;
      53             : 
      54             :             // Check if joint is revolute or prismatic
      55         419 :             is_valid_joint = actual_joint.getTypeName() == "RotAxis";   
      56             :             
      57             : //                              || actual_joint.getTypeName() == "TransAxis";
      58             :             
      59         838 :             auto urdf_joint = _urdf_model->getJoint(actual_joint.getName());
      60         419 :             bool is_mimic_joint = (urdf_joint->mimic == nullptr) ? false : true;
      61             :             
      62             : 
      63             :             // if the joint is revolute or prismatic AND not a mimic (mimic joint is a not actuated joint)
      64         419 :             if ( is_valid_joint && (!is_mimic_joint) ) {
      65             : 
      66         380 :                 _finger_joint_map[finger_name].push_back ( actual_joint.getName() );
      67         380 :                 _joint_finger_map[actual_joint.getName()] = finger_name;
      68         380 :                 _urdf_joint_map[actual_joint.getName()] = _urdf_model->getJoint ( actual_joint.getName() );
      69             : 
      70         380 :                 _joints_num++;
      71             : 
      72             :             }
      73             :         }
      74             : 
      75         190 :         return true;
      76             :     }
      77             : 
      78           0 :     RCLCPP_ERROR_STREAM (_node->get_logger(), "chain from base_link " << base_link << " to tip_link " << tip_link << " not found in the URDF" );
      79             : 
      80           0 :     return false;
      81             : }
      82             : 
      83             : 
      84             : 
      85          72 : bool ROSEE::Parser::parseSRDF() {
      86             : 
      87             :     // initialize srdfdom
      88          72 :     _srdfdom.initFile ( *_urdf_model, _srdf_path );
      89             : 
      90             :     // get the end-effectors in the SRDF file
      91         144 :     std::vector<srdf::Model::EndEffector> srdf_end_effectors = _srdfdom.getEndEffectors();
      92             : 
      93             :     // NOTE only one end-effectors supported
      94             :     // TBD support multiple end-effectors
      95          72 :     if ( srdf_end_effectors.size() != 1 ) {
      96             : 
      97           0 :         return false;
      98             :     }
      99             : 
     100          72 :     RCLCPP_INFO_STREAM (_node->get_logger(), "ros_end_effector Parser found end_effector: " << srdf_end_effectors.at ( 0 ).name_ );
     101             : 
     102             :     // get all the groups in the SRDF
     103         144 :     std::vector<srdf::Model::Group> srdf_groups = _srdfdom.getGroups();
     104             : 
     105             :     // TBD will be a vector
     106         144 :     srdf::Model::Group fingers_group;
     107             :     // find end effector fingers chains group
     108             :     // TBD will be a vector
     109          72 :     int group_num = srdf_groups.size();
     110             :     // TBD will be a vector
     111         144 :     std::string end_effector_group_name = srdf_end_effectors.at ( 0 ).component_group_;
     112         334 :     for ( int i = 0; i < group_num; i++ ) {
     113         262 :         if ( srdf_groups[i].name_ == end_effector_group_name ) {
     114          72 :             fingers_group = srdf_groups[i];
     115          72 :             RCLCPP_INFO_STREAM (_node->get_logger(), "ros_end_effector Parser found group: " << end_effector_group_name << " in the SRDF with the following fingers: " );
     116             :         }
     117             :     }
     118             : 
     119          72 :     _fingers_num = fingers_group.subgroups_.size();
     120          72 :     _fingers_names.resize ( _fingers_num );
     121          72 :     _fingers_group_id.resize ( _fingers_num );
     122             : 
     123             :     // fill the chain names vector
     124         262 :     for ( int i = 0; i < _fingers_num; i++ ) {
     125             : 
     126         190 :         _fingers_names[i] = fingers_group.subgroups_[i];
     127             : 
     128             :         // find the id of the current finger group
     129         898 :         for ( int j = 0; j < group_num; j++ ) {
     130         708 :             if ( srdf_groups[j].name_ == _fingers_names[i] ) {
     131         190 :                 _fingers_group_id[i] = j;
     132             :             }
     133             :         }
     134         190 :         RCLCPP_INFO_STREAM (_node->get_logger(), _fingers_names[i] );
     135             :     }
     136             : 
     137             :     // iterate over the fingers and find revolute joints
     138         262 :     for ( int i = 0; i < _fingers_num; i++ ) {
     139         190 :         srdf::Model::Group current_finger_group = srdf_groups[ _fingers_group_id[i] ];
     140             : 
     141             :         // NOTE only one chain per group
     142         190 :         if ( current_finger_group.chains_.size() != CHAIN_PER_GROUP )  {
     143             : 
     144           0 :             RCLCPP_ERROR_STREAM (_node->get_logger(), "for the finger chain groups you can specify only one chain per group in your SRDF check " << 
     145             :                                current_finger_group.name_.c_str() << " group" );
     146           0 :             return false;
     147             :         }
     148             : 
     149             :         // fill the enabled/disabled joints in chain map
     150         380 :         if ( !getJointsInFinger ( current_finger_group.chains_[0].first,
     151         190 :                                   current_finger_group.chains_[0].second,
     152             :                                   current_finger_group.name_
     153             :                                 ) ) {
     154           0 :             return false;
     155             :         }
     156             :     }
     157             :     
     158          72 :     addNotInFingerJoints();
     159             :     
     160          72 :     removePassiveJoints();
     161             : 
     162             :     // save srdf as string 
     163         144 :     std::ifstream t_srdf ( _srdf_path );
     164          72 :     std::stringstream buffer_srdf;
     165          72 :     buffer_srdf << t_srdf.rdbuf();
     166          72 :     _srdf_string = buffer_srdf.str();
     167             :     
     168          72 :     return true;
     169             : 
     170             : }
     171             : 
     172          72 : void ROSEE::Parser::addNotInFingerJoints() {
     173             :     
     174         635 :     for (auto it : _urdf_model->joints_) { //this contains all joints
     175             :         
     176         563 :         if (it.second->mimic == nullptr) { //not a mimic joint...
     177             :         
     178        1048 :             if (it.second->type == urdf::Joint::CONTINUOUS ||
     179         524 :                 it.second->type == urdf::Joint::REVOLUTE ) {
     180             :                 //it.second->type == urdf::Joint::PRISMATIC
     181             :             
     182         380 :                 if (_urdf_joint_map.find(it.second->name) == _urdf_joint_map.end() ) {
     183             :                     
     184           0 :                     _urdf_joint_map.insert(std::make_pair(it.second->name, it.second));
     185           0 :                     _finger_joint_map["virtual_finger"].push_back ( it.second->name );
     186           0 :                     _joint_finger_map[it.second->name] = "virtual_finger";
     187           0 :                     _joints_num++;
     188             :                 }
     189             :             }
     190             :         }
     191             :         
     192             :     }
     193             :     
     194          72 : }
     195             : 
     196          72 : bool ROSEE::Parser::removePassiveJoints() {
     197             :     
     198          72 :     std::vector<srdf::Model::PassiveJoint> passiveJointList = _srdfdom.getPassiveJoints();
     199             :     
     200          72 :     for (auto passiveJoint : passiveJointList) {
     201             :         //the passive can be also already deleted so we chech if we delete it(e.g. it is also mimic)
     202           0 :         if (_urdf_joint_map.erase(passiveJoint.name_) > 0) {
     203             :             
     204             :             //we have also to remove it from the other maps
     205           0 :             std::string fingerOfPassive = _joint_finger_map.at(passiveJoint.name_);
     206           0 :             _joint_finger_map.erase(passiveJoint.name_);
     207             :             
     208           0 :             for (auto it = _finger_joint_map.at(fingerOfPassive).begin(); 
     209           0 :                  it!= _finger_joint_map.at(fingerOfPassive).end(); ++it){
     210             :                 
     211           0 :                 if (it->compare(passiveJoint.name_) == 0 ) {
     212           0 :                     _finger_joint_map.at(fingerOfPassive).erase(it);
     213           0 :                     break;
     214             :                 }
     215             :             }
     216             : 
     217           0 :             _joints_num--;
     218             :         }   
     219             :     }
     220             : 
     221         144 :     return true;
     222             : }
     223             : 
     224             : 
     225          72 : bool ROSEE::Parser::parseURDF() {
     226             : 
     227         144 :     std::string xml_string;
     228         144 :     std::fstream xml_file ( _urdf_path.c_str(), std::fstream::in );
     229          72 :     if ( xml_file.is_open() ) {
     230             : 
     231       18085 :         while ( xml_file.good() ) {
     232             : 
     233       18013 :             std::string line;
     234       18013 :             std::getline ( xml_file, line );
     235       18013 :             xml_string += ( line + "\n" );
     236             :         }
     237             : 
     238          72 :         xml_file.close();
     239          72 :         _urdf_model = urdf::parseURDF ( xml_string );
     240             : 
     241             :         // create the robot KDL tree from the URDF model
     242          72 :         if ( !kdl_parser::treeFromUrdfModel ( *_urdf_model, _robot_tree ) ) {
     243             : 
     244           0 :             RCLCPP_ERROR_STREAM (_node->get_logger(), "in " << __func__ << " Failed to construct kdl tree" );
     245           0 :             return false;
     246             :         }
     247             : 
     248             :         // save urdf and string (can be useful to have, thanks @alaurenzi!)
     249         144 :         std::ifstream t_urdf ( _urdf_path );
     250          72 :         std::stringstream buffer_urdf;
     251          72 :         buffer_urdf << t_urdf.rdbuf();
     252          72 :         _urdf_string = buffer_urdf.str();
     253             : 
     254          72 :         return true;
     255             : 
     256             :     } else {
     257             : 
     258           0 :         RCLCPP_ERROR_STREAM (_node->get_logger(), "in " << __func__ << " : Can NOT open " << _urdf_path << " !" );
     259           0 :         return false;
     260             :     }
     261             : }
     262             : 
     263             : 
     264          72 : bool ROSEE::Parser::configure() {
     265             : 
     266          72 :     bool ret = true;
     267             : 
     268          72 :     if ( parseURDF() ) {
     269             :         
     270          72 :         if ( parseSRDF() ) {
     271             :             
     272          72 :             RCLCPP_INFO_STREAM (_node->get_logger(), "ROSEndEffector Parser successfully configured using urdf file:  " << _urdf_path 
     273             :                 << "\n\t srdf file: " << _srdf_path << "\n\t actions folder " << _action_path
     274             :             );
     275             :         
     276             :         } else {
     277             :         
     278           0 :             RCLCPP_ERROR_STREAM (_node->get_logger(), "ROSEndEffector Parser error while parsing SRDF");
     279           0 :             ret = false;
     280             :         }
     281             :         
     282             :     } else {
     283             :         
     284           0 :         RCLCPP_ERROR_STREAM (_node->get_logger(), "ROSEndEffector Parser error while parsing URDF");
     285           0 :         ret = false;
     286             :     }
     287             : 
     288             : 
     289             : 
     290             : 
     291          72 :     return ret;
     292             : }
     293             : 
     294             : 
     295             : 
     296           0 : bool ROSEE::Parser::init() {
     297             :     
     298             :     // in ROS2, param must be declare first to be find
     299           0 :     _node->declare_parameter ( "urdf_path", "" );
     300           0 :     _node->declare_parameter ( "srdf_path", "" );
     301           0 :     _node->declare_parameter ( "actions_folder_path", "" );
     302             : 
     303           0 :     if ( _node->get_parameter ( "urdf_path", _urdf_path ) && 
     304           0 :          _node->get_parameter ( "srdf_path", _srdf_path ) &&
     305           0 :          _node->get_parameter ( "actions_folder_path", _action_path )
     306             :     ) {
     307             : 
     308             :         //_action_path = std::string(getenv("HOME")) + "/" + _action_path;
     309             :         
     310           0 :         _is_initialized =  configure();
     311           0 :         return _is_initialized;
     312             :     }
     313             : 
     314             :     // error
     315           0 :     RCLCPP_ERROR_STREAM (_node->get_logger(), "in " << __func__ << " : '_urdf_path' and/or '_srdf_path' and/or 'actions_folder_path' not found on ROS parameter server" );
     316           0 :     return false;
     317             : 
     318             : }
     319             : 
     320             : 
     321          72 : bool ROSEE::Parser::init ( const std::string& urdf_path, const std::string& srdf_path, const std::string& action_path ) {
     322             : 
     323          72 :     _urdf_path = urdf_path;
     324          72 :     _srdf_path = srdf_path;
     325          72 :     _action_path = action_path;
     326             : 
     327          72 :     _is_initialized =  configure();
     328          72 :     return _is_initialized;
     329             : }
     330             : 
     331             : 
     332          20 : void ROSEE::Parser::printEndEffectorFingerJointsMap() const {
     333             : 
     334          20 :     if ( _is_initialized ) {
     335             : 
     336          20 :         RCLCPP_INFO_STREAM (_node->get_logger(), "ROS End Effector: Finger Joints Map" );
     337          20 :         RCLCPP_INFO_STREAM (_node->get_logger(), "-------------------------" );
     338          80 :         for ( auto& chain_joints: _finger_joint_map ) {
     339          60 :             RCLCPP_INFO_STREAM (_node->get_logger(), chain_joints.first );
     340             : 
     341          60 :             int nJointInFinger = chain_joints.second.size();
     342             :             
     343          60 :             if ( nJointInFinger == 0 ) {
     344             :                 
     345           0 :                 RCLCPP_INFO_STREAM (_node->get_logger(), "No actuated joint in this finger" );
     346             :                 
     347             :             } else {
     348             :                 
     349         180 :                 for ( int i = 0; i < nJointInFinger ; i++ ) {
     350         120 :                     RCLCPP_INFO_STREAM (_node->get_logger(), chain_joints.second.at ( i ) );
     351             :                 }
     352             :             }
     353             : 
     354          60 :             RCLCPP_INFO_STREAM (_node->get_logger(), "-------------------------" );
     355             :         }
     356             :     } else {
     357             : 
     358           0 :         RCLCPP_ERROR_STREAM (_node->get_logger(), "in " << __func__ << " :  ROSEE::Parser needs to be initialized. Call init() frist." );
     359             :     }
     360          20 : }
     361             : 
     362          72 : int ROSEE::Parser::getActuatedJointsNumber() const {
     363             :     
     364          72 :     return _joints_num;
     365             : }
     366             : 
     367          72 : std::map< std::string, std::vector< std::string >> ROSEE::Parser::getFingerJointMap() const {
     368             : 
     369          72 :     return _finger_joint_map;
     370             : }
     371             : 
     372           0 : std::map< std::string, std::string > ROSEE::Parser::getJointFingerMap() const {
     373             :     
     374           0 :     return _joint_finger_map;
     375             : }
     376             : 
     377          72 : std::map< std::string, urdf::JointConstSharedPtr > ROSEE::Parser::getUrdfJointMap() const {
     378             : 
     379          72 :     return _urdf_joint_map;
     380             : }
     381             : 
     382           0 : void ROSEE::Parser::getFingerJointMap( std::map< std::string, std::vector< std::string >>& finger_joint_map ) const {
     383             : 
     384           0 :     finger_joint_map = _finger_joint_map;
     385           0 : }
     386             : 
     387           0 : void ROSEE::Parser::getJointFingerMap ( std::map< std::string, std::string >& joint_finger_map ) const {
     388             : 
     389           0 :     joint_finger_map = _joint_finger_map;
     390           0 : }
     391             : 
     392          72 : std::string ROSEE::Parser::getEndEffectorName() const {
     393             : 
     394          72 :     return _urdf_model->getName();
     395             : }
     396             : 
     397           0 : std::string ROSEE::Parser::getUrdfString() const {
     398           0 :     return _urdf_string;
     399             : }
     400             : 
     401           0 : std::string ROSEE::Parser::getSrdfString() const {
     402           0 :     return _srdf_string;
     403             : }
     404             : 
     405             : 
     406          52 : std::string ROSEE::Parser::getActionPath() const {
     407          52 :     return _action_path;
     408             : }
     409             : 
     410             : 
     411             : 
     412             : 

Generated by: LCOV version 1.14