Package dynamic_reconfigure :: Module server

Source Code for Module dynamic_reconfigure.server

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2009, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  """ 
 34  Python client API for dynamic_reconfigure (L{DynamicReconfigureClient}) as well as  
 35  example server implementation (L{DynamicReconfigureServer}). 
 36  """ 
 37   
 38  from __future__ import with_statement 
 39   
 40  try: 
 41      import roslib; roslib.load_manifest('dynamic_reconfigure') 
 42  except: 
 43      pass 
 44  import rospy 
 45  import rosservice                   
 46  import threading 
 47  import time 
 48  import copy 
 49  from dynamic_reconfigure import DynamicReconfigureCallbackException 
 50  from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv 
 51  from dynamic_reconfigure.msg import Config as ConfigMsg 
 52  from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg 
 53  from dynamic_reconfigure.msg import IntParameter, BoolParameter, StrParameter, DoubleParameter, ParamDescription 
 54  from dynamic_reconfigure.encoding import * 
 55   
56 -class Server(object):
57 - def __init__(self, type, callback):
58 self.mutex = threading.Lock() 59 self.type = type 60 self.config = type.defaults.copy() 61 62 self.description = encode_description(type) 63 self._copy_from_parameter_server() 64 self.callback = callback 65 self._clamp(self.config) 66 67 # setup group defaults 68 self.config['groups'] = get_tree(self.description) 69 self.config = initial_config(encode_config(self.config), type.config_description) 70 71 self.descr_topic = rospy.Publisher('~parameter_descriptions', ConfigDescrMsg, latch=True, queue_size=10) 72 self.descr_topic.publish(self.description); 73 74 self.update_topic = rospy.Publisher('~parameter_updates', ConfigMsg, latch=True, queue_size=10) 75 self._change_config(self.config, ~0) # Consistent with the C++ API, the callback gets called with level=~0 (i.e. -1) 76 77 self.set_service = rospy.Service('~set_parameters', ReconfigureSrv, self._set_callback)
78
79 - def update_configuration(self, changes):
80 with self.mutex: 81 new_config = copy.deepcopy(self.config) 82 new_config.update(changes) 83 self._clamp(new_config) 84 return self._change_config(new_config, self._calc_level(new_config, self.config))
85
87 for param in extract_params(self.type.config_description): 88 try: 89 self.config[param['name']] = rospy.get_param("~" + param['name']) 90 except KeyError: 91 pass
92
94 for param in extract_params(self.type.config_description): 95 rospy.set_param('~' + param['name'], self.config[param['name']])
96
97 - def _change_config(self, config, level):
98 self.config = self.callback(config, level) 99 if self.config is None: 100 msg = 'Reconfigure callback should return a possibly updated configuration.' 101 rospy.logerr(msg) 102 raise DynamicReconfigureCallbackException(msg) 103 104 self._copy_to_parameter_server() 105 106 self.update_topic.publish(encode_config(self.config)) 107 108 return self.config
109
110 - def _calc_level(self, config1, config2):
111 level = 0 112 for param in extract_params(self.type.config_description): 113 if config1[param['name']] != config2[param['name']]: 114 level |= param['level'] 115 116 return level
117
118 - def _clamp(self, config):
119 for param in extract_params(self.type.config_description): 120 maxval = self.type.max[param['name']] 121 minval = self.type.min[param['name']] 122 val = config[param['name']] 123 if val > maxval and maxval != "": 124 config[param['name']] = maxval 125 elif val < minval and minval != "": 126 config[param['name']] = minval
127
128 - def _set_callback(self, req):
129 return encode_config(self.update_configuration(decode_config(req.config, self.type.config_description)))
130