def xml_callback(self, chunk): #rospy.loginfo('*******************In PROCESS_XML callback***************') self.lock.acquire() try: # Only grab XML elements for machine tool action requests _, elements, self.action_goals = bridge_library.xml_components(chunk, self.ns, self.action_list, get_goal = True, action_goals = self.action_goals) if elements: # Check for existing handshake, execute it first if self.handshake: for e in elements: if self.handshake == e.attrib['name'] and e.text == 'READY': # Send hand shake signal bridge_library.action_cb((self.adapter, self.di_dict, e.attrib['name'], 'READY')) self.handshake = None elements.remove(e) if self.handshake != None: rospy.logerr('DID NOT RECEIVE READY HANDSHAKE FROM MACHINE TOOL') # Process remaining action requests for e in elements: # Remove XML namespace string from the element tag for hash tables action_text = re.findall(r'(?<=\})\w+',e.tag)[0] # Check if machine tool is requesting an action, if so, run action client if e.text == 'ACTIVE': self.handshake = self.action_client((action_text, self.action_goals[action_text], self.type_handle)) #self.handshake = e.attrib['name'] except Exception as e: rospy.logerr("Generic Action Client: Process XML callback failed: %s, releasing lock" % e) finally: self.lock.release() #rospy.loginfo('*******************Done with PROCESS_XML callback***************') return
def xml_callback(self, chunk): #rospy.loginfo('*******************In PROCESS_XML callback***************') self.lock.acquire() try: # Only grab XML elements for machine tool action requests _, elements, self.action_goals = bridge_library.xml_components( chunk, self.ns, self.action_list, get_goal=True, action_goals=self.action_goals) if elements: # Check for existing handshake, execute it first if self.handshake: for e in elements: if self.handshake == e.attrib[ 'name'] and e.text == 'READY': # Send hand shake signal bridge_library.action_cb( (self.adapter, self.di_dict, e.attrib['name'], 'READY')) self.handshake = None elements.remove(e) if self.handshake != None: rospy.logerr( 'DID NOT RECEIVE READY HANDSHAKE FROM MACHINE TOOL' ) # Process remaining action requests for e in elements: # Remove XML namespace string from the element tag for hash tables action_text = re.findall(r'(?<=\})\w+', e.tag)[0] # Check if machine tool is requesting an action, if so, run action client if e.text == 'ACTIVE': self.handshake = self.action_client( (action_text, self.action_goals[action_text], self.type_handle)) #self.handshake = e.attrib['name'] except Exception as e: rospy.logerr( "Generic Action Client: Process XML callback failed: %s, releasing lock" % e) finally: self.lock.release() #rospy.loginfo('*******************Done with PROCESS_XML callback***************') return
def process_xml(self, xml): nextSeq, elements = bridge_library.xml_components(xml, self.ns, self.di_current) # Create local data item dictionary to track event changes local_di = self.init_di_dict() # Loop through XML elements, update the di_changed and di_current di_list = [di_val for di_list in self.data_items for di_val in di_list] if elements: rospy.logdebug('***********XML -->*************\n%s' % xml) for e in elements: for d_item in di_list: if e.attrib['name'] == bridge_library.split_event(d_item): local_di[d_item] = e.text self.di_current[d_item] = e.text # Update di_current with new state break return nextSeq, local_di
def __init__(self): # Initialize ROS generic client node rospy.init_node('ActionClient') # Setup MTConnect to ROS Conversion self.config = bridge_library.obtain_dataMap() self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace', 'adapter_port', 'service'] self.url = self.config[self.msg_parameters[0]] self.url_port = self.config[self.msg_parameters[1]] self.mtool = self.config[self.msg_parameters[2]] self.ns = dict(m = self.config[self.msg_parameters[3]]) self.port = self.config[self.msg_parameters[4]] self.service = self.config[self.msg_parameters[5]] # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1,self.url,self.url_port)) # Setup MTConnect Adapter for robot status data items self.adapter = Adapter((self.url, self.port)) # Create empty lists for actions, message type handles, etc. self.lib_manifests = [] self.type_handle = None self.action_list = {} self.action_goals = {} self.package = None self.xml_goal = None self.di_dict = {} # XML data item dictionary to store MTConnect Adapter Events self.handshake = None # Setup action client data per the config file self.setup_topic_data() # Add data items to the MTConnect Adapter - must be unique data items bridge_library.add_event((self.adapter, self.action_list, self.di_dict, False)) # Start the adapter rospy.loginfo('Start the Robot Link adapter') self.adapter.start() # Create robot Service Server thread for each machine tool action self.action_service = [] for mt_action in self.action_goals.keys(): self.action_service.append(ActionService(mt_action, self.adapter, self.di_dict, self.service_handle, self.service)) # Establish XML connection, read in current XML while True: try: self.conn = HTTPConnection(self.url, self.url_port) response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current")) body = response.read() break except socket.error as e: rospy.loginfo('HTTP connection error %s' % e) time.sleep(10) # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(body, self.ns, self.action_list) # Start a streaming XML connection response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq)) # Create class lock self.lock = thread.allocate_lock() # Create XML polling thread lp = LongPull(response) lp.long_pull(self.xml_callback) # Runs until user interrupts
def __init__(self): # Initialize the ROS publisher node rospy.init_node('bridge_publisher') # Setup MTConnect to ROS Conversion self.config = bridge_library.obtain_dataMap() self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace'] self.url = self.config[self.msg_parameters[0]] self.url_port = self.config[self.msg_parameters[1]] self.mtool = self.config[self.msg_parameters[2]] self.ns = dict(m = self.config[self.msg_parameters[3]]) # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1,self.url,self.url_port)) # Create the data lists for the topic names, types, manifests, data items, ROS publishers, and ROS messages self.topic_name_list = [] self.topic_type_list = [] self.lib_manifests = [] self.data_items = [] self.pub = [] self.msg = [] self.data_hold = None # Setup topic, data items, pub, etc. via configuration file self.setup_topic_data() # Hash table of persistent CNC event states, only updates when state changes self.di_current = self.init_di_dict() # Hash table to store changed CNC event states self.di_changed = None # Establish XML connection, read in current XML while True: try: self.conn = HTTPConnection(self.url, self.url_port) response = bridge_library.xml_get_response((self.url, self.url_port, None, self.conn, self.mtool + "/current")) body = response.read() break except socket.error as e: rospy.loginfo('HTTP connection error %s' % e) time.sleep(10) # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(body, self.ns, self.di_current) # Use XML to establish current data item state dictionary for di in self.di_current.keys(): name = bridge_library.split_event(di) for e in elements: rospy.loginfo('Element %s --> %s' % (e.tag, e.text)) if name == e.attrib['name']: self.di_current[di] = e.text # Confirm that data items in config file are present in XML for di_set in self.data_items: if not set(di_set).issubset(set(self.di_current.keys())): rospy.logerr('ERROR: INCORRECT EVENTS IN TOPIC CONFIG OR XML AGENT FILE') sys.exit() # Start a streaming XML connection response = bridge_library.xml_get_response((self.url, self.url_port, None, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq)) # Create queue for streaming XML self.XML_queue = Queue() # Create a ROS publishing thread self.ros_publisher() # Streams data from the agent... lp = LongPull(response) lp.long_pull(self.xml_callback) # Runs until user interrupts
def __init__(self): # Initialize ROS generic client node rospy.init_node('ActionClient') # Setup MTConnect to ROS Conversion self.config = bridge_library.obtain_dataMap() self.msg_parameters = [ 'url', 'url_port', 'machine_tool', 'xml_namespace', 'adapter_port', 'service' ] self.url = self.config[self.msg_parameters[0]] self.url_port = self.config[self.msg_parameters[1]] self.mtool = self.config[self.msg_parameters[2]] self.ns = dict(m=self.config[self.msg_parameters[3]]) self.port = self.config[self.msg_parameters[4]] self.service = self.config[self.msg_parameters[5]] # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1, self.url, self.url_port)) # Setup MTConnect Adapter for robot status data items self.adapter = Adapter((self.url, self.port)) # Create empty lists for actions, message type handles, etc. self.lib_manifests = [] self.type_handle = None self.action_list = {} self.action_goals = {} self.package = None self.xml_goal = None self.di_dict = { } # XML data item dictionary to store MTConnect Adapter Events self.handshake = None # Setup action client data per the config file self.setup_topic_data() # Add data items to the MTConnect Adapter - must be unique data items bridge_library.add_event( (self.adapter, self.action_list, self.di_dict, False)) # Start the adapter rospy.loginfo('Start the Robot Link adapter') self.adapter.start() # Create robot Service Server thread for each machine tool action self.action_service = [] for mt_action in self.action_goals.keys(): self.action_service.append( ActionService(mt_action, self.adapter, self.di_dict, self.service_handle, self.service)) # Establish XML connection, read in current XML while True: try: self.conn = HTTPConnection(self.url, self.url_port) response = bridge_library.xml_get_response( (self.url, self.url_port, self.port, self.conn, self.mtool + "/current")) body = response.read() break except socket.error as e: rospy.loginfo('HTTP connection error %s' % e) time.sleep(10) # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(body, self.ns, self.action_list) # Start a streaming XML connection response = bridge_library.xml_get_response( (self.url, self.url_port, self.port, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq)) # Create class lock self.lock = thread.allocate_lock() # Create XML polling thread lp = LongPull(response) lp.long_pull(self.xml_callback) # Runs until user interrupts
def __init__(self): # Initialize ROS generic client node rospy.init_node('robot_link') # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1, 'localhost', 5000)) bridge_library.check_connectivity((1, 'localhost', 5001)) # Global variables self.XML_CNC_queue = Queue() self.XML_RBT_queue = Queue() self.cnc_capture_xml = True self.rbt_capture_xml = True self.cnc_conn = httplib.HTTPConnection('localhost', 5000) self.rbt_conn = httplib.HTTPConnection('localhost', 5001) self.ns = dict(m = 'urn:mtconnect.org:MTConnectStreams:1.2') self.data_items = {'MaterialLoad' : 'MaterialLoad', 'MaterialUnload' : 'MaterialUnload'} # Establish CNC XML connection, read in current XML cnc_response = bridge_library.xml_get_response(('localhost', 5000, None, self.cnc_conn, "/cnc/current")) cnc_body = cnc_response.read() # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(cnc_body, self.ns, self.data_items) # Start a streaming XML connection cnc_response = bridge_library.xml_get_response(('localhost', 5000, None, self.cnc_conn, "/cnc/sample?interval=1000&count=1000&from=" + seq)) # Create CNC XML polling thread cnc_lp = LongPull(cnc_response) self.cnc_thread = threading.Thread(target = cnc_lp.long_pull, args = (self.cnc_xml_callback,)) self.cnc_thread.daemon = True self.cnc_thread.start() rospy.loginfo('STARTED STREAMING CNC XML THREAD') # Establish Robot XML connection, read in current XML rbt_response = bridge_library.xml_get_response(('localhost', 5001, None, self.rbt_conn, "/Robot/current")) rbt_body = rbt_response.read() # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(rbt_body, self.ns, self.data_items) # Start a streaming XML connection rbt_response = bridge_library.xml_get_response(('localhost', 5001, None, self.rbt_conn, "/Robot/sample?interval=1000&count=1000&from=" + seq)) # Create Robot XML polling thread rbt_lp = LongPull(rbt_response) self.rbt_thread = threading.Thread(target = rbt_lp.long_pull, args = (self.rbt_xml_callback,)) self.rbt_thread.daemon = True self.rbt_thread.start() rospy.loginfo('STARTED STREAMING ROBOT XML THREAD') # Create robot initialization publisher thread self.t1 = threading.Thread(target = self.talker) self.t1.daemon = True self.t1.start() rospy.loginfo('STARTED ROBOT INITIALIZATION THREAD') # Create state sequence thread self.t2 = threading.Thread(target = self.run_actions) self.t2.daemon = True self.t2.start() rospy.loginfo('STARTED STATE MACHINE THREAD')
def __init__(self): # Initialize ROS generic client node rospy.init_node('robot_link') # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1, 'localhost', 5000)) bridge_library.check_connectivity((1, 'localhost', 5001)) # Global variables self.XML_CNC_queue = Queue() self.XML_RBT_queue = Queue() self.cnc_capture_xml = True self.rbt_capture_xml = True self.cnc_conn = httplib.HTTPConnection('localhost', 5000) self.rbt_conn = httplib.HTTPConnection('localhost', 5001) self.ns = dict(m='urn:mtconnect.org:MTConnectStreams:1.2') self.data_items = { 'MaterialLoad': 'MaterialLoad', 'MaterialUnload': 'MaterialUnload' } # Establish CNC XML connection, read in current XML cnc_response = bridge_library.xml_get_response( ('localhost', 5000, None, self.cnc_conn, "/cnc/current")) cnc_body = cnc_response.read() # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(cnc_body, self.ns, self.data_items) # Start a streaming XML connection cnc_response = bridge_library.xml_get_response( ('localhost', 5000, None, self.cnc_conn, "/cnc/sample?interval=1000&count=1000&from=" + seq)) # Create CNC XML polling thread cnc_lp = LongPull(cnc_response) self.cnc_thread = threading.Thread(target=cnc_lp.long_pull, args=(self.cnc_xml_callback, )) self.cnc_thread.daemon = True self.cnc_thread.start() rospy.loginfo('STARTED STREAMING CNC XML THREAD') # Establish Robot XML connection, read in current XML rbt_response = bridge_library.xml_get_response( ('localhost', 5001, None, self.rbt_conn, "/Robot/current")) rbt_body = rbt_response.read() # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(rbt_body, self.ns, self.data_items) # Start a streaming XML connection rbt_response = bridge_library.xml_get_response( ('localhost', 5001, None, self.rbt_conn, "/Robot/sample?interval=1000&count=1000&from=" + seq)) # Create Robot XML polling thread rbt_lp = LongPull(rbt_response) self.rbt_thread = threading.Thread(target=rbt_lp.long_pull, args=(self.rbt_xml_callback, )) self.rbt_thread.daemon = True self.rbt_thread.start() rospy.loginfo('STARTED STREAMING ROBOT XML THREAD') # Create robot initialization publisher thread self.t1 = threading.Thread(target=self.talker) self.t1.daemon = True self.t1.start() rospy.loginfo('STARTED ROBOT INITIALIZATION THREAD') # Create state sequence thread self.t2 = threading.Thread(target=self.run_actions) self.t2.daemon = True self.t2.start() rospy.loginfo('STARTED STATE MACHINE THREAD')
def __init__(self): # Initialize ROS generic client node rospy.init_node('ActionServer') # Setup MTConnect to ROS Conversion self.config = bridge_library.obtain_dataMap() self.msg_parameters = ['url', 'url_port', 'machine_tool', 'xml_namespace', 'adapter_port'] self.url = self.config[self.msg_parameters[0]] self.url_port = self.config[self.msg_parameters[1]] self.mtool = self.config[self.msg_parameters[2]] self.ns = dict(m = self.config[self.msg_parameters[3]]) self.port = self.config[self.msg_parameters[4]] # Check for url connectivity, dwell until system timeout bridge_library.check_connectivity((1,self.url,self.url_port)) # Setup MTConnect Adapter for robot status data items self.adapter = Adapter((self.url, self.port)) # Create empty lists for actions, message type handles, etc. self.lib_manifests = [] self.type_handle = None self.action_list = {} self.capture_xml = False self.di_dict = {} # XML data item dictionary to store MTConnect Adapter Events # Create a dictionary of _results to return upon action success self._resultDict = {} # Create a dictionary of action servers self._as = {} # Create a dictionary of server names self.server_name = {} # Setup action client data per the config file self.setup_topic_data() # Add data items to the MTConnect Adapter - must be unique data items bridge_library.add_event((self.adapter, self.action_list, self.di_dict, True)) # Start the adapter rospy.loginfo('Start the Robot Link adapter') self.adapter.start() # Establish XML connection, read in current XML while True: try: self.conn = HTTPConnection(self.url, self.url_port) response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current")) body = response.read() break except socket.error as e: rospy.loginfo('HTTP connection error %s' % e) time.sleep(10) # Parse the XML and determine the current sequence and XML Event elements seq, elements = bridge_library.xml_components(body, self.ns, self.action_list) # Start a streaming XML connection response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/sample?interval=1000&count=1000&from=" + seq)) # Create queue for streaming XML self.XML_queue = Queue() # Create XML polling thread lp = LongPull(response) xml_thread = Thread(target = lp.long_pull, args = (self.xml_callback,)) xml_thread.daemon = True xml_thread.start()
def execute_cb(self, goal): # If goal is OpenDoor, use the goal defined in the message as your key, access it as goal.__slots__[0] action = goal.__slots__[0] # Empty function -- assumes action was successful rospy.loginfo('In %s Callback -- determining action request result.' % self.server_name[action]) # Check to make sure machine tool is READY, if not, ABORT the robot action request # Change to XML Tag format tokens = re.findall(r'([A-Z][a-z]*)', self.server_name[action]) tokenlist = [val.upper() for val in tokens] di_tag = tokenlist[0] + '_' + tokenlist[1] # Check current status of XML Tag check_response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, self.mtool + "/current?path=//DataItem[@type='" + di_tag + "']")) body = check_response.read() _, element = bridge_library.xml_components(body, self.ns, {self.server_name[action]:self.server_name[action]}) # Complete the action request if element[0].text == 'READY': # Execute the action request # Submit goal value to MTConnect via agent (i.e. goal.open_door = 'ACTIVE') bridge_library.action_cb((self.adapter, self.di_dict, action, 'ACTIVE')) robot_hold = 0 # Used to make sure you only change robot state once after 'COMPLETE' received from CNC # Start capturing XML self.capture_xml = True # While loop to poll CNC XML until READY is received for Robot action request dwell = True while dwell == True: try: # Obtain XML chunk if not self.XML_queue.empty(): chunk = self.XML_queue.get() # Parse the XML and determine the current sequence and XML Event elements root = ElementTree.fromstring(chunk) element_list = root.findall('.//m:' + self.server_name[action], namespaces = self.ns) if len(element_list) > 1: rospy.logdebug('XML --> %s' % chunk) if element_list: # Must iterate -- multiple elements possible for a single tag for element in element_list: if element.text == 'ACTIVE': # Set accepted back to action client pass # While polling monitor CNC response for COMPLETE, submit READY handshake elif element.text == 'COMPLETE' and robot_hold == 0: bridge_library.action_cb((self.adapter, self.di_dict, action, 'READY')) robot_hold = 1 elif element.text == 'READY' and robot_hold == 1: dwell = False self.capture_xml = False # When response is READY, set server result and communicate as below: # Extract action attribute result_attribute = self._resultDict[self.server_name[action]].__slots__[0] # Set the attribute per the ROS to MTConnect conversion setattr(self._resultDict[self.server_name[action]], result_attribute, 'READY') # Indicate a successful action self._as[self.server_name[action]].set_succeeded(self._resultDict[self.server_name[action]]) rospy.loginfo('In %s Callback -- action succeeded.' % self.server_name[action]) elif element.text == 'FAIL': bridge_library.action_cb((self.adapter, self.di_dict, action, 'FAIL')) dwell = False self.capture_xml = False # When response is FAIL, set server result and communicate as below: # Extract action attribute. For CNC Actions, only one result --> i.e. OpenDoorResult.__slots__[0] = 'door_ready' result_attribute = self._resultDict[self.server_name[action]].__slots__[0] # Set the attribute per the ROS to MTConnect conversion setattr(self._resultDict[self.server_name[action]], result_attribute, 'FAIL') # Indicate an aborted action self._as[self.server_name[action]].set_aborted(self._resultDict[self.server_name[action]]) rospy.loginfo('In %s Callback -- action aborted by CNC.' % self.server_name[action]) # Release the queue self.XML_queue.task_done() except rospy.ROSInterruptException: rospy.loginfo('program interrupted before completion') else: # Abort the action request, machine tool not ready or faulted # Extract action attribute. For CNC Actions, only one result --> i.e. OpenDoorResult.__slots__[0] = 'door_ready' result_attribute = self._resultDict[self.server_name[action]].__slots__[0] # Set the attribute per the ROS to MTConnect conversion setattr(self._resultDict[self.server_name[action]], result_attribute, 'NOT_READY') # Indicate an aborted action self._as[self.server_name[action]].set_aborted(self._resultDict[self.server_name[action]]) rospy.loginfo('In %s Callback -- action aborted, machine tool NOT_READY, FAULTED, or UNAVAILABLE.' % self.server_name[action]) return