00001
00002
00003
00004
00005 import math
00006 import random
00007 import time
00008
00009 import genpy
00010 import rospy
00011 import rosservice
00012 from opcua import ua, uamethod, common
00013
00014 import ros_server
00015
00016
00017 class OpcUaROSService:
00018 def __init__(self, server, parent, idx, service_name, service_class):
00019 self.server = server
00020 self.name = service_name
00021 self.parent = self.recursive_create_objects(service_name, idx, parent)
00022 self._class = service_class
00023 self.proxy = rospy.ServiceProxy(self.name, self._class)
00024 self.counter = 0
00025 self._nodes = {}
00026 self.expressions = {}
00027 self._eval_locals = {}
00028
00029 for module in (math, random, time):
00030 self._eval_locals.update(module.__dict__)
00031 self._eval_locals['genpy'] = genpy
00032 del self._eval_locals['__name__']
00033 del self._eval_locals['__doc__']
00034
00035 self.sample_req = self._class._request_class()
00036 self.sample_resp = self._class._response_class()
00037 inputs = getargarray(self.sample_req)
00038 self.outputs = getargarray(self.sample_resp)
00039 self.method = self.parent.add_method(idx, self.name, self.call_service, inputs, self.outputs)
00040 rospy.loginfo("Created ROS Service with name: %s", self.name)
00041
00042 @uamethod
00043 def call_service(self, parent, *inputs):
00044 try:
00045 rospy.loginfo("Calling Service with name: " + self.name)
00046 input_msg = self.create_message_instance(inputs, self.sample_req)
00047 rospy.logdebug("Created Input Request for Service " + self.name + " : " + str(input_msg))
00048 response = self.proxy(input_msg)
00049 rospy.logdebug("got response: " + str(response))
00050 rospy.logdebug("Creating response message object")
00051 return_values = []
00052 for slot in response.__slots__:
00053 rospy.logdebug("Converting slot: " + str(getattr(response, slot)))
00054 return_values.append(getattr(response, slot))
00055 rospy.logdebug("Current Response list: " + str(return_values))
00056 return return_values
00057 except (TypeError, rospy.ROSException, rospy.ROSInternalException, rospy.ROSSerializationException,
00058 common.uaerrors.UaError, rosservice.ROSServiceException) as e:
00059 rospy.logerr("Error when calling service " + self.name, e)
00060
00061 def create_message_instance(self, inputs, sample):
00062 rospy.logdebug("Creating message for goal call")
00063 already_set = []
00064 if isinstance(inputs, tuple):
00065 arg_counter = 0
00066 object_counter = 0
00067 while (arg_counter < len(inputs) and object_counter < len(sample.__slots__)):
00068 cur_arg = inputs[arg_counter]
00069 cur_slot = sample.__slots__[object_counter]
00070 real_slot = getattr(sample, cur_slot)
00071 rospy.logdebug(
00072 "cur_arg: " + str(cur_arg) + " cur_slot_name: " + str(cur_slot) + " real slot content: " + str(
00073 real_slot))
00074 if hasattr(real_slot, '_type'):
00075 rospy.logdebug("We found an object with name " + str(cur_slot) + ", creating it recursively")
00076 already_set, arg_counter = self.create_object_instance(already_set, real_slot, cur_slot,
00077 arg_counter, inputs, sample)
00078 object_counter += 1
00079 else:
00080 already_set.append(cur_slot)
00081
00082 setattr(sample, cur_slot, cur_arg)
00083 arg_counter += 1
00084 object_counter += 1
00085
00086 return sample
00087
00088 def create_object_instance(self, already_set, object, name, counter, inputs, sample):
00089 rospy.loginfo("Create Object Instance Notify")
00090 object_counter = 0
00091 while (object_counter < len(object.__slots__) and counter < len(inputs)):
00092 cur_arg = inputs[counter]
00093 cur_slot = object.__slots__[object_counter]
00094 real_slot = getattr(object, cur_slot)
00095 rospy.loginfo(
00096 "cur_arg: " + str(cur_arg) + " cur_slot_name: " + str(cur_slot) + " real slot content: " + str(
00097 real_slot))
00098 if hasattr(real_slot, '_type'):
00099 rospy.logdebug("Recursive Object found in request/response of service call")
00100 already_set, counter = self.create_object_instance(already_set, real_slot, cur_slot, counter, inputs,
00101 sample)
00102 object_counter += 1
00103 else:
00104 already_set.append(cur_slot)
00105 setattr(object, cur_slot, cur_arg)
00106 object_counter += 1
00107 counter += 1
00108
00109 setattr(sample, name, object)
00110 return already_set, counter
00111
00112 def recursive_delete_items(self, item):
00113 self.proxy.close()
00114 for child in item.get_children():
00115 self.recursive_delete_items(child)
00116 if child in self._nodes:
00117 del self._nodes[child]
00118 self.server.server.delete_nodes([child])
00119 self.server.server.delete_nodes([self.method])
00120 ros_server.own_rosnode_cleanup()
00121
00122 def recursive_create_objects(self, name, idx, parent):
00123 hierachy = name.split('/')
00124 if len(hierachy) == 0 or len(hierachy) == 1:
00125 return parent
00126 for name in hierachy:
00127 if name != '':
00128 try:
00129 nodewithsamename = self.server.find_service_node_with_same_name(name, idx)
00130 rospy.logdebug("nodewithsamename for name: " + str(name) + " is : " + str(nodewithsamename))
00131 if nodewithsamename is not None:
00132 rospy.logdebug("recursive call for same name for: " + name)
00133 return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
00134 nodewithsamename)
00135 else:
00136 newparent = parent.add_object(
00137 ua.NodeId(name, parent.nodeid.NamespaceIndex, ua.NodeIdType.String),
00138 ua.QualifiedName(name, parent.nodeid.NamespaceIndex))
00139 return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
00140 newparent)
00141 except IndexError, common.uaerrors.UaError:
00142 newparent = parent.add_object(
00143 ua.NodeId(name + str(random.randint(0, 10000)), parent.nodeid.NamespaceIndex,
00144 ua.NodeIdType.String),
00145 ua.QualifiedName(name, parent.nodeid.NamespaceIndex))
00146 return self.recursive_create_objects(ros_server.nextname(hierachy, hierachy.index(name)), idx,
00147 newparent)
00148 return parent
00149
00150
00151 def getargarray(sample_req):
00152 array = []
00153 for slot_name in sample_req.__slots__:
00154 slot = getattr(sample_req, slot_name)
00155 if hasattr(slot, '_type'):
00156 array_to_merge = getargarray(slot)
00157 array.extend(array_to_merge)
00158 else:
00159 if isinstance(slot, list):
00160 arg = ua.Argument()
00161 arg.Name = slot_name
00162 arg.DataType = ua.NodeId(getobjectidfromtype("array"))
00163 arg.ValueRank = -1
00164 arg.ArrayDimensions = [1]
00165 arg.Description = ua.LocalizedText("Array")
00166 else:
00167 arg = ua.Argument()
00168 arg.Name = slot_name
00169 arg.DataType = ua.NodeId(getobjectidfromtype(type(slot).__name__))
00170 arg.ValueRank = -1
00171 arg.ArrayDimensions = []
00172 arg.Description = ua.LocalizedText(slot_name)
00173 array.append(arg)
00174
00175 return array
00176
00177
00178 def refresh_services(namespace_ros, server, servicesdict, idx, services_object_opc):
00179 rosservices = rosservice.get_service_list(namespace=namespace_ros)
00180
00181 for service_name_ros in rosservices:
00182 try:
00183 if service_name_ros not in servicesdict or servicesdict[service_name_ros] is None:
00184 service = OpcUaROSService(server, services_object_opc, idx, service_name_ros,
00185 rosservice.get_service_class_by_name(service_name_ros))
00186 servicesdict[service_name_ros] = service
00187 except (rosservice.ROSServiceException, rosservice.ROSServiceIOException) as e:
00188 try:
00189 rospy.logerr("Error when trying to refresh services", e)
00190 except TypeError as e2:
00191 rospy.logerr("Error when logging an Exception, can't convert everything to string")
00192
00193 tobedeleted = []
00194 rosservices = rosservice.get_service_list()
00195 for service_nameOPC in servicesdict:
00196 found = False
00197 for rosservice_name in rosservices:
00198 if service_nameOPC == rosservice_name:
00199 found = True
00200 if not found and servicesdict[service_nameOPC] is not None:
00201 servicesdict[service_nameOPC].recursive_delete_items(
00202 server.server.get_node(ua.NodeId(service_nameOPC, idx)))
00203 tobedeleted.append(service_nameOPC)
00204 if len(servicesdict[service_nameOPC].parent.get_children()) == 0:
00205 server.server.delete_nodes([servicesdict[service_nameOPC].parent])
00206 for name in tobedeleted:
00207 del servicesdict[name]
00208
00209
00210 def getobjectidfromtype(type_name):
00211 if type_name == 'bool':
00212 dv = ua.ObjectIds.Boolean
00213 elif type_name == 'byte':
00214 dv = ua.ObjectIds.Byte
00215 elif type_name == 'int':
00216 dv = ua.ObjectIds.Int16
00217 elif type_name == 'int8':
00218 dv = ua.ObjectIds.SByte
00219 elif type_name == 'uint8':
00220 dv = ua.ObjectIds.Byte
00221 elif type_name == 'int16':
00222 dv = ua.ObjectIds.Int16
00223 rospy.roswarn("Int16??")
00224 elif type_name == 'uint16':
00225 dv = ua.ObjectIds.UInt16
00226 elif type_name == 'int32':
00227 dv = ua.ObjectIds.Int32
00228 elif type_name == 'uint32':
00229 dv = ua.ObjectIds.UInt32
00230 elif type_name == 'int64':
00231 dv = ua.ObjectIds.Int64
00232 elif type_name == 'uint64':
00233 dv = ua.ObjectIds.UInt64
00234 elif type_name == 'float' or type_name == 'float32' or type_name == 'float64':
00235 dv = ua.ObjectIds.Float
00236 elif type_name == 'double':
00237 dv = ua.ObjectIds.Double
00238 elif type_name == 'string' or type_name == 'str':
00239 dv = ua.ObjectIds.String
00240 elif type_name == 'array':
00241 dv = ua.ObjectIds.Enumeration
00242 elif type_name == 'Time' or type_name == 'time':
00243 dv = ua.ObjectIds.Time
00244 else:
00245 rospy.logerr("Can't create type with name " + type_name)
00246 return None
00247 return dv