LCOV - code coverage report
Current view: top level - include/ros_end_effector - Utils.h (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 98 135 72.6 %
Date: 2021-10-05 16:55:17 Functions: 29 38 76.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2019 IIT-HHCM
       3             :  * Author: Arturo Laurenzi
       4             :  * email:  arturo.laurenzi@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             : #ifndef __ROSEE_UTILS__
      19             : #define __ROSEE_UTILS__
      20             : 
      21             : #include <cmath>
      22             : #include <memory>
      23             : #include <iostream>
      24             : #include <dlfcn.h>
      25             : 
      26             : //to find relative path for the config files and create directories
      27             : #include <boost/filesystem.hpp>
      28             : #include <fstream>
      29             : 
      30             : #include <chrono>
      31             : #include <atomic>
      32             : 
      33             : namespace ROSEE
      34             : {
      35             : 
      36             : namespace Utils
      37             : {
      38             :     
      39         192 : static bool create_directory(std::string pathDirectory){
      40         384 :     boost::filesystem::path path(pathDirectory);
      41         384 :     return boost::filesystem::create_directories(path);
      42             : }
      43             : 
      44         192 : static void out2file ( std::string pathFile, std::string output) {
      45         384 :     std::ofstream fout ( pathFile );
      46         192 :     fout << output;
      47         192 : }
      48             : 
      49             : // static std::string get_environment_variable( std::string const & key )
      50             : // {
      51             : //     char * val = getenv( key.c_str() );
      52             : //     return val == NULL ? std::string("") : std::string(val);
      53             : // }
      54             : 
      55         123 : static std::vector <std::string> getFilesInDir ( std::string pathFolder ) {
      56             :     
      57         246 :     boost::filesystem::path p (pathFolder);
      58         123 :     std::vector <std::string> retVect;
      59             :     
      60         123 :     if (! boost::filesystem::exists(p) ) {
      61           0 :         std::cerr << "[ERROR " << __func__ << "] path '" << pathFolder << "' does not exists" << std::endl;
      62           0 :         return retVect;
      63             :     }
      64             :     
      65         123 :     if (! boost::filesystem::is_directory(p)){ 
      66           0 :         std::cerr << "[ERROR " << __func__ << "] path '" << pathFolder << "' is not a directory" << std::endl;
      67           0 :         return retVect;
      68             :     }
      69             :     
      70         638 :     for (boost::filesystem::directory_entry& x : boost::filesystem::directory_iterator(p)) {
      71         515 :         retVect.push_back (x.path().filename().string() );
      72             :     }
      73             :     
      74         123 :     return retVect;
      75             : }
      76             :     
      77          10 : static inline int binomial_coefficent(int n, int k) {
      78             : 
      79          10 :     if (k == 0 || k == n){
      80           6 :         return 1;
      81             :     }
      82           4 :     return Utils::binomial_coefficent(n - 1, k - 1) + Utils::binomial_coefficent(n - 1, k);
      83             :     
      84             : }
      85             :     
      86             :     
      87         551 : static std::string getPackagePath() {
      88             :     
      89        1102 :     boost::filesystem::path path(__FILE__);
      90         551 :     path.remove_filename();
      91        1102 :     return path.string() + "/../../";
      92             : }
      93             : 
      94             : template <class KeyType, class ValueType>
      95          14 : static std::vector<KeyType> extract_keys(std::map<KeyType, ValueType> const& input_map) {
      96          14 :   std::vector<KeyType> retval;
      97          45 :   for (auto const& element : input_map) {
      98          31 :     retval.push_back(element.first);
      99             :   }
     100          14 :   return retval;
     101             : }
     102             : 
     103             : /** 
     104             :  * @brief Extract all the string in the set keys of a map. All string are put togheter so
     105             :  * the original meaning of each set is lost
     106             :  * @param input_map the map where extract the keys
     107             :  * @param max_string_number the max number of different string among all the set keys. 
     108             :  *      Useful to not iterate all the map if not necessary. With default value = 0 all 
     109             :  *      map is iterated.
     110             :  * @return vector of extracted string of set keys (string in this vect will be unique)
     111             :  */
     112             : template <class T>
     113           0 : static std::vector<std::string> extract_keys_merged(
     114             :     std::map<std::set<std::string>, T> const& input_map, unsigned int max_string_number = 0) {
     115             :     
     116           0 :     std::set<std::string> allStrings;
     117             :     // if else so we do not check in the for the max_string_number if it is not used (ie ==0)
     118             : 
     119           0 :     if (max_string_number == 0) {
     120           0 :         for (auto const& element : input_map) {
     121           0 :             allStrings.insert( element.first.begin(), element.first.end() );
     122             :         }
     123             :             
     124             :     } else {
     125           0 :         for (auto const& element : input_map) {
     126           0 :             allStrings.insert(element.first.begin(), element.first.end());
     127           0 :             if (max_string_number == allStrings.size()){
     128           0 :                 break;
     129             :             }
     130           0 :             if (max_string_number < allStrings.size() ) {
     131           0 :                 std::cerr << "[ERROR]" << __func__ << " You passed " << max_string_number
     132           0 :                 << " but I found more unique strings in the set keys ( " << allStrings.size()
     133           0 :                 << " found)" << std::endl;
     134           0 :                 return std::vector<std::string>();
     135             :             }
     136             :         }
     137             :     }
     138           0 :     std::vector<std::string> retval (allStrings.begin(), allStrings.end());
     139           0 :     return retval;
     140             : }
     141             : 
     142             : /**
     143             :  * @brief See above, this is the version with pair instead of set
     144             :  */
     145             : template <class T>
     146             : static std::vector<std::string> extract_keys_merged(
     147             :     std::map<std::pair<std::string,std::string>, T> const& input_map, unsigned int max_string_number = 0) {
     148             :     
     149             :     std::set<std::string> allStrings;
     150             :     // if else so we do not check in the for the max_string_number if it is not used (ie ==0)
     151             : 
     152             :     if (max_string_number == 0) {
     153             :         for (auto const& element : input_map) {
     154             :             allStrings.insert( element.first.first);
     155             :             allStrings.insert( element.first.second);
     156             :         }
     157             :             
     158             :     } else {
     159             :         for (auto const& element : input_map) {
     160             :             allStrings.insert( element.first.first);
     161             :             allStrings.insert( element.first.second);
     162             :             if (max_string_number == allStrings.size()){
     163             :                 break;
     164             :             }
     165             :             if (max_string_number < allStrings.size() ) {
     166             :                 std::cerr << "[ERROR]" << __func__ << " You passed " << max_string_number
     167             :                 << " but I found more unique strings in the pair keys ( " << allStrings.size()
     168             :                 << " found)" << std::endl;
     169             :                 return std::vector<std::string>();
     170             :             }
     171             :         }
     172             :     }
     173             :     std::vector<std::string> retval (allStrings.begin(), allStrings.end());
     174             :     return retval;
     175             : }
     176             : 
     177             : /** @brief Return false if two maps have different keys. 
     178             :  * The type of the keys (@p typename) must be the same obviously,
     179             :  * but the values (@p valueType1 and @p valueType2) can be anything, because they are not considered
     180             : */
     181             : template <typename keyType, typename valueType1, typename valueType2>
     182         296 : bool keys_equal (std::map <keyType, valueType1> const &lhs, std::map<keyType, valueType2> const &rhs) {
     183             : 
     184        1266 :     auto pred = [] (decltype(*lhs.begin()) a, decltype(*rhs.begin()) b)
     185        1266 :                    { return (a.first == b.first); };
     186             : 
     187             : 
     188         296 :     return lhs.size() == rhs.size()
     189         296 :         && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
     190             : }
     191             : 
     192             : template <typename Map1, typename Map2>
     193          12 : struct DifferentKeysException : public std::exception {
     194             :     const Map1 *map1;
     195             :     const Map2 *map2;
     196             :     
     197           4 :     DifferentKeysException(const Map1 *map1, const Map2 *map2) :
     198           4 :         map1(map1), map2(map2) {}
     199             :         
     200           0 :     const char * what () const throw () {
     201           0 :         std::stringstream output;
     202           0 :         output << "First map keys:\n";
     203           0 :         for (auto it : *map1) {
     204           0 :             output << "\t" << it.first << "\n";
     205             :         }
     206           0 :         output << ("Second map keys:\n");
     207           0 :         for (auto it : *map2) {
     208           0 :             output << "\t" << it.first << "\n";
     209             :         }
     210           0 :         std::cerr << output.str().c_str() << std::endl;
     211             : 
     212           0 :         return "Maps have different keys";
     213             :     }
     214             : };
     215             : 
     216             : /**
     217             :  * @brief Utils to dynamically load an object. This is used to dynamically load 
     218             :  *  a derived object from a node that only knows the base interface. 
     219             :  *  For example, we call the create_object(ros::nodeHandle) method of a derived EEHAL class
     220             :  *  The object must be a library which will return a RetType pointer with the \p function_name
     221             :  *  This function will "convert" to smart pointer for convenience
     222             :  * @param lib_name the name of the compiled library (eg DummyHal). Do not add the suffix .so
     223             :  * @param function_name The method of \param lib_name which will return a RetType*. 
     224             :  * @param args arguments for the \p function_name , if the case
     225             :  * @return std::shared_ptr<RetType> a pointer to the new created object
     226             :  */
     227             : template <typename RetType, typename... Args>
     228          41 : std::unique_ptr<RetType> loadObject(std::string lib_name, 
     229             :                                     std::string function_name,
     230             :                                     Args... args) {
     231             :     
     232          41 :     if (lib_name.empty()) {
     233             :         
     234           0 :         std::cerr << "[Utils::loadObject] ERROR: Please specify lib_name" << std::endl;
     235           0 :         return nullptr;
     236             :     } 
     237             :     
     238          82 :     std::string lib_name_path = "lib" + lib_name +".so"; 
     239             : 
     240             :     //clear old errors
     241          41 :     dlerror();
     242             : 
     243          41 :     void* lib_handle = dlopen(lib_name_path.c_str(), RTLD_LAZY);
     244          41 :     auto error = dlerror();
     245             : 
     246          41 :     if (!lib_handle || error != NULL) {
     247           0 :         std::cerr << "[Utils::loadObject] ERROR in opening the library: " << error << std::endl;
     248           0 :         return nullptr;
     249             :     }
     250             :     
     251             :     //clear old errors
     252          41 :     dlerror();
     253             :     
     254             :     RetType* (*function)(Args... args);
     255          41 :     function = reinterpret_cast<RetType* (*)(Args... args)>(dlsym(lib_handle, function_name.c_str()));
     256          41 :     error = dlerror();
     257          41 :     if ( error != NULL)  {
     258           0 :         std::cerr << "[Utils::loadObject] ERROR in returning the function: " << error << std::endl;
     259           0 :         return nullptr;
     260             :     }
     261             :     
     262          41 :     RetType* objectRaw = function(args...);
     263             :     
     264          82 :     std::unique_ptr<RetType> objectPtr(objectRaw);
     265             :     
     266          41 :     dlclose(lib_handle);
     267             :     
     268          41 :     return objectPtr;
     269             : }
     270             : 
     271             : //default template as high_resolution_clock
     272             : //copied from https://codereview.stackexchange.com/questions/196245/extremely-simple-timer-class-in-c
     273             : template <typename Clock = std::chrono::high_resolution_clock>
     274             : class Timer
     275             : {
     276             :     typename Clock::time_point start_point;
     277             : 
     278             : public:
     279          41 :     Timer() : start_point(Clock::now()) {}
     280             :     
     281           9 :     void reset() { start_point = Clock::now(); }
     282             :     
     283             :     template <typename Rep = typename Clock::duration::rep, typename Units = typename Clock::duration>
     284         942 :     Rep elapsed_time() const
     285             :     {
     286             :         std::atomic_thread_fence(std::memory_order_relaxed);
     287         942 :         auto counted_time = std::chrono::duration_cast<Units>(Clock::now() - start_point).count();
     288             :         std::atomic_thread_fence(std::memory_order_relaxed);
     289         942 :         return static_cast<Rep>(counted_time);
     290             :     }
     291             : };
     292             : 
     293             : template <typename SignalType>
     294          41 : class SecondOrderFilter
     295             : {
     296             : 
     297             : public:
     298             : 
     299             :     typedef std::shared_ptr<SecondOrderFilter<SignalType>> Ptr;
     300             : 
     301          41 :     SecondOrderFilter() :
     302             :         _omega ( 1.0 ),
     303             :         _eps ( 0.8 ),
     304             :         _ts ( 0.01 ),
     305          41 :         _reset_has_been_called ( false )
     306             :     {
     307          41 :         computeCoeff();
     308          41 :     }
     309             : 
     310             :     SecondOrderFilter ( double omega, double eps, double ts, const SignalType& initial_state ) :
     311             :         _omega ( omega ),
     312             :         _eps ( eps ),
     313             :         _ts ( ts ),
     314             :         _reset_has_been_called ( false )
     315             :     {
     316             :         computeCoeff();
     317             :         reset ( initial_state );
     318             :     }
     319             : 
     320          41 :     void reset ( const SignalType& initial_state )
     321             :     {
     322          41 :         _reset_has_been_called = true;
     323          41 :         _u = initial_state;
     324          41 :         _y = initial_state;
     325          41 :         _yd = initial_state;
     326          41 :         _ydd = initial_state;
     327          41 :         _udd = initial_state;
     328          41 :         _ud = initial_state;
     329          41 :     }
     330             : 
     331       21341 :     const SignalType& process ( const SignalType& input )
     332             :     {
     333             : 
     334       21341 :         if ( !_reset_has_been_called ) {
     335           0 :             reset ( input*0 );
     336             :         }
     337             : 
     338             : 
     339       21341 :         _ydd = _yd;
     340       21341 :         _yd = _y;
     341       21341 :         _udd = _ud;
     342       21341 :         _ud = _u;
     343             : 
     344             : 
     345       21341 :         _u = input;
     346       21341 :         _y = 1.0/_a0 * ( _u + _b1*_ud + _b2*_udd - _a1*_yd - _a2*_ydd );
     347             : 
     348       21341 :         return _y;
     349             :     }
     350             : 
     351             :     const SignalType& getOutput() const
     352             :     {
     353             :         return _y;
     354             :     }
     355             : 
     356          41 :     void setOmega ( double omega )
     357             :     {
     358          41 :         _omega = omega;
     359          41 :         computeCoeff();
     360          41 :     }
     361             : 
     362             :     double getOmega()
     363             :     {
     364             :         return _omega;
     365             :     }
     366             : 
     367          41 :     void setDamping ( double eps )
     368             :     {
     369          41 :         _eps = eps;
     370          41 :         computeCoeff();
     371          41 :     }
     372             : 
     373             :     double getDamping()
     374             :     {
     375             :         return _eps;
     376             :     }
     377             : 
     378          41 :     void setTimeStep ( double ts )
     379             :     {
     380          41 :         _ts = ts;
     381          41 :         computeCoeff();
     382          41 :     }
     383             : 
     384             :     double getTimeStep()
     385             :     {
     386             :         return _ts;
     387             :     }
     388             : 
     389             : private:
     390             : 
     391         164 :     void computeCoeff()
     392             :     {
     393         164 :         _b1 = 2.0;
     394         164 :         _b2 = 1.0;
     395             : 
     396         164 :         _a0 = 1.0 + 4.0*_eps/ ( _omega*_ts ) + 4.0/std::pow ( _omega*_ts, 2.0 );
     397         164 :         _a1 = 2 - 8.0/std::pow ( _omega*_ts, 2.0 );
     398         164 :         _a2 = 1.0 + 4.0/std::pow ( _omega*_ts, 2.0 ) - 4.0*_eps/ ( _omega*_ts );
     399             : 
     400         164 :     }
     401             : 
     402             :     double _omega;
     403             :     double _eps;
     404             :     double _ts;
     405             : 
     406             :     double _b1, _b2;
     407             :     double _a0, _a1, _a2;
     408             : 
     409             :     bool _reset_has_been_called;
     410             : 
     411             :     SignalType _y, _yd, _ydd, _u, _ud, _udd;
     412             : 
     413             : };
     414             : 
     415             : 
     416             : }
     417             : 
     418             : }
     419             : 
     420             : #endif // __ROSEE_UTILS__

Generated by: LCOV version 1.13