pax_global_header00006660000000000000000000000064142040536240014512gustar00rootroot0000000000000052 comment=28929ec44858fd5c99ae82b11f681c773b6fe60c dynamic_reconfigure-1.7.2/000077500000000000000000000000001420405362400155355ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/.gitignore000066400000000000000000000000151420405362400175210ustar00rootroot00000000000000*.pyc build/ dynamic_reconfigure-1.7.2/.hgignore000066400000000000000000000000051420405362400173330ustar00rootroot00000000000000.pyc dynamic_reconfigure-1.7.2/.hgtags000066400000000000000000000136751420405362400170270ustar00rootroot000000000000008ee968b00d67d5fef281c2a5e4f57115c8061d78 driver_common-0.2.0 06740ef3d1419a935ad295615950e32a2b2ec0a2 latest 52910ca5a9bcabbf6c6116150c574b7ea25968f5 latest 0ae185331a3f6b607d3bfa689cad9a720b54065a latest d12220dd8225f637ae0d855982d8b854c11e959d driver_common-0.2.1 298bb34ff3b1c88bacfe450e5e7d9ce0428c9dcb latest d374384b4aa4ca3c79a5a3acab1c86df902a5884 driver_common-0.2.2 0000000000000000000000000000000000000000 latest bac516cacd4e74d200df0ee215c3068f8b4e9e4b latest fb38d87fbb0a5876b1f3ccb0b29897e0f9da9dff driver_common-0.2.3 0000000000000000000000000000000000000000 latest 5c4e100ee2b0ec3b0ca6033ddddcb58971b54764 latest 8657c1160501274e3161233a568bfd4bd0b9bf48 driver_common-0.2.4 0000000000000000000000000000000000000000 latest 5504b07b16fd54e87166f3a108e9b8b9aab4fb24 latest 0000000000000000000000000000000000000000 driver_common-0.2.4 374e17886721dca4de1231ddfd7d4f2ef3505468 driver_common-0.2.4 0000000000000000000000000000000000000000 latest 397123de3765a33896a52ee5dc6648c4b597bd91 latest bd5fb0d13554a71ea9ae340e035db07818c4e1dd driver_common-0.3.0 0000000000000000000000000000000000000000 latest cbe4145931151e0dd9a8fc1aa841b555f28e3369 latest 7e57d7af4c17a9595962f0c11724af168e8414d1 driver_common-0.3.1 0000000000000000000000000000000000000000 latest ec2ce404ddd01ef078ee1927b03ea53d9aa06b02 latest c03eef1f042dcda192272b5057a9d94f3a4d4210 driver_common-1.0.0 0000000000000000000000000000000000000000 latest 8c54705f23e3315d25995f4b966081b9098d84be latest 5e1bcf51f56a22b040f02010d69322b73174426f driver_common-1.0.1 0000000000000000000000000000000000000000 latest 7279eeafbb6593f40d1ae54c7c3da0871048709f latest b27c7ff9965b0d72b538ed738cdcd16cfd46d053 driver_common-1.0.2 0000000000000000000000000000000000000000 latest 9ae1425c1719849e9c93e8612310d98a1eebda9d latest 078e3f3d53b6e08fe218a4c6a892b607acd0c0bb driver_common-1.0.3 0000000000000000000000000000000000000000 driver_common-1.0.3 830d94a31cfd9116e2ed9ea707f0369f5e4843ca driver_common-1.0.3 0000000000000000000000000000000000000000 latest 8ad61da7b77f36684474c3e5f10f76c596ab586d latest 8ad61da7b77f36684474c3e5f10f76c596ab586d cturtle 4e43ef925cb37569582b8ba8ee39e0030dcbb8ad driver_common-1.0.4 0000000000000000000000000000000000000000 cturtle 5d8e3912773bb1ccabc2437ece1c2016a4d596e5 cturtle ff840cde5207e40cc0a7ee389eaf44e367f635f7 driver_common-1.2.0 0000000000000000000000000000000000000000 cturtle 17da218fb89e1f350cc2fa2106daa706b3ea078b cturtle 17da218fb89e1f350cc2fa2106daa706b3ea078b unstable 0000000000000000000000000000000000000000 unstable 17da218fb89e1f350cc2fa2106daa706b3ea078b unstable 843eca5d14d6830d6107de8abdb83a771ffda446 driver_common-1.2.1 0000000000000000000000000000000000000000 cturtle 555a1ccbe400a403969264ff681ade6998ca3020 cturtle 0000000000000000000000000000000000000000 driver_common-1.2.1 ba52cf586cea09d5ce6c3705e34d393f6370c858 driver_common-1.2.1 0000000000000000000000000000000000000000 unstable 5470d28580c88a39b0ec9b95bdd61f049ec06f05 unstable a31c85d9e66aa6e7421f833e6152902b0b5a399a driver_common-1.2.2 0000000000000000000000000000000000000000 cturtle b42609f97b31de720460f5c72ea2b10c214b3042 cturtle 0000000000000000000000000000000000000000 driver_common-1.2.2 f1935191df16c6819e50822da7c9ac9d3f7d020d driver_common-1.2.2 0000000000000000000000000000000000000000 unstable 35fe604d0a26e7f6bd86ce553c6368519b986e33 unstable 5475d749e79d35f036949507bbf6bef028a372ac driver_common-1.2.3 0000000000000000000000000000000000000000 unstable fa2447a319b8a95dfa69f0a6ceb5ffa18a85bb36 unstable 0000000000000000000000000000000000000000 driver_common-1.2.3 692a1f668d25855a3ade0855609db50f6dce777d driver_common-1.2.3 0000000000000000000000000000000000000000 cturtle 5ce3c0856ad36257d8f2e73f727227a1619298c0 cturtle 692a1f668d25855a3ade0855609db50f6dce777d diamondback 0caf2002fcb227c6374fefc9f1ef457476a25d83 dynamic_reconfigure-1.3.0 fa2447a319b8a95dfa69f0a6ceb5ffa18a85bb36 unstable 507b656e2d240c3564d947a62d6c816fdc36c3fc unstable 6a661d02b9ad66dad00a99593091715018271038 dynamic_reconfigure-1.4.0 3e3180e2b66a97713e1130717d00a68b53d42634 dynamic_reconfigure-1.5.0 226f459812467fc1e0588d347c6e360347819443 fuerte e2fe213307ede1c84537fd4ac031ad7a0d9566ae dynamic_reconfigure-1.4.1 226f459812467fc1e0588d347c6e360347819443 fuerte 83ee7ade5de180a6fbc02ea7e7fa34ad3e44e6dd fuerte b243ae76e67724f31703e9e9bb2bf4225ba0c532 dynamic_reconfigure-1.4.2 83ee7ade5de180a6fbc02ea7e7fa34ad3e44e6dd fuerte 43a2008df23ca4a9ad91e87053f52824ba62f7d2 fuerte 9f7838559e297c86e403d7e98e242fee1aca1825 1.5.0 f6220657e14e55d4e89102742487f7cd39dc3e47 1.5.1 ac6b0fc0dd25762a59d1c57bc711ff1d0d125459 1.5.2 79676e1211f6aa94bccc0a1e0ca20d764f9a32ea 1.5.3 968387f4630ef753bf276d4c2656fe164e80fcee 1.5.4 74cbeae9f657222b8c7e8fe43b8ba73c2ab17fae 1.5.5 437cb0932b06de3f471fe15aadb79e72fb00afa7 1.5.6 61194156e72275f53cc82055cbbc50cece6c2693 1.5.7 ef55784a184c8981ecf0bd122a217ab2b0f0c6eb 1.5.8 2b280d04b7dc031cb8afd3a19e41f11dbb26998e 1.5.9 0d1380d1f34d5ef417536cfc54f6efb7e1a2e67d 1,5,10 0d1380d1f34d5ef417536cfc54f6efb7e1a2e67d 1,5,10 0000000000000000000000000000000000000000 1,5,10 a7498ee3711b103e75414f9b4d67a18f92b63a14 1.5.10 0487e65370d0eda39189606436f2ff2fe93140fa 1.5.11 c9a6334afaa2f8c04d4a8939004926c345c91f83 1.5.12 28dd60e918e2f2d1cf9389b603d7183b92641572 1.5.13 2c0ff2fc8ed43c978b0ec3687129c039e206d308 1.5.14 9b1c9b70d24bd7e4448e53d353e68b88ea59448d 1.5.15 e7724acbca45949dd5584fa42dc502a40a4b9603 1.5.16 ab9222e987250b8a4aad6791b7f8b6bf8cf1538f 1.5.17 ffc5832d9ce71810ad8fed620ddf0a9d2172b403 1.5.18 9c23c8bfffae9534d14039dc6d60d9a427ab6d32 1.5.19 844ef175d560f4924e60445a71fec1a8b73a996d 1.5.20 7791d630874fa076f6404acdb01557cf0b0f0549 1.5.21 221f2aa2e604ecb189c5c9d92f6b85fcdf1cbcd6 1.5.22 72b26a1eb2ae59160e23230f7be1b219b895c418 1.5.23 c5f4a55f050c0b55f1a10f10893f0411347b1823 1.5.24 c7f8049b79f42e92b612d7041c5edb7978aa6780 1.5.25 5761c7a4c1c5ca932c7a74732eb7845aa03c47a4 1.5.26 a29ce24024f8df1eb5fc64be6c9d4425b90ff6d6 1.5.27 57da52e43938eded5cdbc047b603ebc9ab818726 1.5.28 aa2484286d6722639f5266a0cff0c840cd311965 1.5.29 3af6ae098c0146ac883a84a8658e3057d0e54e75 1.5.30 dynamic_reconfigure-1.7.2/CHANGELOG.rst000066400000000000000000000214441420405362400175630ustar00rootroot00000000000000^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Changelog for package dynamic_reconfigure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1.7.2 (2022-02-19) ------------------ * Remove calls to string.{join,lower,upper} (`#174 `_) * fix: Race condition on quickly setting and getting config (`#188 `_) * do not use system for generated messages or configs (`#182 `_) * Contributors: Gaël Écorchard, Rokus Ottervanger, Shingo Kitagawa 1.7.1 (2020-08-28) ------------------ * narrow down required boost dependencies (`#160 `_) * Make Config object pickle-able in Python 3 (`#154 `_) * Fix python3 issue in a backward compatible way (`#157 `_) * import setup from setuptools instead of distutils-core (`#153 `_) * Contributors: Alejandro Hernández Cordero, Mikael Arguedas, Scott K Logan 1.7.0 (2020-03-05) ------------------ * Fixing compile error with cpp client when using -Werror=reorder. (`#118 `_) * ConfigType.h.template: fixed warnings (`#136 `_) (`#149 `_) * Bump CMake minimum version to use CMP0048 (`#148 `_) * Use PYTHON_EXECUTABLE to generate config headers. (`#146 `_) * Python3 compatibility (`#135 `_) * Use system on gen headers (`#140 `_) * Fix GCC8 error for unnecessary parentheses (`#132 `_) * fix generate_dynamic_reconfigure_options (`#10 `_) (`#134 `_) * Make Michael Carroll the maintainer (`#125 `_) * Contributors: Christopher Wecht, Markus Grimm, Michael Carroll, Mikael Arguedas, Nicolas Limpert, Sean Yen [MSFT], Victor Lopez 1.6.0 (2018-10-02) ------------------ * fix check preventing range for string and bool parameters (`#122 `_) * Fix build issue on Windows (`#114 `_) * Contributors: Johnson Shih, Mikael Arguedas 1.5.50 (2018-10-02) ------------------- * final-keyword (`#113 `_) * Add final keyword to child class since parent has virtual methods and grand parent doesn't have a virtual destructor. This allows the code to be compiled by clang version 6.0 and above. * [indentation fixups] * Use textwrap dedent for multiline strings * Remove extra indentation in wikidoc * Use textwrap.dedent to form the error message * [test fix] call shutdown to prevent test from hanging (`#119 `_) * Modernize Python code (`#102 `_) * Use new-style classes * Use with statement to ensure files are closed * Python 3 compatibility (`#105 `_) * some randon python cleanup * remove iter* method for their 2/3 compatible equivalent * Contributors: Eric Wieser, Jason Mercer, Mikael Arguedas 1.5.49 (2017-07-27) ------------------- * Pep8 (`#93 `_) * Python3 use print function and not statement (`#92 `_) * add shebang line in setup_custom_pythonpath.sh.in template (`#91 `_) * switch to package format 2 (`#89 `_) * remove trailing whitespaces (`#88 `_) * Reraising DynamicReconfigureCallbackException in case of a failing service call (`#87 `_) * Contributors: Arne Hitzmann, Mikael Arguedas 1.5.48 (2017-04-07) ------------------- * [Bugfix] dont enforce ROS names for constants (`#84 `_) * [Compiler warnings] avoid unused-parameter compiler warnings in specialized ParamDescription::clamp() (`#83 `_) * Contributors: Johannes Meyer, Mikael Arguedas 1.5.47 (2017-03-27) ------------------- * reset received_configuration\_ for every request sent (`#82 `_) * Rename arguments (with a\_ prefix) to avoid Wshadow warnings. (`#80 `_) handle infinity in python generation, fixes (`#77 `_) * Add a c++ Dynamic Reconfigure Client (`#78 `_) * Enforce valid descriptions in cfg files (`#74 `_) * Fix callback returned by get_description_callback (`#73 `_) from ros/description_cb * Contributors: Jeff Eberl, Mikael Arguedas 1.5.46 (2016-11-15) ------------------- * Add missing group params to wikidoc (`#68 `_) The catkin generated wikidoc files were missing parameters defined as groups. Both the Dox and UsageDox file were generated correctly, but the wikidoc was using the wrong method to traverse all groups. * Contributors: Mark Horn 1.5.45 (2016-10-24) ------------------- * Merge pull request `#65 `_ from bulwahn/master address gcc6 build error * address gcc6 build error With gcc6, compiling fails with `stdlib.h: No such file or directory`, as including '-isystem /usr/include' breaks with gcc6, cf., https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129. This commit addresses this issue for this package in the same way it was addressed in various other ROS packages. A list of related commits and pull requests is at: https://github.com/ros/rosdistro/issues/12783 Signed-off-by: Lukas Bulwahn * Contributors: Lukas Bulwahn, Mikael Arguedas 1.5.44 (2016-06-22) ------------------- * Add server namespaces (`#56 `_) * Add optional namespace argument to Python Server * Add test for server with multiple namespaces * Merge pull request `#61 `_ from vagvaz/Issue_51_Unable_to_reload_parameters_from_file fix issue `#51 `_ reloading parameters from dumped file * Contributors: Evangelos Vazaios, Mikael Arguedas, v-lopez 1.5.43 (2016-03-19) ------------------- * add devel space to Python environment to allow .cfg files to import them `#60 `_ * Contributors: Dirk Thomas 1.5.42 (2016-03-15) ------------------- * fix Python environment to make it work on the first run `#59 `_ * Contributors: Dirk Thomas 1.5.41 (2016-03-14) ------------------- * fix Python environment to make it work on the first run `#58 `_ * Contributors: Dirk Thomas, Mikael Arguedas 1.5.40 (2016-03-11) ------------------- * updated maintainer * Contributors: Mikael Arguedas 1.5.39 (2015-04-22) ------------------- * Better error message, to fix `#32 `_ * Make Python callback code consistent with the C++ API * Commented unused parameters to avoid compile warnings * Contributors: Esteve Fernandez, Morgan Quigley 1.5.38 (2014-12-23) ------------------- * Fixes `#35 `_ by setting queue_size to 10 for publishers. * Fixes `#31 `_ by removing boilerplate and copyright info from config header. * Python 3 Support * Honor BUILD_SHARED_LIBS and do not force building shared libraries. * Unicode support * Contributors: Basheer Subei, Esteve Fernandez, Gary Servin, Kei Okada, Scott K Logan 1.5.37 (2014-06-16) ------------------- * Decode level of ParamDescription * Added testsuite * Avoid collisions with parameter names (`#6 `_) * Contributors: Esteve Fernandez, pgorczak dynamic_reconfigure-1.7.2/CMakeLists.txt000066400000000000000000000041141420405362400202750ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) project(dynamic_reconfigure) find_package(catkin REQUIRED COMPONENTS message_generation roscpp std_msgs) find_package(Boost REQUIRED) include_directories(include) include_directories(SYSTEM ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) catkin_python_setup() add_message_files( DIRECTORY msg FILES BoolParameter.msg Config.msg Group.msg IntParameter.msg SensorLevels.msg ConfigDescription.msg DoubleParameter.msg GroupState.msg ParamDescription.msg StrParameter.msg) add_service_files( DIRECTORY srv FILES Reconfigure.srv) generate_messages(DEPENDENCIES std_msgs) if(CATKIN_ENABLE_TESTING) find_package(rostest REQUIRED) set(dynamic_reconfigure_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") include(${dynamic_reconfigure_SOURCE_DIR}/cmake/dynamic_reconfigure-macros.cmake) generate_dynamic_reconfigure_options(cfg/Test.cfg) add_subdirectory(test) endif() catkin_package(LIBRARIES dynamic_reconfigure_config_init_mutex INCLUDE_DIRS include CATKIN_DEPENDS message_runtime std_msgs CFG_EXTRAS dynamic_reconfigure-extras.cmake ) add_library(dynamic_reconfigure_config_init_mutex src/dynamic_reconfigure_config_init_mutex.cpp) target_link_libraries(dynamic_reconfigure_config_init_mutex ${Boost_LIBRARIES}) install(DIRECTORY include/dynamic_reconfigure/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} FILES_MATCHING PATTERN "*.h") install(TARGETS dynamic_reconfigure_config_init_mutex ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}) install(DIRECTORY cmake DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} USE_SOURCE_PERMISSIONS ) install(DIRECTORY msg DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) install(DIRECTORY srv DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) install(DIRECTORY templates DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) catkin_install_python(PROGRAMS scripts/dynparam DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) dynamic_reconfigure-1.7.2/cfg/000077500000000000000000000000001420405362400162745ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/cfg/Test.cfg000066400000000000000000000075121420405362400177010ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. PACKAGE='dynamic_reconfigure_test' from dynamic_reconfigure.parameter_generator_catkin import * gen = ParameterGenerator() gen.const("int_const", int_t, 5, "An int constant.") gen.const("double_const", double_t, 5.6, "A double constant.") gen.const("str_const", str_t, "foo", "A string constant.") gen.const("bool_const", bool_t, True, "A bool constant.") enum = gen.enum([ gen.const("Small", int_t, 0, "A small constant"), gen.const("Medium", int_t, 1, "A medium value"), gen.const("Large", int_t, 2, "A large value"), gen.const("ExtraLarge", int_t, 3, "An extra large value") ], "An enum to set the size.") gen.add("int_enum_", int_t, 1, "Int enum",0, 0, 3, edit_method = enum) gen.add("int_", int_t, 1, "Int parameter",0, -10, 10) gen.add("double_", double_t, 2, "double parameter", 0, -2, 10) gen.add("double_no_minmax", double_t, 2, "double parameter without boundaries", 1) gen.add("double_no_max", double_t, 2, "double parameter without max value", 2, 0) gen.add("str_", str_t, 4, "String parameter","foo") gen.add("mstr_", str_t, 4, "Multibyte String parameter","bar") gen.add("bool_", bool_t, 8, "Boolean parameter",False) gen.add("level", int_t, 16, "Contains the level of the previous change",0) gen.add("int_nodefault", int_t, 0, "Checks against regression of #4499") gen.add("i", int_t, 0, "Checks against regression of https://github.com/ros/dynamic_reconfigure/issues/6") group1 = gen.add_group("Group One", state = True) group1.add("group1_int", int_t, 1, "A second level group parameter", 2) group2 = group1.add_group("GROUP2", type="collapse", state=False) group2.add("group2_double", double_t, 0, "A third level group parameter", 3.333) group2.add("group2_string", str_t, 0, "A third level group parameter", "test string") group2.add("some_other", str_t, 0, "Something", "AAAAAAGGHH") group2.add("variable", bool_t,0, "A boolean", True) group3 = group2.add_group("Group3") group3.add("deep_var_int", int_t, 0, "Were very far down now", 0, 0, 3, edit_method = enum) group3.add("deep_var_bool", bool_t, 0, "Were even farther down now!!", True) group3.add("deep_var_double", double_t, 0, "Were super far down now!!", -1.0) group12 = gen.add_group("Upper Group 2") group12.add("some_param", int_t, 0, "Some param", 20) exit(gen.generate(PACKAGE, "test_reconfigure_server_cpp", "Test")) dynamic_reconfigure-1.7.2/cmake/000077500000000000000000000000001420405362400166155ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/cmake/cfgbuild.cmake000066400000000000000000000100101420405362400213660ustar00rootroot00000000000000# Return a list of all cfg/.cfg files set(GENERATED_CFG_FILES "") macro(add_generated_cfg) list(APPEND GENERATED_CFG_FILES ${ARGV}) endmacro(add_generated_cfg) macro(get_cfgs cfgvar) file(GLOB _cfg_files RELATIVE "${PROJECT_SOURCE_DIR}/cfg" "${PROJECT_SOURCE_DIR}/cfg/*.cfg") set(${cfgvar} ${GENERATED_CFG_FILES}) # Loop over each .cfg file, establishing a rule to compile it foreach(_cfg ${_cfg_files}) # Make sure we didn't get a bogus match (e.g., .#Foo.cfg, which Emacs # might create as a temporary file). the file() # command doesn't take a regular expression, unfortunately. if(${_cfg} MATCHES "^[^\\.].*\\.cfg$") list(APPEND ${cfgvar} ${_cfg}) endif(${_cfg} MATCHES "^[^\\.].*\\.cfg$") endforeach(_cfg) endmacro(get_cfgs) add_custom_target(rospack_gencfg ALL) add_dependencies(rospack_genmsg_libexe rospack_gencfg) macro(gencfg) add_custom_target(rospack_gencfg_real ALL) add_dependencies(rospack_gencfg_real rospack_gencfg) include_directories(${PROJECT_SOURCE_DIR}/cfg/cpp) endmacro(gencfg) rosbuild_find_ros_package(dynamic_reconfigure) macro(gencfg_cpp) get_cfgs(_cfglist) if (_cfglist) set(_autogen "") foreach(_cfg ${_cfglist}) message("MSG: gencfg_cpp on:" ${_cfg}) # Construct the path to the .cfg file set(_input ${PROJECT_SOURCE_DIR}/cfg/${_cfg}) rosbuild_gendeps(${PROJECT_NAME} ${_cfg}) # The .cfg file is its own generator. set(gencfg_cpp_exe "") get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set(gencfg_build_files ${SELF_DIR}/../templates/ConfigType.py.template ${SELF_DIR}/../templates/ConfigType.h.template # ${dynamic_reconfigure_PACKAGE_PATH}/src/dynamic_reconfigure/parameter_generator.py ) string(REPLACE ".cfg" "" _cfg_bare ${_cfg}) set(_output_cpp ${PROJECT_SOURCE_DIR}/cfg/cpp/${PROJECT_NAME}/${_cfg_bare}Config.h) set(_output_dox ${PROJECT_SOURCE_DIR}/docs/${_cfg_bare}Config.dox) set(_output_wikidoc ${PROJECT_SOURCE_DIR}/docs/${_cfg_bare}Config.wikidoc) set(_output_usage ${PROJECT_SOURCE_DIR}/docs/${_cfg_bare}Config-usage.dox) set(_output_py ${PROJECT_SOURCE_DIR}/src/${PROJECT_NAME}/cfg/${_cfg_bare}Config.py) # Add the rule to build the .h the .cfg and the .msg # FIXME Horrible hack. Can't get CMAKE to add dependencies for anything # but the first output in add_custom_command. execute_process( COMMAND ${SELF_DIR}/gendeps ${_input} ERROR_VARIABLE __gencfg_err RESULT_VARIABLE __gencfg_result OUTPUT_VARIABLE __gencfg_autodeps OUTPUT_STRIP_TRAILING_WHITESPACE) if (__gencfg_result) message("ERROR [gendeps] ${__gencfg_result} ${__gencfg_err}") else () if (__gencfg_err) message("[gendeps] ${__gencfg_err}") endif() endif() string(REPLACE "\n" " " ${_input}_AUTODEPS ${__gencfg_autodeps}) separate_arguments(${_input}_AUTODEPS) #message("MSG: " ${${_input}_AUTODEPS}) add_custom_command(OUTPUT ${_output_cpp} ${_output_dox} ${_output_usage} ${_output_py} ${_output_wikidoc} COMMAND ${gencfg_cpp_exe} ${_input} DEPENDS ${_input} ${gencfg_cpp_exe} ${ROS_MANIFEST_LIST} ${gencfg_build_files} ${gencfg_extra_deps} ${${_input}_AUTODEPS}) list(APPEND _autogen ${_output_cpp} ${_output_msg} ${_output_getsrv} ${_output_setsrv} ${_output_dox} ${_output_usage} ${_output_py}) endforeach(_cfg) # Create a target that depends on the union of all the autogenerated # files add_custom_target(ROSBUILD_gencfg_cpp DEPENDS ${_autogen}) # Add our target to the top-level gencfg target, which will be fired if # the user calls gencfg() add_dependencies(rospack_gencfg ROSBUILD_gencfg_cpp) else(_cfglist) message(FATAL_ERROR "Dynamic reconfigure has been invoked but could not find a .cfg to build. Please add one to your package/cfg directory. Aborting.") endif(_cfglist) endmacro(gencfg_cpp) # Call the macro we just defined. gencfg_cpp() dynamic_reconfigure-1.7.2/cmake/dynamic_reconfigure-extras.cmake.em000066400000000000000000000004551420405362400255430ustar00rootroot00000000000000@[if DEVELSPACE]@ # base dir in develspace set(dynamic_reconfigure_BASE_DIR "@(CMAKE_CURRENT_SOURCE_DIR)") @[else]@ # base dir in installspace set(dynamic_reconfigure_BASE_DIR "${dynamic_reconfigure_DIR}/..") @[end if]@ include(${dynamic_reconfigure_BASE_DIR}/cmake/dynamic_reconfigure-macros.cmake) dynamic_reconfigure-1.7.2/cmake/dynamic_reconfigure-macros.cmake000066400000000000000000000134551420405362400251250ustar00rootroot00000000000000macro(generate_dynamic_reconfigure_options) if(${PROJECT_NAME}_CATKIN_PACKAGE) message(FATAL_ERROR "generate_dynamic_reconfigure_options() must be called before catkin_package() in project '${PROJECT_NAME}'") endif() # ensure that package destination variables are defined catkin_destinations() set(_autogen "") foreach(_cfg ${ARGN}) # Construct the path to the .cfg file set(_input ${_cfg}) if(NOT IS_ABSOLUTE ${_input}) set(_input ${PROJECT_SOURCE_DIR}/${_input}) endif() # The .cfg file is its own generator. set(gencfg_build_files ${dynamic_reconfigure_BASE_DIR}/templates/ConfigType.py.template ${dynamic_reconfigure_BASE_DIR}/templates/ConfigType.h.template ) get_filename_component(_cfgonly ${_cfg} NAME_WE) set(_output_cpp ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_INCLUDE_DESTINATION}/${_cfgonly}Config.h) set(_output_py ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg/${_cfgonly}Config.py) set(_output_dox ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION}/docs/${_cfgonly}Config.dox) set(_output_wikidoc ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION}/docs/${_cfgonly}Config.wikidoc) set(_output_usage ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION}/docs/${_cfgonly}Config-usage.dox) # we need to explicitly add the devel space to the PYTHONPATH # since it might contain dynamic_reconfigure or Python code of the current package set("_CUSTOM_PYTHONPATH_ENV") if(EXISTS "${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_PYTHON_DESTINATION}") if(WIN32) configure_file( "${dynamic_reconfigure_BASE_DIR}/cmake/setup_custom_pythonpath.bat.in" "setup_custom_pythonpath.bat" @ONLY ) set("_CUSTOM_PYTHONPATH_ENV" "${CMAKE_CURRENT_BINARY_DIR}/setup_custom_pythonpath.bat") else() configure_file( "${dynamic_reconfigure_BASE_DIR}/cmake/setup_custom_pythonpath.sh.in" "setup_custom_pythonpath.sh" @ONLY ) set("_CUSTOM_PYTHONPATH_ENV" "${CMAKE_CURRENT_BINARY_DIR}/setup_custom_pythonpath.sh") endif() else() # Package could have no ${CATKIN_GLOBAL_PYTHON_DESTINATION} if it doesn't call # catkin_python_setup(), however we still need to use the correct Python. set("_CUSTOM_PYTHONPATH_ENV" "${PYTHON_EXECUTABLE}") endif() assert(CATKIN_ENV) set(_cmd ${CATKIN_ENV} ${_CUSTOM_PYTHONPATH_ENV} ${_input} ${dynamic_reconfigure_BASE_DIR} ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION} ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_INCLUDE_DESTINATION} ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION} ) #file(WRITE ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg/__init__.py) add_custom_command(OUTPUT ${_output_cpp} ${_output_dox} ${_output_usage} ${_output_py} ${_output_wikidoc} COMMAND ${_cmd} DEPENDS ${_input} ${gencfg_build_files} COMMENT "Generating dynamic reconfigure files from ${_cfg}: ${_output_cpp} ${_output_py}" ) list(APPEND ${PROJECT_NAME}_generated ${_output_cpp} ${_output_py} ) install(FILES ${_output_cpp} DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}) endforeach(_cfg) # gencfg target for hard dependency on dynamic_reconfigure generation add_custom_target(${PROJECT_NAME}_gencfg ALL DEPENDS ${${PROJECT_NAME}_generated}) # register target for catkin_package(EXPORTED_TARGETS) list(APPEND ${PROJECT_NAME}_EXPORTED_TARGETS ${PROJECT_NAME}_gencfg) dynreconf_called() endmacro() macro(dynreconf_called) if(NOT dynamic_reconfigure_CALLED) set(dynamic_reconfigure_CALLED TRUE) # mark that generate_dynamic_reconfigure_options() was called in order to detect wrong order of calling with catkin_python_setup() set(${PROJECT_NAME}_GENERATE_DYNAMIC_RECONFIGURE TRUE) # check if catkin_python_setup() installs an __init__.py file for a package with the current project name # in order to skip the installation of a generated __init__.py file set(package_has_static_sources ${${PROJECT_NAME}_CATKIN_PYTHON_SETUP_HAS_PACKAGE_INIT}) # generate empty __init__ to make parent folder of msg/srv a python module if(NOT EXISTS ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/__init__.py) file(WRITE ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/__init__.py "") endif() if(NOT package_has_static_sources) # install package __init__.py install( FILES ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/__init__.py DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION} ) endif() # make sure we can find generated messages and that they overlay all other includes # Use system to skip warnings from these includes include_directories(BEFORE ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}) # pass the include directory to catkin_package() list(APPEND ${PROJECT_NAME}_INCLUDE_DIRS ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}) # ensure that the folder exists file(MAKE_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}) # generate cfg module __init__.py if(NOT EXISTS ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg/__init__.py) file(WRITE ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg/__init__.py "") endif() # compile python code before installing find_package(PythonInterp REQUIRED) install(CODE "execute_process(COMMAND \"${PYTHON_EXECUTABLE}\" -m compileall \"${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg\")") install( DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/cfg DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION} ) endif() endmacro() dynamic_reconfigure-1.7.2/cmake/dynamic_reconfigure/000077500000000000000000000000001420405362400226315ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/cmake/dynamic_reconfigure/__init__.py000066400000000000000000000000001420405362400247300ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/cmake/dynamic_reconfigure/parameter_generator.py000066400000000000000000000034721420405362400272370ustar00rootroot00000000000000#! /usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. str_t = "str" bool_t = "bool" int_t = "int" double_t = "double" class ParameterGenerator(): @staticmethod def dummy(*params, **nparams): return def __getattr__(self, name): return self.dummy dynamic_reconfigure-1.7.2/cmake/gendeps000077500000000000000000000061001420405362400201650ustar00rootroot00000000000000#! /usr/bin/env python # # Software License Agreement (BSD License) # # Copyright (c) 2010, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # Revision $Id$ from __future__ import print_function import sys import inspect import imp import os.path _DYNAMIC_RECONFIGURE_GENERATING_DEPENDENCIES = True def do_nothing(*args): pass if __name__ == "__main__": srcfile = sys.argv[1] start_modules = list(sys.modules) sys.exit = do_nothing exit = do_nothing #dynamic_reconfigure.parameter_generator.ParameterGenerator.generate = do_nothing # Remove our directory from the system path, and replace it with the one # that the file expects to see. sys.path[0] = os.path.dirname(srcfile) f = open(srcfile, 'U') stderr = sys.stderr stdout = sys.stdout sys.stdout = stderr # Avoid clobbering our output. print("Finding dependencies for %s" % srcfile, file=stderr) try: imp.load_module("__main__", f, srcfile, ('.cfg', 'U', 1)) except: errmsg = "load_module did not return. Unable to determine dependencies for file listed above." print('\n'.join(["*" * len(errmsg), errmsg, "*" * len(errmsg)]), file=stderr) raise end_modules = sys.modules for m in end_modules: if not m in start_modules: try: mod_file = inspect.getsourcefile(end_modules[m]) if type(mod_file) == str: for i in range(50): # .eggs on mac are strange, move up the hierarchy until we find the .egg, bail after 50 tries. if os.path.exists(mod_file): print(mod_file, file=stdout) break mod_file = os.path.dirname(mod_file) except: pass dynamic_reconfigure-1.7.2/cmake/setup_custom_pythonpath.bat.in000066400000000000000000000002761420405362400247270ustar00rootroot00000000000000REM generated from dynamic_reconfigure/cmake/setup_custom_pythonpath.bat.in set PYTHONPATH=@CATKIN_DEVEL_PREFIX@/@CATKIN_GLOBAL_PYTHON_DESTINATION@;%PYTHONPATH% call @PYTHON_EXECUTABLE@ %* dynamic_reconfigure-1.7.2/cmake/setup_custom_pythonpath.sh.in000077500000000000000000000003121420405362400245650ustar00rootroot00000000000000#!/usr/bin/env sh # generated from dynamic_reconfigure/cmake/setup_custom_pythonpath.sh.in PYTHONPATH=@CATKIN_DEVEL_PREFIX@/@CATKIN_GLOBAL_PYTHON_DESTINATION@:$PYTHONPATH exec @PYTHON_EXECUTABLE@ "$@" dynamic_reconfigure-1.7.2/epydoc.config000066400000000000000000000004261420405362400202110ustar00rootroot00000000000000[epydoc] name: dynamic_reconfigure modules: dynamic_reconfigure inheritance: included url: http://ros.org/wiki/dynamic_reconfigure frames: no private: no exclude: dynamic_reconfigure.parameter_generator, dynamic_reconfigure.msg, dynamic_reconfigure.srv, dynamic_reconfigure.cfg dynamic_reconfigure-1.7.2/include/000077500000000000000000000000001420405362400171605ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/include/dynamic_reconfigure/000077500000000000000000000000001420405362400231745ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/include/dynamic_reconfigure/client.h000066400000000000000000000313661420405362400246340ustar00rootroot00000000000000/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2015-2016, Myrmex, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Myrmex, Inc nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ /** Author: Aris Synodinos Handles sychronizing node state with the configuration server and setting/getting configuration. */ #ifndef __CLIENT_H__ #define __CLIENT_H__ #include #include #include #include #include #include namespace dynamic_reconfigure { template class Client { public: /** * @brief Client Constructs a statefull dynamic_reconfigure client * @param name The full path of the dynamic_reconfigure::Server * @param config_callback A callback that should be called when the server * informs the clients of a successful reconfiguration * @param description_callback A callback that should be called when the * server infrorms the clients of the description of the reconfiguration * parameters and groups */ Client( const std::string& name, const boost::function config_callback = 0, const boost::function description_callback = 0) : name_(name), nh_(name), received_configuration_(false), received_description_(false), config_callback_(config_callback), description_callback_(description_callback) { set_service_ = nh_.serviceClient("set_parameters"); config_sub_ = nh_.subscribe("parameter_updates", 1, &Client::configurationCallback, this); descr_sub_ = nh_.subscribe("parameter_descriptions", 1, &Client::descriptionCallback, this); } /** * @brief Client Constructs a statefull dynamic_reconfigure client * @param name The full path of the dynamic_reconfigure::Server * @param nh The nodehandle to the full path of the Server (for nodelets) * @param config_callback A callback that should be called when the server * informs the clients of a successful reconfiguration * @param description_callback A callback that should be called when the * server infrorms the clients of the description of the reconfiguration * parameters and groups */ Client( const std::string& name, const ros::NodeHandle& nh, const boost::function config_callback = 0, const boost::function description_callback = 0) : name_(name), nh_(nh), received_configuration_(false), received_description_(false), config_callback_(config_callback), description_callback_(description_callback) { set_service_ = nh_.serviceClient("set_parameters"); config_sub_ = nh_.subscribe("parameter_updates", 1, &Client::configurationCallback, this); descr_sub_ = nh_.subscribe("parameter_descriptions", 1, &Client::descriptionCallback, this); } /** * @brief setConfigurationCallback Sets the user defined configuration * callback function * @param config_callback A function pointer */ void setConfigurationCallback( const boost::function& config_callback) { config_callback_ = config_callback; } /** * @brief setDescriptionCallback Sets the user defined description callback * function * @param description_callback A function pointer */ void setDescriptionCallback(const boost::function& description_callback) { description_callback_ = description_callback; } /** * @brief setConfiguration Attempts to set the configuration to the server * @param configuration The requested configuration * @return True if the server accepted the request (not the reconfiguration) */ bool setConfiguration(const ConfigType& configuration) { ConfigType temp = configuration; return setConfiguration(temp); } /** * @brief setConfiguration Attempts to set the configuration to the server * @param configuration The requested configuration, gets overwritten with the * reply from the reconfigure server * @return True if the server accepted the request (not the reconfiguration) */ bool setConfiguration(ConfigType& configuration) { dynamic_reconfigure::Reconfigure srv; received_configuration_ = false; configuration.__toMessage__(srv.request.config); if (set_service_.call(srv)) { configuration.__fromMessage__(srv.response.config); latest_configuration_.__fromMessage__(srv.response.config); received_configuration_ = true; return true; } else { ROS_WARN("Could not set configuration"); return false; } } /** * @brief getCurrentConfiguration Gets the latest configuration from the * dynamic_reconfigure::Server * @param configuration The object where the configuration will be stored * @param timeout The duration that the client should wait for the * configuration, if set to ros::Duration(0) will wait indefinetely * @return False if the timeout has happened */ bool getCurrentConfiguration( ConfigType& configuration, const ros::Duration& timeout = ros::Duration(0)) { if (timeout == ros::Duration(0)) { ROS_INFO_ONCE("Waiting for configuration..."); boost::mutex::scoped_lock lock(mutex_); while (!received_configuration_) { if (!ros::ok()) return false; cv_.wait(lock); } } else { ros::Time start_time = ros::Time::now(); boost::mutex::scoped_lock lock(mutex_); while (!received_configuration_) { if (!ros::ok()) return false; ros::Duration time_left = timeout - (ros::Time::now() - start_time); if (time_left.toSec() <= 0.0) return false; cv_.wait_for(lock, boost::chrono::nanoseconds(time_left.toNSec())); } } configuration = latest_configuration_; return true; } /** * @brief getDefaultConfiguration Gets the latest default configuration from * the dynamic_reconfigure::Server * @param configuration The object where the configuration will be stored * @param timeout The duration that the client should wait for the * configuration, if set to ros::Duration(0) will wait indefinetely * @return False if the timeout has happened */ bool getDefaultConfiguration( ConfigType& configuration, const ros::Duration& timeout = ros::Duration(0)) { ConfigDescription answer; if (getDescription(answer, timeout)) { configuration.__fromMessage__(answer.dflt); return true; } else { return false; } } /** * @brief getMinConfiguration Gets the latest minimum configuration from * the dynamic_reconfigure::Server * @param configuration The object where the configuration will be stored * @param timeout The duration that the client should wait for the * configuration, if set to ros::Duration(0) will wait indefinetely * @return False if the timeout has happened */ bool getMinConfiguration(ConfigType& configuration, const ros::Duration& timeout = ros::Duration(0)) { ConfigDescription answer; if (getDescription(answer, timeout)) { configuration.__fromMessage__(answer.min); return true; } else { return false; } } /** * @brief getMaxConfiguration Gets the latest maximum configuration from * the dynamic_reconfigure::Server * @param configuration The object where the configuration will be stored * @param timeout The duration that the client should wait for the * configuration, if set to ros::Duration(0) will wait indefinetely * @return False if the timeout has happened */ bool getMaxConfiguration(ConfigType& configuration, const ros::Duration& timeout = ros::Duration(0)) { ConfigDescription answer; if (getDescription(answer, timeout)) { configuration.__fromMessage__(answer.max); return true; } else { return false; } } /** * @brief getName Gets the name of the Dynamic Reconfigure Client * @return Copy of the member variable */ std::string getName() const { return name_; } private: void configurationCallback(const dynamic_reconfigure::Config& configuration) { boost::mutex::scoped_lock lock(mutex_); dynamic_reconfigure::Config temp_config = configuration; received_configuration_ = true; latest_configuration_.__fromMessage__(temp_config); cv_.notify_all(); if (config_callback_) { try { config_callback_(latest_configuration_); } catch (std::exception& e) { ROS_WARN("Configuration callback failed with exception %s", e.what()); } catch (...) { ROS_WARN("Configuration callback failed with unprintable exception"); } } else { ROS_DEBUG( "Unable to call Configuration callback because none was set.\n" \ "See setConfigurationCallback"); } } void descriptionCallback( const dynamic_reconfigure::ConfigDescription& description) { boost::mutex::scoped_lock lock(mutex_); received_description_ = true; latest_description_ = description; cv_.notify_all(); if (description_callback_) { try { description_callback_(description); } catch (std::exception& e) { ROS_WARN("Description callback failed with exception %s", e.what()); } catch (...) { ROS_WARN("Description callback failed with unprintable exception"); } } else { ROS_DEBUG( "Unable to call Description callback because none was set.\n" \ "See setDescriptionCallback"); } } bool getDescription(ConfigDescription& configuration, const ros::Duration& timeout) { if (timeout == ros::Duration(0)) { ROS_INFO_ONCE("Waiting for configuration..."); boost::mutex::scoped_lock lock(mutex_); while (!received_description_) { if (!ros::ok()) return false; cv_.wait(lock); } } else { ros::Time start_time = ros::Time::now(); boost::mutex::scoped_lock lock(mutex_); while (!received_description_) { if (!ros::ok()) return false; ros::Duration time_left = timeout - (ros::Time::now() - start_time); if (time_left.toSec() <= 0.0) return false; cv_.wait_for(lock, boost::chrono::nanoseconds(time_left.toNSec())); } } configuration = latest_description_; return true; } std::string name_; ros::NodeHandle nh_; bool received_configuration_; ConfigType latest_configuration_; bool received_description_; dynamic_reconfigure::ConfigDescription latest_description_; boost::condition_variable cv_; boost::mutex mutex_; ros::ServiceClient set_service_; ros::Subscriber descr_sub_; ros::Subscriber config_sub_; boost::function config_callback_; boost::function description_callback_; }; } #endif // __CLIENT_H__ dynamic_reconfigure-1.7.2/include/dynamic_reconfigure/config_init_mutex.h000066400000000000000000000015101420405362400270540ustar00rootroot00000000000000#ifndef __DYNAMIC_RECONFIGURE__CONFIG_INIT_MUTEX_H__ #define __DYNAMIC_RECONFIGURE__CONFIG_INIT_MUTEX_H__ #include #include // Import/export for windows dll's and visibility for gcc shared libraries. #ifdef ROS_BUILD_SHARED_LIBS // ros is being built around shared libraries #ifdef dynamic_reconfigure_config_init_mutex_EXPORTS // we are building a shared lib/dll #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL ROS_HELPER_EXPORT #else // we are using shared lib/dll #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL ROS_HELPER_IMPORT #endif #else // ros is being built around static libraries #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL #endif namespace dynamic_reconfigure { extern DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL boost::mutex __init_mutex__; } #endif dynamic_reconfigure-1.7.2/include/dynamic_reconfigure/config_tools.h000066400000000000000000000102231420405362400260300ustar00rootroot00000000000000#ifndef __DYNAMIC_RECONFIGURE__CONFIG_TOOLS__ #define __DYNAMIC_RECONFIGURE__CONFIG_TOOLS__ #include #include #include #include namespace dynamic_reconfigure { class ConfigTools { public: static std::vector &getVectorForType(dynamic_reconfigure::Config &set, const bool /*val*/) { return set.bools; } static std::vector &getVectorForType(dynamic_reconfigure::Config &set, const int /*val*/) { return set.ints; } static std::vector &getVectorForType(dynamic_reconfigure::Config &set, const std::string& /*val*/) { return set.strs; } static std::vector &getVectorForType(dynamic_reconfigure::Config &set, const double /*val*/) { return set.doubles; } static const std::vector &getVectorForType(const dynamic_reconfigure::Config &set, const bool /*val*/) { return set.bools; } static const std::vector &getVectorForType(const dynamic_reconfigure::Config &set, const int /*val*/) { return set.ints; } static const std::vector &getVectorForType(const dynamic_reconfigure::Config &set, const std::string& /*val*/) { return set.strs; } static const std::vector &getVectorForType(const dynamic_reconfigure::Config &set, const double /*val*/) { return set.doubles; } static dynamic_reconfigure::BoolParameter makeKeyValuePair(const std::string &name, const bool val) { dynamic_reconfigure::BoolParameter param; param.name = name; param.value = val ; return param; } static dynamic_reconfigure::IntParameter makeKeyValuePair(const std::string &name, const int val) { dynamic_reconfigure::IntParameter param; param.name = name; param.value = val ; return param; } static dynamic_reconfigure::StrParameter makeKeyValuePair(const std::string &name, const std::string &val) { dynamic_reconfigure::StrParameter param; param.name = name; param.value = val ; return param; } static dynamic_reconfigure::DoubleParameter makeKeyValuePair(const std::string &name, const double val) { dynamic_reconfigure::DoubleParameter param; param.name = name; param.value = val ; return param; } template static void appendParameter(dynamic_reconfigure::Config &set, const std::string &name, const T &val) { getVectorForType(set, val).push_back(makeKeyValuePair(name, val)); } template static bool getParameter(const std::vector &vec, const std::string &name, T &val) { for (typename std::vector::const_iterator i = vec.begin(); i != vec.end(); ++i) if (i->name == name) { val = i->value; return true; } return false; } template static bool getParameter(const dynamic_reconfigure::Config &set, const std::string &name, T &val) { return getParameter(getVectorForType(set, val), name, val); } template static void appendGroup(dynamic_reconfigure::Config &set, const std::string &name, int id, int parent, const T &val) { dynamic_reconfigure::GroupState msg; msg.name = name; msg.id= id; msg.parent = parent; msg.state = val.state; set.groups.push_back(msg); } template static bool getGroupState(const dynamic_reconfigure::Config &msg, const std::string &name, T &val) { for(std::vector::const_iterator i = msg.groups.begin(); i != msg.groups.end(); ++i) if(i->name == name) { val.state = i->state; return true; } return false; } static int size(dynamic_reconfigure::Config &msg) { return msg.bools.size() + msg.doubles.size() + msg.ints.size() + msg.strs.size(); } static void clear(dynamic_reconfigure::Config &msg) { msg.bools.clear(); msg.ints.clear(); msg.strs.clear(); msg.doubles.clear(); msg.groups.clear(); } }; } #endif dynamic_reconfigure-1.7.2/include/dynamic_reconfigure/server.h000066400000000000000000000164671420405362400246710ustar00rootroot00000000000000/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2009-2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Willow Garage nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ /** Author: Blaise Gassend Handles synchronizing node state with the configuration server, and handling of services to get and set configuration. */ #ifndef __SERVER_H__ #define __SERVER_H__ #include #include #include #include #include /** * @todo Add diagnostics. */ namespace dynamic_reconfigure { /** * Keeps track of the reconfigure callback function. */ template class Server { public: Server(const ros::NodeHandle &nh = ros::NodeHandle("~")) : node_handle_(nh), mutex_(own_mutex_), own_mutex_warn_(true) { init(); } Server(boost::recursive_mutex &mutex, const ros::NodeHandle &nh = ros::NodeHandle("~")) : node_handle_(nh), mutex_(mutex), own_mutex_warn_(false) { init(); } typedef boost::function CallbackType; void setCallback(const CallbackType &callback) { boost::recursive_mutex::scoped_lock lock(mutex_); callback_ = callback; callCallback(config_, ~0); // At startup we need to load the configuration with all level bits set. (Everything has changed.) updateConfigInternal(config_); } void clearCallback() { boost::recursive_mutex::scoped_lock lock(mutex_); callback_.clear(); } void updateConfig(const ConfigType &config) { if (own_mutex_warn_) { ROS_WARN("updateConfig() called on a dynamic_reconfigure::Server that provides its own mutex. This can lead to deadlocks if updateConfig() is called during an update. Providing a mutex to the constructor is highly recommended in this case. Please forward this message to the node author."); own_mutex_warn_ = false; } updateConfigInternal(config); } void getConfigMax(ConfigType &config) { config = max_; } void getConfigMin(ConfigType &config) { config = min_; } void getConfigDefault(ConfigType &config) { config = default_; } void setConfigMax(const ConfigType &config) { max_ = config; PublishDescription(); } void setConfigMin(const ConfigType &config) { min_ = config; PublishDescription(); } void setConfigDefault(const ConfigType &config) { default_ = config; PublishDescription(); } private: ros::NodeHandle node_handle_; ros::ServiceServer set_service_; ros::Publisher update_pub_; ros::Publisher descr_pub_; CallbackType callback_; ConfigType config_; ConfigType min_; ConfigType max_; ConfigType default_; boost::recursive_mutex &mutex_; boost::recursive_mutex own_mutex_; // Used only if an external one isn't specified. bool own_mutex_warn_; void PublishDescription() { boost::recursive_mutex::scoped_lock lock(mutex_); //Copy over min_ max_ default_ dynamic_reconfigure::ConfigDescription description_message = ConfigType::__getDescriptionMessage__(); max_.__toMessage__(description_message.max, ConfigType::__getParamDescriptions__(),ConfigType::__getGroupDescriptions__()); min_.__toMessage__(description_message.min,ConfigType::__getParamDescriptions__(),ConfigType::__getGroupDescriptions__()); default_.__toMessage__(description_message.dflt,ConfigType::__getParamDescriptions__(),ConfigType::__getGroupDescriptions__()); //Publish description descr_pub_.publish(description_message); } void init() { //Grab copys of the data from the config files. These are declared in the generated config file. min_ = ConfigType::__getMin__(); max_ = ConfigType::__getMax__(); default_ = ConfigType::__getDefault__(); boost::recursive_mutex::scoped_lock lock(mutex_); set_service_ = node_handle_.advertiseService("set_parameters", &Server::setConfigCallback, this); descr_pub_ = node_handle_.advertise("parameter_descriptions", 1, true); descr_pub_.publish(ConfigType::__getDescriptionMessage__()); update_pub_ = node_handle_.advertise("parameter_updates", 1, true); ConfigType init_config = ConfigType::__getDefault__(); init_config.__fromServer__(node_handle_); init_config.__clamp__(); updateConfigInternal(init_config); } void callCallback(ConfigType &config, int level) { if (callback_) // At startup we need to load the configuration with all level bits set. (Everything has changed.) try { callback_(config, level); } catch (std::exception &e) { ROS_WARN("Reconfigure callback failed with exception %s: ", e.what()); } catch (...) { ROS_WARN("Reconfigure callback failed with unprintable exception."); } else ROS_DEBUG("setCallback did not call callback because it was zero."); /// @todo kill this line. } bool setConfigCallback(dynamic_reconfigure::Reconfigure::Request &req, dynamic_reconfigure::Reconfigure::Response &rsp) { boost::recursive_mutex::scoped_lock lock(mutex_); ConfigType new_config = config_; new_config.__fromMessage__(req.config); new_config.__clamp__(); uint32_t level = config_.__level__(new_config); callCallback(new_config, level); updateConfigInternal(new_config); new_config.__toMessage__(rsp.config); return true; } void updateConfigInternal(const ConfigType &config) { boost::recursive_mutex::scoped_lock lock(mutex_); config_ = config; config_.__toServer__(node_handle_); dynamic_reconfigure::Config msg; config_.__toMessage__(msg); update_pub_.publish(msg); } }; } #endif dynamic_reconfigure-1.7.2/msg/000077500000000000000000000000001420405362400163235ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/msg/BoolParameter.msg000066400000000000000000000000271420405362400215660ustar00rootroot00000000000000string name bool value dynamic_reconfigure-1.7.2/msg/Config.msg000066400000000000000000000001541420405362400202400ustar00rootroot00000000000000BoolParameter[] bools IntParameter[] ints StrParameter[] strs DoubleParameter[] doubles GroupState[] groups dynamic_reconfigure-1.7.2/msg/ConfigDescription.msg000066400000000000000000000000611420405362400224410ustar00rootroot00000000000000Group[] groups Config max Config min Config dflt dynamic_reconfigure-1.7.2/msg/DoubleParameter.msg000066400000000000000000000000321420405362400221010ustar00rootroot00000000000000string name float64 value dynamic_reconfigure-1.7.2/msg/Group.msg000066400000000000000000000001151420405362400201240ustar00rootroot00000000000000string name string type ParamDescription[] parameters int32 parent int32 id dynamic_reconfigure-1.7.2/msg/GroupState.msg000066400000000000000000000000551420405362400211300ustar00rootroot00000000000000string name bool state int32 id int32 parent dynamic_reconfigure-1.7.2/msg/IntParameter.msg000066400000000000000000000000301420405362400214170ustar00rootroot00000000000000string name int32 value dynamic_reconfigure-1.7.2/msg/ParamDescription.msg000066400000000000000000000001131420405362400222720ustar00rootroot00000000000000string name string type uint32 level string description string edit_method dynamic_reconfigure-1.7.2/msg/SensorLevels.msg000066400000000000000000000005421420405362400214600ustar00rootroot00000000000000# This message is deprecated, please use driver_base/SensorLevels instead. byte RECONFIGURE_CLOSE = 3 # Parameters that need a sensor to be stopped completely when changed byte RECONFIGURE_STOP = 1 # Parameters that need a sensor to stop streaming when changed byte RECONFIGURE_RUNNING = 0 # Parameters that can be changed while a sensor is streaming dynamic_reconfigure-1.7.2/msg/StrParameter.msg000066400000000000000000000000311420405362400214360ustar00rootroot00000000000000string name string value dynamic_reconfigure-1.7.2/package.xml000066400000000000000000000026401420405362400176540ustar00rootroot00000000000000 dynamic_reconfigure 1.7.2 The dynamic_reconfigure package provides a means to update parameters at runtime without having to restart the node. Michael Carroll BSD http://ros.org/wiki/dynamic_reconfigure https://github.com/ros/dynamic_reconfigure/issues https://github.com/ros/dynamic_reconfigure Blaise Gassend catkin cpp_common message_generation roscpp_serialization rostest libboost-chrono-dev libboost-thread-dev libboost-dev roscpp std_msgs message_runtime roslib rospy rosservice dynamic_reconfigure-1.7.2/rosdoc.yaml000066400000000000000000000000541420405362400177110ustar00rootroot00000000000000 - builder: epydoc config: epydoc.config dynamic_reconfigure-1.7.2/scripts/000077500000000000000000000000001420405362400172245ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/scripts/dynparam000077500000000000000000000206131420405362400207670ustar00rootroot00000000000000#! /usr/bin/env python # # Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # Revision $Id$ from __future__ import print_function NAME='dynparam' import roslib; roslib.load_manifest('dynamic_reconfigure') import rospy import optparse import sys import yaml import dynamic_reconfigure.client def do_list(): connect() list = dynamic_reconfigure.find_reconfigure_services() for s in list: print(s) def do_set_from_parameters(): usage = """Usage: %prog set_from_parameters [options] node Example command line: dynparam set_from_parameters wge100_camera _camera_url:=foo Example launch file: """ parser = optparse.OptionParser(usage=usage, prog=NAME) add_timeout_option(parser) options, args = parser.parse_args(myargv[2:]) if len(args) == 0: parser.error("invalid arguments. Please specify a node name") elif len(args) > 1: parser.error("too many arguments") node = args[0] connect() try: params = rospy.get_param("~") except KeyError: print('error updating parameters: no parameters found on parameter server', file=sys.stderr) return set_params(node, params, timeout=options.timeout) def do_set(): usage = """Usage: %prog set [options] node parameter value or: %prog set [options] node values Examples: dynparam set wge100_camera camera_url foo dynparam set wge100_camera "{'camera_url':'foo', 'brightness':58}" """ args, optparse_args = [], [] for s in myargv[2:]: if s.startswith('-'): if len(s) > 1 and ord(s[1]) >= ord('0') and ord(s[1]) <= ord('9'): args.append(s) else: optparse_args.append(s) else: args.append(s) parser = optparse.OptionParser(usage=usage, prog=NAME) add_timeout_option(parser) options, _ = parser.parse_args(optparse_args) if len(args) > 3: parser.error("too many arguments") elif len(args) < 2: parser.error("invalid arguments. Please specify either a node name, parameter name and parameter value, or a node name and a YAML dictionary") node = args[0] if len(args) == 2: node, value = args[0], args[1] values_dict = yaml.load(value) if type(values_dict) != dict: parser.error('invalid arguments. Please specify either a node name, parameter name and parameter value, or a node name and a YAML dictionary') elif len(args) == 3: node, parameter, value = args[0], args[1], args[2] values_dict = { parameter : value } connect() try: set_params(node, values_dict, timeout=options.timeout) except rospy.service.ServiceException: print('couldn\'t set parameters at node %s' % node) except rospy.exceptions.ROSException: print('couldn\'t set parameters at node %s' % node) def do_get(): usage = "Usage: %prog get [options] node" parser = optparse.OptionParser(usage=usage, prog=NAME) add_timeout_option(parser) options, args = parser.parse_args(myargv[2:]) if len(args) == 0: parser.error("invalid arguments. Please specify a node name") elif len(args) > 1: parser.error("too many arguments") node = args[0] connect() params = get_params(node, timeout=options.timeout) if params is not None: print(params) def do_load(): usage = "Usage: %prog load [options] node file" parser = optparse.OptionParser(usage=usage, prog=NAME) add_timeout_option(parser) options, args = parser.parse_args(myargv[2:]) if len(args) == 0: parser.error("invalid arguments. Please specify a node name") elif len(args) == 1: parser.error("invalid arguments. Please specify an input file") elif len(args) > 2: parser.error("too many arguments") node, path = args[0], args[1] f = open(path, 'r') try: params = {} for doc in yaml.load_all(f.read()): params.update(doc) finally: f.close() connect() set_params(node, params, timeout=options.timeout) def do_dump(): usage = "Usage: %prog dump [options] node file" parser = optparse.OptionParser(usage=usage, prog=NAME) add_timeout_option(parser) options, args = parser.parse_args(myargv[2:]) if len(args) == 0: parser.error("invalid arguments. Please specify a node name") elif len(args) == 1: parser.error("invalid arguments. Please specify an output file") elif len(args) > 2: parser.error("too many arguments") node, path = args[0], args[1] connect() params = get_params(node, timeout=options.timeout) if params is not None: f = open(path, 'w') try: yaml.dump(params, f) return finally: f.close() print("couldn't get parameters from node %s" % node) def get_params(node, timeout=None): client = dynamic_reconfigure.client.Client(node, timeout=timeout) return client.get_configuration(timeout=timeout) def set_params(node, params, timeout=None): client = dynamic_reconfigure.client.Client(node, timeout=timeout) try: client.update_configuration(params) except dynamic_reconfigure.DynamicReconfigureParameterException as e: print('error updating parameters: ' + str(e)) def add_timeout_option(parser): parser.add_option('-t', '--timeout', action='store', type='float', default=None, help='timeout in secs') def print_usage(): print("""dynparam is a command-line tool for getting, setting, and deleting parameters of a dynamically configurable node. Commands: \tdynparam set configure node \tdynparam set_from_parameters copy configuration from parameter server \tdynparam get get node configuration \tdynparam load load configuration from file \tdynparam dump dump configuration to file \tdynparam list list configurable nodes Type dynparam -h for more detailed usage, e.g. 'dynparam get -h' """) sys.exit(1) def connect(): rospy.init_node('dynparam', anonymous=True) if __name__ == '__main__': myargv = rospy.myargv() if len(myargv) == 1: print_usage() else: cmd = myargv[1] try: if cmd == 'list': do_list() elif cmd == 'set_from_parameters': do_set_from_parameters() elif cmd == 'set': do_set() elif cmd == 'get': do_get() elif cmd == 'load': do_load() elif cmd == 'dump': do_dump() else: print_usage() except rospy.exceptions.ROSInterruptException: pass dynamic_reconfigure-1.7.2/setup.py000066400000000000000000000003711420405362400172500ustar00rootroot00000000000000from setuptools import setup from catkin_pkg.python_setup import generate_distutils_setup d = generate_distutils_setup( packages=['dynamic_reconfigure'], package_dir={'': 'src'}, requires=['roslib', 'rospy', 'rosservice'] ) setup(**d) dynamic_reconfigure-1.7.2/src/000077500000000000000000000000001420405362400163245ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/000077500000000000000000000000001420405362400223405ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/__init__.py000066400000000000000000000045001420405362400244500ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Python client API for dynamic_reconfigure (L{Client}) as well as example server implementation (L{Server}). """ import roslib class DynamicReconfigureException(Exception): """ dynamic_reconfigure base exception type """ pass class DynamicReconfigureParameterException(DynamicReconfigureException): """ Exception for parameter errors. """ pass class DynamicReconfigureCallbackException(DynamicReconfigureException): """ Exception for callback errors. """ pass def find_reconfigure_services(): import rosservice return sorted([s[:-len('/set_parameters')] for s in rosservice.get_service_list() if s.endswith('/set_parameters')]) def get_parameter_names(descr): return descr.defaults.keys() dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/client.py000066400000000000000000000324511420405362400241750ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Python client API for dynamic_reconfigure (L{DynamicReconfigureClient}) as well as example server implementation (L{DynamicReconfigureServer}). """ from __future__ import print_function, with_statement try: import roslib; roslib.load_manifest('dynamic_reconfigure') except Exception: pass import rospy import sys import threading import time from dynamic_reconfigure import DynamicReconfigureCallbackException from dynamic_reconfigure import DynamicReconfigureParameterException from dynamic_reconfigure.encoding import decode_config, decode_description, encode_config, extract_params from dynamic_reconfigure.msg import Config as ConfigMsg from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv from rospy.service import ServiceException class Client(object): """ Python dynamic_reconfigure client API """ def __init__(self, name, timeout=None, config_callback=None, description_callback=None): """ Connect to dynamic_reconfigure server and return a client object @param name: name of the server to connect to (usually the node name) @type name: str @param timeout: time to wait before giving up @type timeout: float @param config_callback: callback for server parameter changes @param description_callback: internal use only as the API has not stabilized """ self.name = name self.config = None self.param_description = None self.group_description = None self._param_types = None self._cv = threading.Condition() self._config_callback = config_callback self._description_callback = description_callback self._set_service = self._get_service_proxy('set_parameters', timeout) self._descriptions_sub = self._get_subscriber('parameter_descriptions', ConfigDescrMsg, self._descriptions_msg) self._updates_sub = self._get_subscriber('parameter_updates', ConfigMsg, self._updates_msg) def get_configuration(self, timeout=None): """ Return the latest received server configuration (wait to receive one if none have been received) @param timeout: time to wait before giving up @type timeout: float @return: dictionary mapping parameter names to values or None if unable to retrieve config. @rtype: {str: value} """ if timeout is None or timeout == 0.0: if self.get_configuration(timeout=1.0) is None: print('Waiting for configuration...', file=sys.stderr) with self._cv: while self.config is None: if rospy.is_shutdown(): return None self._cv.wait() else: start_time = time.time() with self._cv: while self.config is None: if rospy.is_shutdown(): return None secs_left = timeout - (time.time() - start_time) if secs_left <= 0.0: break self._cv.wait(secs_left) return self.config def get_parameter_descriptions(self, timeout=None): """ UNSTABLE. Return a description of the parameters for the server. Do not use this method as the type that is returned may change. @param timeout: time to wait before giving up @type timeout: float """ if timeout is None or timeout == 0.0: with self._cv: while self.param_description is None: if rospy.is_shutdown(): return None self._cv.wait() else: start_time = time.time() with self._cv: while self.param_description is None: if rospy.is_shutdown(): return None secs_left = timeout - (time.time() - start_time) if secs_left <= 0.0: break self._cv.wait(secs_left) return self.param_description def get_group_descriptions(self, timeout=None): if timeout is None or timeout == 0.0: with self._cv: while self.group_description is None: if rospy.is_shutdown(): return None self._cv.wait() else: start_time = time.time() with self._cv: while self.group_description is None: if rospy.is_shutdown(): return None secs_left = timeout - (time.time() - start_time) if secs_left <= 0.0: break self._cv.wait(secs_left) return self.group_description def update_configuration(self, changes): """ Change the server's configuration @param changes: dictionary of key value pairs for the parameters that are changing @type changes: {str: value} """ # Retrieve the parameter descriptions if self.param_description is None: self.get_parameter_descriptions() # Cast the parameters to the appropriate types if self.param_description is not None: for name, value in list(changes.items())[:]: if name != 'groups': dest_type = self._param_types.get(name) if dest_type is None: raise DynamicReconfigureParameterException('don\'t know parameter: %s' % name) try: found = False descr = [x for x in self.param_description if x['name'].lower() == name.lower()][0] # Fix not converting bools properly if dest_type is bool and type(value) is str: changes[name] = value.lower() in ("yes", "true", "t", "1") found = True # Handle enums elif type(value) is str and not descr['edit_method'] == '': enum_descr = eval(descr['edit_method']) found = False for const in enum_descr['enum']: if value.lower() == const['name'].lower(): val_type = self._param_type_from_string(const['type']) changes[name] = val_type(const['value']) found = True if not found: if sys.version_info.major < 3: if type(value) is unicode: changes[name] = unicode(value) else: changes[name] = dest_type(value) else: changes[name] = dest_type(value) except ValueError as e: raise DynamicReconfigureParameterException('can\'t set parameter \'%s\' of %s: %s' % (name, str(dest_type), e)) if 'groups' in changes.keys(): changes['groups'] = self.update_groups(changes['groups']) config = encode_config(changes) try: msg = self._set_service(config).config except ServiceException as e: raise DynamicReconfigureCallbackException('service call failed') if self.group_description is None: self.get_group_descriptions() resp = decode_config(msg, self.group_description) return resp def update_groups(self, changes): """ Changes the servers group configuration @param changes: dictionary of key value pairs for the parameters that are changing @type changes: {str: value} """ descr = self.get_group_descriptions() def update_state(group, description): for p, g in description['groups'].items(): if g['name'] == group: description['groups'][p]['state'] = changes[group] else: update_state(group, g) return description for change in changes: descr = update_state(change, descr) return descr def close(self): """ Close connections to the server """ self._descriptions_sub.unregister() self._updates_sub.unregister() ## config_callback def get_config_callback(self): """ Retrieve the config_callback """ return self._config_callback def set_config_callback(self, value): """ Set the config_callback """ self._config_callback = value if self._config_callback is not None: self._config_callback(self.config) config_callback = property(get_config_callback, set_config_callback) ## description_callback def get_description_callback(self): """ Get the current description_callback """ return self._description_callback def set_description_callback(self, value): """ UNSTABLE. Set the description callback. Do not use as the type of the description callback may change. """ self._description_callback = value if self._description_callback is not None: self._description_callback(self.param_description) description_callback = property(get_description_callback, set_description_callback) # Implementation def _get_service_proxy(self, suffix, timeout): service_name = rospy.resolve_name(self.name + '/' + suffix) if timeout is None or timeout == 0.0: try: rospy.wait_for_service(service_name, 1.0) except rospy.exceptions.ROSException: print('Waiting for service %s...' % service_name, file=sys.stderr) rospy.wait_for_service(service_name, timeout) else: rospy.wait_for_service(service_name, timeout) return rospy.ServiceProxy(service_name, ReconfigureSrv) def _get_subscriber(self, suffix, type, callback): topic_name = rospy.resolve_name(self.name + '/' + suffix) return rospy.Subscriber(topic_name, type, callback=callback) def _updates_msg(self, msg): if self.group_description is None: self.get_group_descriptions() self.config = decode_config(msg, self.group_description) with self._cv: self._cv.notifyAll() if self._config_callback is not None: self._config_callback(self.config) def _descriptions_msg(self, msg): self.group_description = decode_description(msg) self.param_description = extract_params(self.group_description) # Build map from parameter name to type self._param_types = {} for p in self.param_description: n, t = p.get('name'), p.get('type') if n is not None and t is not None: self._param_types[n] = self._param_type_from_string(t) with self._cv: self._cv.notifyAll() if self._description_callback is not None: self._description_callback(self.param_description) def _param_type_from_string(self, type_str): if type_str == 'int': return int elif type_str == 'double': return float elif type_str == 'str': return str elif type_str == 'bool': return bool else: raise DynamicReconfigureParameterException('parameter has unknown type: %s. This is a bug in dynamic_reconfigure.' % type_str) dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/encoding.py000066400000000000000000000243121420405362400245020ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. try: import roslib; roslib.load_manifest('dynamic_reconfigure') except Exception: pass import copy import sys from dynamic_reconfigure.msg import BoolParameter, DoubleParameter, IntParameter, ParamDescription, StrParameter from dynamic_reconfigure.msg import Config as ConfigMsg from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg from dynamic_reconfigure.msg import Group as GroupMsg from dynamic_reconfigure.msg import GroupState class Config(dict): def __init__(self, *args, **kwargs): dict.__init__(self, *args, **kwargs) def __getstate__(self): return list(self.__dict__.items()) def __setstate__(self, items): for key, val in items: self.__dict__[key] = val def __repr__(self): return super(Config, self).__repr__() def __setitem__(self, key, value): return super(Config, self).__setitem__(key, value) def __getitem__(self, name): return super(Config, self).__getitem__(name) def __delitem__(self, name): return super(Config, self).__delitem__(name) __getattr__ = __getitem__ __setattr__ = __setitem__ def copy(self): return Config(self) def __deepcopy__(self, memo): c = type(self)({}) for key, value in self.items(): c[copy.deepcopy(key)] = copy.deepcopy(value) return c def encode_description(descr): msg = ConfigDescrMsg() msg.max = encode_config(descr.max) msg.min = encode_config(descr.min) msg.dflt = encode_config(descr.defaults) msg.groups = encode_groups(None, descr.config_description) return msg def encode_groups(parent, group): group_list = [] msg = GroupMsg() msg.name = group['name'] msg.id = group['id'] msg.parent = group['parent'] msg.type = group['type'] for param in group['parameters']: msg.parameters.append(ParamDescription(param['name'], param['type'], param['level'], param['description'], param['edit_method'])) group_list.append(msg) for next in group['groups']: group_list.extend(encode_groups(msg, next)) return group_list def encode_config(config, flat=True): msg = ConfigMsg() for k, v in config.items(): ## @todo add more checks here? if type(v) == int: msg.ints.append(IntParameter(k, v)) elif type(v) == bool: msg.bools.append(BoolParameter(k, v)) elif type(v) == str: msg.strs.append(StrParameter(k, v)) elif sys.version_info.major < 3 and isinstance(v, unicode): msg.strs.append(StrParameter(k, v)) elif type(v) == float: msg.doubles.append(DoubleParameter(k, v)) elif type(v) == dict or isinstance(v, Config): if flat is True: def flatten(g): groups = [] for _name, group in g['groups'].items(): groups.extend(flatten(group)) groups.append(GroupState(group['name'], group['state'], group['id'], group['parent'])) return groups msg.groups.append(GroupState(v['name'], v['state'], v['id'], v['parent'])) msg.groups.extend(flatten(v)) else: msg.groups = [GroupState(x['name'], x['state'], x['id'], x['parent']) for x in v] return msg def group_dict(group): try: state = group.state except AttributeError: state = True if hasattr(group, 'type'): type = group.type else: type = '' return Config({ 'id': group.id, 'parent': group.parent, 'name': group.name, 'type': type, 'state': state, 'groups': Config({}), 'parameters': Config({}), }) def decode_description(msg): mins = decode_config(msg.min) maxes = decode_config(msg.max) defaults = decode_config(msg.dflt) groups = {} grouplist = msg.groups def params_from_msg(msg): params = [] for param in msg.parameters: name = param.name params.append({ 'name': name, 'min': mins[name], 'max': maxes[name], 'default': defaults[name], 'type': param.type, 'level': param.level, 'description': param.description, 'edit_method': param.edit_method, }) return params # grab the default group for group in grouplist: if group.id == 0: groups = group_dict(group) groups['parameters'] = params_from_msg(group) def build_tree(group): children = Config({}) for g in grouplist: if g.id == 0: pass elif g.parent == group['id']: gd = group_dict(g) gd['parameters'] = params_from_msg(g) gd['groups'] = build_tree(gd) # add the dictionary into the tree children[gd['name']] = gd return children groups['groups'] = build_tree(groups) return groups def get_tree(m, group=None): if group is None: for x in m.groups: if x.id == 0: group = x children = Config({}) for g in m.groups: if g.id == 0: pass elif g.parent == group.id: gd = group_dict(g) gd['groups'] = get_tree(m, g) children[gd['name']] = gd if group.id == 0: ret = group_dict(group) ret['groups'] = children return ret else: return children def initial_config(msg, description=None): d = Config([(kv.name, kv.value) for kv in msg.bools + msg.ints + msg.strs + msg.doubles]) def gt(m, descr, group=None): # get the default group if group is None: for x in m.groups: if x.id == 0: group = x children = Config({}) for g in m.groups: if g.id == 0: pass elif g.parent == group.id: gd = group_dict(g) def find_state(gr, dr): for g in dr['groups']: if g['id'] == gr['id']: gr['state'] = g['state'] return else: find_state(gr, g) return find_state(gd, descr) # Get the tree for this group gd['groups'] = gt(m, descr, g) children[gd['name']] = gd if group.id == 0: ret = group_dict(group) ret['groups'] = children return ret else: return children if not msg.groups == [] and description is not None: d["groups"] = gt(msg, description) def add_params(group, descr): for param in descr['parameters']: group['parameters'][param['name']] = d[param['name']] for _n, g in group['groups'].items(): for dr in descr['groups']: if dr['name'] == g['name']: add_params(g, dr) add_params(d['groups'], description) return d def decode_config(msg, description=None): if sys.version_info.major < 3: for s in msg.strs: if not isinstance(s.value, unicode): try: s.value.decode('ascii') except UnicodeDecodeError: s.value = s.value.decode('utf-8') d = Config([(kv.name, kv.value) for kv in msg.bools + msg.ints + msg.strs + msg.doubles]) if not msg.groups == [] and description is not None: d["groups"] = get_tree(msg) def add_params(group, descr): for param in descr['parameters']: if param['name'] in d.keys(): group[param['name']] = d[param['name']] for _n, g in group['groups'].items(): for _nr, dr in descr['groups'].items(): if dr['name'] == g['name']: add_params(g, dr) add_params(d['groups'], description) return d def extract_params(group): params = [] params.extend(group['parameters']) try: for _n, g in group['groups'].items(): params.extend(extract_params(g)) except AttributeError: for g in group['groups']: params.extend(extract_params(g)) return params def get_parents(group, descriptions): parents = [] for p in descriptions['group']: if p['id'] == group['parent']: parents.extend(get_parents(p, descriptions)) parents.append(p) return parents dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/parameter_generator.py000066400000000000000000000625601420405362400267510ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # Author: Blaise Gassend # Given a set of parameters, generates the messages, service types, and # classes to allow runtime reconfiguration. Documentation of a node's # parameters is a handy byproduct. ## @todo # Need to check types of min max and default # Need to put sane error on exceptions from __future__ import print_function import roslib; roslib.load_manifest("dynamic_reconfigure") import roslib.packages from string import Template import os import inspect import sys import re # LINEDEBUG="#line" LINEDEBUG = "//#line" # Convenience names for types str_t = "str" bool_t = "bool" int_t = "int" double_t = "double" id = 0 def check_description(description): quotes = ['"', "'"] for quote in quotes: if description.find(quote) != -1: raise Exception(r"""quotes not allowed in description string `%s`""" % description) def check_name(name): pattern = r'^[a-zA-Z][a-zA-Z0-9_]*$' if not re.match(pattern, name): raise Exception("The name of field \'%s\' does not follow the ROS naming conventions, see http://wiki.ros.org/ROS/Patterns/Conventions" % name) class ParameterGenerator: minval = { 'int': -0x80000000, # 'INT_MIN', 'double': -1e10000, # '-std::numeric_limits::infinity()', 'str': '', 'bool': False, } maxval = { 'int': 0x7FFFFFFF, # 'INT_MAX', 'double': 1e10000, # 'std::numeric_limits::infinity()', 'str': '', 'bool': True, } defval = { 'int': 0, 'double': 0, 'str': '', 'bool': False, } class Group: instances = {} def __init__(self, gen, name, type, state, id, parent): self.name = name.replace(" ", "_") self.type = type self.groups = [] self.parameters = [] self.gen = gen self.id = id self.parent = parent self.state = state self.srcline = inspect.currentframe().f_back.f_lineno self.srcfile = inspect.getsourcefile(inspect.currentframe().f_back.f_code) self.instances[self.id] = self def get_group(self, id): return self.instances[id] def add_group(self, name, type="", state=True): global id group = self.gen.Group(self.gen, name, type, state, id, self.id) id = id + 1 self.groups.append(group) return group def add(self, name, paramtype, level, description, default=None, min=None, max=None, edit_method=""): newparam = { 'name': name, 'type': paramtype, 'default': default, 'level': level, 'description': description, 'min': min, 'max': max, 'srcline': inspect.currentframe().f_back.f_lineno, 'srcfile': inspect.getsourcefile(inspect.currentframe().f_back.f_code), 'edit_method': edit_method, } if type == str_t and (max is not None or min is not None): raise Exception("Max or min specified for %s, which is of string type" % name) check_name(name) check_description(description) self.gen.fill_type(newparam) self.gen.check_type_fill_default(newparam, 'default', self.gen.defval[paramtype]) self.gen.check_type_fill_default(newparam, 'max', self.gen.maxval[paramtype]) self.gen.check_type_fill_default(newparam, 'min', self.gen.minval[paramtype]) self.parameters.append(newparam) # Compile a list of all the parameters in this group def get_parameters(self): params = [] params.extend(self.parameters) for group in self.groups: params.extend(group.get_parameters()) return params def get_parents(self): parents = [] if not self.id == 0: p = self.get_group(self.parent) parents.extend(p.get_parents()) parents.append(self.name) else: parents.append(self.name) return parents def get_field(self): fld = [] fld.extend(self.get_parents()) ret = [] for x in fld: if x == self.name: ret.append(x.lower()) else: ret.append(x.upper()) return '::'.join(ret) def get_class(self, parent=False): cls = [] cls.extend(self.get_parents()) cls = [x.upper() for x in cls] if parent is True: cls.pop() return '::'.join(cls) # dictionary used to create the generated classes def to_dict(self): if self.id == 0: name = "groups" else: name = self.name if self.state: state = 'true' else: state = 'false' return { 'name': self.name, 'type': self.type, 'state': self.state, 'cstate': state, 'id': self.id, 'parent': self.parent, 'parameters': self.parameters, 'groups': [group.to_dict() for group in self.groups], 'srcline': self.srcline, 'srcfile': self.srcfile, 'class': self.get_class(), 'parentclass': self.get_class(parent=True), 'parentname': self.get_group(self.parent).name, 'field': self.get_field(), 'upper': self.name.upper(), 'lower': name.lower(), } def pytype(self, drtype): return {'str': str, 'int': int, 'double': float, 'bool': bool}[drtype] def check_type(self, param, field): drtype = param['type'] name = param['name'] value = param[field] pytype = self.pytype(drtype) if pytype != type(value) and (pytype != float or type(value) != int): raise TypeError("'%s' has type %s, but %s is %s" % (name, drtype, field, repr(value))) param[field] = pytype(value) def fill_type(self, param): param['ctype'] = {'str': 'std::string', 'int': 'int', 'double': 'double', 'bool': 'bool'}[param['type']] param['cconsttype'] = {'str': 'const char * const', 'int': 'const int', 'double': 'const double', 'bool': 'const bool'}[param['type']] def check_type_fill_default(self, param, field, default): value = param[field] # If no value, use default. if value is None: param[field] = default return # Check that value type is compatible with type. self.check_type(param, field) def __init__(self): global id self.group = self.Group(self, "Default", "", True, 0, 0) id = 1 self.constants = [] self.dynconfpath = roslib.packages.get_pkg_dir("dynamic_reconfigure") def const(self, name, type, value, descr): newconst = { 'name': name, 'type': type, 'value': value, 'srcline': inspect.currentframe().f_back.f_lineno, 'srcfile': inspect.getsourcefile(inspect.currentframe().f_back.f_code), 'description': descr } check_description(descr) self.fill_type(newconst) self.check_type(newconst, 'value') self.constants.append(newconst) return newconst # So that we can assign the value easily. def enum(self, constants, description): if len(set(const['type'] for const in constants)) != 1: raise Exception("Inconsistent types in enum!") check_description(description) return repr({'enum': constants, 'enum_description': description}) # Wrap add and add_group for the default group def add(self, name, paramtype, level, description, default=None, min=None, max=None, edit_method=""): self.group.add(name, paramtype, level, description, default, min, max, edit_method) def add_group(self, name, type="", state=True): return self.group.add_group(name, type=type, state=state) def mkdirabs(self, path): if os.path.isdir(path): pass elif os.path.isfile(path): raise OSError("Error creating directory %s, a file with the same name exists" % path) else: head, tail = os.path.split(path) if head and not os.path.isdir(head): self.mkdir(head) if tail: try: os.mkdir(path) except OSError: if not os.path.isdir(path): raise def mkdir(self, path): path = os.path.join(self.pkgpath, path) self.mkdirabs(path) def generate(self, pkgname, nodename, name): self.pkgname = pkgname self.pkgpath = roslib.packages.get_pkg_dir(pkgname) self.name = name self.nodename = nodename self.msgname = name + "Config" # Don't regenerate headers if the config hasn't been modfied cpp_header = os.path.realpath(os.path.join(self.pkgpath, "cpp", pkgname, self.msgname + ".h")) if os.path.exists(cpp_header) and os.path.getmtime(os.path.realpath(__file__)) < os.path.getmtime(cpp_header): exit(0) try: if sys.modules['__main__']._DYNAMIC_RECONFIGURE_GENERATING_DEPENDENCIES: # Done this way because importing this module from gendeps # causes imports of dynamic_reconfigure.msg to fail from at # least some .cfg files. (Not sure why) return except: pass try: # print('**************************************************************') # print('**************************************************************') print(Template("Generating reconfiguration files for $name in $pkgname").substitute( name=self.name, pkgname=self.pkgname)) # print('**************************************************************') # print('**************************************************************') self.generatecpp() self.generatedoc() self.generatewikidoc() self.generateusage() self.generatepy() self.deleteobsolete() except Exception as e: print("Error building srv %s.srv" % name) import traceback traceback.print_exc() exit(1) def generatewikidoc(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname + ".wikidoc"), 'w') print( """# Autogenerated param section. Do not hand edit. param { group.0 { name=Dynamically Reconfigurable Parameters desc=See the [[dynamic_reconfigure]] package for details on dynamically reconfigurable parameters.""", file=f) i = -1 for param in self.group.get_parameters(): i = i + 1 range = "" try: enum = eval(param['edit_method'])['enum'] range = ", ".join(Template("$name ($value): $description").substitute(const) for const in enum) range = "Possible values are: " + range except: if param['type'] == int_t or param['type'] == double_t: range = Template("Range: $min to $max").substitute(param) print(Template( """$i.name= ~$name $i.default= $default $i.type= $type $i.desc=$description $range""" ).substitute(param, range=range, i=i), file=f) print("}\n}\n# End of autogenerated section. You may edit below.", file=f) f.close() def generateusage(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname + "-usage.dox"), 'w') # print("/**", file=f) print("\\subsubsection usage Usage", file=f) print('\\verbatim', file=f) print(Template('').substitute( pkgname=self.pkgname, nodename=self.nodename), file=f) for param in self.group.get_parameters(): print(Template(' ').substitute(param), file=f) print('', file=f) print('\\endverbatim', file=f) print("", file=f) # print("*/", file=f) f.close() def generatedoc(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname + ".dox"), 'w') # print("/**", file=f) print("\\subsubsection parameters ROS parameters", file=f) print("", file=f) print("Reads and maintains the following parameters on the ROS server", file=f) print("", file=f) for param in self.group.get_parameters(): print(Template("- \\b \"~$name\" : \\b [$type] $description min: $min, default: $default, max: $max").substitute(param), file=f) print("", file=f) # print("*/", file=f) f.close() def generateusage(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname + "-usage.dox"), 'w') # print("/**", file=f) print("\\subsubsection usage Usage", file=f) print('\\verbatim', file=f) print(Template('').substitute( pkgname=self.pkgname, nodename=self.nodename), file=f) for param in self.group.get_parameters(): print(Template(' ').substitute(param), file=f) print('', file=f) print('\\endverbatim', file=f) print('', file=f) # print("*/", file=f) f.close() def crepr(self, param, val): type = param["type"] if type == 'str': return '"' + val + '"' if type == 'int': return str(val) if type == 'double': if val == float('inf'): return 'std::numeric_limits::infinity()' elif val == -float('inf'): return '-std::numeric_limits::infinity()' else: return str(val) if type == 'bool': return {True: 1, False: 0}[val] raise TypeError(type) # if type == 'string': # return '"' + val + '"' # if 'uint' in type: # return str(val) + 'ULL' # if 'int' in type: # return str(val) + 'LL' # if 'time' in type: # return 'ros::Time(' + str(val) + ')' # if 'duration' in type: # return 'ros::Duration(' + str(val) + ')' # if 'float' in types: # return str(val) def appendline(self, list, text, param, value=None): if value is None: val = "" else: val = self.crepr(param, param[value]) list.append(Template('${doline} $srcline "$srcfile"\n ' + text).safe_substitute(param, v=val, doline=LINEDEBUG, configname=self.name)) def appendgroup(self, list, group): subgroups = [] for g in group.groups: self.appendgroup(subgroups, g) setters = [] params = [] for p in group.parameters: setters.append(Template(" if(\"${name}\"==(*_i)->name){${name} = boost::any_cast<${ctype}>(val);}").substitute(p)) params.append(Template("${ctype} ${name};").substitute(p)) subgroups = '\n'.join(subgroups) setters = '\n'.join(setters) params = '\n'.join(params) grouptemplate = open(os.path.join(self.dynconfpath, "templates", "GroupClass.h.template")).read() list.append(Template(grouptemplate).safe_substitute(group.to_dict(), subgroups=subgroups, setters=setters, params=params, configname=self.name)) def generatecpp(self): # Read the configuration manipulator template and insert line numbers and file name into template. templatefile = os.path.join(self.dynconfpath, "templates", "ConfigType.h.template") templatelines = [] templatefilesafe = templatefile.replace('\\', '\\\\') # line directive does backslash expansion. curline = 1 f = open(templatefile) for line in f: curline = curline + 1 templatelines.append(Template(line).safe_substitute(linenum=curline, filename=templatefilesafe)) f.close() template = ''.join(templatelines) # Write the configuration manipulator. cfg_cpp_dir = os.path.join("cfg", "cpp", self.pkgname) self.mkdir(cfg_cpp_dir) f = open(os.path.join(self.pkgpath, cfg_cpp_dir, self.name + "Config.h"), 'w') paramdescr = [] groups = [] members = [] constants = [] for const in self.constants: self.appendline(constants, "${cconsttype} ${configname}_${name} = $v;", const, "value") def write_params(group): if group.id == 0: paramdescr.append(Template("${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config> ${name}(\"${name}\", \"${type}\", ${parent}, ${id}, ${cstate}, &${configname}Config::${lower});").safe_substitute(group.to_dict(), configname=self.name)) else: paramdescr.append(Template("${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}> ${name}(\"${name}\", \"${type}\", ${parent}, ${id}, ${cstate}, &${configname}Config::${field});").safe_substitute(group.to_dict(), configname=self.name)) for param in group.parameters: self.appendline(members, "${ctype} ${name};", param) self.appendline(paramdescr, "__min__.${name} = $v;", param, "min") self.appendline(paramdescr, "__max__.${name} = $v;", param, "max") self.appendline(paramdescr, "__default__.${name} = $v;", param, "default") self.appendline( paramdescr, group.to_dict()['name'] + ".abstract_parameters.push_back(${configname}Config::AbstractParamDescriptionConstPtr(new ${configname}Config::ParamDescription<${ctype}>(\"${name}\", \"${type}\", ${level}, " "\"${description}\", \"${edit_method}\", &${configname}Config::${name})));", param) self.appendline( paramdescr, "__param_descriptions__.push_back(${configname}Config::AbstractParamDescriptionConstPtr(new ${configname}Config::ParamDescription<${ctype}>(\"${name}\", \"${type}\", ${level}, " "\"${description}\", \"${edit_method}\", &${configname}Config::${name})));", param) for g in group.groups: write_params(g) self.appendline(paramdescr, "${name}.convertParams();", group.to_dict()) if group.id == 0: self.appendline(paramdescr, "__group_descriptions__.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config>(${name})));", group.to_dict()) else: self.appendline(paramdescr, "${parentname}.groups.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}>(${name})));", group.to_dict()) self.appendline(paramdescr, "__group_descriptions__.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}>(${name})));", group.to_dict()) write_params(self.group) self.appendgroup(groups, self.group) paramdescr = '\n'.join(paramdescr) members = '\n'.join(members) groups = '\n'.join(groups) constants = '\n'.join(constants) f.write(Template(template).substitute( uname=self.name.upper(), configname=self.name, pkgname=self.pkgname, paramdescr=paramdescr, members=members, groups=groups, doline=LINEDEBUG, constants=constants)) f.close() def deleteoneobsolete(self, file): try: os.unlink(file) except OSError: pass def deleteobsolete(self): ### @todo remove this after the transition period. self.deleteoneobsolete(os.path.join(self.pkgpath, "msg", self.msgname + ".msg")) self.deleteoneobsolete(os.path.join("msg", "cpp", self.pkgpath, "msg", self.msgname + ".msg")) self.deleteoneobsolete(os.path.join(self.pkgpath, "srv", "Get" + self.msgname + ".srv")) self.deleteoneobsolete(os.path.join("srv", "cpp", self.pkgpath, "srv", "Get" + self.msgname + ".srv")) self.deleteoneobsolete(os.path.join(self.pkgpath, "srv", "Set" + self.msgname + ".srv")) self.deleteoneobsolete(os.path.join("srv", "cpp", self.pkgpath, "srv", "Set" + self.msgname + ".srv")) # def msgtype(self, type): # return {'int': 'int32', 'bool': 'int8', 'str': 'string', 'double': 'float64'}[type] # # def generatemsg(self): # self.mkdir("msg") # f = open(os.path.join(self.pkgpath, "msg", self.msgname+".msg"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print("", file=f) # for param in self.parameters: # print(Template("$type $name # $description").substitute(param, type=self.msgtype(param['type'])), file=f) # f.close() # # def generategetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Get"+self.msgname+".srv"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print("", file=f) # print("---", file=f) # print(self.msgname, "config", "# Current configuration of node.", file=f) # print(self.msgname, "defaults", "# Minimum values where appropriate.", file=f) # print(self.msgname, "min", "# Minimum values where appropriate.", file=f) # print(self.msgname, "max", "# Maximum values where appropriate.", file=f) # f.close() # # def generatesetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Set"+self.msgname+".srv"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print(self.msgname, "config", "# Requested node configuration.", file=f) # print("---", file=f) # print(self.msgname, "config", "# What the node's configuration was actually set to.", file=f) # f.close() def generatepy(self): # Read the configuration manipulator template and insert line numbers and file name into template. templatefile = os.path.join(self.dynconfpath, "templates", "ConfigType.py.template") f = open(templatefile) template = f.read() f.close() # Write the configuration manipulator. self.mkdir(os.path.join("src", self.pkgname, "cfg")) f = open(os.path.join(self.pkgpath, "src", self.pkgname, "cfg", self.name + "Config.py"), 'w') f.write(Template(template).substitute( name=self.name, pkgname=self.pkgname, pycfgdata=self.group.to_dict())) for const in self.constants: f.write(Template("${configname}_${name} = $v\n").substitute( const, v=repr(const['value']), configname=self.name)) f.close() f = open(os.path.join(self.pkgpath, "src", self.pkgname, "cfg", "__init__.py"), 'a') f.close() f = open(os.path.join(self.pkgpath, "src", self.pkgname, "__init__.py"), 'a') f.close() f = open(os.path.join(self.pkgpath, "src", self.pkgname, "__init__.py"), 'a') f.close() dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/parameter_generator_catkin.py000066400000000000000000000637671420405362400303140ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # Copyright (c) 2015, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # Author: Blaise Gassend # Maintainers: Esteve Fernandez, Morgan Quigley # Given a set of parameters, generates the messages, service types, and # classes to allow runtime reconfiguration. Documentation of a node's # parameters is a handy byproduct. # @todo # Need to check types of min max and default # Need to put sane error on exceptions from __future__ import print_function import inspect import os import re from string import Template import sys import textwrap # LINEDEBUG="#line" LINEDEBUG = "//#line" # Convenience names for types str_t = "str" bool_t = "bool" int_t = "int" double_t = "double" id = 0 def check_description(description): quotes = ['"', "'"] for quote in quotes: if description.find(quote) != -1: raise Exception(r"""quotes not allowed in description string `%s`""" % description) def check_name(name): pattern = r'^[a-zA-Z][a-zA-Z0-9_]*$' if not re.match(pattern, name): raise Exception("The name of field \'%s\' does not follow the ROS naming conventions, see http://wiki.ros.org/ROS/Patterns/Conventions" % name) class ParameterGenerator(object): minval = { 'int': -0x80000000, # 'INT_MIN', 'double': '-std::numeric_limits::infinity()', 'str': '', 'bool': False, } maxval = { 'int': 0x7FFFFFFF, # 'INT_MAX', 'double': 'std::numeric_limits::infinity()', 'str': '', 'bool': True, } defval = { 'int': 0, 'double': 0, 'str': '', 'bool': False, } class Group(object): instances = {} def __init__(self, gen, name, type, state, id, parent): self.name = name.replace(" ", "_") self.type = type self.groups = [] self.parameters = [] self.gen = gen self.id = id self.parent = parent self.state = state self.srcline = inspect.currentframe().f_back.f_lineno self.srcfile = inspect.getsourcefile(inspect.currentframe().f_back.f_code) self.instances[self.id] = self def get_group(self, id): return self.instances[id] def add_group(self, name, type="", state=True): global id group = self.gen.Group(self.gen, name, type, state, id, self.id) id = id + 1 self.groups.append(group) return group def add(self, name, paramtype, level, description, default=None, min=None, max=None, edit_method=""): newparam = { 'name': name, 'type': paramtype, 'default': default, 'level': level, 'description': description, 'min': min, 'max': max, 'srcline': inspect.currentframe().f_back.f_lineno, 'srcfile': inspect.getsourcefile(inspect.currentframe().f_back.f_code), 'edit_method': edit_method, } if (paramtype == str_t or paramtype == bool_t) and (max is not None or min is not None): raise Exception( "Max or min specified for %s, which is of '%s' type" % (name, paramtype)) check_name(name) self.gen.fill_type(newparam) self.gen.check_type_fill_default(newparam, 'default', self.gen.defval[paramtype]) self.gen.check_type_fill_default(newparam, 'max', self.gen.maxval[paramtype]) self.gen.check_type_fill_default(newparam, 'min', self.gen.minval[paramtype]) self.parameters.append(newparam) # Compile a list of all the parameters in this group def get_parameters(self): params = [] params.extend(self.parameters) for group in self.groups: params.extend(group.get_parameters()) return params def get_parents(self): parents = [] if not self.id == 0: p = self.get_group(self.parent) parents.extend(p.get_parents()) parents.append(self.name) else: parents.append(self.name) return parents def get_field(self): fld = [] fld.extend(self.get_parents()) ret = [] for x in fld: if x == self.name: ret.append(x.lower()) else: ret.append(x.upper()) return "::".join(ret) def get_class(self, parent=False): cls = [] cls.extend(self.get_parents()) cls = [x.upper() for x in cls] if parent is True: cls.pop() return "::".join(cls) # dictionary used to create the generated classes def to_dict(self): if self.id == 0: name = "groups" else: name = self.name if self.state: state = 'true' else: state = 'false' return { 'name': self.name, 'type': self.type, 'state': self.state, 'cstate': state, 'id': self.id, 'parent': self.parent, 'parameters': self.parameters, 'groups': [group.to_dict() for group in self.groups], 'srcline': self.srcline, 'srcfile': self.srcfile, 'class': self.get_class(), 'parentclass': self.get_class(parent=True), 'parentname': self.get_group(self.parent).name, 'field': self.get_field(), 'upper': self.name.upper(), 'lower': name.lower() } def pytype(self, drtype): return {'str': str, 'int': int, 'double': float, 'bool': bool}[drtype] def check_type(self, param, field): drtype = param['type'] name = param['name'] value = param[field] pytype = self.pytype(drtype) if pytype != type(value) and (pytype != float or type(value) != int): raise TypeError("'%s' has type %s, but %s is %s" % (name, drtype, field, repr(value))) param[field] = pytype(value) def fill_type(self, param): param['ctype'] = {'str': 'std::string', 'int': 'int', 'double': 'double', 'bool': 'bool'}[param['type']] param['cconsttype'] = {'str': 'const char * const', 'int': 'const int', 'double': 'const double', 'bool': 'const bool'}[param['type']] def check_type_fill_default(self, param, field, default): value = param[field] # If no value, use default. if value is None: param[field] = default return # Check that value type is compatible with type. self.check_type(param, field) def __init__(self): global id self.group = self.Group(self, "Default", "", True, 0, 0) id = 1 self.constants = [] if len(sys.argv) < 5: raise SystemExit(textwrap.dedent("""\ ahhhh! Unexpected command line syntax! Are you trying to call a dynamic_reconfigure configuration generation script directly? When you are using dynamic_reconfigure with python, you don't ever need to invoke the configuration generator script yourself; it loads automatically. If you are using dynamic_reconfigure from C++, you need to add a call to generate_dynamic_reconfigure_options() in your CMakeLists.txt For an example, see http://wiki.ros.org/dynamic_reconfigure/Tutorials Have a nice day """)) self.dynconfpath = sys.argv[1] # FIXME this is awful self.binary_dir = sys.argv[2] self.cpp_gen_dir = sys.argv[3] self.py_gen_dir = sys.argv[4] def const(self, name, type, value, descr): newconst = { 'name': name, 'type': type, 'value': value, 'srcline': inspect.currentframe().f_back.f_lineno, 'srcfile': inspect.getsourcefile(inspect.currentframe().f_back.f_code), 'description': descr } check_description(descr) self.fill_type(newconst) self.check_type(newconst, 'value') self.constants.append(newconst) return newconst # So that we can assign the value easily. def enum(self, constants, description): if len(set(const['type'] for const in constants)) != 1: raise Exception("Inconsistent types in enum!") check_description(description) return repr({'enum': constants, 'enum_description': description}) # Wrap add and add_group for the default group def add(self, name, paramtype, level, description, default=None, min=None, max=None, edit_method=""): self.group.add(name, paramtype, level, description, default, min, max, edit_method) def add_group(self, name, type="", state=True): return self.group.add_group(name, type=type, state=state) def mkdirabs(self, path): if os.path.isdir(path): pass elif os.path.isfile(path): raise OSError("Error creating directory %s, a file with the same name exists" % path) else: try: os.makedirs(path) except OSError: if not os.path.isdir(path): raise def generate(self, pkgname, nodename, name): """ name must match the first part of the configuration file. e.g. given Tutorials.cfg, name must be Tutorials """ try: if sys.modules['__main__']._DYNAMIC_RECONFIGURE_GENERATING_DEPENDENCIES: # Done this way because importing this module from gendeps # causes imports of dynamic_reconfigure.msg to fail from at # least some .cfg files. (Not sure why) return except Exception: pass try: self.pkgname = pkgname self.name = name self.nodename = nodename self.msgname = name + "Config" # print('**************************************************************') # print('**************************************************************') print(Template("Generating reconfiguration files for $name in $pkgname"). substitute(name=self.name, pkgname=self.pkgname)) # print('**************************************************************') # print('**************************************************************') self.generatecpp() self.generatedoc() self.generatewikidoc() self.generateusage() self.generatepy() # self.deleteobsolete() except Exception: print("Error building srv %s.srv" % name) import traceback traceback.print_exc() exit(1) def generatewikidoc(self): self.mkdirabs(os.path.join(self.binary_dir, "docs")) with open(os.path.join(self.binary_dir, "docs", self.msgname + ".wikidoc"), 'w') as f: print(textwrap.dedent("""\ # Autogenerated param section. Do not hand edit. param { group.0 { name=Dynamically Reconfigurable Parameters desc=See the [[dynamic_reconfigure]] package for details on dynamically reconfigurable parameters.""" ), file=f) i = -1 for param in self.group.get_parameters(): i = i + 1 range = "" try: enum = eval(param['edit_method'])['enum'] range = ", ".join(Template("$name ($value): $description").substitute(const) for const in enum) range = "Possible values are: " + range except Exception: if param['type'] == int_t or param['type'] == double_t: range = Template("Range: $min to $max").substitute(param) print(Template(textwrap.dedent("""\ $i.name= ~$name $i.default= $default $i.type= $type $i.desc=$description $range""" )).substitute(param, range=range, i=i), file=f) print("}\n}\n# End of autogenerated section. You may edit below.", file=f) def generatedoc(self): self.mkdirabs("docs") dir_path = os.path.join(self.binary_dir, "docs") self.mkdirabs(dir_path) with open(os.path.join(dir_path, self.msgname + ".dox"), 'w') as f: # print("/**", file=f) print("\\subsubsection parameters ROS parameters", file=f) print("", file=f) print("Reads and maintains the following parameters on the ROS server", file=f) print("", file=f) for param in self.group.get_parameters(): print(Template("- \\b \"~$name\" : \\b [$type] $description min: $min, default: $default, max: $max").substitute(param), file=f) print("", file=f) # print("*/", file=f) def generateusage(self): self.mkdirabs("docs") with open(os.path.join(self.binary_dir, "docs", self.msgname + "-usage.dox"), 'w') as f: # print("/**", file=f) print("\\subsubsection usage Usage", file=f) print('\\verbatim', file=f) print(Template('').substitute( pkgname=self.pkgname, nodename=self.nodename), file=f) for param in self.group.get_parameters(): print(Template(' ').substitute(param), file=f) print('', file=f) print('\\endverbatim', file=f) print("", file=f) # print("*/", file=f) def crepr(self, param, val): type = param["type"] if type == 'str': return '"' + val + '"' if type in ['int', 'double']: return str(val) if type == 'bool': return {True: 1, False: 0}[val] raise TypeError(type) # if type == 'string': # return '"' + val + '"' # if 'uint' in type: # return str(val) + 'ULL' # if 'int' in type: # return str(val) + 'LL' # if 'time' in type: # return 'ros::Time('+str(val)+')' # if 'duration' in type: # return 'ros::Duration('+str(val)+')' # if 'float' in types: # return str(val) def appendline(self, list, text, param, value=None): if value is None: val = "" else: val = self.crepr(param, param[value]) list.append(Template('${doline} $srcline "$srcfile"\n ' + text).safe_substitute(param, v=val, doline=LINEDEBUG, configname=self.name)) def appendgroup(self, list, group): subgroups = [] for g in group.groups: self.appendgroup(subgroups, g) setters = [] params = [] for p in group.parameters: setters.append(Template(" if(\"${name}\"==(*_i)->name){${name} = boost::any_cast<${ctype}>(val);}").substitute(p)) params.append(Template("${ctype} ${name};").substitute(p)) subgroups = "\n".join(subgroups) setters = "\n".join(setters) params = "\n".join(params) grouptemplate = open(os.path.join(self.dynconfpath, "templates", "GroupClass.h.template")).read() list.append(Template(grouptemplate).safe_substitute(group.to_dict(), subgroups=subgroups, setters=setters, params=params, configname=self.name)) def generatecpp(self): # Read the configuration manipulator template and insert line numbers and file name into template. templatefile = os.path.join(self.dynconfpath, "templates", "ConfigType.h.template") templatelines = [] templatefilesafe = templatefile.replace('\\', '\\\\') # line directive does backslash expansion. curline = 1 with open(templatefile) as f: for line in f: curline = curline + 1 templatelines.append(Template(line).safe_substitute(linenum=curline, filename=templatefilesafe)) template = ''.join(templatelines) # Write the configuration manipulator. self.mkdirabs(self.cpp_gen_dir) paramdescr = [] groups = [] members = [] constants = [] for const in self.constants: self.appendline(constants, "${cconsttype} ${configname}_${name} = $v;", const, "value") def write_params(group): if group.id == 0: paramdescr.append(Template("${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config> ${name}(\"${name}\", \"${type}\", ${parent}, ${id}, ${cstate}, &${configname}Config::${lower});").safe_substitute(group.to_dict(), configname=self.name)) else: paramdescr.append(Template("${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}> ${name}(\"${name}\", \"${type}\", ${parent}, ${id}, ${cstate}, &${configname}Config::${field});").safe_substitute(group.to_dict(), configname=self.name)) for param in group.parameters: self.appendline(members, "${ctype} ${name};", param) self.appendline(paramdescr, "__min__.${name} = $v;", param, "min") self.appendline(paramdescr, "__max__.${name} = $v;", param, "max") self.appendline(paramdescr, "__default__.${name} = $v;", param, "default") self.appendline( paramdescr, group.to_dict()['name'] + ".abstract_parameters.push_back(${configname}Config::AbstractParamDescriptionConstPtr(new ${configname}Config::ParamDescription<${ctype}>(\"${name}\", \"${type}\", ${level}, " "\"${description}\", \"${edit_method}\", &${configname}Config::${name})));", param) self.appendline( paramdescr, "__param_descriptions__.push_back(${configname}Config::AbstractParamDescriptionConstPtr(new ${configname}Config::ParamDescription<${ctype}>(\"${name}\", \"${type}\", ${level}, " "\"${description}\", \"${edit_method}\", &${configname}Config::${name})));", param) for g in group.groups: write_params(g) self.appendline(paramdescr, "${name}.convertParams();", group.to_dict()) if group.id == 0: self.appendline(paramdescr, "__group_descriptions__.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config>(${name})));", group.to_dict()) else: self.appendline(paramdescr, "${parentname}.groups.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}>(${name})));", group.to_dict()) self.appendline(paramdescr, "__group_descriptions__.push_back(${configname}Config::AbstractGroupDescriptionConstPtr(new ${configname}Config::GroupDescription<${configname}Config::${class}, ${configname}Config::${parentclass}>(${name})));", group.to_dict()) write_params(self.group) self.appendgroup(groups, self.group) paramdescr = '\n'.join(paramdescr) members = '\n'.join(members) constants = '\n'.join(constants) groups = '\n'.join(groups) with open(os.path.join(self.cpp_gen_dir, self.name + "Config.h"), 'w') as f: f.write(Template(template).substitute( uname=self.name.upper(), configname=self.name, pkgname=self.pkgname, paramdescr=paramdescr, members=members, groups=groups, doline=LINEDEBUG, constants=constants)) print("Wrote header file in " + os.path.join(self.cpp_gen_dir, self.name + "Config.h")) # def deleteoneobsolete(self, file): # try: # os.unlink(file) # except OSError: # pass # def deleteobsolete(self): ### @todo remove this after the transition period. # self.deleteoneobsolete(os.path.join(self.pkgpath, "msg", self.msgname+".msg")) # self.deleteoneobsolete(os.path.join("msg", "cpp", self.pkgpath, "msg", self.msgname+".msg")) # self.deleteoneobsolete(os.path.join(self.pkgpath, "srv", "Get"+self.msgname+".srv")) # self.deleteoneobsolete(os.path.join("srv", "cpp", self.pkgpath, "srv", "Get"+self.msgname+".srv")) # self.deleteoneobsolete(os.path.join(self.pkgpath, "srv", "Set"+self.msgname+".srv")) # self.deleteoneobsolete(os.path.join("srv", "cpp", self.pkgpath, "srv", "Set"+self.msgname+".srv")) # def msgtype(self, type): # return { 'int' : 'int32', 'bool' : 'int8', 'str' : 'string', 'double' : 'float64' }[type] # # def generatemsg(self): # self.mkdir("msg") # f = open(os.path.join(self.pkgpath, "msg", self.msgname+".msg"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print("", file=f) # for param in self.parameters: # print(Template("$type $name # $description").substitute(param, type=self.msgtype(param['type'])), file=f) # f.close() # # def generategetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Get"+self.msgname+".srv"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print("", file=f) # print("---", file=f) # print(self.msgname, "config", "# Current configuration of node.", file=f) # print(self.msgname, "defaults", "# Minimum values where appropriate.", file=f) # print(self.msgname, "min", "# Minimum values where appropriate.", file=f) # print(self.msgname, "max", "# Maximum values where appropriate.", file=f) # f.close() # # def generatesetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Set"+self.msgname+".srv"), 'w') # print("# This is an autogerenated file. Please do not edit.", file=f) # print(self.msgname, "config", "# Requested node configuration.", file=f) # print("---", file=f) # print(self.msgname, "config", "# What the node's configuration was actually set to.", file=f) # f.close() def _rreplace_str_with_val_in_dict(self, orig_dict, old_str, new_val): # Recursively replace any match of old_str by new_val in a dictionary for k, v in orig_dict.items(): if isinstance(v, dict): self._rreplace_str_with_val_in_dict(v, old_str, new_val) elif isinstance(v, list): for idx, i in enumerate(v): if isinstance(i, str) and i == old_str: orig_dict[k][idx] = new_val elif isinstance(i, dict): self._rreplace_str_with_val_in_dict(i, old_str, new_val) elif isinstance(v, str) and v == old_str: orig_dict[k] = new_val return orig_dict def replace_infinity(self, config_dict): config_dict = self._rreplace_str_with_val_in_dict(config_dict, '-std::numeric_limits::infinity()', -float("inf")) config_dict = self._rreplace_str_with_val_in_dict(config_dict, 'std::numeric_limits::infinity()', float("inf")) return config_dict def generatepy(self): # Read the configuration manipulator template and insert line numbers and file name into template. templatefile = os.path.join(self.dynconfpath, "templates", "ConfigType.py.template") with open(templatefile) as f: template = f.read() # Write the configuration manipulator. self.mkdirabs(os.path.join(self.py_gen_dir, "cfg")) with open(os.path.join(self.py_gen_dir, "cfg", self.name + "Config.py"), 'w') as f: pycfgdata = self.replace_infinity(self.group.to_dict()) f.write(Template(template).substitute( name=self.name, pkgname=self.pkgname, pycfgdata=pycfgdata)) for const in self.constants: f.write(Template("${configname}_${name} = $v\n").substitute( const, v=repr(const['value']), configname=self.name)) with open(os.path.join(self.py_gen_dir, "cfg", "__init__.py"), 'a'): pass dynamic_reconfigure-1.7.2/src/dynamic_reconfigure/server.py000066400000000000000000000127531420405362400242300ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Python client API for dynamic_reconfigure (L{DynamicReconfigureClient}) as well as example server implementation (L{DynamicReconfigureServer}). """ from __future__ import with_statement try: import roslib; roslib.load_manifest('dynamic_reconfigure') except Exception: pass import rospy import threading import copy from dynamic_reconfigure import DynamicReconfigureCallbackException from dynamic_reconfigure.encoding import decode_config, encode_config, encode_description, extract_params, get_tree, initial_config from dynamic_reconfigure.msg import Config as ConfigMsg from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv class Server(object): def __init__(self, type, callback, namespace=""): self.mutex = threading.Lock() if not namespace: self.ns = "~" else: if namespace[0] not in ["/", "~"]: namespace = "~" + namespace self.ns = (namespace + "/").replace("//", "/") self.type = type self.config = type.defaults.copy() self.description = encode_description(type) self._copy_from_parameter_server() self.callback = callback self._clamp(self.config) # setup group defaults self.config['groups'] = get_tree(self.description) self.config = initial_config(encode_config(self.config), type.config_description) self.descr_topic = rospy.Publisher(self.ns + 'parameter_descriptions', ConfigDescrMsg, latch=True, queue_size=10) self.descr_topic.publish(self.description) self.update_topic = rospy.Publisher(self.ns + 'parameter_updates', ConfigMsg, latch=True, queue_size=10) self._change_config(self.config, ~0) # Consistent with the C++ API, the callback gets called with level=~0 (i.e. -1) self.set_service = rospy.Service(self.ns + 'set_parameters', ReconfigureSrv, self._set_callback) def update_configuration(self, changes): with self.mutex: new_config = copy.deepcopy(self.config) new_config.update(changes) self._clamp(new_config) return self._change_config(new_config, self._calc_level(new_config, self.config)) def _copy_from_parameter_server(self): for param in extract_params(self.type.config_description): try: self.config[param['name']] = rospy.get_param(self.ns + param['name']) except KeyError: pass def _copy_to_parameter_server(self): for param in extract_params(self.type.config_description): rospy.set_param(self.ns + param['name'], self.config[param['name']]) def _change_config(self, config, level): self.config = self.callback(config, level) if self.config is None: msg = 'Reconfigure callback should return a possibly updated configuration.' rospy.logerr(msg) raise DynamicReconfigureCallbackException(msg) self._copy_to_parameter_server() self.update_topic.publish(encode_config(self.config)) return self.config def _calc_level(self, config1, config2): level = 0 for param in extract_params(self.type.config_description): if config1[param['name']] != config2[param['name']]: level |= param['level'] return level def _clamp(self, config): for param in extract_params(self.type.config_description): maxval = self.type.max[param['name']] minval = self.type.min[param['name']] val = config[param['name']] if val > maxval and maxval != "": config[param['name']] = maxval elif val < minval and minval != "": config[param['name']] = minval def _set_callback(self, req): return encode_config(self.update_configuration(decode_config(req.config, self.type.config_description))) dynamic_reconfigure-1.7.2/src/dynamic_reconfigure_config_init_mutex.cpp000066400000000000000000000001461420405362400266370ustar00rootroot00000000000000#include boost::mutex dynamic_reconfigure::__init_mutex__; dynamic_reconfigure-1.7.2/srv/000077500000000000000000000000001420405362400163475ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/srv/Reconfigure.srv000066400000000000000000000000401420405362400213450ustar00rootroot00000000000000Config config --- Config config dynamic_reconfigure-1.7.2/templates/000077500000000000000000000000001420405362400175335ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/templates/ConfigType.h.template000066400000000000000000000413271420405362400235740ustar00rootroot00000000000000${doline} ${linenum} "${filename}" // ********************************************************* // // File autogenerated for the ${pkgname} package // by the dynamic_reconfigure package. // Please do not edit. // // ********************************************************/ #ifndef __${pkgname}__${uname}CONFIG_H__ #define __${pkgname}__${uname}CONFIG_H__ #if __cplusplus >= 201103L #define DYNAMIC_RECONFIGURE_FINAL final #else #define DYNAMIC_RECONFIGURE_FINAL #endif #include #include #include #include #include #include #include #include namespace ${pkgname} { class ${configname}ConfigStatics; class ${configname}Config { public: class AbstractParamDescription : public dynamic_reconfigure::ParamDescription { public: AbstractParamDescription(std::string n, std::string t, uint32_t l, std::string d, std::string e) { name = n; type = t; level = l; description = d; edit_method = e; } virtual ~AbstractParamDescription() = default; virtual void clamp(${configname}Config &config, const ${configname}Config &max, const ${configname}Config &min) const = 0; virtual void calcLevel(uint32_t &level, const ${configname}Config &config1, const ${configname}Config &config2) const = 0; virtual void fromServer(const ros::NodeHandle &nh, ${configname}Config &config) const = 0; virtual void toServer(const ros::NodeHandle &nh, const ${configname}Config &config) const = 0; virtual bool fromMessage(const dynamic_reconfigure::Config &msg, ${configname}Config &config) const = 0; virtual void toMessage(dynamic_reconfigure::Config &msg, const ${configname}Config &config) const = 0; virtual void getValue(const ${configname}Config &config, boost::any &val) const = 0; }; typedef boost::shared_ptr AbstractParamDescriptionPtr; typedef boost::shared_ptr AbstractParamDescriptionConstPtr; // Final keyword added to class because it has virtual methods and inherits // from a class with a non-virtual destructor. template class ParamDescription DYNAMIC_RECONFIGURE_FINAL : public AbstractParamDescription { public: ParamDescription(std::string a_name, std::string a_type, uint32_t a_level, std::string a_description, std::string a_edit_method, T ${configname}Config::* a_f) : AbstractParamDescription(a_name, a_type, a_level, a_description, a_edit_method), field(a_f) {} T ${configname}Config::* field; virtual void clamp(${configname}Config &config, const ${configname}Config &max, const ${configname}Config &min) const override { if (config.*field > max.*field) config.*field = max.*field; if (config.*field < min.*field) config.*field = min.*field; } virtual void calcLevel(uint32_t &comb_level, const ${configname}Config &config1, const ${configname}Config &config2) const override { if (config1.*field != config2.*field) comb_level |= level; } virtual void fromServer(const ros::NodeHandle &nh, ${configname}Config &config) const override { nh.getParam(name, config.*field); } virtual void toServer(const ros::NodeHandle &nh, const ${configname}Config &config) const override { nh.setParam(name, config.*field); } virtual bool fromMessage(const dynamic_reconfigure::Config &msg, ${configname}Config &config) const override { return dynamic_reconfigure::ConfigTools::getParameter(msg, name, config.*field); } virtual void toMessage(dynamic_reconfigure::Config &msg, const ${configname}Config &config) const override { dynamic_reconfigure::ConfigTools::appendParameter(msg, name, config.*field); } virtual void getValue(const ${configname}Config &config, boost::any &val) const override { val = config.*field; } }; class AbstractGroupDescription : public dynamic_reconfigure::Group { public: AbstractGroupDescription(std::string n, std::string t, int p, int i, bool s) { name = n; type = t; parent = p; state = s; id = i; } virtual ~AbstractGroupDescription() = default; std::vector abstract_parameters; bool state; virtual void toMessage(dynamic_reconfigure::Config &msg, const boost::any &config) const = 0; virtual bool fromMessage(const dynamic_reconfigure::Config &msg, boost::any &config) const =0; virtual void updateParams(boost::any &cfg, ${configname}Config &top) const= 0; virtual void setInitialState(boost::any &cfg) const = 0; void convertParams() { for(std::vector::const_iterator i = abstract_parameters.begin(); i != abstract_parameters.end(); ++i) { parameters.push_back(dynamic_reconfigure::ParamDescription(**i)); } } }; typedef boost::shared_ptr AbstractGroupDescriptionPtr; typedef boost::shared_ptr AbstractGroupDescriptionConstPtr; // Final keyword added to class because it has virtual methods and inherits // from a class with a non-virtual destructor. template class GroupDescription DYNAMIC_RECONFIGURE_FINAL : public AbstractGroupDescription { public: GroupDescription(std::string a_name, std::string a_type, int a_parent, int a_id, bool a_s, T PT::* a_f) : AbstractGroupDescription(a_name, a_type, a_parent, a_id, a_s), field(a_f) { } GroupDescription(const GroupDescription& g): AbstractGroupDescription(g.name, g.type, g.parent, g.id, g.state), field(g.field), groups(g.groups) { parameters = g.parameters; abstract_parameters = g.abstract_parameters; } virtual bool fromMessage(const dynamic_reconfigure::Config &msg, boost::any &cfg) const override { PT* config = boost::any_cast(cfg); if(!dynamic_reconfigure::ConfigTools::getGroupState(msg, name, (*config).*field)) return false; for(std::vector::const_iterator i = groups.begin(); i != groups.end(); ++i) { boost::any n = &((*config).*field); if(!(*i)->fromMessage(msg, n)) return false; } return true; } virtual void setInitialState(boost::any &cfg) const override { PT* config = boost::any_cast(cfg); T* group = &((*config).*field); group->state = state; for(std::vector::const_iterator i = groups.begin(); i != groups.end(); ++i) { boost::any n = boost::any(&((*config).*field)); (*i)->setInitialState(n); } } virtual void updateParams(boost::any &cfg, ${configname}Config &top) const override { PT* config = boost::any_cast(cfg); T* f = &((*config).*field); f->setParams(top, abstract_parameters); for(std::vector::const_iterator i = groups.begin(); i != groups.end(); ++i) { boost::any n = &((*config).*field); (*i)->updateParams(n, top); } } virtual void toMessage(dynamic_reconfigure::Config &msg, const boost::any &cfg) const override { const PT config = boost::any_cast(cfg); dynamic_reconfigure::ConfigTools::appendGroup(msg, name, id, parent, config.*field); for(std::vector::const_iterator i = groups.begin(); i != groups.end(); ++i) { (*i)->toMessage(msg, config.*field); } } T PT::* field; std::vector<${configname}Config::AbstractGroupDescriptionConstPtr> groups; }; ${groups} ${members} ${doline} ${linenum} "${filename}" bool __fromMessage__(dynamic_reconfigure::Config &msg) { const std::vector &__param_descriptions__ = __getParamDescriptions__(); const std::vector &__group_descriptions__ = __getGroupDescriptions__(); int count = 0; for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) if ((*i)->fromMessage(msg, *this)) count++; for (std::vector::const_iterator i = __group_descriptions__.begin(); i != __group_descriptions__.end(); i ++) { if ((*i)->id == 0) { boost::any n = boost::any(this); (*i)->updateParams(n, *this); (*i)->fromMessage(msg, n); } } if (count != dynamic_reconfigure::ConfigTools::size(msg)) { ROS_ERROR("${configname}Config::__fromMessage__ called with an unexpected parameter."); ROS_ERROR("Booleans:"); for (unsigned int i = 0; i < msg.bools.size(); i++) ROS_ERROR(" %s", msg.bools[i].name.c_str()); ROS_ERROR("Integers:"); for (unsigned int i = 0; i < msg.ints.size(); i++) ROS_ERROR(" %s", msg.ints[i].name.c_str()); ROS_ERROR("Doubles:"); for (unsigned int i = 0; i < msg.doubles.size(); i++) ROS_ERROR(" %s", msg.doubles[i].name.c_str()); ROS_ERROR("Strings:"); for (unsigned int i = 0; i < msg.strs.size(); i++) ROS_ERROR(" %s", msg.strs[i].name.c_str()); // @todo Check that there are no duplicates. Make this error more // explicit. return false; } return true; } // This version of __toMessage__ is used during initialization of // statics when __getParamDescriptions__ can't be called yet. void __toMessage__(dynamic_reconfigure::Config &msg, const std::vector &__param_descriptions__, const std::vector &__group_descriptions__) const { dynamic_reconfigure::ConfigTools::clear(msg); for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) (*i)->toMessage(msg, *this); for (std::vector::const_iterator i = __group_descriptions__.begin(); i != __group_descriptions__.end(); ++i) { if((*i)->id == 0) { (*i)->toMessage(msg, *this); } } } void __toMessage__(dynamic_reconfigure::Config &msg) const { const std::vector &__param_descriptions__ = __getParamDescriptions__(); const std::vector &__group_descriptions__ = __getGroupDescriptions__(); __toMessage__(msg, __param_descriptions__, __group_descriptions__); } void __toServer__(const ros::NodeHandle &nh) const { const std::vector &__param_descriptions__ = __getParamDescriptions__(); for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) (*i)->toServer(nh, *this); } void __fromServer__(const ros::NodeHandle &nh) { static bool setup=false; const std::vector &__param_descriptions__ = __getParamDescriptions__(); for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) (*i)->fromServer(nh, *this); const std::vector &__group_descriptions__ = __getGroupDescriptions__(); for (std::vector::const_iterator i = __group_descriptions__.begin(); i != __group_descriptions__.end(); i++){ if (!setup && (*i)->id == 0) { setup = true; boost::any n = boost::any(this); (*i)->setInitialState(n); } } } void __clamp__() { const std::vector &__param_descriptions__ = __getParamDescriptions__(); const ${configname}Config &__max__ = __getMax__(); const ${configname}Config &__min__ = __getMin__(); for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) (*i)->clamp(*this, __max__, __min__); } uint32_t __level__(const ${configname}Config &config) const { const std::vector &__param_descriptions__ = __getParamDescriptions__(); uint32_t level = 0; for (std::vector::const_iterator i = __param_descriptions__.begin(); i != __param_descriptions__.end(); ++i) (*i)->calcLevel(level, config, *this); return level; } static const dynamic_reconfigure::ConfigDescription &__getDescriptionMessage__(); static const ${configname}Config &__getDefault__(); static const ${configname}Config &__getMax__(); static const ${configname}Config &__getMin__(); static const std::vector &__getParamDescriptions__(); static const std::vector &__getGroupDescriptions__(); private: static const ${configname}ConfigStatics *__get_statics__(); }; template <> // Max and min are ignored for strings. inline void ${configname}Config::ParamDescription::clamp(${configname}Config &config, const ${configname}Config &max, const ${configname}Config &min) const { (void) config; (void) min; (void) max; return; } class ${configname}ConfigStatics { friend class ${configname}Config; ${configname}ConfigStatics() { ${paramdescr} ${doline} ${linenum} "${filename}" for (std::vector<${configname}Config::AbstractGroupDescriptionConstPtr>::const_iterator i = __group_descriptions__.begin(); i != __group_descriptions__.end(); ++i) { __description_message__.groups.push_back(**i); } __max__.__toMessage__(__description_message__.max, __param_descriptions__, __group_descriptions__); __min__.__toMessage__(__description_message__.min, __param_descriptions__, __group_descriptions__); __default__.__toMessage__(__description_message__.dflt, __param_descriptions__, __group_descriptions__); } std::vector<${configname}Config::AbstractParamDescriptionConstPtr> __param_descriptions__; std::vector<${configname}Config::AbstractGroupDescriptionConstPtr> __group_descriptions__; ${configname}Config __max__; ${configname}Config __min__; ${configname}Config __default__; dynamic_reconfigure::ConfigDescription __description_message__; static const ${configname}ConfigStatics *get_instance() { // Split this off in a separate function because I know that // instance will get initialized the first time get_instance is // called, and I am guaranteeing that get_instance gets called at // most once. static ${configname}ConfigStatics instance; return &instance; } }; inline const dynamic_reconfigure::ConfigDescription &${configname}Config::__getDescriptionMessage__() { return __get_statics__()->__description_message__; } inline const ${configname}Config &${configname}Config::__getDefault__() { return __get_statics__()->__default__; } inline const ${configname}Config &${configname}Config::__getMax__() { return __get_statics__()->__max__; } inline const ${configname}Config &${configname}Config::__getMin__() { return __get_statics__()->__min__; } inline const std::vector<${configname}Config::AbstractParamDescriptionConstPtr> &${configname}Config::__getParamDescriptions__() { return __get_statics__()->__param_descriptions__; } inline const std::vector<${configname}Config::AbstractGroupDescriptionConstPtr> &${configname}Config::__getGroupDescriptions__() { return __get_statics__()->__group_descriptions__; } inline const ${configname}ConfigStatics *${configname}Config::__get_statics__() { const static ${configname}ConfigStatics *statics; if (statics) // Common case return statics; boost::mutex::scoped_lock lock(dynamic_reconfigure::__init_mutex__); if (statics) // In case we lost a race. return statics; statics = ${configname}ConfigStatics::get_instance(); return statics; } ${constants} } #undef DYNAMIC_RECONFIGURE_FINAL #endif // __${uname}RECONFIGURATOR_H__ dynamic_reconfigure-1.7.2/templates/ConfigType.py.template000066400000000000000000000016131420405362400237670ustar00rootroot00000000000000## ********************************************************* ## ## File autogenerated for the ${pkgname} package ## by the dynamic_reconfigure package. ## Please do not edit. ## ## ********************************************************/ from dynamic_reconfigure.encoding import extract_params inf = float('inf') config_description = ${pycfgdata} min = {} max = {} defaults = {} level = {} type = {} all_level = 0 #def extract_params(config): # params = [] # params.extend(config['parameters']) # for group in config['groups']: # params.extend(extract_params(group)) # return params for param in extract_params(config_description): min[param['name']] = param['min'] max[param['name']] = param['max'] defaults[param['name']] = param['default'] level[param['name']] = param['level'] type[param['name']] = param['type'] all_level = all_level | param['level'] dynamic_reconfigure-1.7.2/templates/GroupClass.h.template000066400000000000000000000010001420405362400235670ustar00rootroot00000000000000class ${upper} { public: ${upper}() { state = true; name = "${name}"; } void setParams(${configname}Config &config, const std::vector params) { for (std::vector::const_iterator _i = params.begin(); _i != params.end(); ++_i) { boost::any val; (*_i)->getValue(config, val); ${setters} } } ${params} bool state; std::string name; ${subgroups} }${lower}; dynamic_reconfigure-1.7.2/test/000077500000000000000000000000001420405362400165145ustar00rootroot00000000000000dynamic_reconfigure-1.7.2/test/CMakeLists.txt000066400000000000000000000024051420405362400212550ustar00rootroot00000000000000add_rostest_gtest(dynamic_reconfigure-test_client_single_threaded test_cpp_client_single_threaded.test test_client_single_threaded.cpp) add_dependencies(dynamic_reconfigure-test_client_single_threaded ${PROJECT_NAME}_gencfg ${PROJECT_NAME}_generate_messages_cpp) target_link_libraries(dynamic_reconfigure-test_client_single_threaded dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES}) add_dependencies(tests dynamic_reconfigure-test_client_single_threaded) add_executable(dynamic_reconfigure-ref_server EXCLUDE_FROM_ALL ref_server.cpp) add_dependencies(dynamic_reconfigure-ref_server ${PROJECT_NAME}_gencfg ${PROJECT_NAME}_generate_messages_cpp ${PROJECT_NAME}_generate_messages_py) target_link_libraries(dynamic_reconfigure-ref_server dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES}) add_dependencies(tests dynamic_reconfigure-ref_server) add_rostest_gtest(dynamic_reconfigure-test_client test_cpp_simple_client.launch test_client.cpp) add_dependencies(dynamic_reconfigure-test_client ${PROJECT_NAME}_gencfg ${PROJECT_NAME}_generate_messages_py) target_link_libraries(dynamic_reconfigure-test_client dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES}) add_dependencies(tests dynamic_reconfigure-test_client) add_rostest(test_python_simple_client.launch) dynamic_reconfigure-1.7.2/test/ref_server.cpp000066400000000000000000000047051420405362400213700ustar00rootroot00000000000000/* * Copyright (c) 2014, Open Source Robotics Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Open Source Robotics Foundation, Inc. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include void callback(dynamic_reconfigure_test::TestConfig &config, uint32_t level) { ROS_INFO("Reconfigure request: %i %f %s %s %i %i Group1: %i Group2: %f %s", config.int_, config.double_, config.str_.c_str(), config.mstr_.c_str(), (int) config.bool_, config.level, config.group1_int, config.group2_double, config.group2_string.c_str()); } int main(int argc, char **argv) { ros::init(argc, argv, "dynamic_reconfigure_test"); dynamic_reconfigure::Server server; dynamic_reconfigure::Server::CallbackType f; f = boost::bind(&callback, _1, _2); server.setCallback(f); ROS_INFO("Spinning node"); ros::spin(); return 0; } dynamic_reconfigure-1.7.2/test/simple_python_client_test.py000077500000000000000000000106211420405362400243600ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Software License Agreement (BSD License) # # Copyright (c) 2014, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import unittest import rospy import dynamic_reconfigure.client class TestSimpleDynamicReconfigureClient(unittest.TestCase): def testsimple(self): client = dynamic_reconfigure.client.Client("ref_server", timeout=5) config = client.get_configuration(timeout=5) self.assertEqual(0, config['int_']) self.assertEqual(0.0, config['double_']) self.assertEqual('foo', config['str_']) self.assertEqual(False, config['bool_']) self.assertEqual(1.0, config['double_no_minmax']) self.assertEqual(2.0, config['double_no_max']) self.assertEqual(-1.0, config['deep_var_double']) int_ = 7 double_ = 0.75 str_ = 'bar' bool_ = True double_no_max_ = 1e+300 double_no_minmax_ = -1e+300 client.update_configuration( {"int_": int_, "double_": double_, "str_": str_, "bool_": bool_, "double_no_max": double_no_max_, "double_no_minmax": double_no_minmax_} ) rospy.sleep(1.0) config = client.get_configuration(timeout=5) self.assertEqual(int_, config['int_']) self.assertEqual(double_, config['double_']) self.assertEqual(str_, config['str_']) self.assertEqual(type(str_), type(config['str_'])) self.assertEqual(bool_, config['bool_']) self.assertEqual(double_no_max_, config['double_no_max']) self.assertEqual(double_no_minmax_, config['double_no_minmax']) def testmultibytestring(self): client = dynamic_reconfigure.client.Client("ref_server", timeout=5) config = client.get_configuration(timeout=5) self.assertEqual('bar', config['mstr_']) # Kanji for konnichi wa (hello) str_ = u"今日は" client.update_configuration( {"mstr_": str_} ) rospy.sleep(1.0) config = client.get_configuration(timeout=5) self.assertEqual(u"今日は", config['mstr_']) self.assertEqual(type(u"今日は"), type(config['mstr_'])) self.assertEqual(u"今日は", rospy.get_param('/ref_server/mstr_')) # Hiragana for konnichi wa (hello) str_ = u"こんにちは" client.update_configuration( {"mstr_": str_} ) rospy.sleep(1.0) config = client.get_configuration(timeout=5) self.assertEqual(u"こんにちは", config['mstr_']) self.assertEqual(type(u"こんにちは"), type(config['mstr_'])) self.assertEqual(u"こんにちは", rospy.get_param('/ref_server/mstr_')) if __name__ == "__main__": import rostest rospy.init_node('simple_python_client_test') rostest.rosrun('dynamic_reconfigure', 'test_simple_dynamic_reconfigure_client_python', TestSimpleDynamicReconfigureClient) dynamic_reconfigure-1.7.2/test/test_client.cpp000066400000000000000000000125711420405362400215430ustar00rootroot00000000000000/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2015-2016, Myrmex, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Willow Garage nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ /** Author: Aris Synodinos Handles sychronizing node state with the ActionServer and setting/getting configuration. */ #include #include #include #include using namespace dynamic_reconfigure; using namespace dynamic_reconfigure_test; TestConfig CONFIG; ConfigDescription DESCRIPTION; void configurationCallback(const TestConfig& config) { ROS_INFO( "Reconfiguration happened: %i %f %s %s %i %i Group1: %i Group2: %f %s", config.int_, config.double_, config.str_.c_str(), config.mstr_.c_str(), (int)config.bool_, config.level, config.group1_int, config.group2_double, config.group2_string.c_str()); CONFIG = config; } void descriptionCallback(const ConfigDescription& description) { ROS_INFO("Received description"); } TEST(dynamic_reconfigure_simple_client, Constructor) { Client client("/ref_server"); client.setConfigurationCallback(&configurationCallback); client.setDescriptionCallback(&descriptionCallback); } TEST(dynamic_reconfigure_simple_client, getConfigs) { Client client("/ref_server", &configurationCallback, &descriptionCallback); EXPECT_TRUE(client.getCurrentConfiguration(CONFIG)); EXPECT_TRUE(client.getDefaultConfiguration(CONFIG)); EXPECT_EQ(0, CONFIG.int_); EXPECT_TRUE(client.getMinConfiguration(CONFIG)); EXPECT_EQ(-10, CONFIG.int_); EXPECT_TRUE(client.getMaxConfiguration(CONFIG)); EXPECT_EQ(10, CONFIG.int_); } TEST(dynamic_reconfigure_simple_client, setConfig) { ROS_INFO("Setting configuration"); Client client("/ref_server", &configurationCallback, &descriptionCallback); TestConfig cfg = TestConfig::__getMax__(); EXPECT_TRUE(client.setConfiguration(cfg)); // int_ goes from -10 to +10 cfg.int_ = -11; EXPECT_TRUE(client.setConfiguration(cfg)); EXPECT_EQ(-10, cfg.int_); cfg.int_ = 11; EXPECT_TRUE(client.setConfiguration(cfg)); EXPECT_EQ(10, cfg.int_); } TEST(dynamic_reconfigure_simple_client, setGetConfig) { ROS_INFO("Setting configuration"); Client client("/ref_server", &configurationCallback, &descriptionCallback); TestConfig cfg = TestConfig::__getMax__(); EXPECT_TRUE(client.setConfiguration(cfg)); // int_ goes from -10 to +10 cfg.int_ = -11; EXPECT_TRUE(client.setConfiguration(cfg)); EXPECT_EQ(-10, cfg.int_); EXPECT_TRUE(client.getCurrentConfiguration(CONFIG)); EXPECT_EQ(-10, CONFIG.int_); cfg.int_ = 11; EXPECT_TRUE(client.setConfiguration(cfg)); EXPECT_TRUE(client.getCurrentConfiguration(CONFIG)); EXPECT_EQ(10, CONFIG.int_); cfg.int_ = 5; EXPECT_TRUE(client.setConfiguration(cfg)); EXPECT_TRUE(client.getCurrentConfiguration(CONFIG)); EXPECT_EQ(5, CONFIG.int_); } TEST(dynamic_reconfigure_simple_client, multipleClients) { Client client1("/ref_server", &configurationCallback); Client client2("/ref_server", &configurationCallback); Client client3("/ref_server", &configurationCallback); client3.setConfiguration(TestConfig::__getDefault__()); ros::Duration(0.2).sleep(); EXPECT_EQ(0, CONFIG.int_); client1.setConfiguration(TestConfig::__getMin__()); ros::Duration(0.2).sleep(); EXPECT_EQ(-10, CONFIG.int_); client2.setConfiguration(TestConfig::__getMax__()); ros::Duration(0.2).sleep(); EXPECT_EQ(10, CONFIG.int_); } int main(int argc, char** argv) { ros::init(argc, argv, "dynamic_reconfigure_client_test"); testing::InitGoogleTest(&argc, argv); ros::AsyncSpinner spinner(2); spinner.start(); int res = RUN_ALL_TESTS(); ros::shutdown(); return res; } dynamic_reconfigure-1.7.2/test/test_client_single_threaded.cpp000066400000000000000000000012401420405362400247330ustar00rootroot00000000000000#include #include #include #include using namespace dynamic_reconfigure_test; using namespace dynamic_reconfigure; TestConfig CONFIG; TEST(dynamic_reconfigure_client_single_thread, singleThreadedSetGet) { Client client("/ref_server"); CONFIG = TestConfig::__getDefault__(); EXPECT_TRUE(client.setConfiguration(CONFIG)); EXPECT_TRUE(client.getCurrentConfiguration(CONFIG)); } int main(int argc, char** argv) { ros::init(argc, argv, "dynamic_reconfigure_single_threaded_client_test"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } dynamic_reconfigure-1.7.2/test/test_cpp.xml000066400000000000000000000000231420405362400210520ustar00rootroot00000000000000 dynamic_reconfigure-1.7.2/test/test_cpp_client_single_threaded.test000066400000000000000000000004511420405362400257750ustar00rootroot00000000000000 dynamic_reconfigure-1.7.2/test/test_cpp_simple_client.launch000066400000000000000000000003601420405362400244370ustar00rootroot00000000000000 dynamic_reconfigure-1.7.2/test/test_python_simple_client.launch000066400000000000000000000003601420405362400251760ustar00rootroot00000000000000 dynamic_reconfigure-1.7.2/test/testclient.py000077500000000000000000000117321420405362400212530ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2009, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import roslib; roslib.load_manifest('dynamic_reconfigure') import rospy from dynamic_reconfigure.client import Client as DynamicReconfigureClient import time # This example assumes that testserver in dynamic_reconfigure is running # with its default node name, and will show how to reconfigure it from # python. # # Note that testserver often changes the parameters it is given, so the # values you get back from it will often be different from the ones you # requested. Look at test/testserver.cpp to understand the changes that are # being made to the parameters. # # In one window do: # rosrun dynamic_reconfigure testserver # # In another window do: # rosrun dynamic_reconfigure testclient.py def print_config(config): for k, v in config.items(): print(k, ":", v) print('') # The config_callback (introduced below) receives a dictionary containing # the current configuration of the server each time the server's # configuration changes. def config_callback(config): print("Got callback, configuration is: ") print_config(config) def new_config_callback(config): global old_callback print("New callback is calling old callback...") old_callback(config) print("New callback is done...") print('') # First you need to connect to the server. You can optionally specify a # timeout and a config_callback that is called each time the server's # configuration changes. If you do not indicate a timeout, the client is # willing to wait forever for the server to be available. # # Note that the config_callback could get called before the constructor # returns. rospy.init_node('testclient_py', anonymous=True) client = DynamicReconfigureClient('/dynamic_reconfigure_test_server', config_callback=config_callback, timeout=5) time.sleep(1) # You can also get the configuration manually by calling get_configuration. print("Configuration from get_configuration:") print_config(client.get_configuration(timeout=5)) time.sleep(1) # You can push changes to the server using the update_configuration method. # You can set any subset of the node's parameters using this method. It # returns out the full new configuration of the server (which may differ # from what you requested if you asked for something illegal). print("Configuration after setting int_ to 4:") print_config(client.update_configuration({'int_': 4})) time.sleep(1) print("Configuration after setting int_ to 0 and bool_ to True:") print_config(client.update_configuration({'int_': 0, 'bool_': True})) time.sleep(1) # You can access constants defined in Test.cfg file in the following way: import dynamic_reconfigure.cfg.TestConfig as Config print("Medium is a constant that is set to 1:", Config.Test_Medium) # This is useful for setting enums: print("Configuration after setting int_enum_ to Medium:") print_config(client.update_configuration({'int_enum_': Config.Test_Medium})) time.sleep(1) # You can use the get_config_callback and set_config_callback methods to # get the current callback or change the callback. It is sometimes useful # not to set the callback in the constructor, but to wait until more # initialization has been done first. Again, the callback will be called # immediately if a configuration is available. old_callback = client.get_config_callback() client.set_config_callback(new_config_callback) time.sleep(1) # When you are done, you can close the client. client.close() dynamic_reconfigure-1.7.2/test/testserver.cpp000066400000000000000000000065231420405362400214340ustar00rootroot00000000000000/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2009-2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Willow Garage nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ #include #include void callback(dynamic_reconfigure::Server& srv, dynamic_reconfigure::TestConfig &config, uint32_t level) { ROS_INFO("Reconfigure request : %i %f %s %i %i Group1:%i Group2: %f %s", config.int_, config.double_, config.str_.c_str(), (int) config.bool_, config.level, config.group1_int, config.group2_double, config.group2_string.c_str()); config.int_ |= 1; config.double_ = -config.double_; config.str_ += "A"; config.bool_ = !config.bool_; config.level = level; dynamic_reconfigure::TestConfig max; srv.getConfigMax(max); max.int_ = max.int_ + 1; srv.setConfigMax(max); ROS_INFO("TEST"); ROS_INFO("Group 2 requested to be set to %d", config.groups.group_one.group2.state); ROS_INFO("group2_doube requested to be set to %f", config.groups.group_one.group2.group2_double); ROS_INFO("Reconfigured to : %i %f %s %i %i", config.int_, config.double_, config.str_.c_str(), (int) config.bool_, config.level); } int main(int argc, char **argv) { ros::init(argc, argv, "dynamic_reconfigure_test_server"); dynamic_reconfigure::Server srvs; dynamic_reconfigure::Server::CallbackType f = boost::bind(&callback, boost::ref(srvs),_1, _2); srvs.setCallback(f); ROS_INFO("Constants are: %i %f %s %i", dynamic_reconfigure::Test_int_const, dynamic_reconfigure::Test_double_const, dynamic_reconfigure::Test_str_const, (int) dynamic_reconfigure::Test_bool_const); ROS_INFO("Starting to spin..."); ros::spin(); return 0; } dynamic_reconfigure-1.7.2/test/testserver.py000077500000000000000000000053421420405362400213030ustar00rootroot00000000000000#! /usr/bin/env python #********************************************************************* # Software License Agreement (BSD License) # # Copyright (c) 2009-2010, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of the Willow Garage nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #********************************************************************/ from __future__ import print_function import roslib; roslib.load_manifest('dynamic_reconfigure') import rospy import dynamic_reconfigure.server from dynamic_reconfigure.cfg import TestConfig import time def main(): rospy.init_node("python_test_server") dynamic_reconfigure.server.Server(TestConfig, reconfigure) while not rospy.is_shutdown(): time.sleep(0.1) def reconfigure(config, level): print(config) rospy.loginfo("Reconfigure request : %i %f %s %s %i" % (config['int_'], config['double_'], config['str_'], config['bool_'], config['level'])) config['int_'] |= 1 config['double_'] = -config['double_'] config['str_'] += "A" config['bool_'] = not config['bool_'] config['level'] = level rospy.loginfo("Reconfigured to : %i %f %s %s %i" % (config['int_'], config['double_'], config['str_'], config['bool_'], config['level'])) return config # Returns the updated configuration. if __name__ == '__main__': main() dynamic_reconfigure-1.7.2/test/testserver2.cpp000066400000000000000000000035501420405362400215130ustar00rootroot00000000000000/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2009-2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Willow Garage nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ // This is here to confirm that including from multiple source files works. #include dynamic_reconfigure-1.7.2/test/testserver_multiple_ns.py000077500000000000000000000070411420405362400237140ustar00rootroot00000000000000#! /usr/bin/env python #********************************************************************* # Software License Agreement (BSD License) # # Copyright (c) 2009-2010, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of the Willow Garage nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #********************************************************************/ from __future__ import print_function import roslib; roslib.load_manifest('dynamic_reconfigure') import rospy import dynamic_reconfigure.server from dynamic_reconfigure.cfg import TestConfig import time def main(): rospy.init_node("python_test_multiple_ns_server") dynamic_reconfigure.server.Server(TestConfig, reconfigure) dynamic_reconfigure.server.Server(TestConfig, reconfigure_alternate_ns, "~alternate_ns") dynamic_reconfigure.server.Server(TestConfig, reconfigure_2lvls_ns, "~alternate_ns/second_lvl") dynamic_reconfigure.server.Server(TestConfig, reconfigure_absolute_ns, "/absolute_ns") while not rospy.is_shutdown(): time.sleep(0.1) def reconfigure(config, level): print(config) config['int_'] |= 1 config['double_'] = -config['double_'] config['str_'] += "A" config['bool_'] = not config['bool_'] config['level'] = level rospy.loginfo("Reconfigured to : %i %f %s %s %i" % (config['int_'], config['double_'], config['str_'], config['bool_'], config['level'])) return config # Returns the updated configuration. def reconfigure_default(config, level): rospy.loginfo("Reconfigure request on default ns") return reconfigure(config, level) def reconfigure_alternate_ns(config, level): rospy.loginfo("Reconfigure request on alternate_ns") return reconfigure(config, level) def reconfigure_2lvls_ns(config, level): rospy.loginfo("Reconfigure request on alternate_ns/second_lvl") return reconfigure(config, level) def reconfigure_absolute_ns(config, level): rospy.loginfo("Reconfigure request on /absolute_ns") return reconfigure(config, level) if __name__ == '__main__': main()