pax_global_header00006660000000000000000000000064125176450510014520gustar00rootroot0000000000000052 comment=6af0e63efb6111cdd611813e71a1044719ee1933 ros-dynamic-reconfigure-1.5.39/000077500000000000000000000000001251764505100163525ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/.gitignore000066400000000000000000000000151251764505100203360ustar00rootroot00000000000000*.pyc build/ ros-dynamic-reconfigure-1.5.39/.hgignore000066400000000000000000000000051251764505100201500ustar00rootroot00000000000000.pyc ros-dynamic-reconfigure-1.5.39/.hgtags000066400000000000000000000136751251764505100176440ustar00rootroot000000000000008ee968b00d67d5fef281c2a5e4f57115c8061d78 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 ros-dynamic-reconfigure-1.5.39/CHANGELOG.rst000066400000000000000000000021661251764505100204000ustar00rootroot00000000000000^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Changelog for package dynamic_reconfigure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 ros-dynamic-reconfigure-1.5.39/CMakeLists.txt000066400000000000000000000042761251764505100211230ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) project(dynamic_reconfigure) find_package(catkin REQUIRED COMPONENTS message_generation roscpp std_msgs) find_package(Boost REQUIRED COMPONENTS system thread) include_directories(include ${catkin_INCLUDE_DIRS}) include_directories(SYSTEM ${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(PROGRAMS scripts/dynparam DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) install(PROGRAMS scripts/reconfigure_gui DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) install(DIRECTORY srv DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) install(DIRECTORY templates DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) ros-dynamic-reconfigure-1.5.39/cfg/000077500000000000000000000000001251764505100171115ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/cfg/Test.cfg000077500000000000000000000071551251764505100205240ustar00rootroot00000000000000#! /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. 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("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) 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")) ros-dynamic-reconfigure-1.5.39/cmake/000077500000000000000000000000001251764505100174325ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/cmake/cfgbuild.cmake000066400000000000000000000100101251764505100222030ustar00rootroot00000000000000# 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() ros-dynamic-reconfigure-1.5.39/cmake/dynamic_reconfigure-extras.cmake.em000066400000000000000000000004551251764505100263600ustar00rootroot00000000000000@[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) ros-dynamic-reconfigure-1.5.39/cmake/dynamic_reconfigure-macros.cmake000066400000000000000000000112341251764505100257330ustar00rootroot00000000000000macro(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) assert(CATKIN_ENV) set(_cmd ${CATKIN_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 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() ros-dynamic-reconfigure-1.5.39/cmake/dynamic_reconfigure/000077500000000000000000000000001251764505100234465ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/cmake/dynamic_reconfigure/__init__.py000066400000000000000000000000001251764505100255450ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/cmake/dynamic_reconfigure/parameter_generator.py000066400000000000000000000034721251764505100300540ustar00rootroot00000000000000#! /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 ros-dynamic-reconfigure-1.5.39/cmake/gendeps000077500000000000000000000061001251764505100210020ustar00rootroot00000000000000#! /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 ros-dynamic-reconfigure-1.5.39/epydoc.config000066400000000000000000000004261251764505100210260ustar00rootroot00000000000000[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 ros-dynamic-reconfigure-1.5.39/include/000077500000000000000000000000001251764505100177755ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/include/dynamic_reconfigure/000077500000000000000000000000001251764505100240115ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/include/dynamic_reconfigure/config_init_mutex.h000066400000000000000000000003361251764505100276760ustar00rootroot00000000000000#ifndef __DYNAMIC_RECONFIGURE__CONFIG_INIT_MUTEX_H__ #define __DYNAMIC_RECONFIGURE__CONFIG_INIT_MUTEX_H__ #include namespace dynamic_reconfigure { extern boost::mutex __init_mutex__; } #endif ros-dynamic-reconfigure-1.5.39/include/dynamic_reconfigure/config_tools.h000066400000000000000000000102441251764505100266500ustar00rootroot00000000000000#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 ros-dynamic-reconfigure-1.5.39/include/dynamic_reconfigure/server.h000066400000000000000000000165131251764505100254760ustar00rootroot00000000000000/********************************************************************* * 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 ros-dynamic-reconfigure-1.5.39/msg/000077500000000000000000000000001251764505100171405ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/msg/BoolParameter.msg000066400000000000000000000000271251764505100224030ustar00rootroot00000000000000string name bool value ros-dynamic-reconfigure-1.5.39/msg/Config.msg000066400000000000000000000001541251764505100210550ustar00rootroot00000000000000BoolParameter[] bools IntParameter[] ints StrParameter[] strs DoubleParameter[] doubles GroupState[] groups ros-dynamic-reconfigure-1.5.39/msg/ConfigDescription.msg000066400000000000000000000000611251764505100232560ustar00rootroot00000000000000Group[] groups Config max Config min Config dflt ros-dynamic-reconfigure-1.5.39/msg/DoubleParameter.msg000066400000000000000000000000321251764505100227160ustar00rootroot00000000000000string name float64 value ros-dynamic-reconfigure-1.5.39/msg/Group.msg000066400000000000000000000001151251764505100207410ustar00rootroot00000000000000string name string type ParamDescription[] parameters int32 parent int32 id ros-dynamic-reconfigure-1.5.39/msg/GroupState.msg000066400000000000000000000000551251764505100217450ustar00rootroot00000000000000string name bool state int32 id int32 parent ros-dynamic-reconfigure-1.5.39/msg/IntParameter.msg000066400000000000000000000000301251764505100222340ustar00rootroot00000000000000string name int32 value ros-dynamic-reconfigure-1.5.39/msg/ParamDescription.msg000066400000000000000000000001131251764505100231070ustar00rootroot00000000000000string name string type uint32 level string description string edit_method ros-dynamic-reconfigure-1.5.39/msg/SensorLevels.msg000066400000000000000000000005421251764505100222750ustar00rootroot00000000000000# 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 ros-dynamic-reconfigure-1.5.39/msg/StrParameter.msg000066400000000000000000000000311251764505100222530ustar00rootroot00000000000000string name string value ros-dynamic-reconfigure-1.5.39/package.xml000066400000000000000000000021231251764505100204650ustar00rootroot00000000000000 dynamic_reconfigure 1.5.39 This unary stack contains the dynamic_reconfigure package which provides a means to change node parameters at any time without having to restart the node. Esteve Fernandez BSD http://ros.org/wiki/dynamic_reconfigure Blaise Gassend catkin boost message_generation roscpp roscpp_serialization rostest std_msgs boost message_runtime roscpp roslib rospy rosservice std_msgs ros-dynamic-reconfigure-1.5.39/rosdoc.yaml000066400000000000000000000000541251764505100205260ustar00rootroot00000000000000 - builder: epydoc config: epydoc.config ros-dynamic-reconfigure-1.5.39/scripts/000077500000000000000000000000001251764505100200415ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/scripts/dynparam000077500000000000000000000205741251764505100216120ustar00rootroot00000000000000#! /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$ 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 >> sys.stderr, 'error updating parameters: no parameters found on parameter server' 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 = file(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 = file(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, 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 ros-dynamic-reconfigure-1.5.39/scripts/reconfigure_gui000077500000000000000000000035741251764505100231540ustar00rootroot00000000000000#! /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. # if __name__ == '__main__': print '\033[91m' + "reconfigure_gui has moved!\n" + '\033[0m' print " Try: " + '\033[92m' + "rosrun rqt_reconfigure rqt_reconfigure\n" + '\033[0m' print " If you see this as part of a tutorial or a script, please update to reflect this change." ros-dynamic-reconfigure-1.5.39/setup.py000066400000000000000000000004241251764505100200640ustar00rootroot00000000000000#!/usr/bin/env python from distutils.core 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) ros-dynamic-reconfigure-1.5.39/src/000077500000000000000000000000001251764505100171415ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/000077500000000000000000000000001251764505100231555ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/__init__.py000066400000000000000000000045051251764505100252720ustar00rootroot00000000000000# 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 import os 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() ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/client.py000066400000000000000000000323701251764505100250120ustar00rootroot00000000000000# 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: pass import rospy import rosservice import sys import threading import time import types from dynamic_reconfigure import DynamicReconfigureParameterException from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv from dynamic_reconfigure.msg import Config as ConfigMsg from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg from dynamic_reconfigure.msg import IntParameter, BoolParameter, StrParameter, DoubleParameter, ParamDescription from dynamic_reconfigure.encoding import * 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 >> sys.stderr, 'Waiting for configuration...' 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 not name is '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) msg = self._set_service(config).config 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() groups = [] 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._config_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 >> sys.stderr, 'Waiting for service %s...' % service_name 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) ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/encoding.py000066400000000000000000000243071251764505100253230ustar00rootroot00000000000000# 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: pass import rospy import inspect import copy import sys 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 from dynamic_reconfigure.msg import IntParameter, BoolParameter, StrParameter, DoubleParameter, ParamDescription class Config(dict): def __init__(self, *args, **kwargs): dict.__init__(self, *args, **kwargs) def __getstate__(self): return 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.iteritems(): 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 type(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 ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/parameter_generator.py000066400000000000000000000617101251764505100275620ustar00rootroot00000000000000# 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 import roslib; roslib.load_manifest("dynamic_reconfigure") import roslib.packages from string import Template import os import inspect import string 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 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 != None or min != None): raise Exception("Max or min specified for %s, which is of string type"%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) 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(string.lower(x)) else: ret.append(string.upper(x)) return string.join(ret, "::") def get_class(self, parent = False): cls = [] cls.extend(self.get_parents()) cls = [string.upper(x) for x in cls] if parent == True: cls.pop() return string.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': string.upper(self.name), 'lower': string.lower(name) } 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 == 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 } 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!") 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, 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 >> f, \ """# 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.""" 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 >> f, Template( """$i.name= ~$name $i.default= $default $i.type= $type $i.desc=$description $range""" ).substitute(param, range = range, i = i) print >> f,"}\n}\n# End of autogenerated section. You may edit below." f.close() def generateusage(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname+"-usage.dox"), 'w') #print >> f, "/**" print >> f, "\\subsubsection usage Usage" print >> f, '\\verbatim' print >> f, Template('').\ substitute(pkgname = self.pkgname, nodename = self.nodename) for param in self.group.get_parameters(): print >> f, Template(' ').substitute(param) print >> f, '' print >> f, '\\endverbatim' print >> f #print >> f, "*/" f.close() def generatedoc(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname+".dox"), 'w') #print >> f, "/**" print >> f, "\\subsubsection parameters ROS parameters" print >> f print >> f, "Reads and maintains the following parameters on the ROS server" print >> f for param in self.group.get_parameters(): print >> f, Template("- \\b \"~$name\" : \\b [$type] $description min: $min, default: $default, max: $max").substitute(param) print >> f #print >> f, "*/" f.close() def generateusage(self): self.mkdir("docs") f = open(os.path.join(self.pkgpath, "docs", self.msgname+"-usage.dox"), 'w') #print >> f, "/**" print >> f, "\\subsubsection usage Usage" print >> f, '\\verbatim' print >> f, Template('').\ substitute(pkgname = self.pkgname, nodename = self.nodename) for param in self.group.get_parameters(): print >> f, Template(' ').substitute(param) print >> f, '' print >> f, '\\endverbatim' print >> f #print >> 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 == 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 = string.join(subgroups, "\n") setters = string.join(setters, "\n") params = string.join(params, "\n") 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 = string.join(paramdescr, '\n') members = string.join(members, '\n') groups = string.join(groups, '\n') constants = string.join(constants, '\n') 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 >> f, "# This is an autogerenated file. Please do not edit." # print >> f, "" # for param in self.parameters: # print >> f, Template("$type $name # $description").substitute(param, type=self.msgtype(param['type'])) # f.close() # # def generategetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Get"+self.msgname+".srv"), 'w') # print >> f, "# This is an autogerenated file. Please do not edit." # print >> f, "" # print >> f, "---" # print >> f, self.msgname, "config", "# Current configuration of node." # print >> f, self.msgname, "defaults", "# Minimum values where appropriate." # print >> f, self.msgname, "min", "# Minimum values where appropriate." # print >> f, self.msgname, "max", "# Maximum values where appropriate." # f.close() # # def generatesetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Set"+self.msgname+".srv"), 'w') # print >> f, "# This is an autogerenated file. Please do not edit." # print >> f, self.msgname, "config", "# Requested node configuration." # print >> f, "---" # print >> f, self.msgname, "config", "# What the node's configuration was actually set to." # 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") templatelines = [] 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() ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/parameter_generator_catkin.py000066400000000000000000000615121251764505100311130ustar00rootroot00000000000000# 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 from string import Template import os import inspect import string 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 class ParameterGenerator: 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: 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 != None or min != None): raise Exception("Max or min specified for %s, which is of string type"%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) 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 == 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 == 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: msg = """ 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 """ print(msg) sys.exit(1) 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 } 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!") 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: 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")) f = open(os.path.join(self.binary_dir, "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.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.mkdirabs("docs") f = open(os.path.join(self.binary_dir, "docs", self.msgname+"-usage.dox"), 'w') #print >> f, "/**" print >> f, "\\subsubsection usage Usage" print >> f, '\\verbatim' print >> f, Template('').\ substitute(pkgname = self.pkgname, nodename = self.nodename) for param in self.group.get_parameters(): print >> f, Template(' ').substitute(param) print >> f, '' print >> f, '\\endverbatim' print >> f #print >> f, "*/" f.close() def generatedoc(self): self.mkdirabs("docs") dir_path = os.path.join(self.binary_dir, "docs") self.mkdirabs(dir_path) f = open(os.path.join(dir_path, self.msgname+".dox"), 'w') #print >> 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 >> f, "*/" f.close() def generateusage(self): self.mkdirabs("docs") f = open(os.path.join(self.binary_dir, "docs", self.msgname+"-usage.dox"), 'w') #print >> 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 >> f, "*/" f.close() 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 == 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. self.mkdirabs(self.cpp_gen_dir) f = open(os.path.join(self.cpp_gen_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) constants = '\n'.join(constants) groups = '\n'.join(groups) 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() 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 >> f, "# This is an autogerenated file. Please do not edit." # print >> f, "" # for param in self.parameters: # print >> f, Template("$type $name # $description").substitute(param, type=self.msgtype(param['type'])) # f.close() # # def generategetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Get"+self.msgname+".srv"), 'w') # print >> f, "# This is an autogerenated file. Please do not edit." # print >> f, "" # print >> f, "---" # print >> f, self.msgname, "config", "# Current configuration of node." # print >> f, self.msgname, "defaults", "# Minimum values where appropriate." # print >> f, self.msgname, "min", "# Minimum values where appropriate." # print >> f, self.msgname, "max", "# Maximum values where appropriate." # f.close() # # def generatesetsrv(self): # self.mkdir("srv") # f = open(os.path.join(self.pkgpath, "srv", "Set"+self.msgname+".srv"), 'w') # print >> f, "# This is an autogerenated file. Please do not edit." # print >> f, self.msgname, "config", "# Requested node configuration." # print >> f, "---" # print >> f, self.msgname, "config", "# What the node's configuration was actually set to." # 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") templatelines = [] f = open(templatefile) template = f.read() f.close() # Write the configuration manipulator. self.mkdirabs(os.path.join(self.py_gen_dir, "cfg")) f = open(os.path.join(self.py_gen_dir, "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.py_gen_dir, "cfg", "__init__.py"), 'a') f.close() ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure/server.py000066400000000000000000000125111251764505100250350ustar00rootroot00000000000000# 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: pass import rospy import rosservice import threading import time import copy from dynamic_reconfigure import DynamicReconfigureCallbackException from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv from dynamic_reconfigure.msg import Config as ConfigMsg from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg from dynamic_reconfigure.msg import IntParameter, BoolParameter, StrParameter, DoubleParameter, ParamDescription from dynamic_reconfigure.encoding import * class Server(object): def __init__(self, type, callback): self.mutex = threading.Lock() 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('~parameter_descriptions', ConfigDescrMsg, latch=True, queue_size=10) self.descr_topic.publish(self.description); self.update_topic = rospy.Publisher('~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('~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("~" + param['name']) except KeyError: pass def _copy_to_parameter_server(self): for param in extract_params(self.type.config_description): rospy.set_param('~' + 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))) ros-dynamic-reconfigure-1.5.39/src/dynamic_reconfigure_config_init_mutex.cpp000066400000000000000000000001461251764505100274540ustar00rootroot00000000000000#include boost::mutex dynamic_reconfigure::__init_mutex__; ros-dynamic-reconfigure-1.5.39/srv/000077500000000000000000000000001251764505100171645ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/srv/Reconfigure.srv000066400000000000000000000000401251764505100221620ustar00rootroot00000000000000Config config --- Config config ros-dynamic-reconfigure-1.5.39/templates/000077500000000000000000000000001251764505100203505ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/templates/ConfigType.h.template000066400000000000000000000400361251764505100244050ustar00rootroot00000000000000${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__ #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 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; template class ParamDescription : public AbstractParamDescription { public: ParamDescription(std::string name, std::string type, uint32_t level, std::string description, std::string edit_method, T ${configname}Config::* f) : AbstractParamDescription(name, type, level, description, edit_method), field(f) {} T (${configname}Config::* field); virtual void clamp(${configname}Config &config, const ${configname}Config &max, const ${configname}Config &min) const { 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 { if (config1.*field != config2.*field) comb_level |= level; } virtual void fromServer(const ros::NodeHandle &nh, ${configname}Config &config) const { nh.getParam(name, config.*field); } virtual void toServer(const ros::NodeHandle &nh, const ${configname}Config &config) const { nh.setParam(name, config.*field); } virtual bool fromMessage(const dynamic_reconfigure::Config &msg, ${configname}Config &config) const { return dynamic_reconfigure::ConfigTools::getParameter(msg, name, config.*field); } virtual void toMessage(dynamic_reconfigure::Config &msg, const ${configname}Config &config) const { dynamic_reconfigure::ConfigTools::appendParameter(msg, name, config.*field); } virtual void getValue(const ${configname}Config &config, boost::any &val) const { 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; } 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; template class GroupDescription : public AbstractGroupDescription { public: GroupDescription(std::string name, std::string type, int parent, int id, bool s, T PT::* f) : AbstractGroupDescription(name, type, parent, id, s), field(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 { 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 { 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 { 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 { 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 { 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} } #endif // __${uname}RECONFIGURATOR_H__ ros-dynamic-reconfigure-1.5.39/templates/ConfigType.py.template000066400000000000000000000016221251764505100246040ustar00rootroot00000000000000## ********************************************************* ## ## 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'] ros-dynamic-reconfigure-1.5.39/templates/GroupClass.h.template000066400000000000000000000010001251764505100244040ustar00rootroot00000000000000class ${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}; ros-dynamic-reconfigure-1.5.39/test/000077500000000000000000000000001251764505100173315ustar00rootroot00000000000000ros-dynamic-reconfigure-1.5.39/test/CMakeLists.txt000066400000000000000000000007011251764505100220670ustar00rootroot00000000000000add_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 pthread dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES}) add_dependencies(tests dynamic_reconfigure-ref_server) add_rostest(test_python_simple_client.launch) ros-dynamic-reconfigure-1.5.39/test/ref_server.cpp000066400000000000000000000047051251764505100222050ustar00rootroot00000000000000/* * 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; } ros-dynamic-reconfigure-1.5.39/test/simple_python_client_test.py000077500000000000000000000077011251764505100252020ustar00rootroot00000000000000#!/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_']) int_ = 7 double_ = 0.75 str_ = 'bar' bool_ = True client.update_configuration( {"int_": int_, "double_": double_, "str_": str_, "bool_": bool_} ) 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_']) 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) ros-dynamic-reconfigure-1.5.39/test/test_cpp.xml000066400000000000000000000000231251764505100216670ustar00rootroot00000000000000 ros-dynamic-reconfigure-1.5.39/test/test_python_simple_client.launch000066400000000000000000000003621251764505100260150ustar00rootroot00000000000000 ros-dynamic-reconfigure-1.5.39/test/testclient.py000077500000000000000000000116541251764505100220730ustar00rootroot00000000000000#!/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. 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.iteritems(): 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() ros-dynamic-reconfigure-1.5.39/test/testserver.cpp000066400000000000000000000065251251764505100222530ustar00rootroot00000000000000/********************************************************************* * 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; } ros-dynamic-reconfigure-1.5.39/test/testserver.py000077500000000000000000000053011251764505100221130ustar00rootroot00000000000000#! /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. #********************************************************************/ 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() ros-dynamic-reconfigure-1.5.39/test/testserver2.cpp000066400000000000000000000035501251764505100223300ustar00rootroot00000000000000/********************************************************************* * 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