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 re
00027 import time
00028 import urllib2
00029 from Queue import Queue
00030 from threading import Thread, Timer
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 class GenericActionServer():
00071
00072 def __init__(self):
00073
00074 rospy.init_node('ActionServer')
00075
00076
00077 self.config = bridge_library.obtain_dataMap()
00078 self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace', 'adapter_port']
00079 self.url = self.config[self.msg_parameters[0]]
00080 self.url_port = self.config[self.msg_parameters[1]]
00081 self.mtool = self.config[self.msg_parameters[2]]
00082 self.ns = dict(m = self.config[self.msg_parameters[3]])
00083 self.port = self.config[self.msg_parameters[4]]
00084
00085
00086 bridge_library.check_connectivity((1,self.url,self.url_port))
00087
00088
00089 self.adapter = Adapter((self.url, self.port))
00090
00091
00092 self.lib_manifests = []
00093 self.type_handle = None
00094 self.action_list = {}
00095 self.capture_xml = False
00096 self.di_dict = {}
00097
00098
00099 self._resultDict = {}
00100
00101
00102 self._as = {}
00103
00104
00105 self.server_name = {}
00106
00107
00108 self.setup_topic_data()
00109
00110
00111 bridge_library.add_event((self.adapter, self.action_list, self.di_dict, True))
00112
00113
00114 rospy.loginfo('Start the Robot Link adapter')
00115 self.adapter.start()
00116
00117
00118 while True:
00119 try:
00120 self.conn = HTTPConnection(self.url, self.url_port)
00121 response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current"))
00122 body = response.read()
00123 break
00124 except socket.error as e:
00125 rospy.loginfo('HTTP connection error %s' % e)
00126 time.sleep(10)
00127
00128
00129 seq, elements = bridge_library.xml_components(body, self.ns, self.action_list)
00130
00131
00132 response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq))
00133
00134
00135 self.XML_queue = Queue()
00136
00137
00138 lp = LongPull(response)
00139 xml_thread = Thread(target = lp.long_pull, args = (self.xml_callback,))
00140 xml_thread.daemon = True
00141 xml_thread.start()
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 def setup_topic_data(self):
00155 for package, action in self.config.items():
00156 if package not in self.msg_parameters:
00157
00158 if package not in self.lib_manifests:
00159 roslib.load_manifest(package)
00160 self.lib_manifests.append(package)
00161
00162
00163 rospy.loginfo('Importing --> ' + package + '.msg')
00164 self.type_handle = import_module(package + '.msg')
00165
00166
00167 for request in action:
00168
00169 self.action_list[request] = request
00170
00171
00172 di_conv = bridge_library.split_event(request)
00173 self.server_name[di_conv] = request
00174
00175
00176 request_class = getattr(self.type_handle, request + 'Result')
00177 self._resultDict[request] = request_class()
00178
00179
00180 action_class = getattr(self.type_handle, request + 'Action')
00181
00182
00183 self._as[request] = actionlib.SimpleActionServer(request + 'Client', action_class, self.execute_cb, False)
00184
00185
00186 self._as[request].start()
00187 return
00188
00189
00190
00191
00192
00193
00194
00195 def execute_cb(self, goal):
00196
00197 action = goal.__slots__[0]
00198
00199
00200 rospy.loginfo('In %s Callback -- determining action request result.' % self.server_name[action])
00201
00202
00203
00204
00205 tokens = re.findall(r'([A-Z][a-z]*)', self.server_name[action])
00206 tokenlist = [val.upper() for val in tokens]
00207 di_tag = tokenlist[0] + '_' + tokenlist[1]
00208
00209
00210 check_response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current?path=//DataItem[@type='" + di_tag + "']"))
00211 body = check_response.read()
00212 _, element = bridge_library.xml_components(body, self.ns, {self.server_name[action]:self.server_name[action]})
00213
00214
00215 if element[0].text == 'READY':
00216
00217 bridge_library.action_cb((self.adapter, self.di_dict, action, 'ACTIVE'))
00218
00219 robot_hold = 0
00220
00221
00222 self.capture_xml = True
00223
00224
00225 dwell = True
00226 while dwell == True:
00227 try:
00228
00229 if not self.XML_queue.empty():
00230 chunk = self.XML_queue.get()
00231
00232
00233 root = ElementTree.fromstring(chunk)
00234 element_list = root.findall('.//m:' + self.server_name[action], namespaces = self.ns)
00235 if len(element_list) > 1:
00236 rospy.logdebug('XML --> %s' % chunk)
00237 if element_list:
00238
00239 for element in element_list:
00240 if element.text == 'ACTIVE':
00241
00242 pass
00243
00244
00245 elif element.text == 'COMPLETE' and robot_hold == 0:
00246 bridge_library.action_cb((self.adapter, self.di_dict, action, 'READY'))
00247 robot_hold = 1
00248
00249 elif element.text == 'READY' and robot_hold == 1:
00250 dwell = False
00251 self.capture_xml = False
00252
00253
00254
00255 result_attribute = self._resultDict[self.server_name[action]].__slots__[0]
00256
00257
00258 setattr(self._resultDict[self.server_name[action]], result_attribute, 'READY')
00259
00260
00261 self._as[self.server_name[action]].set_succeeded(self._resultDict[self.server_name[action]])
00262 rospy.loginfo('In %s Callback -- action succeeded.' % self.server_name[action])
00263
00264 elif element.text == 'FAIL':
00265 bridge_library.action_cb((self.adapter, self.di_dict, action, 'FAIL'))
00266 dwell = False
00267 self.capture_xml = False
00268
00269
00270
00271 result_attribute = self._resultDict[self.server_name[action]].__slots__[0]
00272
00273
00274 setattr(self._resultDict[self.server_name[action]], result_attribute, 'FAIL')
00275
00276
00277 self._as[self.server_name[action]].set_aborted(self._resultDict[self.server_name[action]])
00278 rospy.loginfo('In %s Callback -- action aborted by CNC.' % self.server_name[action])
00279
00280
00281 self.XML_queue.task_done()
00282 except rospy.ROSInterruptException:
00283 rospy.loginfo('program interrupted before completion')
00284 else:
00285
00286 result_attribute = self._resultDict[self.server_name[action]].__slots__[0]
00287
00288
00289 setattr(self._resultDict[self.server_name[action]], result_attribute, 'NOT_READY')
00290
00291
00292 self._as[self.server_name[action]].set_aborted(self._resultDict[self.server_name[action]])
00293 rospy.loginfo('In %s Callback -- action aborted, machine tool NOT_READY, FAULTED, or UNAVAILABLE.' % self.server_name[action])
00294 return
00295
00296
00297
00298
00299
00300 def xml_callback(self, chunk):
00301
00302 try:
00303 if self.capture_xml == True:
00304 self.XML_queue.put(chunk)
00305 if self.XML_queue.qsize() > 1:
00306 rospy.logdebug('STORED XML INTO QUEUE, WAITING ON ROS ACTION SERVER, QUEUE SIZE --> %s' % self.XML_queue.qsize())
00307 except Exception as e:
00308 rospy.logerr("Bridge Server: Process XML callback failed: %s, releasing lock" % e)
00309 finally:
00310 pass
00311
00312 return
00313
00314 if __name__ == '__main__':
00315 try:
00316 rospy.loginfo('Started Generic Action Server')
00317 robot_action = GenericActionServer()
00318 rospy.spin()
00319 except rospy.ROSInterruptException:
00320 rospy.loginfo('program interrupted before completion')
00321 xml_thread.join()