00001
00002
00003 """
00004 Copyright 2013 Southwest Research Institute
00005
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009
00010 http://www.apache.org/licenses/LICENSE-2.0
00011
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 """
00018
00019
00020 import sys
00021 import os
00022 import optparse
00023 import yaml
00024 import operator
00025 import thread
00026 import threading
00027 import re
00028 import time
00029 import socket
00030 import urllib2
00031 from importlib import import_module
00032 from httplib import HTTPConnection
00033 from xml.etree import ElementTree
00034
00035
00036 import bridge_library
00037
00038
00039 path, file = os.path.split(__file__)
00040 sys.path.append(os.path.realpath(path) + '/src')
00041 from data_item import Event, SimpleCondition, Sample, ThreeDSample
00042 from mtconnect_adapter import Adapter
00043 from long_pull import LongPull
00044
00045
00046 import roslib
00047 import rospy
00048 import actionlib
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 class GenericActionClient(object):
00073
00074 def __init__(self):
00075
00076 rospy.init_node('ActionClient')
00077
00078
00079 self.config = bridge_library.obtain_dataMap()
00080 self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace', 'adapter_port', 'service']
00081 self.url = self.config[self.msg_parameters[0]]
00082 self.url_port = self.config[self.msg_parameters[1]]
00083 self.mtool = self.config[self.msg_parameters[2]]
00084 self.ns = dict(m = self.config[self.msg_parameters[3]])
00085 self.port = self.config[self.msg_parameters[4]]
00086 self.service = self.config[self.msg_parameters[5]]
00087
00088
00089 bridge_library.check_connectivity((1,self.url,self.url_port))
00090
00091
00092 self.adapter = Adapter((self.url, self.port))
00093
00094
00095 self.lib_manifests = []
00096 self.type_handle = None
00097 self.action_list = {}
00098 self.action_goals = {}
00099 self.package = None
00100 self.xml_goal = None
00101 self.di_dict = {}
00102 self.handshake = None
00103
00104
00105 self.setup_topic_data()
00106
00107
00108 bridge_library.add_event((self.adapter, self.action_list, self.di_dict, False))
00109
00110
00111 rospy.loginfo('Start the Robot Link adapter')
00112 self.adapter.start()
00113
00114
00115 self.action_service = []
00116 for mt_action in self.action_goals.keys():
00117 self.action_service.append(ActionService(mt_action, self.adapter, self.di_dict, self.service_handle, self.service))
00118
00119
00120 while True:
00121 try:
00122 self.conn = HTTPConnection(self.url, self.url_port)
00123 response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current"))
00124 body = response.read()
00125 break
00126 except socket.error as e:
00127 rospy.loginfo('HTTP connection error %s' % e)
00128 time.sleep(10)
00129
00130
00131 seq, elements = bridge_library.xml_components(body, self.ns, self.action_list)
00132
00133
00134 response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq))
00135
00136
00137 self.lock = thread.allocate_lock()
00138
00139
00140 lp = LongPull(response)
00141 lp.long_pull(self.xml_callback)
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 def setup_topic_data(self):
00157 for package, action in self.config.items():
00158 if package not in self.msg_parameters:
00159
00160 if package not in self.lib_manifests:
00161 roslib.load_manifest(package)
00162 self.lib_manifests.append(package)
00163
00164
00165 rospy.loginfo('Importing --> ' + package + '.msg')
00166 self.type_handle = import_module(package + '.msg')
00167 self.service_handle = import_module(package + '.srv')
00168
00169
00170 self.package = package
00171
00172 for action_req in action.keys():
00173
00174 goal_tag = self.config[package][action_req].keys()[0]
00175 self.action_list[action_req] = {goal_tag : self.config[package][action_req][goal_tag].keys()}
00176
00177
00178 self.action_goals[action_req] = None
00179 return
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 def action_client(self, cb_data):
00191
00192 rospy.init_node('ActionClient')
00193
00194
00195 name, goals, handle = cb_data
00196 rospy.loginfo('Launched %s Action CLient' % name)
00197
00198
00199
00200 action_type = getattr(handle, name + 'Action')
00201 client = actionlib.SimpleActionClient(name + 'Client', action_type)
00202
00203
00204 rospy.loginfo('Waiting for %s Dedicated Action Server' % name)
00205 client.wait_for_server()
00206 rospy.loginfo('%s Dedicated Action Server Activated' % name)
00207
00208
00209
00210 goal_handle = getattr(handle, name + 'Goal')
00211 goal = goal_handle()
00212
00213
00214 if self.action_goals[name] == None:
00215
00216 goal_tag = self.action_list[name].keys()[0]
00217 response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn,
00218 self.mtool + "/current?path=//DataItem[@type='" + goal_tag.upper() +"']"))
00219 body = response.read()
00220 root = ElementTree.fromstring(body)
00221
00222
00223 self.action_goals = bridge_library.set_goal(name, self.action_list[name], root, self.ns, self.action_goals)
00224
00225
00226 for attrib, attrib_type, action_goal in zip(goal_handle.__slots__, goal_handle._slot_types, self.action_goals[name]):
00227 if bridge_library.type_check(attrib_type, action_goal) == False:
00228 rospy.logerr('INCOMPATIBLE GOAL TYPES ROS MSG: %s --> XML: %s' % (attrib_type, type(action_goal)))
00229 sys.exit()
00230
00231
00232 try:
00233 for attrib, xml_goal in zip(goal_handle.__slots__, self.action_goals[name]):
00234 setattr(goal, attrib, xml_goal)
00235 except Exception as e:
00236 rospy.logerr("ROS Action %s Client failed: %s" % (name, e))
00237
00238
00239 rospy.loginfo('Sending the goal')
00240 name_conv = bridge_library.split_event(name)
00241 client.send_goal(goal, done_cb = None, active_cb = bridge_library.action_cb((self.adapter, self.di_dict, name_conv, 'ACTIVE')))
00242
00243
00244
00245 rospy.loginfo('Waiting for result')
00246 client.wait_for_result()
00247
00248
00249 result = client.get_state()
00250
00251
00252 rospy.loginfo('Returning the result --> %s' % result)
00253
00254
00255 data_item = bridge_library.split_event(name)
00256
00257
00258 if result == 3:
00259 rospy.loginfo('Sending COMPLETE flag')
00260 bridge_library.action_cb((self.adapter, self.di_dict, data_item, 'COMPLETE'))
00261 return name
00262 elif result == 4:
00263 rospy.loginfo('%s ABORTED, terminating action request' % data_item)
00264 bridge_library.action_cb((self.adapter, self.di_dict, data_item, 'FAIL'))
00265 return None
00266
00267
00268
00269
00270
00271
00272
00273 def xml_callback(self, chunk):
00274
00275 self.lock.acquire()
00276 try:
00277
00278 _, elements, self.action_goals = bridge_library.xml_components(chunk, self.ns, self.action_list, get_goal = True, action_goals = self.action_goals)
00279
00280 if elements:
00281
00282 if self.handshake:
00283 for e in elements:
00284 if self.handshake == e.attrib['name'] and e.text == 'READY':
00285
00286 bridge_library.action_cb((self.adapter, self.di_dict, e.attrib['name'], 'READY'))
00287 self.handshake = None
00288 elements.remove(e)
00289 if self.handshake != None:
00290 rospy.logerr('DID NOT RECEIVE READY HANDSHAKE FROM MACHINE TOOL')
00291
00292 for e in elements:
00293
00294 action_text = re.findall(r'(?<=\})\w+',e.tag)[0]
00295
00296
00297 if e.text == 'ACTIVE':
00298 self.handshake = self.action_client((action_text, self.action_goals[action_text], self.type_handle))
00299
00300
00301 except Exception as e:
00302 rospy.logerr("Generic Action Client: Process XML callback failed: %s, releasing lock" % e)
00303 finally:
00304 self.lock.release()
00305
00306 return
00307
00308
00309 class ActionService(GenericActionClient):
00310 def __init__(self, mt_action, adapt, data_item_dict, service_handle, service_state):
00311
00312 self.mt_action = mt_action
00313 self.adapt = adapt
00314 self.data_item_dict = data_item_dict
00315 self.service_hndle = service_handle
00316 self.service_state = service_state
00317
00318 rospy.loginfo('STARTED %s SERVICE SERVER THREAD' % mt_action)
00319 self.ss_thread = threading.Thread(target = self.action_service_server)
00320 self.ss_thread.daemon = True
00321 self.ss_thread.start()
00322
00323 def action_service_server(self):
00324 self.as_name = bridge_library.split_event(self.mt_action)
00325 action_service_class = getattr(self.service_hndle, self.service_state)
00326 s = rospy.Service(self.mt_action + '/' + 'set_mtconnect_state', action_service_class, self.robot_state_callback)
00327 rospy.spin()
00328 return
00329
00330 def robot_state_callback(self, request):
00331 rospy.loginfo('SERVICE REQUEST --> %s' % request.state_flag)
00332 response_service_class = getattr(self.service_hndle, self.service_state + 'Response')
00333 if request.state_flag == -1:
00334 try:
00335 bridge_library.action_cb((self.adapt, self.data_item_dict, self.as_name, 'NOT_READY'))
00336 return response_service_class(True)
00337 except:
00338 return response_service_class(False)
00339 elif request.state_flag == 0:
00340 try:
00341 bridge_library.action_cb((self.adapt, self.data_item_dict, self.as_name, 'READY'))
00342 return response_service_class(True)
00343 except:
00344 return response_service_class(False)
00345
00346
00347 if __name__ == '__main__':
00348 try:
00349 rospy.loginfo('Starting Generic Action Client')
00350 robot_action = GenericActionClient()
00351 except rospy.ROSInterruptException:
00352 rospy.loginfo('program interrupted before completion')
00353