From 72bc080af0eadf9558e157f6051e7e5e1d0638cf Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Sun, 29 Oct 2017 20:34:13 +0100 Subject: [PATCH 01/22] Separate ParameterBase & derived generation --- include/rosparam_handler/ParametersBase.h | 88 +++++++++++++++++ templates/Parameters.h.template | 111 ++++++++++++---------- 2 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 include/rosparam_handler/ParametersBase.h diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h new file mode 100644 index 0000000..4ff33dc --- /dev/null +++ b/include/rosparam_handler/ParametersBase.h @@ -0,0 +1,88 @@ +/** + * \file ParametersBase.h + * + * Created on: Oct 28, 2017 + * \author: Jeremie Deray + */ + +//#pragma once + +#ifndef _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ +#define _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ + +#include +#include +#include + +namespace rosparam_handler { + +/// \brief ParametersBase A base struct for struct generated by rosparam_handler. +struct ParametersBase { + + ParametersBase(const ros::NodeHandle& private_node_handle) + : globalNamespace{"/"}, + privateNamespace{private_node_handle.getNamespace() + "/"}, + nodeName{rosparam_handler::getNodeName(private_node_handle)} {} + + virtual ~ParametersBase() = default; + + /// \brief Get values from parameter server + /// + /// Will fail if a value can not be found and no default value is given. + inline void fromParamServer(){ + if(!fromParamServerImpl()){ + missingParamsWarning(); + rosparam_handler::exit("RosparamHandler: GetParam could net retrieve parameter."); + } + ROS_DEBUG_STREAM(*this); + } + + /// \brief Set parameters on ROS parameter server. + virtual void toParamServer() = 0; + + /// \brief Update configurable parameters. + /// + /// \param config dynamic reconfigure struct + /// \level ? + template + inline void fromConfig(const T& config, const uint32_t level = 0){ +#ifdef DYNAMIC_RECONFIGURE_FOUND + fromConfigImpl(config, level); +#else + ROS_FATAL_STREAM("dynamic_reconfigure was not found during compilation. So fromConfig() is not available. Please recompile with dynamic_reconfigure."); + rosparam_handler::exit("dynamic_reconfigure was not found during compilation. So fromConfig() is not available. Please recompile with dynamic_reconfigure."); +#endif + } + + /// \brief Stream operator for printing parameter struct + inline friend std::ostream& operator<<(std::ostream& os, const ParametersBase& p) + { + return p.print(os); + } + +protected: + + virtual bool fromParamServerImpl() = 0; + + template + void fromConfigImpl(const T& config, const uint32_t level); + //{ + // ROS_FATAL_STREAM("Called function fromConfigImpl with unknown input argument type."); + // rosparam_handler::exit("Called function fromConfigImpl with unknown input argument type."); + //} + + virtual std::ostream& print(std::ostream& os) const = 0; + + /// \brief Issue a warning about missing default parameters. + virtual void missingParamsWarning() = 0; + + const std::string globalNamespace = {"/"}; + const std::string privateNamespace; + const std::string nodeName; +}; + +using ParametersPtr = boost::shared_ptr; + +} // namespace rosparam_handler + +#endif /* _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ */ diff --git a/templates/Parameters.h.template b/templates/Parameters.h.template index a493f0d..183c94f 100644 --- a/templates/Parameters.h.template +++ b/templates/Parameters.h.template @@ -6,82 +6,91 @@ // // ********************************************************/ -#pragma once +#ifndef _${pkgname}_ROSPARAM_HANDLER_${ClassName}Parameters_H_ +#define _${pkgname}_ROSPARAM_HANDLER_${ClassName}Parameters_H_ + +#include -#include -#include -#include #ifdef DYNAMIC_RECONFIGURE_FOUND #include <${pkgname}/${ClassName}Config.h> #else struct ${ClassName}Config{}; #endif - namespace ${pkgname} { /// \brief Parameter struct generated by rosparam_handler -struct ${ClassName}Parameters { +struct ${ClassName}Parameters : public rosparam_handler::ParametersBase { using Config = ${ClassName}Config; - ${ClassName}Parameters(const ros::NodeHandle& private_node_handle) - : globalNamespace{"/"}, - privateNamespace{private_node_handle.getNamespace() + "/"}, - nodeName{rosparam_handler::getNodeName(private_node_handle)} {} - - /// \brief Get values from parameter server - /// - /// Will fail if a value can not be found and no default value is given. - void fromParamServer(){ - bool success = true; -$fromParamServer -$test_limits - if(!success){ - missingParamsWarning(); - rosparam_handler::exit("RosparamHandler: GetParam could net retrieve parameter."); - } - ROS_DEBUG_STREAM(*this); - } + inline ${ClassName}Parameters(const ros::NodeHandle& private_node_handle) : + ParametersBase(private_node_handle) {} /// \brief Set parameters on ROS parameter server. - void toParamServer(){ -$toParamServer + void toParamServer() override { +$toParamServer } - /// \brief Update configurable parameters. - /// - /// \param config dynamic reconfigure struct - /// \level ? - void fromConfig(const Config& config, const uint32_t level = 0){ -#ifdef DYNAMIC_RECONFIGURE_FOUND -$fromConfig -#else - ROS_FATAL_STREAM("dynamic_reconfigure was not found during compilation. So fromConfig() is not available. Please recompile with dynamic_reconfigure."); - rosparam_handler::exit("dynamic_reconfigure was not found during compilation. So fromConfig() is not available. Please recompile with dynamic_reconfigure."); -#endif - } + $parameters - /// \brief Stream operator for printing parameter struct - friend std::ostream& operator<<(std::ostream& os, const ${ClassName}Parameters& p) - { - os << "[" << p.nodeName << "]\nNode " << p.nodeName << " has the following parameters:\n" -$string_representation; - return os; - } +protected: - $parameters + /// \brief Get values from parameter server + /// + /// Will fail if a value can not be found and no default value is given. + inline bool fromParamServerImpl() override { + + bool success = true; + + $fromParamServer + $test_limits + + return success; + + } + + /// \brief Print function to be called from base stream operator for printing parameter struct + inline std::ostream& print(std::ostream& os) const override + { + os << "[" << nodeName << "]\nNode " << nodeName << " has the following parameters:\n" + $string_representation; + return os; + } -private: /// \brief Issue a warning about missing default parameters. - void missingParamsWarning(){ + inline void missingParamsWarning() override { ROS_WARN_STREAM("[" << nodeName << "]\nThe following parameters do not have default values and need to be specified:\n" $non_default_params ); } - const std::string globalNamespace; - const std::string privateNamespace; - const std::string nodeName; }; } // namespace ${pkgname} + +#ifdef DYNAMIC_RECONFIGURE_FOUND +namespace rosparam_handler +{ + + // Specialize base class fromConfigImpl. + + template<> + inline void ParametersBase::fromConfigImpl<${pkgname}::${ClassName}Config>( + const ${pkgname}::${ClassName}Config& config, const uint32_t level ) + { + try { + ${pkgname}::${ClassName}Parameters& casted_ref = dynamic_cast<${pkgname}::${ClassName}Parameters&>(*this); + + $fromConfig + } + catch (const std::bad_cast& e) + { + ROS_FATAL("In ParametersBase::fromConfig, bad cast to type ${pkgname}::${ClassName}Parameters !"); + rosparam_handler::exit("In ParametersBase::fromConfig, bad cast to type ${pkgname}::${ClassName}Parameters !"); + } + } + +} +#endif + +#endif /* _${pkgname}_ROSPARAM_HANDLER_${ClassName}Parameters_H_ */ From 1b9ef584deea0b6f6ec2e0155b52ae530fc5af51 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Sun, 29 Oct 2017 20:34:41 +0100 Subject: [PATCH 02/22] fix derived parameter generation script --- src/rosparam_handler/parameter_generator_catkin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rosparam_handler/parameter_generator_catkin.py b/src/rosparam_handler/parameter_generator_catkin.py index 015b112..5602f49 100644 --- a/src/rosparam_handler/parameter_generator_catkin.py +++ b/src/rosparam_handler/parameter_generator_catkin.py @@ -434,7 +434,7 @@ def _generatehpp(self): # Test for configurable params if param['configurable']: - from_config.append(Template(' $name = config.$name;').substitute(name=name)) + from_config.append(Template(' casted_ref.$name = config.$name;').substitute(name=name)) # Test limits if param['is_vector']: @@ -451,7 +451,7 @@ def _generatehpp(self): paramname=full_name, name=name, max=param['max'], type=ttype)) # Add debug output - string_representation.append(Template(' << "\t" << p.$namespace << "$name:" << p.$name << ' + string_representation.append(Template(' << "\t" << $namespace << "$name:" << $name << ' '"\\n"\n').substitute(namespace=namespace, name=name)) param_entries = "\n".join(param_entries) From 77a8b73309cf6024a5c8086ffabd8060c67000d1 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Sun, 29 Oct 2017 20:35:07 +0100 Subject: [PATCH 03/22] add gtest for ParameterBase --- test/cfg/Bar.params | 16 +++ test/cfg/Foo.params | 16 +++ test/src/test_base_param.cpp | 240 +++++++++++++++++++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 test/cfg/Bar.params create mode 100644 test/cfg/Foo.params create mode 100644 test/src/test_base_param.cpp diff --git a/test/cfg/Bar.params b/test/cfg/Bar.params new file mode 100644 index 0000000..e37c2e9 --- /dev/null +++ b/test/cfg/Bar.params @@ -0,0 +1,16 @@ +#!/usr/bin/env python +####### workaround so that the module is found ####### +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__),"../../src")) +###################################################### + +from rosparam_handler.parameter_generator_catkin import * +gen = ParameterGenerator() + +# Parameters with different types +gen.add("str_param", paramtype="std::string", description="A string parameter", default="param b", configurable=True) +gen.add("vector_int_param", paramtype="std::vector", description="A vector of int parameter", default=[1,2,3]) + +#Syntax : Package, Node, Config Name(The final name will be MyDummyConfig) +exit(gen.generate("rosparam_handler", "rosparam_handler_test", "Bar")) diff --git a/test/cfg/Foo.params b/test/cfg/Foo.params new file mode 100644 index 0000000..3f4eace --- /dev/null +++ b/test/cfg/Foo.params @@ -0,0 +1,16 @@ +#!/usr/bin/env python +####### workaround so that the module is found ####### +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__),"../../src")) +###################################################### + +from rosparam_handler.parameter_generator_catkin import * +gen = ParameterGenerator() + +# Parameters with different types +gen.add("int_param", paramtype="int", description="An Integer parameter", default=1, configurable=True) +gen.add("str_param", paramtype="std::string", description="A string parameter", default="param a", configurable=True) + +#Syntax : Package, Node, Config Name(The final name will be MyDummyConfig) +exit(gen.generate("rosparam_handler", "rosparam_handler_test", "Foo")) diff --git a/test/src/test_base_param.cpp b/test/src/test_base_param.cpp new file mode 100644 index 0000000..9292822 --- /dev/null +++ b/test/src/test_base_param.cpp @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include + +typedef rosparam_handler::FooParameters FooParameters; +typedef rosparam_handler::BarParameters BarParameters; + +typedef rosparam_handler::FooConfig ConfigA; +typedef rosparam_handler::BarConfig ConfigB; + +class TestRosparamHandlerBase : public testing::Test +{ +public: + + TestRosparamHandlerBase() = default; + ~TestRosparamHandlerBase() = default; + + struct DummyBase + { + DummyBase(const std::string& nh_namespace) : + nh_(nh_namespace) { } + + virtual ~DummyBase() = default; + + template + void init() + { + params_ptr_ = boost::make_shared(nh_); + } + + void fromParamServer() + { + params_ptr_->fromParamServer(); + } + + void toParamServer() + { + params_ptr_->toParamServer(); + } + + std::string getNamespace() + { + return nh_.getNamespace(); + } + + rosparam_handler::ParametersPtr params_ptr_; + + ros::NodeHandle nh_ = ros::NodeHandle("~"); + }; + + struct Foo : public DummyBase + { + Foo() : DummyBase("foo"), dr_srv_(nh_) + { + init(); + + dynamic_reconfigure::Server::CallbackType cb; + cb = boost::bind(&Foo::configCallback, this, _1, _2); + dr_srv_.setCallback(cb); + } + + void configCallback(ConfigA &config, uint32_t level) + { + params_ptr_->fromConfig(config); + } + + dynamic_reconfigure::Server dr_srv_; + }; + + struct Bar : public DummyBase + { + Bar() : DummyBase("bar"), dr_srv_(nh_) + { + init(); + + dynamic_reconfigure::Server::CallbackType cb; + cb = boost::bind(&Bar::configCallback, this, _1, _2); + dr_srv_.setCallback(cb); + } + + void configCallback(ConfigB &config, uint32_t level) + { + params_ptr_->fromConfig(config); + } + + dynamic_reconfigure::Server dr_srv_; + }; + + Foo foo_; + Bar bar_; +}; + +TEST_F(TestRosparamHandlerBase, Defaults) { + + ASSERT_NO_THROW(foo_.fromParamServer()); + ASSERT_NO_THROW(bar_.fromParamServer()); + + boost::shared_ptr foo_param_ptr; + boost::shared_ptr bar_param_ptr; + + ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + + ASSERT_EQ(1, foo_param_ptr->int_param); + ASSERT_EQ("param a", foo_param_ptr->str_param); + + ASSERT_EQ("param b", bar_param_ptr->str_param); + ASSERT_EQ(std::vector({1, 2, 3}), bar_param_ptr->vector_int_param); +} + +TEST_F(TestRosparamHandlerBase, DefaultsOnParamServer) { + + ASSERT_NO_THROW(foo_.fromParamServer()); + ASSERT_NO_THROW(bar_.fromParamServer()); + + boost::shared_ptr foo_param_ptr; + boost::shared_ptr bar_param_ptr; + + ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + + ros::NodeHandle nh("~"); + + // values should now be set on param server + { + int value; + ASSERT_TRUE(nh.getParam(foo_.getNamespace() + "/int_param", value)); + ASSERT_EQ(value, foo_param_ptr->int_param); + } + { + std::string value; + ASSERT_TRUE(nh.getParam(foo_.getNamespace() + "/str_param", value)); + ASSERT_EQ(value, foo_param_ptr->str_param); + } + { + std::vector value; + ASSERT_TRUE(nh.getParam(bar_.getNamespace() + "/vector_int_param", value)); + ASSERT_EQ(value, bar_param_ptr->vector_int_param); + } + { + std::string value; + ASSERT_TRUE(nh.getParam(bar_.getNamespace() + "/str_param", value)); + ASSERT_EQ(value, bar_param_ptr->str_param); + } +} + +TEST_F(TestRosparamHandlerBase, SetParamOnServer) { + + ASSERT_NO_THROW(foo_.fromParamServer()); + ASSERT_NO_THROW(bar_.fromParamServer()); + + boost::shared_ptr foo_param_ptr; + boost::shared_ptr bar_param_ptr; + + ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + + foo_param_ptr->int_param = 9; + foo_param_ptr->str_param = "Hello"; + + bar_param_ptr->vector_int_param = {4,2}; + bar_param_ptr->str_param = "World"; + + ASSERT_NO_THROW(foo_.toParamServer()); + ASSERT_NO_THROW(bar_.toParamServer()); + + ros::NodeHandle nh("~"); + + // values should now be set on param server + { + int value; + ASSERT_TRUE(nh.getParam(foo_.getNamespace() + "/int_param", value)); + ASSERT_EQ(value, foo_param_ptr->int_param); + } + { + std::string value; + ASSERT_TRUE(nh.getParam(foo_.getNamespace() + "/str_param", value)); + ASSERT_EQ(value, foo_param_ptr->str_param); + } + { + std::vector value; + ASSERT_TRUE(nh.getParam(bar_.getNamespace() + "/vector_int_param", value)); + ASSERT_EQ(value, bar_param_ptr->vector_int_param); + } + { + std::string value; + ASSERT_TRUE(nh.getParam(bar_.getNamespace() + "/str_param", value)); + ASSERT_EQ(value, bar_param_ptr->str_param); + } +} + +TEST_F(TestRosparamHandlerBase, DynamicReconf) +{ + ASSERT_NO_THROW(foo_.fromParamServer()); + ASSERT_NO_THROW(bar_.fromParamServer()); + + boost::shared_ptr foo_param_ptr; + boost::shared_ptr bar_param_ptr; + + ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + + dynamic_reconfigure::ReconfigureRequest srv_req; + dynamic_reconfigure::ReconfigureResponse srv_resp; + dynamic_reconfigure::Config conf; + + dynamic_reconfigure::IntParameter int_param; + int_param.name = "int_param"; + int_param.value = 0; + + dynamic_reconfigure::StrParameter str_param; + str_param.name = "str_param"; + str_param.value = "dynamic foo string"; + + conf.ints.push_back(int_param); + conf.strs.push_back(str_param); + + srv_req.config = conf; + + ros::service::call(foo_.getNamespace() + "/set_parameters", srv_req, srv_resp); + + conf = dynamic_reconfigure::Config(); + str_param.name = "str_param"; + str_param.value = "dynamic bar string"; + + conf.strs.push_back(str_param); + + srv_req.config = conf; + + ros::service::call(bar_.getNamespace() + "/set_parameters", srv_req, srv_resp); + + ros::Duration(1).sleep(); + + ASSERT_EQ(0, foo_param_ptr->int_param); + ASSERT_EQ("dynamic foo string", foo_param_ptr->str_param); + + ASSERT_EQ("dynamic bar string", bar_param_ptr->str_param); +} From af7d2115c2e5d858d206756dba937abb85ebb467 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 11:58:36 +0100 Subject: [PATCH 04/22] authors & cosmetic --- include/rosparam_handler/ParametersBase.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h index 4ff33dc..6bd4463 100644 --- a/include/rosparam_handler/ParametersBase.h +++ b/include/rosparam_handler/ParametersBase.h @@ -2,11 +2,13 @@ * \file ParametersBase.h * * Created on: Oct 28, 2017 - * \author: Jeremie Deray + * + * \authors: Claudio Bandera + * Sascha Wirges + * Niels Ole Salscheider + * Jeremie Deray */ -//#pragma once - #ifndef _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ #define _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ @@ -16,7 +18,7 @@ namespace rosparam_handler { -/// \brief ParametersBase A base struct for struct generated by rosparam_handler. +/// \brief ParametersBase An abstract base struct for struct generated by rosparam_handler. struct ParametersBase { ParametersBase(const ros::NodeHandle& private_node_handle) @@ -66,10 +68,6 @@ struct ParametersBase { template void fromConfigImpl(const T& config, const uint32_t level); - //{ - // ROS_FATAL_STREAM("Called function fromConfigImpl with unknown input argument type."); - // rosparam_handler::exit("Called function fromConfigImpl with unknown input argument type."); - //} virtual std::ostream& print(std::ostream& os) const = 0; From c4842a6799264cb632630659032fa8db180c19de Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 12:05:26 +0100 Subject: [PATCH 05/22] add some doc --- include/rosparam_handler/ParametersBase.h | 5 +++++ templates/Parameters.h.template | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h index 6bd4463..6b0eb6e 100644 --- a/include/rosparam_handler/ParametersBase.h +++ b/include/rosparam_handler/ParametersBase.h @@ -64,11 +64,16 @@ struct ParametersBase { protected: + /// \brief The actual implementation of 'fromParamServer' + /// overriden by the derived class virtual bool fromParamServerImpl() = 0; + /// \brief The actual implementation os 'fromConfig' specialized + /// for the 'DerivedConfig' type. template void fromConfigImpl(const T& config, const uint32_t level); + /// \brief A helper function for ostram operator << virtual std::ostream& print(std::ostream& os) const = 0; /// \brief Issue a warning about missing default parameters. diff --git a/templates/Parameters.h.template b/templates/Parameters.h.template index 183c94f..031e365 100644 --- a/templates/Parameters.h.template +++ b/templates/Parameters.h.template @@ -32,6 +32,8 @@ struct ${ClassName}Parameters : public rosparam_handler::ParametersBase { $toParamServer } + /// \brief the parameters members. + $parameters protected: @@ -50,7 +52,7 @@ protected: } - /// \brief Print function to be called from base stream operator for printing parameter struct + /// \brief print. A helper function to be called from base stream operator for printing parameter struct inline std::ostream& print(std::ostream& os) const override { os << "[" << nodeName << "]\nNode " << nodeName << " has the following parameters:\n" @@ -72,7 +74,8 @@ $non_default_params ); namespace rosparam_handler { - // Specialize base class fromConfigImpl. + /// \brief Specialize base class fromConfigImpl. + /// to handle ${pkgname}::${ClassName}Config template<> inline void ParametersBase::fromConfigImpl<${pkgname}::${ClassName}Config>( From e5641d99861df3c136db32f45fc6317fded3dcc8 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 15:14:36 +0100 Subject: [PATCH 06/22] avoid some unused param warning --- templates/Parameters.h.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/Parameters.h.template b/templates/Parameters.h.template index 031e365..5c4a59e 100644 --- a/templates/Parameters.h.template +++ b/templates/Parameters.h.template @@ -79,14 +79,14 @@ namespace rosparam_handler template<> inline void ParametersBase::fromConfigImpl<${pkgname}::${ClassName}Config>( - const ${pkgname}::${ClassName}Config& config, const uint32_t level ) + const ${pkgname}::${ClassName}Config& config, const uint32_t /*level*/ ) { try { ${pkgname}::${ClassName}Parameters& casted_ref = dynamic_cast<${pkgname}::${ClassName}Parameters&>(*this); $fromConfig } - catch (const std::bad_cast& e) + catch (const std::bad_cast& /*e*/) { ROS_FATAL("In ParametersBase::fromConfig, bad cast to type ${pkgname}::${ClassName}Parameters !"); rosparam_handler::exit("In ParametersBase::fromConfig, bad cast to type ${pkgname}::${ClassName}Parameters !"); From 9a9865f345a9c04be98ac0aaa0ff9228604e40b2 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 15:15:35 +0100 Subject: [PATCH 07/22] fix mode for tests params files --- test/cfg/Bar.params | 0 test/cfg/Foo.params | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/cfg/Bar.params mode change 100644 => 100755 test/cfg/Foo.params diff --git a/test/cfg/Bar.params b/test/cfg/Bar.params old mode 100644 new mode 100755 diff --git a/test/cfg/Foo.params b/test/cfg/Foo.params old mode 100644 new mode 100755 From 2ad01b4cb18897b4e1ba678212242990dd7f0164 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 15:35:11 +0100 Subject: [PATCH 08/22] add documentation about use of ParameterPtr --- doc/HowToUseYourParameterPtr.md | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 doc/HowToUseYourParameterPtr.md diff --git a/doc/HowToUseYourParameterPtr.md b/doc/HowToUseYourParameterPtr.md new file mode 100644 index 0000000..49e58e2 --- /dev/null +++ b/doc/HowToUseYourParameterPtr.md @@ -0,0 +1,89 @@ +# How to Use Your `rosparam_handler::ParameterPtr` +**Description**: This tutorial will familiarize you with how you can use the autogenerated parameter structs in your nodes from a base class smart-pointer. It is thus recommended to read the tutorial [How to use your parameters struct file](HowToUseYourParametersStruct.md) if you haven't yet. +**Tutorial Level**: INTERMEDIATE + +## Generated files +When creating params files as described in [How to write your first .params file](HowToWriteYourFirstParamsFile.md), you will end up with the following two files: +- *'include/rosparam_tutorials/TutorialParameters.h'* +- *'include/rosparam_tutorials/TutorialConfig.h'* + +The 'Parameters.h' file will hold a struct called `Parameters`. +The 'Config.h' file will hold the normal dynamic_reconfigure Config struct. + +For your code it is enough to include the \*Parameters.h file, e.g. + +```cpp +#include "rosparam_tutorials/TutorialParameters.h" +``` + +You can now add an instance of the base parameter pointer to your class: + +```cpp +rosparam_tutorials::ParametersPtr params_ptr_; +``` + +## Initializing the pointer. +When initializing your node, the params pointer `params_ptr_` must be instantiated to the appropriate parameter type with a private `NodeHandle`. + +```cpp +MyNodeClass::MyNodeClass() + : params_ptr_{boost::make_shared(ros::NodeHandle("~"))} +{ + ... +} +``` + +In case your node has several classes, each using a different `ParameterPtr` object, the private `NodeHandle` must have a sub-namespace that is unique to your object in order to avoid parameters name collision. + +```cpp +MyNodeClass::MyClass() + : params_ptr_{boost::make_shared(ros::NodeHandle("~/my_class"))} +{ + ... +} + +MyNodeClass::MyOtherClass() + : params_ptr_{boost::make_shared(ros::NodeHandle("~/my_other_class"))} +{ + ... +} +``` + +## Initializing the struct. + +The call to `fromParamServer()` is done the very same manner as for a normal parameter object. +It will take care of getting all parameter values from the parameter server, checking their type, and checking that a default value is set, if you haven't provided one on your own. If you have specified a default value, but the parameter is not yet present on the parameter server, it will be set. When min and max values are specified, these bounds will be checked as well. + +```cpp +MyNodeClass::MyNodeClass() + : params_ptr_{boost::make_shared(ros::NodeHandle("~"))} +{ + params_ptr_->fromParamServer(); +} +``` + +If you do not use a class (which you should do though in my opinion), you can create it like so: +```cpp +rosparam_tutorials::ParametersPtr params_ptr{boost::make_shared(ros::NodeHandle("~"))} +params_ptr->fromParamServer(); +``` +Note: If you have set the logger level for your node to debug, you will get information on which values have been retrieved. +Note: If you use nodelets, you have to use the `getPrivateNodeHandle()` function instead. + +## Using dynamic_reconfigure +Your dynamic_reconfigure callback can now look as simple as: +```cpp +void reconfigureRequest(TutorialConfig& config, uint32_t level) { + params_ptr_->fromConfig(config); +} +``` +This will update all values that were specified as configurable. At the same time, it assures that all dynamic_reconfigure parameters live in the same namespace as those on the parameter server to avoid problems with redundant parameters. + +You can find a running version of this example code in the [rosparam_handler_tutorial](https://github.com/cbandera/rosparam_handler_tutorial)-Repository + +## Setting parameters on the server +If you change your parameters at runtime from within the code, you can upload the current state of the parameters with +```cpp +params_ptr_->toParamServer(); +``` +This will set all non-const parameters with their current value on the ros parameter server. From 8ee952e88989804b2d57648871b2067e14b280e7 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Thu, 2 Nov 2017 15:43:55 +0100 Subject: [PATCH 09/22] pointer declaration in separate file for cheaper include --- include/rosparam_handler/ParametersBase.h | 3 +-- include/rosparam_handler/pointer.hpp | 24 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 include/rosparam_handler/pointer.hpp diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h index 6b0eb6e..f8fdf40 100644 --- a/include/rosparam_handler/ParametersBase.h +++ b/include/rosparam_handler/ParametersBase.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace rosparam_handler { @@ -84,8 +85,6 @@ struct ParametersBase { const std::string nodeName; }; -using ParametersPtr = boost::shared_ptr; - } // namespace rosparam_handler #endif /* _ROSPARAM_HANDLER_PARAMETERS_BASE_H_ */ diff --git a/include/rosparam_handler/pointer.hpp b/include/rosparam_handler/pointer.hpp new file mode 100644 index 0000000..43c1758 --- /dev/null +++ b/include/rosparam_handler/pointer.hpp @@ -0,0 +1,24 @@ +/** + * \file pointer.h + * + * Created on: Oct 28, 2017 + * + * \authors: Jeremie Deray + */ + +#ifndef _ROSPARAM_HANDLER_POINTER_H_ +#define _ROSPARAM_HANDLER_POINTER_H_ + +#include + +namespace rosparam_handler { + +/// \brief forward declaration +struct ParametersBase; + +/// \brief base pointer declaration +using ParametersPtr = boost::shared_ptr; + +} /* namespace rosparam_handler */ + +#endif /* _ROSPARAM_HANDLER_POINTER_H_ */ From 18d5116585ab86f23dcf2e660b0e9683338b8197 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 29 Nov 2017 16:17:05 +0100 Subject: [PATCH 10/22] add helpers dynamic/static_parameters_cast --- include/rosparam_handler/pointer.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/rosparam_handler/pointer.hpp b/include/rosparam_handler/pointer.hpp index 43c1758..1f752aa 100644 --- a/include/rosparam_handler/pointer.hpp +++ b/include/rosparam_handler/pointer.hpp @@ -19,6 +19,18 @@ struct ParametersBase; /// \brief base pointer declaration using ParametersPtr = boost::shared_ptr; +template +T static_parameters_cast(const rosparam_handler::ParametersPtr& ptr) +{ + return boost::static_pointer_cast(ptr); +} + +template +T dynamic_parameters_cast(const rosparam_handler::ParametersPtr& ptr) +{ + return boost::dynamic_pointer_cast(ptr); +} + } /* namespace rosparam_handler */ #endif /* _ROSPARAM_HANDLER_POINTER_H_ */ From 923c7beb04376e44c9a4e4d7e282d57b8919a8e3 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 29 Nov 2017 17:32:03 +0100 Subject: [PATCH 11/22] fix helpers dynamic/static_parameters_cast >< --- include/rosparam_handler/pointer.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rosparam_handler/pointer.hpp b/include/rosparam_handler/pointer.hpp index 1f752aa..3db8e6b 100644 --- a/include/rosparam_handler/pointer.hpp +++ b/include/rosparam_handler/pointer.hpp @@ -20,13 +20,13 @@ struct ParametersBase; using ParametersPtr = boost::shared_ptr; template -T static_parameters_cast(const rosparam_handler::ParametersPtr& ptr) +boost::shared_ptr static_parameters_cast(const rosparam_handler::ParametersPtr& ptr) { return boost::static_pointer_cast(ptr); } template -T dynamic_parameters_cast(const rosparam_handler::ParametersPtr& ptr) +boost::shared_ptr dynamic_parameters_cast(const rosparam_handler::ParametersPtr& ptr) { return boost::dynamic_pointer_cast(ptr); } From 39a0ed793c0793013dc00735cb3dd2d0b02913bf Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Tue, 5 Dec 2017 18:26:27 +0100 Subject: [PATCH 12/22] Namespace/Node string members not const anymore --- include/rosparam_handler/ParametersBase.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h index f8fdf40..8820aed 100644 --- a/include/rosparam_handler/ParametersBase.h +++ b/include/rosparam_handler/ParametersBase.h @@ -80,9 +80,9 @@ struct ParametersBase { /// \brief Issue a warning about missing default parameters. virtual void missingParamsWarning() = 0; - const std::string globalNamespace = {"/"}; - const std::string privateNamespace; - const std::string nodeName; + std::string globalNamespace = {"/"}; + std::string privateNamespace; + std::string nodeName; }; } // namespace rosparam_handler From 8cbce55fd516903474100d8c70589b6a740c42d4 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Tue, 5 Dec 2017 18:08:48 +0100 Subject: [PATCH 13/22] ParametersBase copy constructor & assignment operator --- include/rosparam_handler/ParametersBase.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/rosparam_handler/ParametersBase.h b/include/rosparam_handler/ParametersBase.h index 8820aed..b1536c0 100644 --- a/include/rosparam_handler/ParametersBase.h +++ b/include/rosparam_handler/ParametersBase.h @@ -27,8 +27,21 @@ struct ParametersBase { privateNamespace{private_node_handle.getNamespace() + "/"}, nodeName{rosparam_handler::getNodeName(private_node_handle)} {} + ParametersBase(const ParametersBase& o) + : globalNamespace(o.globalNamespace) + , privateNamespace(o.privateNamespace) + , nodeName(o.nodeName) {} + virtual ~ParametersBase() = default; + ParametersBase& operator=(const ParametersBase& o) + { + globalNamespace = o.globalNamespace; + privateNamespace = o.privateNamespace; + nodeName = o.nodeName; + return *this; + } + /// \brief Get values from parameter server /// /// Will fail if a value can not be found and no default value is given. From 646f8891f3059b8d7fa3f5005481ca3e5e8b4205 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Tue, 5 Dec 2017 18:09:43 +0100 Subject: [PATCH 14/22] add copy constructor & assignment operator to generated parameter class --- .../parameter_generator_catkin.py | 11 ++++++++++- templates/Parameters.h.template | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/rosparam_handler/parameter_generator_catkin.py b/src/rosparam_handler/parameter_generator_catkin.py index 5602f49..5f8af7b 100644 --- a/src/rosparam_handler/parameter_generator_catkin.py +++ b/src/rosparam_handler/parameter_generator_catkin.py @@ -383,6 +383,8 @@ def _generatehpp(self): template = f.read() param_entries = [] + copy_constructor_entries = [] + assignment_operator_entries = [] string_representation = [] from_server = [] to_server = [] @@ -427,6 +429,8 @@ def _generatehpp(self): else: param_entries.append(Template(' ${type} ${name}; /*!< ${description} */').substitute( type=param['type'], name=name, description=param['description'])) + copy_constructor_entries.append(Template(' , ${name}(o.${name})').substitute(name=name)) + assignment_operator_entries.append(Template(' ${name} = o.${name};').substitute(name=name)) from_server.append(Template(' success &= rosparam_handler::getParam($paramname, $name$default);').substitute( paramname=full_name, name=name, default=default, description=param['description'])) to_server.append( @@ -455,6 +459,8 @@ def _generatehpp(self): '"\\n"\n').substitute(namespace=namespace, name=name)) param_entries = "\n".join(param_entries) + copy_constructor_entries = "\n".join(copy_constructor_entries) + assignment_operator_entries = "\n".join(assignment_operator_entries) string_representation = "".join(string_representation) non_default_params = "".join(non_default_params) from_server = "\n".join(from_server) @@ -463,7 +469,10 @@ def _generatehpp(self): test_limits = "\n".join(test_limits) content = Template(template).substitute(pkgname=self.pkgname, ClassName=self.classname, - parameters=param_entries, fromConfig=from_config, + parameters=param_entries, + copyConstructor=copy_constructor_entries, + assignOperator=assignment_operator_entries, + fromConfig=from_config, fromParamServer=from_server, string_representation=string_representation, non_default_params=non_default_params, nodename=self.nodename, diff --git a/templates/Parameters.h.template b/templates/Parameters.h.template index 5c4a59e..7cfb7d3 100644 --- a/templates/Parameters.h.template +++ b/templates/Parameters.h.template @@ -25,7 +25,22 @@ struct ${ClassName}Parameters : public rosparam_handler::ParametersBase { using Config = ${ClassName}Config; inline ${ClassName}Parameters(const ros::NodeHandle& private_node_handle) : - ParametersBase(private_node_handle) {} + rosparam_handler::ParametersBase(private_node_handle) {} + + inline ${ClassName}Parameters(const ${ClassName}Parameters& o) + : ParametersBase(o) + $copyConstructor + + { + // + } + + ${ClassName}Parameters& operator=(const ${ClassName}Parameters& o) + { + rosparam_handler::ParametersBase::operator=(o); + $assignOperator + return *this; + } /// \brief Set parameters on ROS parameter server. void toParamServer() override { From 38ca4fd617459097127bc1c817e59dae710a5964 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 10 Jan 2018 11:50:50 +0100 Subject: [PATCH 15/22] expand test_base_param --- test/src/test_base_param.cpp | 54 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/test/src/test_base_param.cpp b/test/src/test_base_param.cpp index 9292822..f87c9d6 100644 --- a/test/src/test_base_param.cpp +++ b/test/src/test_base_param.cpp @@ -45,6 +45,12 @@ class TestRosparamHandlerBase : public testing::Test return nh_.getNamespace(); } + template + void configCallback(T& config, uint32_t /*level*/) + { + params_ptr_->fromConfig(config); + } + rosparam_handler::ParametersPtr params_ptr_; ros::NodeHandle nh_ = ros::NodeHandle("~"); @@ -56,16 +62,10 @@ class TestRosparamHandlerBase : public testing::Test { init(); - dynamic_reconfigure::Server::CallbackType cb; - cb = boost::bind(&Foo::configCallback, this, _1, _2); + auto cb = boost::bind(&DummyBase::configCallback, this, _1, _2); dr_srv_.setCallback(cb); } - void configCallback(ConfigA &config, uint32_t level) - { - params_ptr_->fromConfig(config); - } - dynamic_reconfigure::Server dr_srv_; }; @@ -75,16 +75,10 @@ class TestRosparamHandlerBase : public testing::Test { init(); - dynamic_reconfigure::Server::CallbackType cb; - cb = boost::bind(&Bar::configCallback, this, _1, _2); + auto cb = boost::bind(&DummyBase::configCallback, this, _1, _2); dr_srv_.setCallback(cb); } - void configCallback(ConfigB &config, uint32_t level) - { - params_ptr_->fromConfig(config); - } - dynamic_reconfigure::Server dr_srv_; }; @@ -100,9 +94,20 @@ TEST_F(TestRosparamHandlerBase, Defaults) { boost::shared_ptr foo_param_ptr; boost::shared_ptr bar_param_ptr; + // Test casting ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + ASSERT_NE(nullptr, foo_param_ptr); + ASSERT_NE(nullptr, bar_param_ptr); + + // Test casting with helper function + ASSERT_NO_THROW(foo_param_ptr = rosparam_handler::dynamic_parameters_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = rosparam_handler::dynamic_parameters_cast(bar_.params_ptr_)); + + ASSERT_NE(nullptr, foo_param_ptr); + ASSERT_NE(nullptr, bar_param_ptr); + ASSERT_EQ(1, foo_param_ptr->int_param); ASSERT_EQ("param a", foo_param_ptr->str_param); @@ -118,8 +123,11 @@ TEST_F(TestRosparamHandlerBase, DefaultsOnParamServer) { boost::shared_ptr foo_param_ptr; boost::shared_ptr bar_param_ptr; - ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); - ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + ASSERT_NO_THROW(foo_param_ptr = rosparam_handler::dynamic_parameters_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = rosparam_handler::dynamic_parameters_cast(bar_.params_ptr_)); + + ASSERT_NE(nullptr, foo_param_ptr); + ASSERT_NE(nullptr, bar_param_ptr); ros::NodeHandle nh("~"); @@ -154,8 +162,11 @@ TEST_F(TestRosparamHandlerBase, SetParamOnServer) { boost::shared_ptr foo_param_ptr; boost::shared_ptr bar_param_ptr; - ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); - ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + ASSERT_NO_THROW(foo_param_ptr = rosparam_handler::dynamic_parameters_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = rosparam_handler::dynamic_parameters_cast(bar_.params_ptr_)); + + ASSERT_NE(nullptr, foo_param_ptr); + ASSERT_NE(nullptr, bar_param_ptr); foo_param_ptr->int_param = 9; foo_param_ptr->str_param = "Hello"; @@ -199,8 +210,11 @@ TEST_F(TestRosparamHandlerBase, DynamicReconf) boost::shared_ptr foo_param_ptr; boost::shared_ptr bar_param_ptr; - ASSERT_NO_THROW(foo_param_ptr = boost::dynamic_pointer_cast(foo_.params_ptr_)); - ASSERT_NO_THROW(bar_param_ptr = boost::dynamic_pointer_cast(bar_.params_ptr_)); + ASSERT_NO_THROW(foo_param_ptr = rosparam_handler::dynamic_parameters_cast(foo_.params_ptr_)); + ASSERT_NO_THROW(bar_param_ptr = rosparam_handler::dynamic_parameters_cast(bar_.params_ptr_)); + + ASSERT_NE(nullptr, foo_param_ptr); + ASSERT_NE(nullptr, bar_param_ptr); dynamic_reconfigure::ReconfigureRequest srv_req; dynamic_reconfigure::ReconfigureResponse srv_resp; From 63a7ee8cdc509a2625b7db03b4ef332164bc126c Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 10 Jan 2018 12:34:47 +0100 Subject: [PATCH 16/22] add tests for parameters copy --- test/src/test_copy.cpp | 118 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 test/src/test_copy.cpp diff --git a/test/src/test_copy.cpp b/test/src/test_copy.cpp new file mode 100644 index 0000000..0dd20f2 --- /dev/null +++ b/test/src/test_copy.cpp @@ -0,0 +1,118 @@ +#include +#include +#include + +typedef rosparam_handler::DefaultsParameters ParamType; + +TEST(RosparamHandler, CopyInit) { + ParamType testParams(ros::NodeHandle("~")); + ASSERT_NO_THROW(testParams.fromParamServer()); + + ASSERT_EQ(1, testParams.int_param_w_default); + ASSERT_DOUBLE_EQ(1.1, testParams.double_param_w_default); + ASSERT_EQ("Hello World", testParams.str_param_w_default); + ASSERT_TRUE(testParams.bool_param_w_default); + + ASSERT_EQ(std::vector({1, 2, 3}), testParams.vector_int_param_w_default); + ASSERT_EQ(std::vector({1.1, 1.2, 1.3}), testParams.vector_double_param_w_default); + ASSERT_EQ(std::vector({false, true}), testParams.vector_bool_param_w_default); + ASSERT_EQ(std::vector({"Hello", "World"}), testParams.vector_string_param_w_default); + + std::map tmp{{"Hello", "World"}}; + ASSERT_EQ(tmp, testParams.map_param_w_default); + + ASSERT_EQ(1, testParams.enum_param_w_default); + + testParams.int_param_w_default = 2; + testParams.double_param_w_default = 2.2; + testParams.str_param_w_default = "Foo Bar"; + testParams.bool_param_w_default = false; + testParams.vector_int_param_w_default = {4, 5, 6}; + testParams.vector_double_param_w_default = {1.4, 1.5, 1.6}; + testParams.vector_bool_param_w_default = {true, false}; + testParams.vector_string_param_w_default = {"Foo", "Bar"}; + testParams.map_param_w_default = {{"Foo", "Bar"}}; + testParams.enum_param_w_default = 2; + + ParamType testParamsCopy(testParams); + + ASSERT_EQ(2, testParamsCopy.int_param_w_default); + ASSERT_DOUBLE_EQ(2.2, testParamsCopy.double_param_w_default); + ASSERT_EQ("Foo Bar", testParamsCopy.str_param_w_default); + ASSERT_FALSE(testParamsCopy.bool_param_w_default); + + ASSERT_EQ(std::vector({4, 5, 6}), testParamsCopy.vector_int_param_w_default); + ASSERT_EQ(std::vector({1.4, 1.5, 1.6}), testParamsCopy.vector_double_param_w_default); + ASSERT_EQ(std::vector({true, false}), testParamsCopy.vector_bool_param_w_default); + ASSERT_EQ(std::vector({"Foo", "Bar"}), testParamsCopy.vector_string_param_w_default); + + tmp = {{"Foo", "Bar"}}; + ASSERT_EQ(tmp, testParamsCopy.map_param_w_default); + + ASSERT_EQ(2, testParamsCopy.enum_param_w_default); +} + +TEST(RosparamHandler, CopyAssign) { + ParamType testParams(ros::NodeHandle("~")); + ASSERT_NO_THROW(testParams.fromParamServer()); + + ASSERT_EQ(1, testParams.int_param_w_default); + ASSERT_DOUBLE_EQ(1.1, testParams.double_param_w_default); + ASSERT_EQ("Hello World", testParams.str_param_w_default); + ASSERT_TRUE(testParams.bool_param_w_default); + + ASSERT_EQ(std::vector({1, 2, 3}), testParams.vector_int_param_w_default); + ASSERT_EQ(std::vector({1.1, 1.2, 1.3}), testParams.vector_double_param_w_default); + ASSERT_EQ(std::vector({false, true}), testParams.vector_bool_param_w_default); + ASSERT_EQ(std::vector({"Hello", "World"}), testParams.vector_string_param_w_default); + + std::map tmp{{"Hello", "World"}}; + ASSERT_EQ(tmp, testParams.map_param_w_default); + + ASSERT_EQ(1, testParams.enum_param_w_default); + + ParamType testParamsCopy(ros::NodeHandle("~")); + ASSERT_NO_THROW(testParamsCopy.fromParamServer()); + + ASSERT_EQ(1, testParamsCopy.int_param_w_default); + ASSERT_DOUBLE_EQ(1.1, testParamsCopy.double_param_w_default); + ASSERT_EQ("Hello World", testParamsCopy.str_param_w_default); + ASSERT_TRUE(testParamsCopy.bool_param_w_default); + + ASSERT_EQ(std::vector({1, 2, 3}), testParamsCopy.vector_int_param_w_default); + ASSERT_EQ(std::vector({1.1, 1.2, 1.3}), testParamsCopy.vector_double_param_w_default); + ASSERT_EQ(std::vector({false, true}), testParamsCopy.vector_bool_param_w_default); + ASSERT_EQ(std::vector({"Hello", "World"}), testParamsCopy.vector_string_param_w_default); + + ASSERT_EQ(tmp, testParamsCopy.map_param_w_default); + + ASSERT_EQ(1, testParamsCopy.enum_param_w_default); + + testParams.int_param_w_default = 2; + testParams.double_param_w_default = 2.2; + testParams.str_param_w_default = "Foo Bar"; + testParams.bool_param_w_default = false; + testParams.vector_int_param_w_default = {4, 5, 6}; + testParams.vector_double_param_w_default = {1.4, 1.5, 1.6}; + testParams.vector_bool_param_w_default = {true, false}; + testParams.vector_string_param_w_default = {"Foo", "Bar"}; + testParams.map_param_w_default = {{"Foo", "Bar"}}; + testParams.enum_param_w_default = 2; + + testParamsCopy = testParams; + + ASSERT_EQ(2, testParamsCopy.int_param_w_default); + ASSERT_DOUBLE_EQ(2.2, testParamsCopy.double_param_w_default); + ASSERT_EQ("Foo Bar", testParamsCopy.str_param_w_default); + ASSERT_FALSE(testParamsCopy.bool_param_w_default); + + ASSERT_EQ(std::vector({4, 5, 6}), testParamsCopy.vector_int_param_w_default); + ASSERT_EQ(std::vector({1.4, 1.5, 1.6}), testParamsCopy.vector_double_param_w_default); + ASSERT_EQ(std::vector({true, false}), testParamsCopy.vector_bool_param_w_default); + ASSERT_EQ(std::vector({"Foo", "Bar"}), testParamsCopy.vector_string_param_w_default); + + tmp = {{"Foo", "Bar"}}; + ASSERT_EQ(tmp, testParamsCopy.map_param_w_default); + + ASSERT_EQ(2, testParamsCopy.enum_param_w_default); +} From 42005c100f3e9ecc6509de566e767ebd30575395 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 10 Jan 2018 12:41:57 +0100 Subject: [PATCH 17/22] doc copy parameters --- doc/HowToUseYourParameterStruct.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/HowToUseYourParameterStruct.md b/doc/HowToUseYourParameterStruct.md index 74b223d..acdd88d 100644 --- a/doc/HowToUseYourParameterStruct.md +++ b/doc/HowToUseYourParameterStruct.md @@ -54,6 +54,17 @@ This will update all values that were specified as configurable. At the same tim You can find a running version of this example code in the [rosparam_handler_tutorial](https://github.com/cbandera/rosparam_handler_tutorial)-Repository +## From another parameters structure +You can also simply copy your current parameters: +```cpp +rosparam_tutorials::TutorialParameters params_{ros::NodeHandle("~")} +params_.fromParamServer(); + +rosparam_tutorials::TutorialParameters params_copy_(params_); +// equivalently +params_copy_ = params_; +``` + ## Setting parameters on the server If you change your parameters at runtime from within the code, you can upload the current state of the parameters with ```cpp From 8ce9d0b208e2520b9024163c077a6bb451c598b7 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 10 Jan 2018 13:13:30 +0100 Subject: [PATCH 18/22] some extra doc --- doc/HowToUseYourParameterPtr.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/doc/HowToUseYourParameterPtr.md b/doc/HowToUseYourParameterPtr.md index 49e58e2..6a39987 100644 --- a/doc/HowToUseYourParameterPtr.md +++ b/doc/HowToUseYourParameterPtr.md @@ -22,7 +22,7 @@ You can now add an instance of the base parameter pointer to your class: rosparam_tutorials::ParametersPtr params_ptr_; ``` -## Initializing the pointer. +## Initializing the pointer When initializing your node, the params pointer `params_ptr_` must be instantiated to the appropriate parameter type with a private `NodeHandle`. ```cpp @@ -49,7 +49,7 @@ MyNodeClass::MyOtherClass() } ``` -## Initializing the struct. +## Initializing the struct The call to `fromParamServer()` is done the very same manner as for a normal parameter object. It will take care of getting all parameter values from the parameter server, checking their type, and checking that a default value is set, if you haven't provided one on your own. If you have specified a default value, but the parameter is not yet present on the parameter server, it will be set. When min and max values are specified, these bounds will be checked as well. @@ -70,6 +70,34 @@ params_ptr->fromParamServer(); Note: If you have set the logger level for your node to debug, you will get information on which values have been retrieved. Note: If you use nodelets, you have to use the `getPrivateNodeHandle()` function instead. +## Retrieving the actual parameter + +Since you are using here a `ParametersPtr`, you cannot access directly the parameters held by the structure: +```cpp +params_ptr_->my_int = 42; // Will NOT compile +``` + +To do so, you have to cast the base pointer to its appropriate derived type: +```cpp +boost::shared_ptr params_ptr_cast = rosparam_handler::dynamic_parameters_cast(params_ptr_); +assert(params_ptr_cast != nullptr); + +if (params_ptr_cast != nullptr) +{ + params_ptr_cast->my_int = 42; +} +``` +Both dynamic and static cast helper function are provided: +```cpp +auto my_cast = rosparam_handler::dynamic_parameters_cast(ptr); +auto my_cast = rosparam_handler::static_parameters_cast(ptr); +``` +which simply are aliases to: +```cpp +auto my_cast = boost::dynamic_pointer_cast(ptr); +auto my_cast = boost::static_pointer_cast_cast(ptr); +``` + ## Using dynamic_reconfigure Your dynamic_reconfigure callback can now look as simple as: ```cpp From 3a7483eb3022eaf0d8c0974d8f3eaf2f97517876 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Wed, 10 Jan 2018 13:17:36 +0100 Subject: [PATCH 19/22] rename test file --- test/src/{test_base_param.cpp => test_baseParams.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/src/{test_base_param.cpp => test_baseParams.cpp} (100%) diff --git a/test/src/test_base_param.cpp b/test/src/test_baseParams.cpp similarity index 100% rename from test/src/test_base_param.cpp rename to test/src/test_baseParams.cpp From 190ef18548137ca9e716ed1ef31017b2f5012af3 Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Tue, 23 Jan 2018 13:32:23 +0100 Subject: [PATCH 20/22] add some more *Ptr typedef --- include/rosparam_handler/pointer.hpp | 1 + templates/Parameters.h.template | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/rosparam_handler/pointer.hpp b/include/rosparam_handler/pointer.hpp index 3db8e6b..8ef79f5 100644 --- a/include/rosparam_handler/pointer.hpp +++ b/include/rosparam_handler/pointer.hpp @@ -18,6 +18,7 @@ struct ParametersBase; /// \brief base pointer declaration using ParametersPtr = boost::shared_ptr; +using ParametersConstPtr = boost::shared_ptr; template boost::shared_ptr static_parameters_cast(const rosparam_handler::ParametersPtr& ptr) diff --git a/templates/Parameters.h.template b/templates/Parameters.h.template index 7cfb7d3..2e5f32d 100644 --- a/templates/Parameters.h.template +++ b/templates/Parameters.h.template @@ -23,6 +23,8 @@ namespace ${pkgname} { struct ${ClassName}Parameters : public rosparam_handler::ParametersBase { using Config = ${ClassName}Config; + using Ptr = boost::shared_ptr<${ClassName}Parameters>; + using ConstPtr = boost::shared_ptr; inline ${ClassName}Parameters(const ros::NodeHandle& private_node_handle) : rosparam_handler::ParametersBase(private_node_handle) {} @@ -83,6 +85,9 @@ $non_default_params ); }; +using ${ClassName}ParametersPtr = ${ClassName}Parameters::Ptr; +using ${ClassName}ParametersConstPtr = ${ClassName}Parameters::ConstPtr; + } // namespace ${pkgname} #ifdef DYNAMIC_RECONFIGURE_FOUND From 1561f33067aafe0feead352e145d576a0e4265ec Mon Sep 17 00:00:00 2001 From: Jeremie Deray Date: Tue, 23 Jan 2018 15:59:47 +0100 Subject: [PATCH 21/22] fix tests collision with namespaces --- test/launch/params/test_launch_parameters.yaml | 2 +- test/launch/rosparam_handler.test | 2 +- test/src/test_copy.cpp | 4 ++-- test/src/test_defaults.cpp | 6 +++--- test/src/test_defaultsAtLaunch.cpp | 2 +- test/src/test_defaultsMissing.cpp | 2 +- test/src/test_dynamicReconfigure.cpp | 8 +------- test/src/test_minMax.cpp | 4 ++-- 8 files changed, 12 insertions(+), 18 deletions(-) diff --git a/test/launch/params/test_launch_parameters.yaml b/test/launch/params/test_launch_parameters.yaml index f7fe217..0cd1c1e 100644 --- a/test/launch/params/test_launch_parameters.yaml +++ b/test/launch/params/test_launch_parameters.yaml @@ -19,4 +19,4 @@ vector_double_param_wo_default: [1.1, 1.2, 1.3] vector_bool_param_wo_default: [false, true] vector_string_param_wo_default: ["Hello","World"] map_param_wo_default: {"Hello": "World"} -enum_param_wo_default: 1 \ No newline at end of file +enum_param_wo_default: 1 diff --git a/test/launch/rosparam_handler.test b/test/launch/rosparam_handler.test index cfecce2..c42da59 100644 --- a/test/launch/rosparam_handler.test +++ b/test/launch/rosparam_handler.test @@ -1,6 +1,6 @@ - + diff --git a/test/src/test_copy.cpp b/test/src/test_copy.cpp index 0dd20f2..62936a2 100644 --- a/test/src/test_copy.cpp +++ b/test/src/test_copy.cpp @@ -5,7 +5,7 @@ typedef rosparam_handler::DefaultsParameters ParamType; TEST(RosparamHandler, CopyInit) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~copy_init")); ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(1, testParams.int_param_w_default); @@ -53,7 +53,7 @@ TEST(RosparamHandler, CopyInit) { } TEST(RosparamHandler, CopyAssign) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~copy_assign")); ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(1, testParams.int_param_w_default); diff --git a/test/src/test_defaults.cpp b/test/src/test_defaults.cpp index ef3312d..c58e531 100644 --- a/test/src/test_defaults.cpp +++ b/test/src/test_defaults.cpp @@ -6,7 +6,7 @@ typedef rosparam_handler::DefaultsParameters ParamType; typedef rosparam_handler::DefaultsConfig ConfigType; TEST(RosparamHandler, Defaults) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~defaults")); ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(1, testParams.int_param_w_default); @@ -26,7 +26,7 @@ TEST(RosparamHandler, Defaults) { } TEST(RosparamHandler, DefaultsOnParamServer) { - ros::NodeHandle nh("~"); + ros::NodeHandle nh("~defaults_on_param_server"); ParamType testParams(nh); ASSERT_NO_THROW(testParams.fromParamServer()); @@ -84,7 +84,7 @@ TEST(RosparamHandler, DefaultsOnParamServer) { } TEST(RosparamHandler, SetParamOnServer) { - ros::NodeHandle nh("~"); + ros::NodeHandle nh("~set_param_on_server"); ParamType testParams(nh); ASSERT_NO_THROW(testParams.fromParamServer()); diff --git a/test/src/test_defaultsAtLaunch.cpp b/test/src/test_defaultsAtLaunch.cpp index 4e935f9..d3d4c73 100644 --- a/test/src/test_defaultsAtLaunch.cpp +++ b/test/src/test_defaultsAtLaunch.cpp @@ -6,7 +6,7 @@ typedef rosparam_handler::DefaultsAtLaunchParameters ParamType; typedef rosparam_handler::DefaultsAtLaunchConfig ConfigType; TEST(RosparamHandler, DefaultsAtLaunch) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~defaults_at_launch")); ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(1, testParams.int_param_wo_default); diff --git a/test/src/test_defaultsMissing.cpp b/test/src/test_defaultsMissing.cpp index 6910285..b33ba92 100644 --- a/test/src/test_defaultsMissing.cpp +++ b/test/src/test_defaultsMissing.cpp @@ -6,6 +6,6 @@ typedef rosparam_handler::DefaultsMissingParameters ParamType; typedef rosparam_handler::DefaultsMissingConfig ConfigType; TEST(RosparamHandler, DefaultsMissing) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~default_missing")); ASSERT_THROW(testParams.fromParamServer(), std::runtime_error); } diff --git a/test/src/test_dynamicReconfigure.cpp b/test/src/test_dynamicReconfigure.cpp index eb71c66..bc775c1 100644 --- a/test/src/test_dynamicReconfigure.cpp +++ b/test/src/test_dynamicReconfigure.cpp @@ -12,7 +12,7 @@ class TestDynamicReconfigure : public testing::Test public: TestDynamicReconfigure() - : nh("~") + : nh("~dynamic_reconfigure") , testParams(nh) , drSrv(nh) { @@ -36,12 +36,6 @@ class TestDynamicReconfigure : public testing::Test TEST_F(TestDynamicReconfigure, DynamicReconf) { - // Delete in case they are still on the server. - nh.deleteParam("int_param_w_default"); - nh.deleteParam("double_param_w_default"); - nh.deleteParam("str_param_w_default"); - nh.deleteParam("bool_param_w_default"); - ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(1, testParams.int_param_w_default); diff --git a/test/src/test_minMax.cpp b/test/src/test_minMax.cpp index 4d21f96..42102e8 100644 --- a/test/src/test_minMax.cpp +++ b/test/src/test_minMax.cpp @@ -6,7 +6,7 @@ typedef rosparam_handler::MinMaxParameters ParamType; typedef rosparam_handler::MinMaxConfig ConfigType; TEST(RosparamHandler, MinMax) { - ParamType testParams(ros::NodeHandle("~")); + ParamType testParams(ros::NodeHandle("~min_max")); ASSERT_NO_THROW(testParams.fromParamServer()); ASSERT_EQ(2, testParams.int_param_w_minmax); @@ -17,4 +17,4 @@ TEST(RosparamHandler, MinMax) { std::map tmp{{"value1", 0.}, {"value2", 1.2}, {"value3", 2.}}; ASSERT_EQ(tmp, testParams.map_param_w_minmax); -} \ No newline at end of file +} From 952d752b08cc1a61a83a26c5036ce2302320aa30 Mon Sep 17 00:00:00 2001 From: artivis Date: Sat, 9 Jun 2018 11:37:20 +0200 Subject: [PATCH 22/22] init var with default at construction --- src/rosparam_handler/parameter_generator_catkin.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/rosparam_handler/parameter_generator_catkin.py b/src/rosparam_handler/parameter_generator_catkin.py index 5f8af7b..ce8b078 100644 --- a/src/rosparam_handler/parameter_generator_catkin.py +++ b/src/rosparam_handler/parameter_generator_catkin.py @@ -407,17 +407,21 @@ def _generatehpp(self): # Test for default value if param["default"] is None: + value = "" default = "" non_default_params.append(Template(' << "\t" << $namespace << "$name" << " ($type) ' '\\n"\n').substitute( namespace=namespace, name=name, type=param["type"])) else: if param['is_vector']: - default = ', {}'.format(str(param['type']) + "{" + self._get_cvaluelist(param, "default") + "}") + value = ' = {}'.format("{" + self._get_cvaluelist(param, "default") + "}") + default = ', ' + name elif param['is_map']: - default = ', {}'.format(str(param['type']) + "{" + self._get_cvaluedict(param, "default") + "}") + value = ' = {}'.format("{" + self._get_cvaluedict(param, "default") + "}") + default = ', ' + name else: - default = ', {}'.format(str(param['type']) + "{" + self._get_cvalue(param, "default") + "}") + value = ' = {}'.format(self._get_cvalue(param, "default")) + default = ', ' + name # Test for constant value if param['constant']: @@ -427,8 +431,8 @@ def _generatehpp(self): default=self._get_cvalue(param, "default"))) from_server.append(Template(' rosparam_handler::testConstParam($paramname);').substitute(paramname=full_name)) else: - param_entries.append(Template(' ${type} ${name}; /*!< ${description} */').substitute( - type=param['type'], name=name, description=param['description'])) + param_entries.append(Template(' ${type} ${name}${value}; /*!< ${description} */').substitute( + type=param['type'], name=name, value=value, description=param['description'])) copy_constructor_entries.append(Template(' , ${name}(o.${name})').substitute(name=name)) assignment_operator_entries.append(Template(' ${name} = o.${name};').substitute(name=name)) from_server.append(Template(' success &= rosparam_handler::getParam($paramname, $name$default);').substitute(