diff --git a/CMakeLists.txt b/CMakeLists.txt index fb83ccf5399baef48a2267f0657cf68d8bbd60db..7dafd62f1dcd36919049428014466507f73cb70e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,10 +185,10 @@ SET(HDRS_UTILS include/core/utils/converter.h include/core/utils/eigen_assert.h include/core/utils/eigen_predicates.h - include/core/utils/loader.hpp + include/core/utils/loader.h include/core/utils/logging.h include/core/utils/make_unique.h - include/core/utils/params_server.hpp + include/core/utils/params_server.h include/core/utils/singleton.h include/core/utils/utils_gtest.h include/core/utils/converter_utils.h @@ -287,7 +287,7 @@ SET(HDRS_SOLVER ) SET(HDRS_YAML - include/core/yaml/parser_yaml.hpp + include/core/yaml/parser_yaml.h include/core/yaml/yaml_conversion.h ) #SOURCES @@ -321,6 +321,8 @@ SET(SRCS_MATH ) SET(SRCS_UTILS src/utils/converter_utils.cpp + src/utils/params_server.cpp + src/utils/loader.cpp ) SET(SRCS_CAPTURE @@ -369,6 +371,7 @@ SET(SRCS_SOLVER src/solver/solver_manager.cpp ) SET(SRCS_YAML + src/yaml/parser_yaml.cpp src/yaml/processor_odom_3d_yaml.cpp src/yaml/sensor_odom_2d_yaml.cpp src/yaml/sensor_odom_3d_yaml.cpp diff --git a/hello_wolf/hello_wolf_autoconf.cpp b/hello_wolf/hello_wolf_autoconf.cpp index a97d8d2f9c5c7fb8c7f1f37c12330038beb3ba98..a387adfe9656523c37d025bb3a74f0f198281b3d 100644 --- a/hello_wolf/hello_wolf_autoconf.cpp +++ b/hello_wolf/hello_wolf_autoconf.cpp @@ -9,7 +9,7 @@ // wolf core includes #include "core/common/wolf.h" #include "core/capture/capture_odom_2d.h" -#include "core/yaml/parser_yaml.hpp" +#include "core/yaml/parser_yaml.h" #include "core/ceres_wrapper/ceres_manager.h" // hello wolf local includes diff --git a/hello_wolf/sensor_range_bearing.h b/hello_wolf/sensor_range_bearing.h index e62bfc1a5cd4ff7115cac06f9738204c71017f2b..491efff4f533edc993051482de7d0e84562a790a 100644 --- a/hello_wolf/sensor_range_bearing.h +++ b/hello_wolf/sensor_range_bearing.h @@ -9,7 +9,7 @@ #define HELLO_WOLF_SENSOR_RANGE_BEARING_H_ #include "core/sensor/sensor_base.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { diff --git a/include/core/ceres_wrapper/ceres_manager.h b/include/core/ceres_wrapper/ceres_manager.h index 914002ef1d180aa7e5b85716a84334f5ce944e8a..802ab7b49dabf93455f8f93fc8c30745415fe33e 100644 --- a/include/core/ceres_wrapper/ceres_manager.h +++ b/include/core/ceres_wrapper/ceres_manager.h @@ -8,7 +8,7 @@ //wolf includes #include "core/solver/solver_manager.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" #include "core/ceres_wrapper/cost_function_wrapper.h" #include "core/ceres_wrapper/local_parametrization_wrapper.h" #include "core/ceres_wrapper/create_numeric_diff_cost_function.h" diff --git a/include/core/common/params_base.h b/include/core/common/params_base.h index 5295bc0ac17f941503a8f28e462962290a9ee82b..80f6516415e28ddce47ab272415604014ffb0a66 100644 --- a/include/core/common/params_base.h +++ b/include/core/common/params_base.h @@ -1,7 +1,7 @@ #ifndef PARAMS_BASE_H_ #define PARAMS_BASE_H_ -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { struct ParamsBase diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h index 36f3ce94e88681f32529f28b1bd02c93ee5316ab..f2b19ef05c22f7a4c6777f889031dbda45d80a5b 100644 --- a/include/core/problem/problem.h +++ b/include/core/problem/problem.h @@ -18,7 +18,7 @@ struct ProcessorParamsBase; #include "core/common/wolf.h" #include "core/frame/frame_base.h" #include "core/state_block/state_block.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" #include "core/sensor/sensor_factory.h" #include "core/processor/processor_factory.h" #include "core/processor/is_motion.h" @@ -349,7 +349,7 @@ class Problem : public std::enable_shared_from_this<Problem> bool constr_by = false, // bool metric = true, // bool state_blocks = false) const; - bool check(int verbose_level) const; + bool check(int verbose_level = 0) const; bool check(bool verbose, std::ostream& stream) const; }; diff --git a/include/core/processor/processor_motion.h b/include/core/processor/processor_motion.h index ddaa1af0fe1c586fc72d53c7f8fec5a0a0988d97..81a9184ad4798ccbaac1ebd61a194f6e287331b4 100644 --- a/include/core/processor/processor_motion.h +++ b/include/core/processor/processor_motion.h @@ -13,7 +13,7 @@ #include "core/processor/processor_base.h" #include "core/processor/is_motion.h" #include "core/common/time_stamp.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" // std #include <iomanip> diff --git a/include/core/processor/processor_odom_2d.h b/include/core/processor/processor_odom_2d.h index 6d46ab61a32c1b9573f386c97f1ae671086478c6..b03416837ec1b0a6a86a67ff0cf40fdf820b1370 100644 --- a/include/core/processor/processor_odom_2d.h +++ b/include/core/processor/processor_odom_2d.h @@ -12,7 +12,7 @@ #include "core/capture/capture_odom_2d.h" #include "core/factor/factor_odom_2d.h" #include "core/math/rotations.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { diff --git a/include/core/sensor/sensor_factory.h b/include/core/sensor/sensor_factory.h index 3930176443a22cebb8c9591253af7f58b0a40a2c..daf01499ac759d799517cdd73ab830fb6ccaf4d5 100644 --- a/include/core/sensor/sensor_factory.h +++ b/include/core/sensor/sensor_factory.h @@ -16,7 +16,7 @@ struct ParamsSensorBase; // wolf #include "core/common/factory.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { diff --git a/include/core/sensor/sensor_odom_2d.h b/include/core/sensor/sensor_odom_2d.h index d6a431d3102b0a82a218ee71247552066c1ef8eb..45499f5c56fb342ed8a82b8521e6c2e156d06031 100644 --- a/include/core/sensor/sensor_odom_2d.h +++ b/include/core/sensor/sensor_odom_2d.h @@ -3,7 +3,7 @@ //wolf includes #include "core/sensor/sensor_base.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { diff --git a/include/core/sensor/sensor_odom_3d.h b/include/core/sensor/sensor_odom_3d.h index 67efe1e9af27f8456401c400766dcbf32f44057b..3d08375b4fc30e43f07f201a5653d5e83a258381 100644 --- a/include/core/sensor/sensor_odom_3d.h +++ b/include/core/sensor/sensor_odom_3d.h @@ -10,7 +10,7 @@ //wolf includes #include "core/sensor/sensor_base.h" -#include "core/utils/params_server.hpp" +#include "core/utils/params_server.h" namespace wolf { diff --git a/include/core/utils/loader.h b/include/core/utils/loader.h new file mode 100644 index 0000000000000000000000000000000000000000..6f1a4cc68c2d0dcb20a6ef18f53ec259507fc176 --- /dev/null +++ b/include/core/utils/loader.h @@ -0,0 +1,32 @@ +#ifndef LOADER_H +#define LOADER_H + +#include <string> + +class Loader{ +protected: + std::string path_; +public: + Loader(std::string _file); + virtual void load() = 0; + virtual void close() = 0; +}; + +class LoaderRaw: public Loader{ + void* resource_; +public: + LoaderRaw(std::string _file); + ~LoaderRaw(); + void load(); + void close(); +}; +// class LoaderPlugin: public Loader{ +// ClassLoader* resource_; +// void load(){ +// this->resource_ = new ClassLoader(this->path_); +// } +// void close(){ +// delete this->resource_; +// } +// }; +#endif diff --git a/include/core/utils/loader.hpp b/include/core/utils/loader.hpp deleted file mode 100644 index 3d867d799b36bfd53fb42e93577554caf1b050c1..0000000000000000000000000000000000000000 --- a/include/core/utils/loader.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef LOADER_HPP -#define LOADER_HPP -#include <dlfcn.h> -#include <string> -#include <stdexcept> -class Loader{ -protected: - std::string path_; -public: - Loader(std::string _file){ - this->path_ = _file; - } - virtual void load() = 0; - virtual void close() = 0; -}; -class LoaderRaw: public Loader{ - void* resource_; -public: - LoaderRaw(std::string _file): - Loader(_file) - { - // - } - ~LoaderRaw(){ - this->close(); - } - void load(){ - this->resource_ = dlopen(this->path_.c_str(), RTLD_LAZY); - if(not this->resource_) - throw std::runtime_error("Couldn't load resource with path " + this->path_ + "\n" + "Error info: " + dlerror()); - } - void close(){ - if(this->resource_) dlclose(this->resource_); - } -}; -// class LoaderPlugin: public Loader{ -// ClassLoader* resource_; -// void load(){ -// this->resource_ = new ClassLoader(this->path_); -// } -// void close(){ -// delete this->resource_; -// } -// }; -#endif \ No newline at end of file diff --git a/include/core/utils/params_server.h b/include/core/utils/params_server.h new file mode 100644 index 0000000000000000000000000000000000000000..e8b473ca26703f17ea932cca4d1e913717108026 --- /dev/null +++ b/include/core/utils/params_server.h @@ -0,0 +1,55 @@ +#ifndef PARAMS_SERVER_H +#define PARAMS_SERVER_H + +#include "core/utils/converter.h" + +#include <map> +#include <exception> + +namespace wolf{ + +class MissingValueException : public std::runtime_error +{ +public: + MissingValueException(std::string _msg) : std::runtime_error(_msg) {} +}; + +class ParamsServer{ + std::map<std::string, std::string> params_; +public: + ParamsServer(); + ParamsServer(std::map<std::string, std::string> _params); + ~ParamsServer(){ + // + } + + void print(); + + + void addParam(std::string _key, std::string _value); + + void addParams(std::map<std::string, std::string> _params); + + // template<typename T> + // T getParam(std::string key, std::string def_value) const { + // if(params_.find(key) != params_.end()){ + // return converter<T>::convert(params_.find(key)->second); + // }else{ + // return converter<T>::convert(def_value); + // } + // } + + template<typename T> + T getParam(std::string _key) const { + if(params_.find(_key) != params_.end()){ + return converter<T>::convert(params_.find(_key)->second); + }else{ + throw MissingValueException("The following key: '" + _key + "' has not been found in the parameters server."); + } + } + +}; + +} + +#endif diff --git a/include/core/utils/params_server.hpp b/include/core/utils/params_server.hpp deleted file mode 100644 index a750eab79f4ee90b39e4e21d1926129897c29d92..0000000000000000000000000000000000000000 --- a/include/core/utils/params_server.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef PARAMS_SERVER_HPP -#define PARAMS_SERVER_HPP - -#include "core/utils/converter.h" -//#include "core/yaml/parser_yaml.hpp" - -#include <vector> -#include <regex> -#include <map> -#include <exception> - -namespace wolf{ - -class MissingValueException : public std::runtime_error -{ -public: - MissingValueException(std::string msg) : std::runtime_error(msg) {} -}; - -class ParamsServer{ - std::map<std::string, std::string> _params; -public: - ParamsServer(){ - _params = std::map<std::string, std::string>(); - } - ParamsServer(std::map<std::string, std::string> params){ - _params = params; - } - ~ParamsServer(){ - // - } - - void print(){ - for(auto it : _params) - std::cout << it.first << "~~" << it.second << std::endl; - } - - - void addParam(std::string key, std::string value){ - _params.insert(std::pair<std::string, std::string>(key, value)); - } - - void addParams(std::map<std::string, std::string> params) - { - _params.insert(params.begin(), params.end()); - } - - // template<typename T> - // T getParam(std::string key, std::string def_value) const { - // if(_params.find(key) != _params.end()){ - // return converter<T>::convert(_params.find(key)->second); - // }else{ - // return converter<T>::convert(def_value); - // } - // } - - template<typename T> - T getParam(std::string key) const { - if(_params.find(key) != _params.end()){ - return converter<T>::convert(_params.find(key)->second); - }else{ - throw MissingValueException("The following key: '" + key + "' has not been found in the parameters server."); - } - } - -}; - -} - -#endif diff --git a/include/core/yaml/parser_yaml.h b/include/core/yaml/parser_yaml.h new file mode 100644 index 0000000000000000000000000000000000000000..1b6f659ebd609dffef4f3c472800cf32714f22e1 --- /dev/null +++ b/include/core/yaml/parser_yaml.h @@ -0,0 +1,80 @@ +#ifndef PARSER_YAML_H +#define PARSER_YAML_H + +#include "core/utils/converter.h" +#include "core/common/wolf.h" + +#include "yaml-cpp/yaml.h" + +namespace wolf +{ +class ParserYAML { + struct ParamsInitSensor{ + std::string type_; + std::string name_; + std::string plugin_; + YAML::Node n_; + }; + struct ParamsInitProcessor{ + std::string type_; + std::string name_; + std::string name_assoc_sensor_; + std::string plugin_; + YAML::Node n_; + }; + struct SubscriberManager{ + std::string package_; + std::string subscriber_; + std::string topic_; + std::string sensor_name_; + YAML::Node n_; + }; + struct PublisherManager{ + std::string subscriber_; + std::string topic_; + std::string period_; + YAML::Node n_; + }; + std::map<std::string, std::string> params_; + std::string active_name_; + std::vector<ParamsInitSensor> paramsSens_; + std::vector<ParamsInitProcessor> paramsProc_; + std::stack<std::string> parsing_file_; + std::string file_; + std::string path_root_; + std::vector<SubscriberManager> subscriber_managers_; + std::vector<PublisherManager> publisher_managers_; + YAML::Node problem; + std::string generatePath(std::string); + YAML::Node loadYAML(std::string); + void insert_register(std::string, std::string); +public: + ParserYAML(std::string _file, std::string _path_root = "", + bool _freely_parse = false); + ~ParserYAML() + { + // + } + void parse_freely(); + std::map<std::string, std::string> getParams(); + + private: + void walkTree(std::string _file); + void walkTree(std::string _file, std::vector<std::string>& _tags); + void walkTree(std::string _file, std::vector<std::string>& _tags, std::string _hdr); +/** @Brief Recursively walks the YAML tree while filling a map with the values parsed from the file + * @param YAML node to be parsed + * @param tags represents the path from the root of the YAML tree to the current node + * @param hdr is the name of the current YAML node + */ + void walkTreeR(YAML::Node _n, std::vector<std::string>& _tags, std::string _hdr); + void updateActiveName(std::string _tag); +/** @Brief Parse the sensors, processors, callbacks and files elements of the YAML file. We assume that these elements + are defined at the top level of the YAML file. + * @param file is the path to the YAML file */ + void parseFirstLevel(std::string _file); + std::string tagsToString(std::vector<std::string>& _tags); + void parse(); +}; +} +#endif diff --git a/include/core/yaml/parser_yaml.hpp b/include/core/yaml/parser_yaml.hpp deleted file mode 100644 index 22f584d76bab2aa2c3a6bd6ca30edbeb4873a4ea..0000000000000000000000000000000000000000 --- a/include/core/yaml/parser_yaml.hpp +++ /dev/null @@ -1,532 +0,0 @@ -#ifndef PARSER_YAML_HPP -#define PARSER_YAML_HPP - -#include "core/utils/converter.h" -#include "core/common/wolf.h" - -#include "yaml-cpp/yaml.h" - -#include <string> -#include <vector> -#include <list> -#include <stack> -#include <regex> -#include <map> -#include <iostream> -#include <algorithm> -#include <numeric> - -namespace { - //====== START OF FORWARD DECLARATION ======== - std::string parseAtomicNode(YAML::Node); - std::string fetchMapEntry(YAML::Node); - std::string mapToString(std::map<std::string,std::string>); - //====== END OF FORWARD DECLARATION ======== - -/** @Brief Interprets a map as being atomic and thus parses it as a single entity. We assume that the map has as values only scalars and sequences. - * @param n the node representing a map - * @return std::map<std::string, std::string> populated with the key,value pairs in n - */ -std::map<std::string, std::string> fetchAsMap(YAML::Node n){ - assert(n.Type() == YAML::NodeType::Map && "trying to fetch as Map a non-Map node"); - auto m = std::map<std::string, std::string>(); - for(const auto& kv : n){ - std::string key = kv.first.as<std::string>(); - switch (kv.second.Type()) { - case YAML::NodeType::Scalar : { - std::string value = kv.second.Scalar(); - m.insert(std::pair<std::string,std::string>(key, value)); - break; - } - case YAML::NodeType::Sequence : { - std::string aux = parseAtomicNode(kv.second); - m.insert(std::pair<std::string,std::string>(key, aux)); - break; - } - case YAML::NodeType::Map : { - std::string value = fetchMapEntry(kv.second); - std::regex r("^\\$.*"); - if (std::regex_match(key, r)) key = key.substr(1,key.size()-1); - m.insert(std::pair<std::string,std::string>(key, value)); - break; - } - default: - assert(1 == 0 && "Unsupported node Type at fetchAsMap"); - break; - } - } - return m; -} - std::string fetchMapEntry(YAML::Node n){ - switch (n.Type()) { - case YAML::NodeType::Scalar: { - return n.Scalar(); - break; - } - case YAML::NodeType::Sequence: { - return parseAtomicNode(n); - break; - } - case YAML::NodeType::Map: { - return mapToString(fetchAsMap(n)); - break; - } - default: { - assert(1 == 0 && "Unsupported node Type at fetchMapEntry"); - return ""; - break; - } - } - } - /** @Brief Transforms a std::map<std::string,std::string> to its std::string representation [{k1:v1},{k2:v2},{k3:v3},...] - * @param _map just a std::map<std::string,std::string> - * @return <b>{std::string}</b> [{k1:v1},{k2:v2},{k3:v3},...] - */ - std::string mapToString(std::map<std::string,std::string> _map){ - std::string result = ""; - auto v = std::vector<std::string>(); - std::transform(_map.begin(), _map.end(), back_inserter(v), [](const std::pair<std::string,std::string> p){return "{" + p.first + ":" + p.second + "}";}); - auto concat = [](std::string ac, std::string str)-> std::string { - return ac + str + ","; - }; - std::string aux = ""; - std::string accumulated = std::accumulate(v.begin(), v.end(), aux, concat); - if(accumulated.size() > 1) accumulated = accumulated.substr(0,accumulated.size() - 1); - else accumulated = ""; - return "[" + accumulated + "]"; - } - /** @Brief Generates a std::string representing a YAML sequence. The sequence is assumed to be scalar or at most be a sequence of sequences of scalars. - * @param n a vector of YAML::Node that represents a YAML::Sequence - * @return <b>{std::string}</b> representing the YAML sequence - */ - std::string parseAtomicNode(YAML::Node n){ - std::string aux = ""; - bool first = true; - std::string separator = ""; - switch(n.Type()){ - case YAML::NodeType::Scalar: - return n.Scalar(); - break; - case YAML::NodeType::Sequence: - for(auto it : n){ - aux += separator + parseAtomicNode(it); - if(first){ - separator = ","; - first = false; - } - } - return "[" + aux + "]"; - break; - case YAML::NodeType::Map: - return mapToString(fetchAsMap(n)); - break; - default: - return ""; - break; - } - } - - /** @Brief checks if a node of the YAML tree is atomic. Only works if the nodes are of type - * Scalar, Sequence or Map. - * @param key is the key associated to the node n if n.Type() == YAML::NodeType::Map - * @param n node to be test for atomicity - */ - bool isAtomic(std::string key, YAML::Node n){ - assert(n.Type() != YAML::NodeType::Undefined && n.Type() != YAML::NodeType::Null && "Cannot determine atomicity of Undefined/Null node"); - std::regex r("^\\$.*"); - bool is_atomic = true; - switch(n.Type()){ - case YAML::NodeType::Scalar: - return true; - break; - case YAML::NodeType::Sequence: - for(auto it : n) { - switch(it.Type()){ - case YAML::NodeType::Map: - for(const auto& kv : it){ - is_atomic = is_atomic and isAtomic(kv.first.as<std::string>(), it); - } - break; - default: - is_atomic = is_atomic and isAtomic("", it); - break; - } - } - return is_atomic; - break; - case YAML::NodeType::Map: - is_atomic = std::regex_match(key, r); - return is_atomic; - break; - default: - throw std::runtime_error("Cannot determine atomicity of node type " + std::to_string(n.Type())); - return false; - break; - } - return false; - } -} -class ParserYAML { - struct ParamsInitSensor{ - std::string _type; - std::string _name; - std::string _plugin; - YAML::Node n; - }; - struct ParamsInitProcessor{ - std::string _type; - std::string _name; - std::string _name_assoc_sensor; - std::string _plugin; - YAML::Node n; - }; - struct SubscriberManager{ - std::string _package; - std::string _subscriber; - std::string _topic; - std::string _sensor_name; - YAML::Node n; - }; - struct PublisherManager{ - std::string _subscriber; - std::string _topic; - std::string _period; - YAML::Node n; - }; - std::map<std::string, std::string> _params; - std::string _active_name; - std::vector<ParamsInitSensor> _paramsSens; - std::vector<ParamsInitProcessor> _paramsProc; - std::stack<std::string> _parsing_file; - std::string _file; - std::string _path_root; - std::vector<SubscriberManager> _subscriber_managers; - std::vector<PublisherManager> _publisher_managers; - YAML::Node problem; - std::string generatePath(std::string); - YAML::Node loadYAML(std::string); - void insert_register(std::string, std::string); -public: - ParserYAML(std::string file, std::string path_root = "", - bool freely_parse = false) { - _params = std::map<std::string, std::string>(); - _active_name = ""; - _paramsSens = std::vector<ParamsInitSensor>(); - _paramsProc = std::vector<ParamsInitProcessor>(); - _subscriber_managers = std::vector<SubscriberManager>(); - _publisher_managers = std::vector<PublisherManager>(); - _parsing_file = std::stack<std::string>(); - _file = file; - if (path_root != "") { - std::regex r(".*/ *$"); - if (not std::regex_match(path_root, r)) - _path_root = path_root + "/"; - else - _path_root = path_root; - } - if(not freely_parse) this->parse(); - else this->parse_freely(); - } - ~ParserYAML() - { - // - } - void parse_freely(); - std::map<std::string, std::string> getParams(); - - private: - void walkTree(std::string file); - void walkTree(std::string file, std::vector<std::string>& tags); - void walkTree(std::string file, std::vector<std::string>& tags, std::string hdr); - void walkTreeR(YAML::Node n, std::vector<std::string>& tags, std::string hdr); - void updateActiveName(std::string tag); - void parseFirstLevel(std::string file); - std::string tagsToString(std::vector<std::string>& tags); - void parse(); -}; -std::string ParserYAML::generatePath(std::string file){ - std::regex r("^/.*"); - if(std::regex_match(file, r)){ - return file; - }else{ - return _path_root + file; - } -} -YAML::Node ParserYAML::loadYAML(std::string file){ - try{ - // std::cout << "Parsing " << generatePath(file) << std::endl; - WOLF_INFO("Parsing file: ", generatePath(file)); - return YAML::LoadFile(generatePath(file)); - }catch (YAML::BadFile& e){ - throw std::runtime_error("Couldn't load file " + generatePath(file) + ". Tried to open it from " + this->_parsing_file.top()); - } -} -std::string ParserYAML::tagsToString(std::vector<std::string> &tags){ - std::string hdr = ""; - for(auto it : tags){ - hdr = hdr + "/" + it; - } - return hdr; -} -void ParserYAML::walkTree(std::string file){ - YAML::Node n; - n = loadYAML(generatePath(file)); - this->_parsing_file.push(generatePath(file)); - std::vector<std::string> hdrs = std::vector<std::string>(); - walkTreeR(n, hdrs, ""); - this->_parsing_file.pop(); -} -void ParserYAML::walkTree(std::string file, std::vector<std::string>& tags){ - YAML::Node n; - n = loadYAML(generatePath(file)); - this->_parsing_file.push(generatePath(file)); - walkTreeR(n, tags, ""); - this->_parsing_file.pop(); -} -void ParserYAML::walkTree(std::string file, std::vector<std::string>& tags, std::string hdr){ - YAML::Node n; - n = loadYAML(generatePath(file)); - this->_parsing_file.push(generatePath(file)); - walkTreeR(n, tags, hdr); - this->_parsing_file.pop(); -} -/** @Brief Recursively walks the YAML tree while filling a map with the values parsed from the file -* @param YAML node to be parsed -* @param tags represents the path from the root of the YAML tree to the current node -* @param hdr is the name of the current YAML node -*/ -void ParserYAML::walkTreeR(YAML::Node n, std::vector<std::string>& tags, std::string hdr){ - switch (n.Type()) { - case YAML::NodeType::Scalar : { - std::regex r("^@.*"); - if(std::regex_match(n.Scalar(), r)){ - std::string str = n.Scalar(); - walkTree(str.substr(1,str.size() - 1), tags, hdr); - }else{ - insert_register(hdr, n.Scalar()); - } - break; - } - case YAML::NodeType::Sequence : { - if(isAtomic("", n)){ - insert_register(hdr, parseAtomicNode(n)); - }else{ - for(const auto& kv : n){ - walkTreeR(kv, tags, hdr); - } - } - break; - } - case YAML::NodeType::Map : { - for(const auto& kv : n){ - if(isAtomic(kv.first.as<std::string>(), n)){ - std::string key = kv.first.as<std::string>(); - //WOLF_DEBUG("KEY IN MAP ATOMIC ", hdr + "/" + key); - key = key.substr(1,key.size() - 1); - insert_register(hdr + "/" + key, parseAtomicNode(kv.second)); - }else{ - /* - If key=="follow" then the parser will assume that the value is a path and will parse - the (expected) yaml file at the specified path. Note that this does not increase the header depth. - The following example shows how the header remains unafected: - @my_main_config | @some_path - - cov_det: 1 | - my_value : 23 - - follow: "@some_path" | - - var: 1.2 | - Resulting map: - cov_det -> 1 - my_value-> 23 - var: 1.2 - Instead of: - cov_det -> 1 - follow/my_value-> 23 - var: 1.2 - Which would result from the following yaml files - @my_main_config | @some_path - - cov_det: 1 | - my_value : 23 - - $follow: "@some_path" | - - var: 1.2 | - */ - std::string key = kv.first.as<std::string>(); - //WOLF_DEBUG("KEY IN MAP NON ATOMIC ", key); - std::regex rr("follow"); - if(not std::regex_match(kv.first.as<std::string>(), rr)) { - tags.push_back(kv.first.as<std::string>()); - if(tags.size() == 2) this->updateActiveName(kv.first.as<std::string>()); - walkTreeR(kv.second, tags, hdr +"/"+ kv.first.as<std::string>()); - tags.pop_back(); - if(tags.size() == 1) this->updateActiveName(""); - }else{ - walkTree(kv.second.as<std::string>(), tags, hdr); - } - } - } - break; - } - case YAML::NodeType::Null : - break; - default: - assert(1 == 0 && "Unsupported node Type at walkTreeR."); - break; - } -} -void ParserYAML::updateActiveName(std::string tag){ - this->_active_name = tag; -} -/** @Brief Parse the sensors, processors, callbacks and files elements of the YAML file. We assume that these elements - are defined at the top level of the YAML file. - * @param file is the path to the YAML file */ -void ParserYAML::parseFirstLevel(std::string file){ - YAML::Node n; - n = loadYAML(generatePath(file)); - - YAML::Node n_config = n["config"]; - // assert(n_config.Type() == YAML::NodeType::Map && "trying to parse config node but found a non-Map node"); - if(n_config.Type() != YAML::NodeType::Map) throw std::runtime_error("Could not find config node. Please make sure that your YAML file " + generatePath(file) + " starts with 'config:'"); - if(n_config["problem"].Type() != YAML::NodeType::Map) throw std::runtime_error("Could not find problem node. Please make sure that the 'config' node in YAML file " + generatePath(file) + " has a 'problem' entry"); - this->problem = n_config["problem"]; - std::vector<std::map<std::string, std::string>> map_container; - try{ - for(const auto& kv : n_config["sensors"]){ - ParamsInitSensor pSensor = {kv["type"].Scalar(), kv["name"].Scalar(), kv["plugin"].Scalar(), kv}; - _paramsSens.push_back(pSensor); - map_container.push_back(std::map<std::string, std::string>({ - {"type", kv["type"].Scalar()}, - {"name", kv["name"].Scalar()}, - {"plugin", kv["plugin"].Scalar()} - })); - } - insert_register("sensors", wolf::converter<std::string>::convert(map_container)); - map_container.clear(); - } catch(YAML::InvalidNode& e){ - throw std::runtime_error("Error parsing sensors @" + generatePath(file) + ". Please make sure that each sensor entry has 'type', 'name' and 'plugin' entries."); - } - - try{ - for(const auto& kv : n_config["processors"]){ - ParamsInitProcessor pProc = {kv["type"].Scalar(), kv["name"].Scalar(), kv["sensor_name"].Scalar(), kv["plugin"].Scalar(), kv}; - _paramsProc.push_back(pProc); - map_container.push_back(std::map<std::string, std::string>({ - {"type", kv["type"].Scalar()}, - {"name", kv["name"].Scalar()}, - {"plugin", kv["plugin"].Scalar()}, - {"sensor_name", kv["sensor_name"].Scalar()}})); - } - insert_register("processors", - wolf::converter<std::string>::convert(map_container)); - map_container.clear(); - } catch(YAML::InvalidNode& e){ - throw std::runtime_error("Error parsing processors @" + generatePath(file) + ". Please make sure that each processor has 'type', 'name', 'plugin' and 'sensor_name' entries."); - } - try { - for (const auto &kv : n_config["ROS subscriber"]) { - SubscriberManager pSubscriberManager = {kv["package"].Scalar(), kv["type"].Scalar(), kv["topic"].Scalar(), kv["sensor_name"].Scalar(), kv}; - _subscriber_managers.push_back(pSubscriberManager); - map_container.push_back(std::map<std::string, std::string>({ - {"package", kv["package"].Scalar()}, - {"type", kv["type"].Scalar()}, - {"topic", kv["topic"].Scalar()}, - {"sensor_name", kv["sensor_name"].Scalar()}})); - } - insert_register("ROS subscriber", wolf::converter<std::string>::convert(map_container)); - map_container.clear(); - } catch (YAML::InvalidNode &e) { - throw std::runtime_error("Error parsing subscriber @" + generatePath(file) + ". Please make sure that each manager has 'package', 'type', 'topic' and 'sensor_name' entries."); - } - - try { - for (const auto &kv : n_config["ROS publisher"]) { - WOLF_DEBUG("WHAT"); - PublisherManager pPublisherManager = {kv["type"].Scalar(), kv["topic"].Scalar(), kv["period"].Scalar(), kv}; - _publisher_managers.push_back(pPublisherManager); - map_container.push_back(std::map<std::string, std::string>({ - {"type", kv["type"].Scalar()}, - {"topic", kv["topic"].Scalar()}, - {"period", kv["period"].Scalar()}})); - } - insert_register("ROS publisher", wolf::converter<std::string>::convert(map_container)); - map_container.clear(); - } catch (YAML::InvalidNode &e) { - throw std::runtime_error("Error parsing publisher @" + generatePath(file) + ". Please make sure that each manager has 'type', 'topic' and 'period' entries."); - } -} -std::map<std::string,std::string> ParserYAML::getParams(){ - std::map<std::string,std::string> rtn = _params; - return rtn; -} -void ParserYAML::parse(){ - this->_parsing_file.push(generatePath(this->_file)); - this->parseFirstLevel(this->_file); - - if(this->problem.Type() != YAML::NodeType::Undefined){ - std::vector<std::string> tags = std::vector<std::string>(); - this->walkTreeR(this->problem, tags , "problem"); - } - for(auto it : _paramsSens){ - std::vector<std::string> tags = std::vector<std::string>(); - tags.push_back("sensor"); - this->walkTreeR(it.n , tags , "sensor/" + it._name); - } - for(auto it : _paramsProc){ - std::vector<std::string> tags = std::vector<std::string>(); - tags.push_back("processor"); - this->walkTreeR(it.n , tags , "processor/" + it._name); - } - std::list<std::string> plugins, packages; - for (const auto& it : this->_paramsSens) - plugins.push_back(it._plugin); - for (const auto& it : this->_paramsProc) - plugins.push_back(it._plugin); - for (const auto& it : this->_subscriber_managers) - packages.push_back(it._package); - plugins.sort(); - plugins.unique(); - packages.sort(); - packages.unique(); - insert_register("plugins", wolf::converter<std::string>::convert(plugins)); - insert_register("packages", wolf::converter<std::string>::convert(packages)); - - YAML::Node n; - n = loadYAML(generatePath(this->_file)); - - if (n.Type() == YAML::NodeType::Map) - { - for (auto it : n) - { - auto node = it.second; - // WOLF_INFO("WUT ", it.first); - std::vector<std::string> tags = std::vector<std::string>(); - if(it.first.as<std::string>() != "config") - this->walkTreeR(node, tags, it.first.as<std::string>()); - else - { - for (auto itt : node) - { - std::string node_key = itt.first.as<std::string>(); - if (node_key != "problem" and node_key != "sensors" and node_key != "processors" and - node_key != "ROS subscriber" and node_key != "ROS publisher") - { - this->walkTreeR(itt.second, tags, node_key); - } - } - } - } - }else - { - std::vector<std::string> tags = std::vector<std::string>(); - this->walkTreeR(n, tags, ""); - } - this->_parsing_file.pop(); - } -void ParserYAML::parse_freely(){ - this->_parsing_file.push(generatePath(this->_file)); - std::vector<std::string> tags = std::vector<std::string>(); - this->walkTreeR(loadYAML(this->_file), tags, ""); - this->_parsing_file.pop(); -} -void ParserYAML::insert_register(std::string key, std::string value){ - if(key.substr(0,1) == "/") key = key.substr(1,key.size()-1); - auto inserted_it = _params.insert(std::pair<std::string, std::string>(key, value)); - if(not inserted_it.second) WOLF_WARN("Skipping key '", key, "' with value '", value, "'. There already exists the register: (", inserted_it.first->first, ",", inserted_it.first->second, ")"); -} -#endif diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp index b81f9c8752bb047ae702a092c8f20458a29f3153..e79de9572f545e85142450497f3d4780621adc7b 100644 --- a/src/problem/problem.cpp +++ b/src/problem/problem.cpp @@ -12,8 +12,8 @@ #include "core/processor/processor_factory.h" #include "core/state_block/state_block.h" #include "core/utils/logging.h" -#include "core/utils/params_server.hpp" -#include "core/utils/loader.hpp" +#include "core/utils/params_server.h" +#include "core/utils/loader.h" #include "core/utils/check_log.hpp" @@ -1877,9 +1877,12 @@ void Problem::perturb(double amplitude) // Frames and Captures for (auto& F : getTrajectory()->getFrameList()) { - F->perturb(amplitude); - for (auto& C : F->getCaptureList()) - C->perturb(amplitude); + if (F->isKeyOrAux()) + { + F->perturb(amplitude); + for (auto& C : F->getCaptureList()) + C->perturb(amplitude); + } } // Landmarks diff --git a/src/utils/loader.cpp b/src/utils/loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fdf6984b6a3de57fa8a8ae062232a685897209f --- /dev/null +++ b/src/utils/loader.cpp @@ -0,0 +1,37 @@ +#include "core/utils/loader.h" + +#include <dlfcn.h> +#include <stdexcept> + +Loader::Loader(std::string _file) +{ + path_ = _file; +} +LoaderRaw::LoaderRaw(std::string _file) : Loader(_file) +{ + // +} +LoaderRaw::~LoaderRaw() +{ + close(); +} +void LoaderRaw::load() +{ + resource_ = dlopen(path_.c_str(), RTLD_LAZY); + if (not resource_) + throw std::runtime_error("Couldn't load resource with path " + path_ + "\n" + "Error info: " + dlerror()); +} +void LoaderRaw::close() +{ + if (resource_) + dlclose(resource_); +} +// class LoaderPlugin: public Loader{ +// ClassLoader* resource_; +// void load(){ +// resource_ = new ClassLoader(path_); +// } +// void close(){ +// delete resource_; +// } +// }; diff --git a/src/utils/params_server.cpp b/src/utils/params_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6344466792706c9e499695721f95e781089ec07e --- /dev/null +++ b/src/utils/params_server.cpp @@ -0,0 +1,28 @@ +#include "core/utils/params_server.h" + +using namespace wolf; + +ParamsServer::ParamsServer() +{ + params_ = std::map<std::string, std::string>(); +} +ParamsServer::ParamsServer(std::map<std::string, std::string> _params) +{ + params_ = _params; +} + +void ParamsServer::print() +{ + for (auto it : params_) + std::cout << it.first << "~~" << it.second << std::endl; +} + +void ParamsServer::addParam(std::string _key, std::string _value) +{ + params_.insert(std::pair<std::string, std::string>(_key, _value)); +} + +void ParamsServer::addParams(std::map<std::string, std::string> _params) +{ + params_.insert(_params.begin(), _params.end()); +} diff --git a/src/yaml/parser_yaml.cpp b/src/yaml/parser_yaml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..267d0c9da2024abd59ed5b529d13de7680d14472 --- /dev/null +++ b/src/yaml/parser_yaml.cpp @@ -0,0 +1,547 @@ +#include "core/yaml/parser_yaml.h" + +#include <string> +#include <vector> +#include <list> +#include <stack> +#include <regex> +#include <map> +#include <iostream> +#include <algorithm> +#include <numeric> + +using namespace wolf; +namespace { + //====== START OF FORWARD DECLARATION ======== + std::string parseAtomicNode(YAML::Node); + std::string fetchMapEntry(YAML::Node); + std::string mapToString(std::map<std::string,std::string>); + //====== END OF FORWARD DECLARATION ======== + +/** @Brief Interprets a map as being atomic and thus parses it as a single entity. We assume that the map has as values only scalars and sequences. + * @param n the node representing a map + * @return std::map<std::string, std::string> populated with the key,value pairs in n + */ +std::map<std::string, std::string> fetchAsMap(YAML::Node _n){ + assert(_n.Type() == YAML::NodeType::Map && "trying to fetch as Map a non-Map node"); + auto m = std::map<std::string, std::string>(); + for(const auto& kv : _n){ + std::string key = kv.first.as<std::string>(); + switch (kv.second.Type()) { + case YAML::NodeType::Scalar : { + std::string value = kv.second.Scalar(); + m.insert(std::pair<std::string,std::string>(key, value)); + break; + } + case YAML::NodeType::Sequence : { + std::string aux = parseAtomicNode(kv.second); + m.insert(std::pair<std::string,std::string>(key, aux)); + break; + } + case YAML::NodeType::Map : { + std::string value = fetchMapEntry(kv.second); + std::regex r("^\\$.*"); + if (std::regex_match(key, r)) key = key.substr(1,key.size()-1); + m.insert(std::pair<std::string,std::string>(key, value)); + break; + } + default: + assert(1 == 0 && "Unsupported node Type at fetchAsMap"); + break; + } + } + return m; +} + std::string fetchMapEntry(YAML::Node _n){ + switch (_n.Type()) { + case YAML::NodeType::Scalar: { + return _n.Scalar(); + break; + } + case YAML::NodeType::Sequence: { + return parseAtomicNode(_n); + break; + } + case YAML::NodeType::Map: { + return mapToString(fetchAsMap(_n)); + break; + } + default: { + assert(1 == 0 && "Unsupported node Type at fetchMapEntry"); + return ""; + break; + } + } + } + /** @Brief Transforms a std::map<std::string,std::string> to its std::string representation [{k1:v1},{k2:v2},{k3:v3},...] + * @param map_ just a std::map<std::string,std::string> + * @return <b>{std::string}</b> [{k1:v1},{k2:v2},{k3:v3},...] + */ + std::string mapToString(std::map<std::string,std::string> _map){ + std::string result = ""; + auto v = std::vector<std::string>(); + std::transform(_map.begin(), _map.end(), back_inserter(v), [](const std::pair<std::string,std::string> p){return "{" + p.first + ":" + p.second + "}";}); + auto concat = [](std::string ac, std::string str)-> std::string { + return ac + str + ","; + }; + std::string aux = ""; + std::string accumulated = std::accumulate(v.begin(), v.end(), aux, concat); + if(accumulated.size() > 1) accumulated = accumulated.substr(0,accumulated.size() - 1); + else accumulated = ""; + return "[" + accumulated + "]"; + } + /** @Brief Generates a std::string representing a YAML sequence. The sequence is assumed to be scalar or at most be a sequence of sequences of scalars. + * @param n a vector of YAML::Node that represents a YAML::Sequence + * @return <b>{std::string}</b> representing the YAML sequence + */ + std::string parseAtomicNode(YAML::Node _n){ + std::string aux = ""; + bool first = true; + std::string separator = ""; + switch(_n.Type()){ + case YAML::NodeType::Scalar: + return _n.Scalar(); + break; + case YAML::NodeType::Sequence: + for(auto it : _n){ + aux += separator + parseAtomicNode(it); + if(first){ + separator = ","; + first = false; + } + } + return "[" + aux + "]"; + break; + case YAML::NodeType::Map: + return mapToString(fetchAsMap(_n)); + break; + default: + return ""; + break; + } + } + + /** @Brief checks if a node of the YAML tree is atomic. Only works if the nodes are of type + * Scalar, Sequence or Map. + * @param key is the key associated to the node n if n.Type() == YAML::NodeType::Map + * @param n node to be test for atomicity + */ + bool isAtomic(std::string _key, YAML::Node _n){ + assert(_n.Type() != YAML::NodeType::Undefined && _n.Type() != YAML::NodeType::Null && "Cannot determine atomicity of Undefined/Null node"); + std::regex r("^\\$.*"); + bool is_atomic = true; + switch(_n.Type()){ + case YAML::NodeType::Scalar: + return true; + break; + case YAML::NodeType::Sequence: + for(auto it : _n) { + switch(it.Type()){ + case YAML::NodeType::Map: + for(const auto& kv : it){ + is_atomic = is_atomic and isAtomic(kv.first.as<std::string>(), it); + } + break; + default: + is_atomic = is_atomic and isAtomic("", it); + break; + } + } + return is_atomic; + break; + case YAML::NodeType::Map: + is_atomic = std::regex_match(_key, r); + return is_atomic; + break; + default: + throw std::runtime_error("Cannot determine atomicity of node type " + std::to_string(_n.Type())); + return false; + break; + } + return false; + } +} +ParserYAML::ParserYAML(std::string _file, std::string path_root, bool freely_parse) +{ + params_ = std::map<std::string, std::string>(); + active_name_ = ""; + paramsSens_ = std::vector<ParamsInitSensor>(); + paramsProc_ = std::vector<ParamsInitProcessor>(); + subscriber_managers_ = std::vector<SubscriberManager>(); + publisher_managers_ = std::vector<PublisherManager>(); + parsing_file_ = std::stack<std::string>(); + file_ = _file; + if (path_root != "") + { + std::regex r(".*/ *$"); + if (not std::regex_match(path_root, r)) + path_root_ = path_root + "/"; + else + path_root_ = path_root; + } + if (not freely_parse) + parse(); + else + parse_freely(); +} + +std::string ParserYAML::generatePath(std::string _file) +{ + std::regex r("^/.*"); + if (std::regex_match(_file, r)) + { + return _file; + } + else + { + return path_root_ + _file; + } +} +YAML::Node ParserYAML::loadYAML(std::string _file) +{ + try + { + // std::cout << "Parsing " << generatePath(_file) << std::endl; + WOLF_INFO("Parsing file: ", generatePath(_file)); + return YAML::LoadFile(generatePath(_file)); + } + catch (YAML::BadFile& e) + { + throw std::runtime_error("Couldn't load file " + generatePath(_file) + ". Tried to open it from " + + parsing_file_.top()); + } +} +std::string ParserYAML::tagsToString(std::vector<std::string>& _tags) +{ + std::string hdr = ""; + for (auto it : _tags) + { + hdr = hdr + "/" + it; + } + return hdr; +} +void ParserYAML::walkTree(std::string _file) +{ + YAML::Node n; + n = loadYAML(generatePath(_file)); + parsing_file_.push(generatePath(_file)); + std::vector<std::string> hdrs = std::vector<std::string>(); + walkTreeR(n, hdrs, ""); + parsing_file_.pop(); +} +void ParserYAML::walkTree(std::string _file, std::vector<std::string>& _tags) +{ + YAML::Node n; + n = loadYAML(generatePath(_file)); + parsing_file_.push(generatePath(_file)); + walkTreeR(n, _tags, ""); + parsing_file_.pop(); +} +void ParserYAML::walkTree(std::string _file, std::vector<std::string>& _tags, std::string hdr) +{ + YAML::Node n; + n = loadYAML(generatePath(_file)); + parsing_file_.push(generatePath(_file)); + walkTreeR(n, _tags, hdr); + parsing_file_.pop(); +} +void ParserYAML::walkTreeR(YAML::Node _n, std::vector<std::string>& _tags, std::string hdr) +{ + switch (_n.Type()) + { + case YAML::NodeType::Scalar: + { + std::regex r("^@.*"); + if (std::regex_match(_n.Scalar(), r)) + { + std::string str = _n.Scalar(); + walkTree(str.substr(1, str.size() - 1), _tags, hdr); + } + else + { + insert_register(hdr, _n.Scalar()); + } + break; + } + case YAML::NodeType::Sequence: + { + if (isAtomic("", _n)) + { + insert_register(hdr, parseAtomicNode(_n)); + } + else + { + for (const auto& kv : _n) + { + walkTreeR(kv, _tags, hdr); + } + } + break; + } + case YAML::NodeType::Map: + { + for (const auto& kv : _n) + { + if (isAtomic(kv.first.as<std::string>(), _n)) + { + std::string key = kv.first.as<std::string>(); + // WOLF_DEBUG("KEY IN MAP ATOMIC ", hdr + "/" + key); + key = key.substr(1, key.size() - 1); + insert_register(hdr + "/" + key, parseAtomicNode(kv.second)); + } + else + { + /* + If key=="follow" then the parser will assume that the value is a path and will parse + the (expected) yaml file at the specified path. Note that this does not increase the header depth. + The following example shows how the header remains unafected: + @my_main_config | @some_path + - cov_det: 1 | - my_value : 23 + - follow: "@some_path" | + - var: 1.2 | + Resulting map: + cov_det -> 1 + my_value-> 23 + var: 1.2 + Instead of: + cov_det -> 1 + follow/my_value-> 23 + var: 1.2 + Which would result from the following yaml files + @my_main_config | @some_path + - cov_det: 1 | - my_value : 23 + - $follow: "@some_path" | + - var: 1.2 | + */ + std::string key = kv.first.as<std::string>(); + // WOLF_DEBUG("KEY IN MAP NON ATOMIC ", key); + std::regex rr("follow"); + if (not std::regex_match(kv.first.as<std::string>(), rr)) + { + _tags.push_back(kv.first.as<std::string>()); + if (_tags.size() == 2) + updateActiveName(kv.first.as<std::string>()); + walkTreeR(kv.second, _tags, hdr + "/" + kv.first.as<std::string>()); + _tags.pop_back(); + if (_tags.size() == 1) + updateActiveName(""); + } + else + { + walkTree(kv.second.as<std::string>(), _tags, hdr); + } + } + } + break; + } + case YAML::NodeType::Null: + break; + default: + assert(1 == 0 && "Unsupported node Type at walkTreeR."); + break; + } +} +void ParserYAML::updateActiveName(std::string _tag) +{ + active_name_ = _tag; +} +void ParserYAML::parseFirstLevel(std::string _file) +{ + YAML::Node n; + n = loadYAML(generatePath(_file)); + + YAML::Node n_config = n["config"]; + // assert(n_config.Type() == YAML::NodeType::Map && "trying to parse config node but found a non-Map node"); + if (n_config.Type() != YAML::NodeType::Map) + throw std::runtime_error("Could not find config node. Please make sure that your YAML file " + + generatePath(_file) + " starts with 'config:'"); + if (n_config["problem"].Type() != YAML::NodeType::Map) + throw std::runtime_error("Could not find problem node. Please make sure that the 'config' node in YAML file " + + generatePath(_file) + " has a 'problem' entry"); + problem = n_config["problem"]; + std::vector<std::map<std::string, std::string>> map_container; + try + { + for (const auto& kv : n_config["sensors"]) + { + ParamsInitSensor pSensor = { kv["type"].Scalar(), kv["name"].Scalar(), kv["plugin"].Scalar(), kv }; + paramsSens_.push_back(pSensor); + map_container.push_back(std::map<std::string, std::string>({ { "type", kv["type"].Scalar() }, + { "name", kv["name"].Scalar() }, + { "plugin", kv["plugin"].Scalar() } })); + } + insert_register("sensors", wolf::converter<std::string>::convert(map_container)); + map_container.clear(); + } + catch (YAML::InvalidNode& e) + { + throw std::runtime_error("Error parsing sensors @" + generatePath(_file) + + ". Please make sure that each sensor entry has 'type', 'name' and 'plugin' entries."); + } + + try + { + for (const auto& kv : n_config["processors"]) + { + ParamsInitProcessor pProc = { + kv["type"].Scalar(), kv["name"].Scalar(), kv["sensor_name"].Scalar(), kv["plugin"].Scalar(), kv + }; + paramsProc_.push_back(pProc); + map_container.push_back( + std::map<std::string, std::string>({ { "type", kv["type"].Scalar() }, + { "name", kv["name"].Scalar() }, + { "plugin", kv["plugin"].Scalar() }, + { "sensor_name", kv["sensor_name"].Scalar() } })); + } + insert_register("processors", wolf::converter<std::string>::convert(map_container)); + map_container.clear(); + } + catch (YAML::InvalidNode& e) + { + throw std::runtime_error("Error parsing processors @" + generatePath(_file) + + ". Please make sure that each processor has 'type', 'name', 'plugin' and " + "'sensor_name' entries."); + } + try + { + for (const auto& kv : n_config["ROS subscriber"]) + { + SubscriberManager pSubscriberManager = { + kv["package"].Scalar(), kv["type"].Scalar(), kv["topic"].Scalar(), kv["sensor_name"].Scalar(), kv + }; + subscriber_managers_.push_back(pSubscriberManager); + map_container.push_back( + std::map<std::string, std::string>({ { "package", kv["package"].Scalar() }, + { "type", kv["type"].Scalar() }, + { "topic", kv["topic"].Scalar() }, + { "sensor_name", kv["sensor_name"].Scalar() } })); + } + insert_register("ROS subscriber", wolf::converter<std::string>::convert(map_container)); + map_container.clear(); + } + catch (YAML::InvalidNode& e) + { + throw std::runtime_error("Error parsing subscriber @" + generatePath(_file) + + ". Please make sure that each manager has 'package', 'type', 'topic' and " + "'sensor_name' entries."); + } + + try + { + for (const auto& kv : n_config["ROS publisher"]) + { + WOLF_DEBUG("WHAT"); + PublisherManager pPublisherManager = { + kv["type"].Scalar(), kv["topic"].Scalar(), kv["period"].Scalar(), kv + }; + publisher_managers_.push_back(pPublisherManager); + map_container.push_back(std::map<std::string, std::string>({ { "type", kv["type"].Scalar() }, + { "topic", kv["topic"].Scalar() }, + { "period", kv["period"].Scalar() } })); + } + insert_register("ROS publisher", wolf::converter<std::string>::convert(map_container)); + map_container.clear(); + } + catch (YAML::InvalidNode& e) + { + throw std::runtime_error("Error parsing publisher @" + generatePath(_file) + + ". Please make sure that each manager has 'type', 'topic' and 'period' entries."); + } +} +std::map<std::string, std::string> ParserYAML::getParams() +{ + std::map<std::string, std::string> rtn = params_; + return rtn; +} +void ParserYAML::parse() +{ + parsing_file_.push(generatePath(file_)); + parseFirstLevel(file_); + + if (problem.Type() != YAML::NodeType::Undefined) + { + std::vector<std::string> tags = std::vector<std::string>(); + walkTreeR(problem, tags, "problem"); + } + for (auto it : paramsSens_) + { + std::vector<std::string> tags = std::vector<std::string>(); + tags.push_back("sensor"); + walkTreeR(it.n_, tags, "sensor/" + it.name_); + } + for (auto it : paramsProc_) + { + std::vector<std::string> tags = std::vector<std::string>(); + tags.push_back("processor"); + walkTreeR(it.n_, tags, "processor/" + it.name_); + } + std::list<std::string> plugins, packages; + for (const auto& it : paramsSens_) + plugins.push_back(it.plugin_); + for (const auto& it : paramsProc_) + plugins.push_back(it.plugin_); + for (const auto& it : subscriber_managers_) + packages.push_back(it.package_); + plugins.sort(); + plugins.unique(); + packages.sort(); + packages.unique(); + insert_register("plugins", wolf::converter<std::string>::convert(plugins)); + insert_register("packages", wolf::converter<std::string>::convert(packages)); + + YAML::Node n; + n = loadYAML(generatePath(file_)); + + if (n.Type() == YAML::NodeType::Map) + { + for (auto it : n) + { + auto node = it.second; + // WOLF_INFO("WUT ", it.first); + std::vector<std::string> tags = std::vector<std::string>(); + if (it.first.as<std::string>() != "config") + walkTreeR(node, tags, it.first.as<std::string>()); + else + { + for (auto itt : node) + { + std::string node_key = itt.first.as<std::string>(); + if (node_key != "problem" and node_key != "sensors" and node_key != "processors" and + node_key != "ROS subscriber" and node_key != "ROS publisher") + { + walkTreeR(itt.second, tags, node_key); + } + } + } + } + } + else + { + std::vector<std::string> tags = std::vector<std::string>(); + walkTreeR(n, tags, ""); + } + parsing_file_.pop(); +} +void ParserYAML::parse_freely() +{ + parsing_file_.push(generatePath(file_)); + std::vector<std::string> tags = std::vector<std::string>(); + walkTreeR(loadYAML(file_), tags, ""); + parsing_file_.pop(); +} +void ParserYAML::insert_register(std::string _key, std::string _value) +{ + if (_key.substr(0, 1) == "/") + _key = _key.substr(1, _key.size() - 1); + auto inserted_it = params_.insert(std::pair<std::string, std::string>(_key, _value)); + if (not inserted_it.second) + WOLF_WARN("Skipping key '", + _key, + "' with value '", + _value, + "'. There already exists the register: (", + inserted_it.first->first, + ",", + inserted_it.first->second, + ")"); +} diff --git a/test/gtest_param_server.cpp b/test/gtest_param_server.cpp index 18f6b1eded0955faf7c6b823e25bbde62894203d..1f1f468360e1aa5073606f8ea32e7d82cafbc438 100644 --- a/test/gtest_param_server.cpp +++ b/test/gtest_param_server.cpp @@ -1,8 +1,8 @@ #include "core/utils/utils_gtest.h" #include "core/utils/converter.h" #include "core/common/wolf.h" -#include "core/yaml/parser_yaml.hpp" -#include "core/utils/params_server.hpp" +#include "core/yaml/parser_yaml.h" +#include "core/utils/params_server.h" using namespace std; using namespace wolf; diff --git a/test/gtest_parser_yaml.cpp b/test/gtest_parser_yaml.cpp index c8702619bc5150eb688bcb7dccfa11f71ab909e5..de5164ec6a9db61ad8a0344e8e6ee6d6e52dec16 100644 --- a/test/gtest_parser_yaml.cpp +++ b/test/gtest_parser_yaml.cpp @@ -1,7 +1,7 @@ #include "core/utils/utils_gtest.h" #include "core/utils/converter.h" #include "core/common/wolf.h" -#include "core/yaml/parser_yaml.hpp" +#include "core/yaml/parser_yaml.h" using namespace std; using namespace wolf;