GithubHelp home page GithubHelp logo

mit-spark / config_utilities Goto Github PK

View Code? Open in Web Editor NEW
23.0 5.0 4.0 457 KB

Automatic C++ config structs and tools.

License: BSD 3-Clause "New" or "Revised" License

CMake 1.53% C++ 97.06% C 0.54% Python 0.87%
config cpp ros tools utilities yaml

config_utilities's Introduction

CMake: Build ROS Noetic: Build

config_utilities

config_utilities is a minimal but powerful C++ library, providing tools to parse, verify, and print C++ config structs and configurable objects.

Table of contents

Credits

This library was developed by Lukas Schmid and Nathan Hughes at the MIT-SPARK Lab, based on functionalities in ethz-asl/config_utilities and Hydra, and is released under a BSD-3-Clause License! Additional contributions welcome! This work was supported in part by the Swiss National Science Foundation and Amazon.

Why config_utilities?

Among many other, the key features of config_utilities include:

  • Minimal dependencies: Only C++17 standard library and yaml-cpp.

  • Declare any struct a config, also from external projects:

    namespace external_project {
        void declare_config(ExternalObject& config); // that's all!
    }   // namespace external_project
  • Minimal and clear, human readable interfaces for config definitions:

    void declare_config(MyConfig& config) {
        using namespace config;
        name("MyConfig");                             // Name for printing.
        field(config.distance, "distance", "m");      // Field definition.
        check(config.distance, GT, 0.0, "distance");  // Ensure 'distance > 0'.
    }
  • Everything related to a config is defined in a single place.

    void declare_config(MyConfig& config) { /* ALL the information about a config is here */ }
  • Parse any declared config from various data sources, without pulling in dependencies on data sources into core libraries:

    core.cpp {
        struct MyConfig { ... };
        void declare_config(MyConfig& config) { ... };
    }  // Depends only on C++ and yaml-cpp.
    
    application.cpp {
        MyConfig config1 = fromYamlFile<MyConfig>(file_path);
        MyConfig config2 = fromRos<MyConfig>(node_handle);
    }  // Pull in dependencies as needed.
  • Automatically implements frequently used functionalities, such as checking for valid parameters and formatting to string:

    MyObject(const MyConfig& config) : config_(checkValid(config)) {
        // Do magic with config_, which has valid parameters only.
        std::cout << config_ << std::endl;
    }
  • Automatic run-time module creation based on specified configurations:

    static auto registration = Registration<Base, MyDerived>("my_derived");
    
    const std::string module_type = "my_derived";
    std::unique_ptr<Base> module = create(module_type);
  • Informative, clear, and human readable printing of potentially complicated config structs:

    =================================== MyConfig ===================================
    distance [m]:                 -0.9876
    A ridiculously long field name that will not be wrapped: Short Value (default)
    A ridiculously long field name that will also not be wrapped:
                                  A really really really ridiculously long string th
                                  at will be wrapped. (default)
    A really really really really really really ridiculously long field name that wi
    ll be wrapped:                A really really really ridiculously long string th
                                  at will also be wrapped. (default)
    vec:                          [5, 4, 3, 2, 1]
    map:                          {b: 2, c: 3, d: 4, e: 5}
    mat:                          [[1, 2, 3],
                                   [4, 5, 6],
                                   [7, 8, 9]]
    my_enum:                      B
    sub_config [SubConfig] (default):
       f:                         0.123 (default)
       s:                         test (default)
       sub_sub_config [SubSubConfig] (default):
          color:                  [255, 127, 0] (default)
          size:                   5 (default)
    ================================================================================
    
  • Verbose warnings and errors if desired for clear and easy development and use:

    =================================== MyConfig ===================================
    Warning: Check failed for 'distance': param > 0 (is: '-1').
    Warning: Check failed for 'subconfig.f': param within [0, 100) (is: '123').
    Warning: Failed to parse param 'vec': Data is not a sequence.
    Warning: Failed to parse param 'mat': Incompatible Matrix dimensions: Requested
            3x3 but got 3x4.
    Warning: Failed to parse param 'my_enum': Name 'D' is out of bounds for enum wit
            h names ['A', 'B', 'C'].
    Warning: Failed to parse param 'uint': Value '-1' underflows storage min of '0'.
    ================================================================================
    
    [ERROR] No module of type 'NotRegistered' registered to the factory for BaseT='d
    emo::Base' and ConstructorArguments={'int'}. Registered are: 'DerivedB', 'Derive
    dA'.
    
    [ERROR] Cannot create a module of type 'DerivedA': No modules registered to the
    factory for BaseT='demo::Base' and ConstructorArguments={'int', 'float'}. Regist
    er modules using a static config::Registration<BaseT, DerivedT, ConstructorArgum
    ents...> struct.
    

Installation

This package is compatible with catkin and catkin_simple. Just clone it into your workspace and you should be all set!

cd ~/catkin_ws/src
git clone [email protected]:MIT-SPARK/config_utilities.git
catkin build config_utilities

If you want to build and install without catkin/ROS, that is easy, too! Just clone this repository and build via CMake:

git clone [email protected]:MIT-SPARK/config_utilities.git
cd config_utilities/config_utilities
mkdir build
cd build
cmake ..
make -j

# optionally install this package
sudo make install

How to config_utilities

We provide detailed introductions about everything you need to know about config_utilities in the following tutorials and some verbose example demos that you can run.

The (non-ros) demos can be run via the run_demo.py utility in the scripts directory. If you are building this library via catkin, you can run one of the following to see the results of one of the corresponding demo files:

python3 scripts/run_demo.py config
python3 scripts/run_demo.py inheritance
python3 scripts/run_demo.py factory

ℹī¸ Note
If you're building via cmake, you can point run_demo.py to the build directory with -b/--build_path.

The ros demo can be run via:

roslaunch config_utilities demo_ros.launch

If you are looking for a specific use case that is not in the tutorials or demos, chances are you can find a good example in the tests/ directory!

Example Projects using config_utilities

Many cool projects are already using this config_utilities! (Unfortunately they're mostly currently private, we will list them soon as they become publicly available). Check them out for some more ideas of what config_utilities can do!

config_utilities's People

Contributors

floriantschopp avatar nathanhhughes avatar nkhedekar avatar schmluk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

config_utilities's Issues

`demo_params.yaml` does not exist in the `resources` folder.

Hello, maintainers!

I just tested a roslaunch version of config_utilities, but the error message comes as follows:

RLException: error loading <rosparam> tag: 
	file does not exist [/home/shapelim/config_ws/src/config_utilities/config_utilities/demos/resources/demo_params.yaml]
XML is <rosparam file="$(find config_utilities)/demos/resources/demo_params.yaml"/>
The traceback for the exception was written to the log file

since in demo_ros.launch, it requires $(find config_utilities)/demos/resources/demo_params.yaml, but it does not exist.


I guess it should be params.yaml, right?

If I tested it by using params.yaml, then it output as follows:

SUMMARY
========

PARAMETERS
 * /demo_ros/b: False
 * /demo_ros/distance: -0.9876
 * /demo_ros/i: 123
 * /demo_ros/map/b: 2
 * /demo_ros/map/c: 3
 * /demo_ros/map/d: 4
 * /demo_ros/map/e: 5
 * /demo_ros/mat: [[1, 2, 3], [4, 5...
 * /demo_ros/my_enum: B
 * /demo_ros/s: a string in a file
 * /demo_ros/sub_ns/color: [255, 255, 255]
 * /demo_ros/sub_ns/f: 55555.55555
 * /demo_ros/sub_ns/size: 101010101
 * /demo_ros/vec: [5, 4, 3, 2, 1]
 * /rosdistro: noetic
 * /rosversion: 1.16.0

NODES
  /
    demo_ros (config_utilities/demo_ros)

ROS_MASTER_URI=http://localhost:11311

process[demo_ros-1]: started with pid [4049935]
[ INFO] [1703653451.855092553]: 
=================================== MyConfig ===================================
i:                            123
distance [m]:                 -0.9876
b:                            false
vec:                          [5, 4, 3, 2, 1]
map:                          {b: 2, c: 3, d: 4, e: 5}
mat:                          [[1, 2, 3],
                               [4, 5, 6],
                               [7, 8, 9]]
my_enum:                      B
sub_config [SubConfig] (default):
   f:                         0.123 (default)
   s:                         test (default)
================================================================================
[ INFO] [1703653451.862168879]: I'm a DerivedA with config.f='0.123'.
[ WARN] [1703653451.867913264]: Errors parsing config 'MyConfig':
=================================== MyConfig ===================================
Warning: Failed to parse param 'vec': Data is not a sequence.
================================================================================
[ WARN] [1703653451.868092917]: Invalid config 'MyConfig':
=================================== MyConfig ===================================
Warning: Check [1/2] failed for 'i': param > 0 (is: '-1').
================================================================================
[ERROR] [1703653451.872575964]: No module of type 'A random type' registered to the factory for BaseT='demo::Base' and ConstructorArguments={}. Registered are: 'DerivedB', 'DerivedA'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.