예제 #1
0
    def action_client(self, cb_data):
        # Execute ROS Action
        rospy.init_node('ActionClient')
        
        # Unpack action client data
        name, goals, handle = cb_data
        rospy.loginfo('Launched %s Action CLient' % name)
        
        # Creates the SimpleActionClient, passing the type of the action (MaterialLoadAction) to the constructor.
        # i.e. name = 'MaterialLoad', action_type = mtconnect_msgs.msg.MaterialLoadAction
        action_type = getattr(handle, name + 'Action')
        client = actionlib.SimpleActionClient(name + 'Client', action_type)
        
        # Waits until the action server has started up and started listening for goals.
        rospy.loginfo('Waiting for %s Dedicated Action Server' % name)
        client.wait_for_server()
        rospy.loginfo('%s Dedicated Action Server Activated' % name)

        # Creates a MaterialLoad goal to send to the action server.
        # i.e. goal = mtconnect_msgs.msg.MaterialLoad()
        goal_handle = getattr(handle, name + 'Goal')
        goal = goal_handle()
        
        # Check to make sure the action goal has been set
        if self.action_goals[name] == None:
            # Ping the current url for the goal Event
            goal_tag = self.action_list[name].keys()[0]
            response = bridge_library.xml_get_response((self.url, self.url_port, self.port, self.conn, 
                                                        self.mtool + "/current?path=//DataItem[@type='" + goal_tag.upper() +"']"))
            body = response.read()
            root = ElementTree.fromstring(body)

            # Set the action goals
            self.action_goals = bridge_library.set_goal(name, self.action_list[name], root, self.ns, self.action_goals)
            
        # Check goal source for required attributes
        for attrib, attrib_type, action_goal in zip(goal_handle.__slots__, goal_handle._slot_types, self.action_goals[name]):
            if bridge_library.type_check(attrib_type, action_goal) == False:
                rospy.logerr('INCOMPATIBLE GOAL TYPES ROS MSG: %s --> XML: %s' % (attrib_type, type(action_goal)))
                sys.exit()
        
        # Set the goal attributes from XML data
        try:
            for attrib, xml_goal in zip(goal_handle.__slots__, self.action_goals[name]):
                setattr(goal, attrib, xml_goal)
        except Exception as e:
            rospy.logerr("ROS Action %s Client failed: %s" % (name, e))
        
        # Sends the goal to the action server.
        rospy.loginfo('Sending the goal')
        name_conv = bridge_library.split_event(name)
        client.send_goal(goal, done_cb = None, active_cb = bridge_library.action_cb((self.adapter, self.di_dict, name_conv, 'ACTIVE')))
        
        
        # Waits for the server to finish performing the action.
        rospy.loginfo('Waiting for result')
        client.wait_for_result()
        
        # Obtain result state
        result = client.get_state()
        
        # Prints out the result of the executing action
        rospy.loginfo('Returning the result --> %s' % result)
        
        # Set the Robot XML data item
        data_item = bridge_library.split_event(name)
        
        # Submit converted result to host via MTConnect adapter
        if result == 3: # SUCCEEDED from actionlib_msgs.msg.GoalStatus
            rospy.loginfo('Sending COMPLETE flag')
            bridge_library.action_cb((self.adapter, self.di_dict, data_item, 'COMPLETE'))
            return name
        elif result == 4: # ABORTED from actionlib_msgs.msg.GoalStatus
            rospy.loginfo('%s ABORTED, terminating action request' % data_item)
            bridge_library.action_cb((self.adapter, self.di_dict, data_item, 'FAIL'))
            return None
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
 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
예제 #5
0
    def action_client(self, cb_data):
        # Execute ROS Action
        rospy.init_node('ActionClient')

        # Unpack action client data
        name, goals, handle = cb_data
        rospy.loginfo('Launched %s Action CLient' % name)

        # Creates the SimpleActionClient, passing the type of the action (MaterialLoadAction) to the constructor.
        # i.e. name = 'MaterialLoad', action_type = mtconnect_msgs.msg.MaterialLoadAction
        action_type = getattr(handle, name + 'Action')
        client = actionlib.SimpleActionClient(name + 'Client', action_type)

        # Waits until the action server has started up and started listening for goals.
        rospy.loginfo('Waiting for %s Dedicated Action Server' % name)
        client.wait_for_server()
        rospy.loginfo('%s Dedicated Action Server Activated' % name)

        # Creates a MaterialLoad goal to send to the action server.
        # i.e. goal = mtconnect_msgs.msg.MaterialLoad()
        goal_handle = getattr(handle, name + 'Goal')
        goal = goal_handle()

        # Check to make sure the action goal has been set
        if self.action_goals[name] == None:
            # Ping the current url for the goal Event
            goal_tag = self.action_list[name].keys()[0]
            response = bridge_library.xml_get_response(
                (self.url, self.url_port, self.port, self.conn, self.mtool +
                 "/current?path=//DataItem[@type='" + goal_tag.upper() + "']"))
            body = response.read()
            root = ElementTree.fromstring(body)

            # Set the action goals
            self.action_goals = bridge_library.set_goal(
                name, self.action_list[name], root, self.ns, self.action_goals)

        # Check goal source for required attributes
        for attrib, attrib_type, action_goal in zip(goal_handle.__slots__,
                                                    goal_handle._slot_types,
                                                    self.action_goals[name]):
            if bridge_library.type_check(attrib_type, action_goal) == False:
                rospy.logerr(
                    'INCOMPATIBLE GOAL TYPES ROS MSG: %s --> XML: %s' %
                    (attrib_type, type(action_goal)))
                sys.exit()

        # Set the goal attributes from XML data
        try:
            for attrib, xml_goal in zip(goal_handle.__slots__,
                                        self.action_goals[name]):
                setattr(goal, attrib, xml_goal)
        except Exception as e:
            rospy.logerr("ROS Action %s Client failed: %s" % (name, e))

        # Sends the goal to the action server.
        rospy.loginfo('Sending the goal')
        name_conv = bridge_library.split_event(name)
        client.send_goal(goal,
                         done_cb=None,
                         active_cb=bridge_library.action_cb(
                             (self.adapter, self.di_dict, name_conv,
                              'ACTIVE')))

        # Waits for the server to finish performing the action.
        rospy.loginfo('Waiting for result')
        client.wait_for_result()

        # Obtain result state
        result = client.get_state()

        # Prints out the result of the executing action
        rospy.loginfo('Returning the result --> %s' % result)

        # Set the Robot XML data item
        data_item = bridge_library.split_event(name)

        # Submit converted result to host via MTConnect adapter
        if result == 3:  # SUCCEEDED from actionlib_msgs.msg.GoalStatus
            rospy.loginfo('Sending COMPLETE flag')
            bridge_library.action_cb(
                (self.adapter, self.di_dict, data_item, 'COMPLETE'))
            return name
        elif result == 4:  # ABORTED from actionlib_msgs.msg.GoalStatus
            rospy.loginfo('%s ABORTED, terminating action request' % data_item)
            bridge_library.action_cb(
                (self.adapter, self.di_dict, data_item, 'FAIL'))
            return None
예제 #6
0
 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')
예제 #7
0
    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')
예제 #8
0
 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()
예제 #9
0
 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