Package dynamic_reconfigure :: Module client

Source Code for Module dynamic_reconfigure.client

  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  import roslib; roslib.load_manifest('dynamic_reconfigure') 
 41  import rospy 
 42  import rosservice                   
 43  import sys 
 44  import threading 
 45  import time 
 46  from dynamic_reconfigure import DynamicReconfigureParameterException 
 47  from dynamic_reconfigure.srv import Reconfigure as ReconfigureSrv 
 48  from dynamic_reconfigure.msg import Config as ConfigMsg 
 49  from dynamic_reconfigure.msg import ConfigDescription as ConfigDescrMsg 
 50  from dynamic_reconfigure.msg import IntParameter, BoolParameter, StrParameter, DoubleParameter, ParamDescription 
 51  from dynamic_reconfigure.encoding import * 
 52   
53 -class Client(object):
54 """ 55 Python dynamic_reconfigure client API 56 """
57 - def __init__(self, name, timeout=None, config_callback=None, description_callback=None):
58 """ 59 Connect to dynamic_reconfigure server and return a client object 60 61 @param name: name of the server to connect to (usually the node name) 62 @type name: str 63 @param timeout: time to wait before giving up 64 @type timeout: float 65 @param config_callback: callback for server parameter changes 66 @param description_callback: internal use only as the API has not stabilized 67 """ 68 self.name = name 69 self.config = None 70 self.param_description = None 71 72 self._param_types = None 73 74 self._cv = threading.Condition() 75 76 self._config_callback = config_callback 77 self._description_callback = description_callback 78 79 self._set_service = self._get_service_proxy('set_parameters', timeout) 80 self._updates_sub = self._get_subscriber('parameter_updates', ConfigMsg, self._updates_msg) 81 self._descriptions_sub = self._get_subscriber('parameter_descriptions', ConfigDescrMsg, self._descriptions_msg)
82
83 - def get_configuration(self, timeout=None):
84 """ 85 Return the latest received server configuration (wait to receive 86 one if none have been received) 87 88 @param timeout: time to wait before giving up 89 @type timeout: float 90 @return: dictionary mapping parameter names to values or None if unable to retrieve config. 91 @rtype: {str: value} 92 """ 93 if timeout is None or timeout == 0.0: 94 if self.get_configuration(timeout=1.0) is None: 95 print >> sys.stderr, 'Waiting for configuration...' 96 97 with self._cv: 98 while self.config is None: 99 if rospy.is_shutdown(): 100 return None 101 self._cv.wait() 102 else: 103 start_time = time.time() 104 with self._cv: 105 while self.config is None: 106 if rospy.is_shutdown(): 107 return None 108 secs_left = timeout - (time.time() - start_time) 109 if secs_left <= 0.0: 110 break 111 self._cv.wait(secs_left) 112 113 return self.config
114
115 - def get_parameter_descriptions(self, timeout=None):
116 """ 117 UNSTABLE. Return a description of the parameters for the server. 118 Do not use this method as the type that is returned may change. 119 120 @param timeout: time to wait before giving up 121 @type timeout: float 122 """ 123 if timeout is None or timeout == 0.0: 124 with self._cv: 125 while self.param_description is None: 126 if rospy.is_shutdown(): 127 return None 128 self._cv.wait() 129 else: 130 start_time = time.time() 131 with self._cv: 132 while self.param_description is None: 133 if rospy.is_shutdown(): 134 return None 135 secs_left = timeout - (time.time() - start_time) 136 if secs_left <= 0.0: 137 break 138 self._cv.wait(secs_left) 139 140 return self.param_description
141
142 - def update_configuration(self, changes):
143 """ 144 Change the server's configuration 145 146 @param changes: dictionary of key value pairs for the parameters that are changing 147 @type changes: {str: value} 148 """ 149 # Retrieve the parameter descriptions 150 if self.param_description is None: 151 self.get_parameter_descriptions() 152 153 # Cast the parameters to the appropriate types 154 if self.param_description is not None: 155 for name, value in changes.items()[:]: 156 dest_type = self._param_types.get(name) 157 if dest_type is None: 158 raise DynamicReconfigureParameterException('don\'t know parameter: %s' % name) 159 160 try: 161 changes[name] = dest_type(value) 162 except ValueError, e: 163 raise DynamicReconfigureParameterException('can\'t set parameter \'%s\' of %s: %s' % (name, str(dest_type), e)) 164 165 config = encode_config(changes) 166 msg = self._set_service(config).config 167 resp = decode_config(msg) 168 169 return resp
170
171 - def close(self):
172 """ 173 Close connections to the server 174 """ 175 self._updates_sub.unregister() 176 self._descriptions_sub.unregister()
177 178 ## config_callback 179
180 - def get_config_callback(self):
181 """ 182 Retrieve the config_callback 183 """ 184 return self._config_callback
185
186 - def set_config_callback(self, value):
187 """ 188 Set the config_callback 189 """ 190 self._config_callback = value 191 if self._config_callback is not None: 192 self._config_callback(self.config)
193 194 config_callback = property(get_config_callback, set_config_callback) 195 196 ## description_callback 197
198 - def get_description_callback(self):
199 """ 200 Get the current description_callback 201 """ 202 return self._config_callback
203
204 - def set_description_callback(self, value):
205 """ 206 UNSTABLE. Set the description callback. Do not use as the type of the 207 description callback may change. 208 """ 209 self._description_callback = value 210 if self._description_callback is not None: 211 self._description_callback(self.param_description)
212 213 description_callback = property(get_description_callback, set_description_callback) 214 215 # Implementation 216
217 - def _get_service_proxy(self, suffix, timeout):
218 service_name = rospy.resolve_name(self.name + '/' + suffix) 219 if timeout is None or timeout == 0.0: 220 try: 221 rospy.wait_for_service(service_name, 1.0) 222 except rospy.exceptions.ROSException: 223 print >> sys.stderr, 'Waiting for service %s...' % service_name 224 rospy.wait_for_service(service_name, timeout) 225 else: 226 rospy.wait_for_service(service_name, timeout) 227 228 return rospy.ServiceProxy(service_name, ReconfigureSrv)
229
230 - def _get_subscriber(self, suffix, type, callback):
231 topic_name = rospy.resolve_name(self.name + '/' + suffix) 232 233 return rospy.Subscriber(topic_name, type, callback=callback)
234
235 - def _updates_msg(self, msg):
236 self.config = decode_config(msg) 237 238 with self._cv: 239 self._cv.notifyAll() 240 if self._config_callback is not None: 241 self._config_callback(self.config)
242
243 - def _descriptions_msg(self, msg):
244 self.param_description = decode_description(msg) 245 246 # Build map from parameter name to type 247 self._param_types = {} 248 for p in self.param_description: 249 n, t = p.get('name'), p.get('type') 250 if n is not None and t is not None: 251 self._param_types[n] = self._param_type_from_string(t) 252 253 with self._cv: 254 self._cv.notifyAll() 255 if self._description_callback is not None: 256 self._description_callback(self.param_description)
257
258 - def _param_type_from_string(self, type_str):
259 if type_str == 'int': return int 260 elif type_str == 'double': return float 261 elif type_str == 'str': return str 262 elif type_str == 'bool': return bool 263 else: 264 raise DynamicReconfigureParameterException('parameter has unknown type: %s. This is a bug in dynamic_reconfigure.' % type_str)
265