ros_services.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Thanks to:
00004 # https://github.com/ros-visualization/rqt_common_plugins/blob/groovy-devel/rqt_service_caller/src/rqt_service_caller/service_caller_widget.py
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         # Build the Array of inputs
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                     # set the attribute in the request
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                 # sets the object as an attribute in the request were trying to build
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     # use extra iteration as to not get "dict changed during iteration" errors
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


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Sat Jun 8 2019 18:26:23