{"id":16105100,"url":"https://github.com/noam-dori/dynamica","last_synced_at":"2026-04-20T03:37:19.136Z","repository":{"id":186077833,"uuid":"155350822","full_name":"Noam-Dori/dynamica","owner":"Noam-Dori","description":"a ROS package that allows persistent and dynamic reconfiguration of parameters in a JSON-like manner","archived":false,"fork":false,"pushed_at":"2019-03-25T05:57:06.000Z","size":47,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-29T18:55:44.268Z","etag":null,"topics":["cpp","cpp98","dynamic-reconfigure","ros","ros-kinetic"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Noam-Dori.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-30T08:34:25.000Z","updated_at":"2019-03-25T05:57:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"b0e70992-a650-48ae-806e-274b8283caed","html_url":"https://github.com/Noam-Dori/dynamica","commit_stats":null,"previous_names":["noam-dori/dynamica"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Noam-Dori/dynamica","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noam-Dori%2Fdynamica","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noam-Dori%2Fdynamica/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noam-Dori%2Fdynamica/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noam-Dori%2Fdynamica/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Noam-Dori","download_url":"https://codeload.github.com/Noam-Dori/dynamica/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noam-Dori%2Fdynamica/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32032000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp98","dynamic-reconfigure","ros","ros-kinetic"],"created_at":"2024-10-09T19:08:26.412Z","updated_at":"2026-04-20T03:37:19.118Z","avatar_url":"https://github.com/Noam-Dori.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"Dynamica\n==================================================\n\nDynamica is the successor to the ROS standard package [dynamic_reconfigure](http://wiki.ros.org/dynamic_reconfigure).\nIt includes the features included in its extensions \n[ddyanmic_reconfigure](https://github.com/awesomebytes/ddaynmic_reconfigure) \nand [3d_reconfigure](https://github.com/wew84/3d_reconfigure)\n\n## Dependencies\nDynamica depends only on the default packages.\n\n## Features\n* all features from dyanmic_reconfigure, including their GUI\n* persistance of parameters - any change you did to the parameters will be saved and reloaded\n* extendable parameters via code - allows to give the parameters extra features\n* the ability to 'lock' parameters - disable them from reconfiguration until unlocked.\n* the ability to add and remove parameters to the reconfigure server during runtime.\n* extnesion of the param types to a JSON-like configuration (array and object params)\n* server \u0026 client models for **C++**, **python** (maybe **Java**, **Javascript**?)\n\n## Configuration\nOther than the installation of the package to your workspace, no other configuration is needed.\nThe package used is called ``dynamica``,\nand this both the namespace and the include directory used to implement the program.\n\n# FROM HERE STUFF IS NOT RIGHT AND WILL BE CHANGED IN DUE TIME\n\n## Implementation\nlet us look into the following code, which implements Dynamica:\n````cpp\n#include \u003cros/ros.h\u003e\n\n#include \u003cdynamica/dynamica.h\u003e\n#include \u003cdynamica/param/dd_all_params.h\u003e\n\nusing namespace dynamica;\n\nvoid callback(const ParamMap\u0026 map, int) {\n    ROS_INFO(\"Reconfigure Request: %d %f %s %s %ld\",\n            get(map, \"int_param\").toInt(), get(map, \"double_param\").toDouble(),\n            get(map, \"str_param\").toString().c_str(),\n            get(map, \"bool_param\").toBool() ? \"True\" : \"False\",\n            map.size());\n}\n\nint main(int argc, char **argv) {\n    // ROS init stage\n    ros::init(argc, argv, \"ddynamic_tutorials\");\n    ros::NodeHandle nh;\n\n    // DDynamic setup stage\n    DDynamicReconfigure dd(nh);\n    dd.add(new IntParam(\"int_param\", 0, \"An Integer parameter\", 50, 0, 100));\n    dd.add(new DoubleParam(\"double_param\", 0, \"A double parameter\", .5, 0, 1));\n    dd.add(new StringParam(\"str_param\", 0, \"A string parameter\", \"Hello World\"));\n    dd.add(new BoolParam(\"bool_param\", 0, \"A Boolean parameter\", true));\n    std::map\u003cstd::string, int\u003e dict; // An enum to set size\n        dict[\"Small\"] = 0;      // A small constant\n        dict[\"Medium\"] = 1;     // A medium constant\n        dict[\"Large\"] = 2;      // A large constant\n        dict[\"ExtraLarge\"] = 3; // An extra large constant\n    dd.add(new EnumParam(\"enum_param\", 0, \"A size parameter which is edited via an enum\", 1, dict));\n    dd.start(callback);\n\n    // Actual Server Node code\n    ROS_INFO(\"Spinning node\");\n    ros::spin();\n    return 0;\n}\n````\nThis segment of code is used for declaring the configuration file and for setting up the server in place of the node which uses the parameters.\n\n### Breakdown\n\nLet's break down the code line by line:\n```cpp\n#include \u003cros/ros.h\u003e\n\n#include \u003cdynamica/dynamica.h\u003e\n#include \u003cdynamica/param/dd_all_params.h\u003e\n\nusing namespace dynamica;\n```\nIn here, we import all needed files:\n* ``\u003cros/ros.h\u003e`` provides basic ROS management.\n* ``\u003cdynamica/dynamica.h\u003e`` provides the Dynamica API\n* ``\u003cdynamica/param/dd_all_params.h\u003e`` allows you to use all default parameter types.\n\nThe non include line allows us to use classes and functions provided in the ``dynamica`` namespace\nwithout mentioning what package they are from.\n\nIn contrast to dynamic_reconfigure, these do not change.\n\n```cpp\nvoid callback(const ParamMap\u0026 map, int) {\n    ROS_INFO(\"Reconfigure Request: %d %f %s %s %ld\",\n            get(map, \"int_param\").toInt(), get(map, \"double_param\").toDouble(),\n            get(map, \"str_param\").toString().c_str(),\n            get(map, \"bool_param\").toBool() ? \"True\" : \"False\",\n            map.size());\n}\n```\n\nThis is the callback used when Dynamica receives a parameter change request.\nIt takes two parameters: the first is a map of the new configuration mapping from the name of the parameter to the actual parameter object,\nand the second is the level, which is the highest level of severity caused by the parameter change.\nThis is calculated by applying the OR operator on all levels of the parameters that changed.\n\nIn this callback the level is not used, but we do print out the new configuration.\n\n```cpp\nint main(int argc, char **argv) {\n    // ROS init stage\n    ros::init(argc, argv, \"ddynamic_tutorials\");\n    ros::NodeHandle nh;\n```\n\nAll this section do is initialise our ROS node and its handler.\nThis is default stuff you do anyways.\n\n```cpp\n    // DDynamic setup stage\n    DDynamicReconfigure dd(nh);\n    dd.add(new IntParam(\"int_param\", 0, \"An Integer parameter\", 50, 0, 100));\n    dd.add(new DoubleParam(\"double_param\", 0, \"A double parameter\", .5, 0, 1));\n    dd.add(new StringParam(\"str_param\", 0, \"A string parameter\", \"Hello World\"));\n    dd.add(new BoolParam(\"bool_param\", 0, \"A Boolean parameter\", true));\n```\n\nThis is we start using Dynamica. First, we initialise our Dynamica object.\nThen, we start adding parameters to it. In Dynamica, adding parameters is not just a simple function,\nbut you have to add a parameter object (an instance of the abstract ``Param`` class).\nLet's look into the param objects above to see some common factors:\n* The type of the parameter is declared first by specifying ``new DDType()``.\n  For example, adding a new int parameter is done by doing ``dd.add(new IntParam(...))``\n\n* Within the param constructor, the first argument is the name of the parameter.\n  For example, in our int parameter, the name is set to ``\"int_param\"``.\n\n* The second argument is the level of the parameter, that is,\n  what needs to be reset or redone in the software/hardware in order to reapply this parameter?\n  Usually, the higher the level, the more drastic measures you need to take to re-implement the parameter.\n\n* The third parameter is the description of the parameter. This is great for documentation and for commandline tools.\n\n* The fourth parameter is the default value. Depending on the type of parameter, each may treat this argument differently.\n\n* ``IntParam`` and ``DoubleParam`` have a fifth and sixth optional parameters: minimum and maximum allowed values.\n  While the server side does not care about these values, the client may want to know these.\n\n* It is important to note that the first 4 arguments are standardised for all param types,\n  but from there onwards each param type may choose what to place there.\n\n```cpp\n    std::map\u003cstd::string, int\u003e dict; // An enum to set size\n        dict[\"Small\"] = 0;      // A small constant\n        dict[\"Medium\"] = 1;     // A medium constant\n        dict[\"Large\"] = 2;      // A large constant\n        dict[\"ExtraLarge\"] = 3; // An extra large constant\n    dd.add(new EnumParam(\"enum_param\", 0, \"A size parameter which is edited via an enum\", 1, dict));\n```\n\nHere we add an int-enum parameter to our Dynamica. ``EnumParam`` is an int like parameter that also contains a dictionary\nto remap predefined strings to usable integers. This param type has a required 5th argument (in contract to ``IntParam`` having 5th and 6th optional)\nwhich is a ``std::map\u003cstd::string,int\u003e`` object mapping string values to integers.\n\nIn the code above we can see how to create a dictionary of our liking:\n\n* we first initiate a map and name it with ``std::map\u003cstd::string,int\u003e dict``.\n* we then populate it with the format ``dict[\u003ckey\u003e] = \u003cvalue\u003e`` where ``\u003ckey\u003e`` is the string alias for the value,\n  and ``\u003cvalue\u003e`` is the value you want to give an alias to.\n\nThis dictionary is then added into the enum as the 5th argument.\n\n```cpp\n    dd.start(callback);\n\n    // Actual Server Node code\n    ROS_INFO(\"Spinning node\");\n    ros::spin();\n    return 0;\n}\n```\n\nThis section of code actually allows Dynamica to start working. Let's look into the two sections:\n* ``dd.start(callback)`` sets the callback of Dynamica to be the method ``callback`` and jump starts Dynamica.\n* ``ros::spin()`` allows Dynamica to listen to parameter-change requests.\n  Although the node now requires a spin, this does not mean you cannot add your own service-servers and subscribers to this node.\n  ``ros::spin()`` can take care of multiple subscribers/service-servers in the same spinners (although in the same thread).\n  If you want Dynamica and your actual node to work on separate threads, consider using ``ros::MultiThreadedSpinner``.\n  Dynamica only uses 1 service-server and no subscribers, so 1 thread for it is more than enough.\n\n### How does this compare with Dynamic-Reconfigure?\nLet's go over the main differences between Dynamica's implementation with dynamic_reconfigure's implementation:\n\n#### Parameter Generation\n\n**dynamic_reconfigure:**\n```python\nfrom dynamic_reconfigure.parameter_generator_catkin import *\n\nPACKAGE = \"dynamic_tutorials\"\n\ngen = ParameterGenerator()\n\ngen.add(\"int_param\",    int_t,    0, \"An Integer parameter\", 50,  0, 100)\ngen.add(\"double_param\", double_t, 0, \"A double parameter\",    .5, 0,   1)\ngen.add(\"str_param\",    str_t,    0, \"A string parameter\",  \"Hello World\")\ngen.add(\"bool_param\",   bool_t,   0, \"A Boolean parameter\",  True)\n\nsize_enum = gen.enum([ gen.const(\"Small\",      int_t, 0, \"A small constant\"),\n                       gen.const(\"Medium\",     int_t, 1, \"A medium constant\"),\n                       gen.const(\"Large\",      int_t, 2, \"A large constant\"),\n                       gen.const(\"ExtraLarge\", int_t, 3, \"An extra large constant\")],\n                     \"An enum to set size\")\n\ngen.add(\"size\", int_t, 0, \"A size parameter which is edited via an enum\", 1, 0, 3, edit_method=size_enum)\n\nexit(gen.generate(PACKAGE, \"dynamic_tutorials\", \"Tutorials\"))\n```\n**Dynamica:**\n```cpp\nDDynamicReconfigure dd(nh);\n\ndd.add(new IntParam(\"int_param\", 0, \"An Integer parameter\", 50, 0, 100));\ndd.add(new DoubleParam(\"double_param\", 0, \"A double parameter\", .5, 0, 1));\ndd.add(new StringParam(\"str_param\", 0, \"A string parameter\", \"Hello World\"));\ndd.add(new BoolParam(\"bool_param\", 0, \"A Boolean parameter\", true));\n\nstd::map\u003cstd::string, int\u003e dict; // An enum to set size\n    dict[\"Small\"] = 0;      // A small constant\n    dict[\"Medium\"] = 1;     // A medium constant\n    dict[\"Large\"] = 2;      // A large constant\n    dict[\"ExtraLarge\"] = 3; // An extra large constant\n\ndd.add(new EnumParam(\"enum_param\", 0, \"A size parameter which is edited via an enum\", 1, dict));\n\ndd.start(callback);\n```\nWhile these two code snippets accomplish the exact same things, they do so in different manners:\n* dynamic_reconfigure specifies the type of the parameter using a string (for example ``int_t = \"int\"``), while Dynamica uses classes to accomplish that (``new IntParam`` in place of ``int_t``).\n  \n  Why classes instead of strings? In contrast to strings, classes can be extended and modified so they get a special treatment.\n  Take enums for example. In order to work with enums, dynamic_reconfigure had to add a whole new parameter input to handle the dictionary of the enums,\n  while Dynamica simply extended the ``IntParam`` class (to ``EnumParam``) to handle dictionaries.\n  \n  This will be discussed more thoroughly on \"Architecture\".\n  \n* Enums are dramatically different. \n    * Dynamica uses well defined standard C++ objects for its dictionaries,\n      while dynamic_reconfigure defines its own constants and enums. This allows you to use well known and reliable API instead of a loosely defined one.\n  \n    * while ``EnumParam`` is an extension of ``IntParam``, you do not need to mention that. The API takes care of that for you!\n      An added bonus of this is that the enums automatically inference their boundaries, you don't need to mention ``int_t, max, min``.\n      \n    * Dynamica's supported physical enums have been stripped of descriptions and the constants were as well.\n      This is because the descriptions were not used anywhere. You can still make enums with const and enum descriptions, but they will not be used anywhere.\n      Adding line comments to the parameters is a good alternative.\n\n* Dynamica requires a node handler. This is due to how dynamic_reconfigure handles parameters in its ROS architecture for C++.\n\n* all parameters provided in dynamic_reconfigure's last line are not needed in Dynamica, which requires nothing.\n\n#### Callback \u0026 Server\n\n**dynamic_reconfigure:**\n```cpp\nvoid callback(dynamic_tutorials::TutorialsConfig \u0026config, uint32_t level) {\n  ROS_INFO(\"Reconfigure Request: %d %f %s %s %d\", \n            config.int_param, config.double_param, \n            config.str_param.c_str(), \n            config.bool_param?\"True\":\"False\", \n            config.size);\n}\n\nint main(int argc, char **argv) {\n  ros::init(argc, argv, \"dynamic_tutorials\");\n\n  dynamic_reconfigure::Server\u003cdynamic_tutorials::TutorialsConfig\u003e server;\n  dynamic_reconfigure::Server\u003cdynamic_tutorials::TutorialsConfig\u003e::CallbackType f;\n\n  f = boost::bind(\u0026callback, _1, _2);\n  server.setCallback(f);\n\n  ROS_INFO(\"Spinning node\");\n  ros::spin();\n  return 0;\n}\n```\n**Dynamica:**\n```cpp\nvoid callback(const ParamMap\u0026 map, int) {\n    ROS_INFO(\"Reconfigure Request: %d %f %s %s %ld\",\n            get(map, \"int_param\").toInt(), get(map, \"double_param\").toDouble(),\n            get(map, \"str_param\").toString().c_str(),\n            get(map, \"bool_param\").toBool() ? \"True\" : \"False\",\n            map.size());\n}\n\nint main(int argc, char **argv) {\n    ros::init(argc, argv, \"ddynamic_tutorials\");\n    ros::NodeHandle nh;\n\n    DDynamicReconfigure dd(nh);\n    \n    dd.start(callback);\n\n    ROS_INFO(\"Spinning node\");\n    ros::spin();\n    return 0;\n}\n```\n\n* The callback of the dynamic_reconfigure requires a custom data-type per configuration. This is problematic, especially if you want dynamic parameters like vectors.\n  Dynamica uses ``ParamMap`` as its parameter container, which is generic and can work over multiple config types (and therefore can handle vectors)\n  \n  This also changes the way to access these parameters.\n  ``ParamMap`` is actually a map from string to a pointer to the generic parameter used with the parameter generator.\n  This allows you to use all functions ``std::map`` provides, and regardless, Dynamica has additional API that could be used on ``ParamMap`` objects,\n  such as ``dynamica::get`` and ``dynamica::at``.\n  \n  The generic interface no longer gives you a specific primitive value, but rather an instance of ``dynamica::Value``,\n  which must be converted into a primitive type. While a bit cumbersome, this does allow rather implicit conversion between types.\n  \n* The Dynamica server does not internally initialise a node handler. This means you can implement Dynamica within the node that actually uses the parameters.\n\n* Dynamica actually needs you to start it. While a disadvantage, it is done anyways on dynamic_reconfigure,\n  and Dynamica also has ``DDynamicReconfigure::setCallback`` to change callbacks, so nothing much is lost.\n\n* again, Dynamica does not require you to have a custom made config class, making your init code a lot shorter.\n\n* ``start`` is a bit more fluid and allows you to place member function pointers or regular function pointers instead of ``boost::function``.\n  This helps clean up the code.\n\n### Simplified API\n\n#### Value\n\nThe Value class is used to wrap all basic data-types (bool,int,double,string) in something generic.\nThe value object always stores an explicit basic data-type.\nThis has three main uses:\n\n1. Values can represent all basic data-types. This means that arguments that need something relatively similar from all basic data-types can now just use the value in its argument.\n   This also goes for when you need to return something that is of different data-types from different classes (one can only return integer, other can only return strings).\n\n2. Values can be explicitly converted to all basic data-types they wrap. \n   This means that converting an int to a string is far easier.\n\n3. Values store the type they were instantiated with. This can be tested against to get the original piece of data the value stored.\n\n##### Constructors\n\n``Value(int val)``,``Value(double val)``,``Value(bool val)``,``Value(string val)``,``Value(const char* val)``\nare all constructors that assign the value type to the type they are given (with the exception for ``const char*`` which returns string and is there for convenience),\nthen store the value itself in its basic form.\n\n##### Getter\n\nThere is only one true getter: ``getType()``, which returns the string name of the type it stores.\n\n##### Converters\n\nEach basic data-type has its own converter: ``toInt()``,``toDouble()``,``toBool()``,``toString()``.\nWhen one is called, the value will attempt to return a converted form of what it stores into the required data-type.\nThe value does not just use an implicit cast. It tries to convert the data-type according to common needs that are not answered with other one-liners.\nFor example, converting a string to an int, a Value will first attempt to scan the string and see it fits a numeric format.\nIf it succeeds, it will convert and return that number. Otherwise, it will return the next best thing: a hash value of the string.\n\n#### Param\n\nThe Param class is *the* abstraction of all parameter types, and is the template for creating them.\nAt this point, not much is known about the parameter, but the following:\n\n* the parameter has a name\n* the parameter has a severity level\n* the parameter has a description\n* the parameter contains some value, though its type and contents are unknown.\n\nOther than storing data, the parameter also has specialised methods to interact with DDynamicReconfigure in order to apply changes and send them.\nThese methods should not be touched by the user.\n\nSince this class is abstract, the class has multiple implementations whicch are not directly exposed but are used,\nso its worth checking out their descriptions.\n\nWhile this class is abstract, it does have one implemented thing, and that is its stream operator (`\u003c\u003c`) which can be freely used.\n\n##### Generic Constructor\n\nWhile Param is abstract, all of its concrete implementations should follow this guideline:\n```cpp\nDD\u003cType\u003e(const string \u0026name, unsigned int level, const string \u0026description, \u003csome-type\u003e def, \u003cextra-args\u003e)\n```\nWhere:\n* ``\u003cType\u003e`` is the type name you are implementing\n* ``name`` is the reference name\n* ``level`` is the severity level\n* ``description`` is the object's description\n* ``def`` is the default value and the first value stored right after construction.\n\nYou may then include extra arguments as you wish, required or optional.\n\n##### Getters\n\nparameters have three well known getters:\n* ``getName()`` gets the name of the parameter.\n* ``getLevel()`` gets the severity level of the parameter.\n* ``getValue()`` gets the value the parameter stores.\n\nOther getters, such as \"getDesc()\", may be added in the future.\n\nthe parameters also have a stream (``\u003c\u003c``) operator which can be used to convert said parameters into neat strings.\n\n##### Setter\n\n2D-params are only required to be dynamic with their values,\nso the only setter they are required to have is ``setValue(Value val)``,\nwhich changes the value the parameter stores.\n\n##### Testers\n\nDDParams are also required to have some out-of-the-box testing features:\n* ``sameType(Value val)`` checks whether or not \n  the raw value stored in the value is compatible with the given parameter.\n  Compatible is a very broad word in this scenario.\n  It means that the value can be placed in the parameter regardless of other limitations.\n\n* ``sameValue(Value val)`` checks whether or not the value stored in the value object,\n  when converted to the type of the internal value, are equal. This acts regardless of type.\n\n#### DDynamicReconfigure\n\nThe DDynamicReconfigure class is the main class responsible for keeping track of parameters basic properties,\nvalues, descriptions, etc.\n\nIt is also responsible of handling callbacks, config change requests, description setup and config setup, and the ROS publishers and services.\n\nTo operate a DDynamic instance, you must go through the following procedure:\n\n1. Construct a DDynamicReconfigure instance with proper handling.\n2. Add parameters to the instance as needed with any of the ``add`` methods.\n3. Start the ROS services with any of the ``start`` methods.\n4. If you need to change the callback after startup you may do so using ``setCallback``.\n5. When you need to get any of the stored parameters, call either ``get`` or ``at`` on this instance,\n   rather than through the callback.\n\n##### Constructor\n\nDDynamicReconfigure has one sole constructor: ``DDynamicReconfigure(NodeHandle \u0026nh)`` which constructs the instance and\nsets the handler to the one you are using.\n\n##### Parameter Handling\n\nAll parameter handling is done through registration using an ``add`` function:\n\n* ``add(ParamPtr param)`` is the main function which uses boost's shared pointers to represent the data in a virtual manner (and allows polymorphism)\n* ``add(Param *param)`` is a convenience function which converts ``param`` into a shared pointer and uses the other add function.\n\nBoth of these functions will add a generic ``Param`` object into the given instance and will index it for later searches.\nPerhaps in the future a \"remove(string name)\" function will be added.\n\n##### Callback Handling \u0026 Startup\n\nBelow are the two default functions that are used by the rest:\n\n* ``start()`` initializes all publishers and services and releases the needed messages for the commandline and other clients.\n* ``setCallback(ReconfigureFunction callback)`` sets the triggered callback to the one specified, and triggers nothing else.\n\nThere is also ``clearCallback()`` which resets the callback to do nothing when triggered.\n\nFollowing are convenience function which utilize ``start()`` and ``setCallback()``:\n\n* ``start(ReconfigureFunction callback)`` calls start(), then setCallback(callback)\n* ``start(void(*callback)(const ParamMap\u0026, int))`` remaps the void pointer to a boost function (of type ``ReconfigureFunction``) then calls start(callback)\n* ``template\u003cclass T\u003e void start(void(T::*callback)(const ParamMap\u0026, int), T *obj)``\n  binds the **member** function into a boost function (of type ``ReconfigureFunction``) then calls start(callback)\n\n##### Parameter Fetching\n\nThere are multiple proper ways to get the values stored within the DDynamicReconfigure instance:\n\n* through ``at(string name)``: this will get you the pointer to the parameter with the name you specified.\n  If no such parameter exists it will return you a null-pointer (be careful not to de-reference those!)\n\n* through ``get(string name)``: this will get you the value stored in the parameter with the name you specified.\n  If no such parameter exists it will return you a value storing a NULL character.\n\n* through the stream (``\u003c\u003c``) operator: this will convert the Dynamica instance into a string and stream it into the\n  given streamer.\n\nboth ``at`` and ``get`` have alternate static versions which apply directly on ``ParamMap`` objects.\n\n## Architecture\n\n### Code Design\n\n#### Include Structure:\n\n![](http://www.plantuml.com/plantuml/png/3OnDIuP054Rt_efQjCm9JB8WqcXJ44Nu4hIH-RZgu7p8dNiT_FSDFAk7SqwVI2AnTzMr3Tgn0KPtjHBjwKa8bBbUBAsiE07g60W2rJfw8JEaw46T14aOSmRfhPuG2ZFRXH54XjpTtneuHAcBsJgO4Y5hglTol53S83mFxpzt-FNuyA7KvLDVpAiST3isgg6vu-_VRakj-ZlMCGytpLjPrKCmHVy7)\n\nTo operate Dynamica, you will need to include 2 file types:\n\n* The ``dynamica`` file, which gives you access to the ``DDynamicReconfigure`` class,\n  the ``Param`` class, the ``DDValue`` class, and the toolbox methods.\n  This will allow you to operate on the top level API without caring about what type of parameters you will get.\n\n* the file ``dd_all_params`` or any of the ``Param`` implementations. You will need the implementations to insert physical \n  (and not abstract) parameters into your ``DDynamicReconfigure`` server.\n  As a shortcut, ``dd_all_params`` gives you all basic parameter types (int,double,bool,string,enum) in one include.\n\nAs a bonus, you also get two static class-less methods: ``get`` and ``at``.\n\n#### Class Structure:\n\n![](http://www.plantuml.com/plantuml/png/3OnBIyD054Rt_HMwS6d6HmDH43EIZRfgmOBTX7dS96Fc4Uwzqw7_te5lzN7EwOaLSWv-T-kYyTb2Hd-pC6_qAWIgqioEbwmp0PeK6I8t9WMX2b0AeAyC9AozHXMS6H4gCxav8uW2fTlVMxY8MXV6AwAH6BFXPglFEwSLuflyF3wWXDFJYlmrdDpXyNl_yN9e_xhsz-UevKgjFbzWAlBkUQZRzH1jrVy1)\n\nLike the API section shows, there are only 3 major classes: ``DDValue``,``Param``,``DDynamicReconfigure``.\n\nThe DDValue class is a concrete class which should not be inherited, since it wraps physical values. \nEach instance stores 5 values: one for each type is can handle, and one to store the type.\nWhen a value is instantiated, the value is stored in its raw form according to the chosen type,\nand the rest stay with default values. When the value is accessed only then is the value converted (but not saved!)\n\nThe Param interface class is an abstract class which should be implemented. \nIts basic implementations (int,double,bool,string) have already been implemented in the standard package.\nThese basic forms can also be further extended. For example, EnumParam **extends** IntParam because it has all of the features IntParam has.\nThis can be done to other Param implementations, and you can also further extend the extended classes (for example, DDInvertibleEnum).\nAn example is given at the Extension section if you want to look more into this.\nWhen anny Param implementation is extended, the user has access to everything within the object so that he can do what he needs to.\n\nThe DDynamicReconfigure class is the concrete class that does the work against ROS and interfaces with the user.\nUnlike DDValue, this class can be extended, and it has an internal API that can aid users who wish to extend this class.\nIn the Extension section below this is elaborated. Keep in mind that extending DDynamicReconfigure is not required.\nWhile DDynamicReconfigure allows extension, it does not provide full access to everything,\nsince the base function of DDynamic should not be modified.\n\n### ROS Design\n\n![](http://www.plantuml.com/plantuml/png/3OnDIyKm44Nt_HMwS6aZg222s8BWgo8QGOHkGZwcRMoJb9b9m_lt1kxcmZcd8zR8EMpDfOzsomuoRXSByqwFGg0kxUnvoIOJe4sH8N9hKn2w0AK0vin0mhbprC5RXL2PoSyPGHGe3tVN3WvHwm8JAMBCbjkz_cTEAyIdVlY-mTFRwxiCgAIHu_JpgORVrG38hzF7ljAz6Oy_MVghsvUwfeFegluF)\n\nLike dynamic_reconfigure, Dynamica is built on two subscribers and one service:\n\n* ``info_pub_`` publishes to topic \"/parameter_descriptions\", and is responsible for updating the descriptions of the parameter for commandline.\n* ``value_pub_`` publishes to \"/parameter_descriptions\", and is responsible for updating the configuration values for commandline and client.\n* ``set_service`` publishes and listens to requests on \"/set_parameters\", and is used to trigger parameter updates.\n  It also contains the new parameters sent from client or commandline.\n\nSince the DDynamicReconfigure object is held on the server side, so are these ROS entities.\n\n## Extension\n\n***In all of these extensions, make sure to add the proper includes!***\n\n### Adding a new Parameter type\n\nTo add a new parameter type, you must either:\n* Extend one of the existing classes\n* Implement the base class, ``Param``.\n\nIn some cases, you might want your class to extend multiple classes, for example ``DDIntVector`` both implements ``DDVector`` and extends ``IntParam``.\n(``DDVector`` does not exist in the standard param library).\n\nLet us look into an example implementation of the param type \"DDIntEnforcer\", which will update other parameters to its value when it updates.\n\n```cpp\n#ifndef dynamica_INT_ENFORCER_PARAM_H\n#define dynamica_INT_ENFORCER_PARAM_H\n\n#include \u003cdynamica/param/dd_int_param.h\u003e\n#include \u003clist\u003e\n\nnamespace my_dd_reconfig {\n    // class definition\n    class DDIntEnforcer : public IntParam {\n    public:\n\n        void setValue(Value val);\n        \n        // adds a parameter to be enforced by this param.\n        DDIntEnforcer \u0026addEnforced(ParamPtr param);\n        \n        // removes a parameter from being enforced by this param.\n        void removeEnforced(ParamPtr param);\n\n        /**\n         * creates a new int enforcer param\n         * @param name the name of the parameter\n         * @param level the change level\n         * @param def the default value\n         * @param description details about the parameter\n         * @param max the maximum allowed value. Defaults to INT32_MAX\n         * @param min the minimum allowed value. Defaults to INT32_MIN\n         */\n        inline DDIntEnforcer(const string \u0026name, unsigned int level, const string \u0026description,\n                int def, int max = INT32_MAX, int min = INT32_MIN) :\n                IntParam(name,level,description,def) {};\n\n    protected:\n        list\u003cParamPtr\u003e enforced_params_;\n    };\n    \n    DDIntEnforcer::setValue(Value val) {\n        val_ = val.toInt();\n        for(list\u003cParamPtr\u003e::iterator it = enforced_params_.begin(); it != enforced_params_.end(); ++it) {\n            if(!enforced_params_[it].sameValue(val)) {\n                enforced_params_[it].setValue(val);\n            }\n        }\n    };\n    \n    DDIntEnforcer \u0026DDIntEnforcer::addEnforced(ParamPtr param) {\n        enforced_params_.push_back(param);\n        return *this;\n    };\n    \n    void DDIntEnforcer::removeEnforced(ParamPtr param) {\n        enforced_params_.remove(param);\n    };\n}\n\n#endif //dynamica_INT_ENFORCER_PARAM_H\n```\n\nNotice how nothing within this class is private. This allows further extension of this class.\nMoreover, notice that in here we are also using variables inherited from ``IntParam``, specifically ``val_``.\n\n### Extending DDynamic's functions\n\nExtending DDynamicReconfigure means that you need additional functionality from the parameter server which Dynamica does not provide.\nIf that is the case, extending a class from DDynamic gives you access to make new methods as need for the extra functionality,\nand access to the following to make work with DDynamic a bit easier:\n* ``nh_``: this is the node handler used to create all publishers and subscribers in the parent class.\n* ``params_`` this is the current parameter map Dynamica uses to update parameters and add new ones.\n* ``info_pub_``: As explained before, this is the publisher responsible of updating the descriptions for the parameters and other metadata for the client and commandline.\n* ``value_pub_``: This is the publisher responsible for updating the configuration values for the client and commandline.\n* ``makeInfo()``: This is a helper method that generates a new Description message to be published by ``info_pub_``.\n  The message can be modified.\n* ``makeConfiguration()``: This is a helper method that generates a new Description message to be published by ``value_pub_``.\n  The message can be modified.\n* ``internalCallback()``: This is a helper method that allows you to call the base param change callback built into Dynamica.\n\nFrom there, it's your choice what to do with these.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoam-dori%2Fdynamica","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoam-dori%2Fdynamica","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoam-dori%2Fdynamica/lists"}