1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23   
 24   
 25   
 26   
 27   
 28   
 29   
 30   
 31   
 32   
 33   
 34   
 35  """ 
 36  Support for ROS Names 
 37   
 38  See: U{http://www.ros.org/wiki/Names} 
 39  """ 
 40   
 41  import sys 
 42  import os 
 43   
 44  from rosgraph.names import namespace, get_ros_namespace, ns_join, make_global_ns, load_mappings, \ 
 45       SEP, GLOBALNS, REMAP, ANYTYPE, \ 
 46       is_global, is_private 
 47  import rosgraph.names 
 48   
 49  from rospy.exceptions import ROSException 
 50  from rospy.impl.validators import ParameterInvalid 
 51   
 52  TOPIC_ANYTYPE = ANYTYPE  
 53  SERVICE_ANYTYPE = ANYTYPE  
 54   
 55  import struct 
 56   
 57  if sys.hexversion > 0x03000000:  
 59          return isinstance(s, str)  
  60  else: 
 62          return isinstance(s, basestring)  
  63   
 65      """ 
 66      Put name in canonical form. Double slashes '//' are removed and 
 67      name is returned without any trailing slash, e.g. /foo/bar 
 68      @param name: ROS name 
 69      @type  name: str 
 70      """ 
 71      if not name or name == SEP: 
 72          return name 
 73      elif name[0] == SEP: 
 74          return '/' + '/'.join([x for x in name.split(SEP) if x]) 
 75      else: 
 76          return '/'.join([x for x in name.split(SEP) if x])         
  77       
 78       
 79       
 80   
 81   
 82   
 83   
 84   
 85   
 86  _mappings = load_mappings(sys.argv) 
 87  _resolved_mappings = {} 
 88   
 90      """ 
 91      Re-initialize the name remapping table. 
 92   
 93      @param argv: Command line arguments to this program. ROS reads 
 94          these arguments to find renaming params.  
 95      @type  argv: [str] 
 96      """ 
 97      global _mappings 
 98      _mappings = load_mappings(argv) 
  99   
100   
117   
119      """ 
120      The need for this function is complicated -- Topics and Services can be created before init_node is called. 
121      In general, this is okay, unless the name is a ~name, in which 
122      case we have to raise an ValueError 
123   
124      @param name: ROS name to resolve 
125      @type  name: str 
126      @raise ValueError: if name is a ~name 
127      @raise ROSInitException: if name is remapped to a ~name 
128      """ 
129      if is_private(name): 
130          raise ValueError("~name topics cannot be created before init_node() has been called") 
131   
132       
133      fake_caller_id = ns_join(get_namespace(), 'node') 
134      fake_resolved = rosgraph.names.resolve_name(name, fake_caller_id) 
135   
136      for m, v in _mappings.items(): 
137          if rosgraph.names.resolve_name(m, fake_caller_id) == fake_resolved: 
138              if is_private(name): 
139                  raise ROSInitException("due to the way this node is written, %s cannot be remapped to a ~name. \nThe declaration of topics/services must be moved after the call to init_node()"%name) 
140              else: 
141                  return rosgraph.names.resolve_name(v, fake_caller_id) 
142      return fake_resolved 
 143   
145      """ 
146      Get mapping table with unresolved names 
147       
148      @return: command-line remappings {name: name} 
149      @rtype: {str: str} 
150      """ 
151      return _mappings 
 152   
154      """ 
155      Get mapping table with resolved names 
156       
157      @return: command-line remappings {name: name} 
158      @rtype: {str: str} 
159      """ 
160      return _resolved_mappings 
 161   
162   
164      """ 
165      Resolve a ROS name to its global, canonical form. Private ~names 
166      are resolved relative to the node name.  
167   
168      @param name: name to resolve. 
169      @type  name: str 
170      @param caller_id: node name to resolve relative to. To 
171      resolve to local namespace, omit this parameter (or use None) 
172      @type  caller_id: str 
173      @return: Resolved name. If name is empty/None, resolve_name 
174      returns parent namespace. If namespace is empty/None, 
175      @rtype: str 
176      """ 
177      if not caller_id: 
178          caller_id = get_name() 
179      if not name:  
180          return namespace(caller_id) 
181   
182      name = str(name)   
183      name = canonicalize_name(name) 
184      if name[0] == SEP:  
185          resolved_name = name 
186      elif is_private(name):  
187          resolved_name = ns_join(caller_id, name[1:]) 
188      else:  
189          resolved_name = namespace(caller_id) + name 
190   
191       
192       
193       
194      if resolved_name in _resolved_mappings: 
195          return _resolved_mappings[resolved_name] 
196      else: 
197          return resolved_name 
 198   
199   
200 -def remap_name(name, caller_id=None, resolved=True): 
 201      """ 
202      Remap a ROS name. This API should be used to instead of 
203      resolve_name for APIs in which you don't wish to resolve the name 
204      unless it is remapped. 
205      @param name: name to remap 
206      @type  name: str 
207       
208      @param resolved: if True (default), use resolved names in remappings, which is the standard for ROS.  
209      @type  resolved: bool 
210       
211      @return: Remapped name 
212      @rtype: str 
213      """ 
214      if not caller_id: 
215          caller_id = get_caller_id() 
216      if name in _mappings: 
217          return rosgraph.names.resolve_name(_mappings[name], caller_id) 
218      return name 
 219   
221      """ 
222      Convert the global caller_id to a relative name within the namespace. For example, for 
223      namespace '/foo' and name '/foo/bar/name', the return value will 
224      be 'bar/name' 
225   
226      WARNING: scoped_name does not validate that name is actually within 
227      the supplied namespace. 
228      @param caller_id: caller ID, in canonical form 
229      @type  caller_id: str 
230      @param name: name to scope 
231      @type  name: str 
232      @return: name scoped to the caller_id's namespace.  
233      @rtype: str 
234      """ 
235      if not is_global(caller_id): 
236          raise ROSException("caller_id must be global") 
237      return canonicalize_name(name)[len(namespace(caller_id)):] 
 238   
239   
240   
241   
242   
243   
244   
245   
247      if not param_value or not isstring(param_value): 
248          raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name)             
249       
250       
251      if ':' in param_value or ' ' in param_value: 
252          raise ParameterInvalid("ERROR: parameter [%s] contains illegal chars"%param_name)  
253       
254      return rosgraph.names.resolve_name(param_value, caller_id, remappings=None) 
 255   
257      if not param_value or not isstring(param_value): 
258          raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name)             
259       
260       
261      if ':' in param_value or ' ' in param_value: 
262          raise ParameterInvalid("ERROR: parameter [%s] contains illegal chars"%param_name)  
263      return param_value 
 264       
266      """ 
267      Validator that resolves names and also ensures that they are not empty 
268      @param param_name: name 
269      @type  param_name: str 
270      @param resolve: if True/omitted, the name will be resolved to 
271         a global form. Otherwise, no resolution occurs. 
272      @type  resolve: bool 
273      @return: resolved parameter value 
274      @rtype: str 
275      """ 
276      def validator(param_value, caller_id): 
277          if resolve: 
278              return valid_name_validator_resolved(param_name, param_value, caller_id) 
279          return valid_name_validator_unresolved(param_name, param_value, caller_id)         
 280      return validator 
281   
283      """ 
284      Validator that checks for valid, global graph resource name. 
285      @return: parameter value 
286      @rtype: str 
287      """ 
288      def validator(param_value, caller_id): 
289          if not param_value or not isstring(param_value): 
290              raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name) 
291           
292          if not is_global(param_value): 
293              raise ParameterInvalid("ERROR: parameter [%s] must be a globally referenced name"%param_name)             
294          return param_value 
 295      return validator 
296   
297   
298   
299   
300   
301  _caller_namespace = get_ros_namespace() 
302  _caller_id = _caller_namespace+'unnamed'  
303   
305      """ 
306      Get namespace of local node.  
307      @return: fully-qualified name of local node or '' if not applicable 
308      @rtype: str 
309      """ 
310      return _caller_namespace 
 311   
313      """ 
314      Get fully resolved name of local node. If this is not a node, 
315      use empty string 
316      @return: fully-qualified name of local node or '' if not applicable 
317      @rtype: str 
318      """     
319      return _caller_id 
 320   
321   
322  get_caller_id = get_name 
323   
325      """ 
326      Internal API. 
327      Set the global name (i.e. caller_id) and namespace. Methods can 
328      check what the name of the current node is by calling get_caller_id. 
329   
330      The caller_id is important as it is the first parameter to any API 
331      call on a remote node.  Invoked by ROSNode constructor 
332      @param caller_id: new caller ID 
333      @type  caller_id: str 
334      """     
335      global _caller_id, _caller_namespace 
336      _caller_id = caller_id 
337      _caller_namespace = namespace(caller_id) 
 338