robot_sim.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
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 # Import standard Python modules
00020 import sys
00021 import os
00022 from Queue import Queue
00023 from threading import Thread, Timer
00024 from xml.etree import ElementTree
00025 import threading
00026 import time
00027 import urllib2
00028 import httplib
00029 import socket
00030 
00031 # Import custom ROS-MTConnect function library
00032 import bridge_library
00033 
00034 # Import custom Python modules for MTConnect Adapter interface
00035 path, file = os.path.split(__file__)
00036 sys.path.append(os.path.realpath(path) + '/src')
00037 from long_pull import LongPull
00038 
00039 # Import ROS Python Modules, and ROS mtconnect_msgs package
00040 import roslib
00041 roslib.load_manifest('mtconnect_msgs')
00042 import rospy
00043 import mtconnect_msgs.msg
00044 
00045 # Import Custom Action Clients
00046 import closechuck
00047 import closedoor
00048 import opendoor
00049 import openchuck
00050 
00051 class RobotSim():
00052     def __init__(self):
00053         # Initialize ROS generic client node
00054         rospy.init_node('robot_link')
00055         
00056         # Check for url connectivity, dwell until system timeout
00057         bridge_library.check_connectivity((1, 'localhost', 5000))
00058         bridge_library.check_connectivity((1, 'localhost', 5001))
00059         
00060         # Global variables
00061         self.XML_CNC_queue = Queue()
00062         self.XML_RBT_queue = Queue()
00063         self.cnc_capture_xml = True
00064         self.rbt_capture_xml = True
00065         self.cnc_conn = httplib.HTTPConnection('localhost', 5000)
00066         self.rbt_conn = httplib.HTTPConnection('localhost', 5001)
00067         self.ns = dict(m = 'urn:mtconnect.org:MTConnectStreams:1.2')
00068         self.data_items = {'MaterialLoad' : 'MaterialLoad', 'MaterialUnload' : 'MaterialUnload'}
00069         
00070         # Establish CNC XML connection, read in current XML
00071         cnc_response = bridge_library.xml_get_response(('localhost', 5000, None, self.cnc_conn, "/cnc/current"))
00072         cnc_body = cnc_response.read()
00073         
00074         # Parse the XML and determine the current sequence and XML Event elements
00075         seq, elements = bridge_library.xml_components(cnc_body, self.ns, self.data_items)
00076         
00077         # Start a streaming XML connection
00078         cnc_response = bridge_library.xml_get_response(('localhost', 5000, None, self.cnc_conn, "/cnc/sample?interval=1000&count=1000&from=" + seq))
00079         
00080         # Create CNC XML polling thread
00081         cnc_lp = LongPull(cnc_response)
00082         self.cnc_thread = threading.Thread(target = cnc_lp.long_pull, args = (self.cnc_xml_callback,))
00083         self.cnc_thread.daemon = True
00084         self.cnc_thread.start()
00085         rospy.loginfo('STARTED STREAMING CNC XML THREAD')
00086         
00087         # Establish Robot XML connection, read in current XML
00088         rbt_response = bridge_library.xml_get_response(('localhost', 5001, None, self.rbt_conn, "/Robot/current"))
00089         rbt_body = rbt_response.read()
00090         
00091         # Parse the XML and determine the current sequence and XML Event elements
00092         seq, elements = bridge_library.xml_components(rbt_body, self.ns, self.data_items)
00093         
00094         # Start a streaming XML connection
00095         rbt_response = bridge_library.xml_get_response(('localhost', 5001, None, self.rbt_conn, "/Robot/sample?interval=1000&count=1000&from=" + seq))
00096         
00097         # Create Robot XML polling thread
00098         rbt_lp = LongPull(rbt_response)
00099         self.rbt_thread = threading.Thread(target = rbt_lp.long_pull, args = (self.rbt_xml_callback,))
00100         self.rbt_thread.daemon = True
00101         self.rbt_thread.start()
00102         rospy.loginfo('STARTED STREAMING ROBOT XML THREAD')
00103         
00104         # Create robot initialization publisher thread
00105         self.t1 = threading.Thread(target = self.talker)
00106         self.t1.daemon = True
00107         self.t1.start()
00108         rospy.loginfo('STARTED ROBOT INITIALIZATION THREAD')
00109         
00110         # Create state sequence thread
00111         self.t2 = threading.Thread(target = self.run_actions)
00112         self.t2.daemon = True
00113         self.t2.start()
00114         rospy.loginfo('STARTED STATE MACHINE THREAD')
00115 
00116     def stop_thread(self):
00117         self.t1.join()
00118         self.t2.join()
00119         self.cnc_thread.join()
00120         self.rbt_thread.join()
00121         return
00122  
00123     def talker(self):
00124         rospy.loginfo('Starting ROS Robot State Publisher Thread')
00125         pub1 = rospy.Publisher('RobotStateTopic', mtconnect_msgs.msg.RobotStates)
00126         pub2 = rospy.Publisher('RobotSpindleTopic', mtconnect_msgs.msg.RobotSpindle)
00127     
00128         msg1 = mtconnect_msgs.msg.RobotStates()
00129         msg2 = mtconnect_msgs.msg.RobotSpindle()
00130         
00131         while not rospy.is_shutdown():
00132             msg1.header.stamp = rospy.Time.now()
00133             msg1.avail.val = 1 # Available
00134             msg1.mode.val = 2 # Automatic
00135             msg1.rexec.val = 1 # Active
00136             
00137             msg2.c_unclamp.val = 1
00138             msg2.s_inter.val = 1
00139     
00140             pub1.publish(msg1)
00141             pub2.publish(msg2)
00142         return
00143 
00144     def run_actions(self):
00145         rospy.loginfo('Starting Robot State Machine Thread')
00146         cnc_state = None
00147         robot_state = None
00148         sequence = None
00149         
00150         while True:
00151             # Determine if CNC is in MaterialLoad or MaterialUnload sequence
00152             if not self.XML_CNC_queue.empty():
00153                 cnc_body = self.XML_CNC_queue.get()
00154                 cnc_root = ElementTree.fromstring(cnc_body)
00155                 tokenML = cnc_root.findall('.//m:MaterialLoad', namespaces = self.ns)
00156                 tokenMUL = cnc_root.findall('.//m:MaterialUnload', namespaces = self.ns)
00157                 
00158                 if tokenML and tokenML[0].text == 'ACTIVE':
00159                     if sequence is None:
00160                         sequence = 'MaterialLoad'
00161                     cnc_state = tokenML[0].text
00162                     self.cnc_capture_xml = False
00163                     rospy.loginfo('CNC XML %s --> %s' % (sequence, tokenML[0].text))
00164                 elif tokenMUL and tokenMUL[0].text == 'ACTIVE':
00165                     if sequence is None:
00166                         sequence = 'MaterialUnload'
00167                     cnc_state = tokenMUL[0].text
00168                     self.cnc_capture_xml = False
00169                     rospy.loginfo('CNC XML %s --> %s' % (sequence, tokenMUL[0].text))
00170                 
00171                 # Release the queue
00172                 self.XML_CNC_queue.task_done()
00173                 
00174             
00175             # Determine if the ROBOT has acknowledged the MaterialLoad or MaterialUnload sequence
00176             if not self.XML_RBT_queue.empty():
00177                 rbt_body = self.XML_RBT_queue.get()
00178                 rbt_root = ElementTree.fromstring(rbt_body)
00179                 tokenML = rbt_root.findall('.//m:MaterialLoad', namespaces = self.ns)
00180                 tokenMUL = rbt_root.findall('.//m:MaterialUnload', namespaces = self.ns)
00181                 
00182                 if tokenML and tokenML[0].text == 'ACTIVE':
00183                     if sequence is None:
00184                         sequence = 'MaterialLoad'
00185                     robot_state = tokenML[0].text
00186                     self.rbt_capture_xml = False
00187                     rospy.loginfo('ROBOT XML %s --> %s' % (sequence, tokenML[0].text))
00188                 elif tokenMUL and tokenMUL[0].text == 'ACTIVE':
00189                     if sequence is None:
00190                         sequence = 'MaterialUnload'
00191                     robot_state = tokenMUL[0].text
00192                     self.rbt_capture_xml = False
00193                     rospy.loginfo('ROBOT XML %s --> %s' % (sequence, tokenMUL[0].text))
00194                 
00195                 self.XML_RBT_queue.task_done()
00196             
00197             # If material load for both devices is ACTIVE, start chuck & door close sequence
00198             if cnc_state == 'ACTIVE' and robot_state == 'ACTIVE' and sequence == 'MaterialLoad':
00199                 rospy.loginfo('Starting Action Clients required by Material Load')
00200                 
00201                 # launch close chuck action client
00202                 #opendoor.open_door_client()
00203                 #rospy.loginfo('OpenDoor Action Completed')
00204                 closechuck.close_chuck_client()
00205                 rospy.loginfo('CloseChuck Action Completed')
00206                 
00207                 # start capturing XML again
00208                 self.cnc_capture_xml = True
00209                 self.rbt_capture_xml = True
00210                 
00211                 # launch close door action client
00212                 closedoor.close_door_client()
00213                 rospy.loginfo('CloseDoor Action Completed')
00214                 
00215                 # reset state variables
00216                 cnc_state = None
00217                 robot_state = None
00218                 sequence = None
00219             
00220             # If material unload for both devices is ACTIVE, start chuck & door open sequence
00221             if cnc_state == 'ACTIVE' and robot_state == 'ACTIVE' and sequence == 'MaterialUnload':
00222                 rospy.loginfo('Starting Action Clients required by Material Unload')
00223                 
00224                 # launch open door action client
00225                 opendoor.open_door_client()
00226                 rospy.loginfo('OpenDoor Action Completed')
00227                 
00228                 # start capturing XML again
00229                 self.cnc_capture_xml = True
00230                 self.rbt_capture_xml = True
00231                 
00232                 # launch open chuck action client
00233                 openchuck.open_chuck_client()
00234                 rospy.loginfo('OpenChuck Action Completed')
00235                 
00236                 # reset state variables
00237                 cnc_state = None
00238                 robot_state = None
00239                 sequence = None
00240                 
00241                 # allow time for CNC state machine to initialize
00242                 time.sleep(5)
00243         return
00244 
00245     def cnc_xml_callback(self, chunk):
00246         #rospy.loginfo('*******************In CNC XML Queue callback***************')
00247         if self.cnc_capture_xml == True:
00248             try:
00249                 self.XML_CNC_queue.put(chunk)
00250                 rospy.loginfo('PUTTING CNC XML INTO QUEUE. NUMBER OF QUEUED OBJECTS %s' % self.XML_CNC_queue.qsize())
00251                 if self.XML_CNC_queue.qsize() > 1:
00252                     rospy.loginfo('STORED CNC XML INTO QUEUE, WAITING ON ROS ACTION SERVER, QUEUE SIZE --> %s' % self.XML_CNC_queue.qsize())
00253             except Exception as e:
00254                 rospy.logerr("Robot Simulation: CNC XML Queue callback failed: %s, releasing lock" % e)
00255             finally:
00256                 pass
00257         #rospy.loginfo('*******************Done with CNC XML Queue callback***************')
00258         return
00259     
00260     def rbt_xml_callback(self, chunk):
00261         #rospy.loginfo('*******************In ROBOT XML Queue callback***************')
00262         if self.rbt_capture_xml == True:
00263             try:
00264                 self.XML_RBT_queue.put(chunk)
00265                 rospy.loginfo('PUTTING ROBOT XML INTO QUEUE. NUMBER OF QUEUED OBJECTS %s' % self.XML_RBT_queue.qsize())
00266                 if self.XML_RBT_queue.qsize() > 1:
00267                     rospy.loginfo('STORED ROBOT XML INTO QUEUE, WAITING ON ROS ACTION SERVER, QUEUE SIZE --> %s' % self.XML_RBT_queue.qsize())
00268             except Exception as e:
00269                 rospy.logerr("Robot Simulation: ROBOT XML Queue callback failed: %s, releasing lock" % e)
00270             finally:
00271                 pass
00272         #rospy.loginfo('*******************Done with ROBOT XML Queue callback***************')
00273         return
00274 
00275     
00276 if __name__ == '__main__':
00277     try:
00278         rospy.loginfo('Launching robot_link node, CTRL-C to terminate')
00279         simulator = RobotSim()
00280         rospy.spin()
00281     except rospy.ROSInterruptException:
00282         RobotSim.stop_thread()


mtconnect_ros_bridge
Author(s): Stephen L. Wiedmann
autogenerated on Mon Jan 6 2014 11:30:45