ros_services.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # Thanks to:
4 # https://github.com/ros-visualization/rqt_common_plugins/blob/groovy-devel/rqt_service_caller/src/rqt_service_caller/service_caller_widget.py
5 import math
6 import random
7 import time
8 
9 import genpy
10 import rospy
11 import rosservice
12 from opcua import ua, uamethod, common
13 
14 import ros_server
15 
16 
18  def __init__(self, server, parent, idx, service_name, service_class):
19  self.server = server
20  self.name = service_name
21  self.parent = self.recursive_create_objects(service_name, idx, parent)
22  self._class = service_class
23  self.proxy = rospy.ServiceProxy(self.name, self._class)
24  self.counter = 0
25  self._nodes = {}
26  self.expressions = {}
27  self._eval_locals = {}
28 
29  for module in (math, random, time):
30  self._eval_locals.update(module.__dict__)
31  self._eval_locals['genpy'] = genpy
32  del self._eval_locals['__name__']
33  del self._eval_locals['__doc__']
34  # Build the Array of inputs
35  self.sample_req = self._class._request_class()
36  self.sample_resp = self._class._response_class()
37  inputs = getargarray(self.sample_req)
39  self.method = self.parent.add_method(idx, self.name, self.call_service, inputs, self.outputs)
40  rospy.loginfo("Created ROS Service with name: %s", self.name)
41 
42  @uamethod
43  def call_service(self, parent, *inputs):
44  try:
45  rospy.loginfo("Calling Service with name: " + self.name)
46  input_msg = self.create_message_instance(inputs, self.sample_req)
47  rospy.logdebug("Created Input Request for Service " + self.name + " : " + str(input_msg))
48  response = self.proxy(input_msg)
49  rospy.logdebug("got response: " + str(response))
50  rospy.logdebug("Creating response message object")
51  return_values = []
52  for slot in response.__slots__:
53  rospy.logdebug("Converting slot: " + str(getattr(response, slot)))
54  return_values.append(getattr(response, slot))
55  rospy.logdebug("Current Response list: " + str(return_values))
56  return return_values
57  except (TypeError, rospy.ROSException, rospy.ROSInternalException, rospy.ROSSerializationException,
58  common.uaerrors.UaError, rosservice.ROSServiceException) as e:
59  rospy.logerr("Error when calling service " + self.name, e)
60 
61  def create_message_instance(self, inputs, sample):
62  rospy.logdebug("Creating message for goal call")
63  already_set = []
64  if isinstance(inputs, tuple):
65  arg_counter = 0
66  object_counter = 0
67  while (arg_counter < len(inputs) and object_counter < len(sample.__slots__)):
68  cur_arg = inputs[arg_counter]
69  cur_slot = sample.__slots__[object_counter]
70  real_slot = getattr(sample, cur_slot)
71  rospy.logdebug(
72  "cur_arg: " + str(cur_arg) + " cur_slot_name: " + str(cur_slot) + " real slot content: " + str(
73  real_slot))
74  if hasattr(real_slot, '_type'):
75  rospy.logdebug("We found an object with name " + str(cur_slot) + ", creating it recursively")
76  already_set, arg_counter = self.create_object_instance(already_set, real_slot, cur_slot,
77  arg_counter, inputs, sample)
78  object_counter += 1
79  else:
80  already_set.append(cur_slot)
81  # set the attribute in the request
82  setattr(sample, cur_slot, cur_arg)
83  arg_counter += 1
84  object_counter += 1
85 
86  return sample
87 
88  def create_object_instance(self, already_set, object, name, counter, inputs, sample):
89  rospy.loginfo("Create Object Instance Notify")
90  object_counter = 0
91  while (object_counter < len(object.__slots__) and counter < len(inputs)):
92  cur_arg = inputs[counter]
93  cur_slot = object.__slots__[object_counter]
94  real_slot = getattr(object, cur_slot)
95  rospy.loginfo(
96  "cur_arg: " + str(cur_arg) + " cur_slot_name: " + str(cur_slot) + " real slot content: " + str(
97  real_slot))
98  if hasattr(real_slot, '_type'):
99  rospy.logdebug("Recursive Object found in request/response of service call")
100  already_set, counter = self.create_object_instance(already_set, real_slot, cur_slot, counter, inputs,
101  sample)
102  object_counter += 1
103  else:
104  already_set.append(cur_slot)
105  setattr(object, cur_slot, cur_arg)
106  object_counter += 1
107  counter += 1
108  # sets the object as an attribute in the request were trying to build
109  setattr(sample, name, object)
110  return already_set, counter
111 
112  def recursive_delete_items(self, item):
113  self.proxy.close()
114  for child in item.get_children():
115  self.recursive_delete_items(child)
116  if child in self._nodes:
117  del self._nodes[child]
118  self.server.server.delete_nodes([child])
119  self.server.server.delete_nodes([self.method])
121 
122  def recursive_create_objects(self, name, idx, parent):
123  hierachy = name.split('/')
124  if len(hierachy) == 0 or len(hierachy) == 1:
125  return parent
126  for name in hierachy:
127  if name != '':
128  try:
129  nodewithsamename = self.server.find_service_node_with_same_name(name, idx)
130  rospy.logdebug("nodewithsamename for name: " + str(name) + " is : " + str(nodewithsamename))
131  if nodewithsamename is not None:
132  rospy.logdebug("recursive call for same name for: " + name)
133  return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
134  nodewithsamename)
135  else:
136  newparent = parent.add_object(
137  ua.NodeId(name, parent.nodeid.NamespaceIndex, ua.NodeIdType.String),
138  ua.QualifiedName(name, parent.nodeid.NamespaceIndex))
139  return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
140  newparent)
141  except IndexError, common.uaerrors.UaError:
142  newparent = parent.add_object(
143  ua.NodeId(name + str(random.randint(0, 10000)), parent.nodeid.NamespaceIndex,
144  ua.NodeIdType.String),
145  ua.QualifiedName(name, parent.nodeid.NamespaceIndex))
146  return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
147  newparent)
148  return parent
149 
150 
151 def getargarray(sample_req):
152  array = []
153  for slot_name in sample_req.__slots__:
154  slot = getattr(sample_req, slot_name)
155  if hasattr(slot, '_type'):
156  array_to_merge = getargarray(slot)
157  array.extend(array_to_merge)
158  else:
159  if isinstance(slot, list):
160  arg = ua.Argument()
161  arg.Name = slot_name
162  arg.DataType = ua.NodeId(getobjectidfromtype("array"))
163  arg.ValueRank = -1
164  arg.ArrayDimensions = [1]
165  arg.Description = ua.LocalizedText("Array")
166  else:
167  arg = ua.Argument()
168  arg.Name = slot_name
169  arg.DataType = ua.NodeId(getobjectidfromtype(type(slot).__name__))
170  arg.ValueRank = -1
171  arg.ArrayDimensions = []
172  arg.Description = ua.LocalizedText(slot_name)
173  array.append(arg)
174 
175  return array
176 
177 
178 def refresh_services(namespace_ros, server, servicesdict, idx, services_object_opc):
179  rosservices = rosservice.get_service_list(namespace=namespace_ros)
180 
181  for service_name_ros in rosservices:
182  try:
183  if service_name_ros not in servicesdict or servicesdict[service_name_ros] is None:
184  service = OpcUaROSService(server, services_object_opc, idx, service_name_ros,
185  rosservice.get_service_class_by_name(service_name_ros))
186  servicesdict[service_name_ros] = service
187  except (rosservice.ROSServiceException, rosservice.ROSServiceIOException) as e:
188  try:
189  rospy.logerr("Error when trying to refresh services", e)
190  except TypeError as e2:
191  rospy.logerr("Error when logging an Exception, can't convert everything to string")
192  # use extra iteration as to not get "dict changed during iteration" errors
193  tobedeleted = []
194  rosservices = rosservice.get_service_list()
195  for service_nameOPC in servicesdict:
196  found = False
197  for rosservice_name in rosservices:
198  if service_nameOPC == rosservice_name:
199  found = True
200  if not found and servicesdict[service_nameOPC] is not None:
201  servicesdict[service_nameOPC].recursive_delete_items(
202  server.server.get_node(ua.NodeId(service_nameOPC, idx)))
203  tobedeleted.append(service_nameOPC)
204  if len(servicesdict[service_nameOPC].parent.get_children()) == 0:
205  server.server.delete_nodes([servicesdict[service_nameOPC].parent])
206  for name in tobedeleted:
207  del servicesdict[name]
208 
209 
210 def getobjectidfromtype(type_name):
211  if type_name == 'bool':
212  dv = ua.ObjectIds.Boolean
213  elif type_name == 'byte':
214  dv = ua.ObjectIds.Byte
215  elif type_name == 'int':
216  dv = ua.ObjectIds.Int16
217  elif type_name == 'int8':
218  dv = ua.ObjectIds.SByte
219  elif type_name == 'uint8':
220  dv = ua.ObjectIds.Byte
221  elif type_name == 'int16':
222  dv = ua.ObjectIds.Int16
223  rospy.roswarn("Int16??")
224  elif type_name == 'uint16':
225  dv = ua.ObjectIds.UInt16
226  elif type_name == 'int32':
227  dv = ua.ObjectIds.Int32
228  elif type_name == 'uint32':
229  dv = ua.ObjectIds.UInt32
230  elif type_name == 'int64':
231  dv = ua.ObjectIds.Int64
232  elif type_name == 'uint64':
233  dv = ua.ObjectIds.UInt64
234  elif type_name == 'float' or type_name == 'float32' or type_name == 'float64':
235  dv = ua.ObjectIds.Float
236  elif type_name == 'double':
237  dv = ua.ObjectIds.Double
238  elif type_name == 'string' or type_name == 'str':
239  dv = ua.ObjectIds.String
240  elif type_name == 'array':
241  dv = ua.ObjectIds.Enumeration
242  elif type_name == 'Time' or type_name == 'time':
243  dv = ua.ObjectIds.Time
244  else:
245  rospy.logerr("Can't create type with name " + type_name)
246  return None
247  return dv
def refresh_services(namespace_ros, server, servicesdict, idx, services_object_opc)
def recursive_create_objects(self, name, idx, parent)
def recursive_delete_items(self, item)
def nextname(hierachy, index_of_last_processed)
Definition: ros_server.py:15
def create_message_instance(self, inputs, sample)
Definition: ros_services.py:61
def getobjectidfromtype(type_name)
def __init__(self, server, parent, idx, service_name, service_class)
Definition: ros_services.py:18
def getargarray(sample_req)
def own_rosnode_cleanup()
Definition: ros_server.py:27
def call_service(self, parent, inputs)
Definition: ros_services.py:43
def create_object_instance(self, already_set, object, name, counter, inputs, sample)
Definition: ros_services.py:88


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Tue Jan 19 2021 03:12:44