ssm_introspection.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2015 Airbus
00004 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
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 import os
00019 import datetime
00020 
00021 import rospy
00022 
00023 from std_msgs.msg import String, Empty, Bool, Int8
00024 from rosgraph_msgs.msg import Log
00025 
00026 from xml.etree import ElementTree as ET
00027 
00028 from python_qt_binding.QtGui import *
00029 from python_qt_binding.QtCore import *
00030 from python_qt_binding import loadUi
00031 
00032 from airbus_pyqt_extend import QtAgiCore
00033 
00034 from airbus_cobot_gui import plugin, ControlMode, EmergencyStopState
00035 
00036 from scxml import SCXMLState
00037 from airbus_ssm_core import ssm_main
00038 from airbus_ssm_core.srv import SSM_init
00039 from airbus_ssm_plugin import xdot_qt
00040 
00041 from ast import literal_eval
00042 from functools import partial
00043 from PyQt4.Qt import QByteArray, QPixmap
00044 
00045 
00046 SERVER_NAME = '/ssm'
00047 #####################################
00048 
00049 from res import R
00050 
00051 class SSMRunnable(QThread):
00052     
00053     def __init__(self, parent, tmp_file = None):
00054         QThread.__init__(self, parent)
00055         self.SSM_Main = ssm_main.ssmMain()
00056         
00057     def run(self):
00058         while(rospy.is_shutdown == False):
00059             rospy.spinOnce()
00060             rospy.sleep(0.1)
00061         
00062 
00063 class SSMIntrospection(plugin.Plugin):
00064     
00065     trigger_status = pyqtSignal()
00066     trigger_treeview = pyqtSignal()
00067     trigger_dotcode = pyqtSignal()
00068     trigger_log = pyqtSignal()
00069     
00070     def __init__(self, context):
00071         plugin.Plugin.__init__(self, context)
00072         
00073     def onCreate(self, param):
00074         
00075         loadUi(R.layouts.mainwindow, self)
00076         
00077         self._scxml_model = QStandardItemModel()
00078         self._scxml_model.setHorizontalHeaderLabels([R.values.strings.scxml_header()])
00079         self.scxml_treeview.setModel(self._scxml_model)
00080         self.scxml_treeview.setIconSize(QSize(24,24))       
00081         
00082         ##SET UP BUTTON
00083         self.open_button.setIcon(QIcon(R.images.ic_folder))
00084         self.open_button.setIconSize(QSize(50,50))
00085         self.open_button.setEnabled(False)
00086         self.connect(self.open_button, SIGNAL('clicked()'), self.openSCXMLFile)
00087         
00088         self.preempt_button.setIcon(QIcon(R.images.ic_preempt))
00089         self.preempt_button.setIconSize(QSize(100,100))
00090         self.preempt_button.setEnabled(False)
00091         self.connect(self.preempt_button, SIGNAL('clicked()'), self._preempt_ssm)
00092         
00093         self.start_button.setIcon(QIcon(R.images.ic_start))
00094         self.start_button.setIconSize(QSize(50,50))
00095         self.start_button.setEnabled(False)
00096         self.connect(self.start_button, SIGNAL('clicked()'), self._start_button_clicked)
00097         
00098         self.pause_button.setIcon(QIcon(R.images.ic_pause))
00099         self.pause_button.setIconSize(QSize(50,50))
00100         self.pause_button.setEnabled(False)
00101         self.connect(self.pause_button, SIGNAL('clicked()'), self._pause_button_clicked)
00102 
00103         self.rearm_button.setIcon(QIcon(R.images.ic_rearm))
00104         self.rearm_button.setIconSize(QSize(80,80))
00105         self.rearm_button.setEnabled(False)
00106         self.connect(self.rearm_button, SIGNAL('clicked()'), self._rearm_button_clicked)
00107         self.dotWidget = xdot_qt.DotWidget(self)
00108         self.gridLayout_4.addWidget(self.dotWidget)
00109         
00110          ##Setup Thread
00111         
00112         self._ssm_runnable = SSMRunnable(self)
00113         self._ssm_runnable.start()
00114         
00115         ##Setup Publisher / Subscriber
00116         self._server_name = rospy.get_param('ssm_server_name', '/ssm')
00117 
00118         self._ssm_tree_view_sub = rospy.Subscriber(self._server_name+'/ssm_status',
00119                                                     String,
00120                                                     self._ssm_tree_view_cb)
00121         
00122         self._ssm_dotcode_sub = rospy.Subscriber(self._server_name+'/ssm_dotcode',
00123                                                     String,
00124                                                     self._ssm_dotcode_cb)
00125 
00126         self._ssm_ready_sub = rospy.Subscriber(self._server_name + '/status',
00127                                                Int8,
00128                                                self._ssm_status_cb, queue_size=1)
00129         
00130         self._log_sub = rospy.Subscriber('/rosout', 
00131                                          Log, 
00132                                          self._log_cb)
00133         
00134         self._preempt_pub = rospy.Publisher(self._server_name+'/preempt', Empty, queue_size=1)
00135         
00136         self._start_pub = rospy.Publisher(self._server_name+'/start', Empty, queue_size=1)
00137         
00138         self._pause_pub = rospy.Publisher(self._server_name+'/pause', Bool, queue_size=1)
00139         
00140         self._request_tree_view_pub = rospy.Publisher(self._server_name+'/status_request', Empty, queue_size=1)
00141         
00142         self.trigger_status.connect(self.updateStatus)
00143         self.trigger_treeview.connect(self.updateTreeView)
00144         self.trigger_dotcode.connect(self.updateGraphdot)
00145         self.trigger_log.connect(self.updateLog)
00146 
00147         self._ssm_status = 0
00148         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_pending").scaled(50,50))
00149         
00150         self._tree_view_dict = None
00151         #self._log = ""
00152 
00153         self._tree_view = False
00154         self._ssm_loaded = False
00155         self._ssm_paused = False
00156         self._auto_reload = False
00157         
00158            
00159     def clearAllStates(self):
00160         self._tree_view = False
00161         self._scxml_model.clear()
00162         
00163     ###STATUS DEFINITION
00164     def _not_loaded(self):
00165         self._clear_tree_view()
00166         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_pending").scaled(50,50))
00167         self.status_label.setText("NOT LOADED ")
00168         self.start_button.setEnabled(False)
00169         self.pause_button.setEnabled(False)
00170         self.open_button.setEnabled(True)
00171         self.rearm_button.setEnabled(False)
00172         self.preempt_button.setEnabled(False)
00173         
00174     def _ready_state(self):
00175         ready_gif = QMovie(R.images.ic_ready)
00176         ready_gif.setCacheMode(QMovie.CacheAll)
00177         ready_gif.setScaledSize(QSize(50,50))
00178         ready_gif.setSpeed(100)
00179         self.ssm_status.setMovie(ready_gif)
00180         ready_gif.start()
00181         self.status_label.setText("READY ")
00182         self.start_button.setEnabled(True)
00183         self.pause_button.setEnabled(False)
00184         self.open_button.setEnabled(True)
00185         self.rearm_button.setEnabled(False)
00186         self.preempt_button.setEnabled(False)
00187         self.rearm_button.setStyleSheet("background-color: transparent")
00188     
00189     def _running_state(self):
00190         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_ok").scaled(50,50))
00191         self.status_label.setText("RUNNING ")
00192         self.start_button.setEnabled(False)
00193         self.pause_button.setEnabled(True)
00194         self.open_button.setEnabled(False)
00195         self.rearm_button.setEnabled(False)
00196         self.preempt_button.setEnabled(True)
00197     
00198     def _pause_state(self):
00199         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_pause").scaled(50,50))
00200         self.status_label.setText("PAUSE ")
00201         self.start_button.setEnabled(True)
00202         self.pause_button.setEnabled(False)
00203         self.open_button.setEnabled(False)
00204         self.rearm_button.setEnabled(False)
00205         self.preempt_button.setEnabled(True)
00206         
00207     def _preempt_state(self):
00208         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_error").scaled(50,50))
00209         self.status_label.setText("ERROR ")
00210         self.start_button.setEnabled(False)
00211         self.pause_button.setEnabled(False)
00212         self.open_button.setEnabled(False)
00213         self.rearm_button.setEnabled(True)
00214         self.rearm_button.setStyleSheet("background-color: red")
00215         self.preempt_button.setEnabled(False)
00216         
00217     def _finish_state(self):
00218         self.ssm_status.setPixmap(R.getPixmapById("ic_ssm_ok").scaled(50,50))
00219         self.status_label.setText("FINISHED ")
00220         self.start_button.setEnabled(False)
00221         self.pause_button.setEnabled(False)
00222         self.open_button.setEnabled(True)
00223         self.rearm_button.setEnabled(False)
00224         self.preempt_button.setEnabled(False)
00225         if(self.auto_reload.isChecked()):
00226             self._load_SSM()
00227         else:
00228             self._not_loaded()
00229         
00230     def updateLog(self):
00231         self.log_txt.setText(self._log)
00232         
00233     
00234     def updateStatus(self):
00235             status = self._ssm_status 
00236             if status == 0:
00237                 self._not_loaded()
00238             elif status == 1: ##Ready
00239                 self._ready_state()
00240             elif status == 2: ##Running
00241                 self._running_state()
00242             elif status == -1: ##Pause
00243                 self._pause_state()
00244             elif status == -2: ##Error / Preempt
00245                 self._preempt_state()
00246             elif status == -10: ##Error / Preempt
00247                 self._not_loaded()
00248             elif status == 10: ##Finish
00249                 self._finish_state()
00250                 
00251     def updateGraphdot(self):       
00252         self.dotWidget.set_dotcode(self._dotcode)
00253         self.dotWidget.zoom_to_fit()
00254       
00255     def updateTreeView(self):
00256 
00257         if (self._tree_view == False):
00258             self._construct_tree_view(self._tree_view_dict)
00259             self._tree_view = True
00260         else:
00261             self._update_tree_view(self._tree_view_dict,self._scxml_model.item(0))
00262             
00263     def _log_cb(self, log):
00264         if(log.name == rospy.get_name()):
00265             strtime = datetime.datetime.now().strftime("[%Y/%m/%d-%H:%M:%S] ")
00266             self._log = strtime+str(log.msg)
00267             self.trigger_log.emit()
00268     
00269     def _ssm_tree_view_cb(self, msg):
00270         self._tree_view_dict = literal_eval(str(msg.data))
00271         self.trigger_treeview.emit()
00272             
00273     def _ssm_status_cb(self, msg):
00274         self._ssm_status = msg.data
00275         self.trigger_status.emit()
00276     
00277     def _ssm_dotcode_cb(self, msg):
00278         self._dotcode = msg.data
00279         self.trigger_dotcode.emit()
00280         
00281     
00282     def openSCXMLFile(self): 
00283         
00284         self._ssm_status = 0
00285         self.updateStatus()
00286               
00287         fdial = QFileDialog()
00288         try:
00289             rospy.get_param("/ssm_node/scxml_file")
00290             default_f = rospy.get_param("/ssm_node/scxml_file")
00291             
00292         except KeyError:
00293             default_f = QtAgiCore.get_pkg_dir_from_prefix("${airbus_ssm_core}")
00294             
00295         scxmlfile = fdial.getOpenFileName(self, "Open SCXML",'',"SCXML (*.scxml)", None, QFileDialog.DontUseNativeDialog)
00296         if scxmlfile[0] == "":
00297             return
00298 
00299         self._scxml_model.setHorizontalHeaderLabels([scxmlfile[0]])
00300         rospy.set_param('/ssm_node/scxml_file',scxmlfile[0])
00301         self._load_SSM()
00302         
00303         
00304             
00305     def _load_SSM(self):
00306         try:
00307             result = self._wait_ssm_isready()
00308             if(result == True):
00309                 self._ssm_loaded = True
00310                 self._wait_tree_view()
00311             else:
00312                 self._not_loaded()             
00313         except KeyError as e:
00314              self._not_loaded()
00315     
00316     def _wait_ssm_isready(self):
00317         rospy.wait_for_service(self._server_name+'/srv/init',10)
00318         try:
00319             _init_srv = rospy.ServiceProxy(self._server_name+'/srv/init',SSM_init)
00320             call_ = String()
00321             call_.data = rospy.get_param("/ssm_node/scxml_file")
00322             resp = _init_srv(call_)
00323             return resp.result.data
00324         except rospy.ServiceException, e:
00325             rospy.logerr('Service call failed : %s'%e)
00326             raise rospy.ServiceException(e)
00327 
00328     def _wait_tree_view(self):
00329         self._request_tree_view_pub.publish()
00330                 
00331     def _start_button_clicked(self):
00332         if(self._ssm_paused == True):
00333             self._ssm_paused = False
00334             self._pause_pub.publish(False) 
00335         else :
00336             self._start_pub.publish() 
00337 
00338     def _pause_button_clicked(self):
00339         if(self._ssm_paused == False):
00340             self._ssm_paused = True
00341             self._pause_pub.publish(True)
00342             
00343     def _rearm_button_clicked(self):
00344         self._load_SSM()
00345         
00346     def _preempt_ssm(self):
00347         self._preempt_pub.publish()
00348         self._ssm_paused = False
00349         
00350     def _construct_tree_view(self, tree_view):
00351 
00352         graph = SCXMLState("ROOT",SCXMLState.PARENT_STATE)
00353         #FIND ROOT
00354         for state, value in tree_view.iteritems():
00355             if state=="ROOT":
00356                 self._add_states_into_treeview(state, value, graph, tree_view)
00357         
00358         self._scxml_model.appendRow(graph)
00359         self.scxml_treeview.expandAll()
00360     
00361     def _add_states_into_treeview(self, state, value, graph, tree_view):
00362         
00363         for state_, value_ in value.iteritems():
00364             child = SCXMLState(state_, SCXMLState.SIMPLE_STATE)
00365             graph.appendRow(child)
00366             for state__, value__ in tree_view.iteritems():
00367                 if(state_ == state__):
00368                     child.setType(SCXMLState.PARENT_STATE)
00369                     self._add_states_into_treeview(state__, value__, child, tree_view)    
00370         
00371     def _update_tree_view(self, tree_view, item):
00372         if(item.type() == SCXMLState.PARENT_STATE):
00373             for state, value in tree_view.iteritems():
00374                 if(item.get_name() == state):
00375                     for i_item in range(item.rowCount()):
00376                         for state_, value_ in value.iteritems():
00377                             if(item.child(i_item).get_name() == state_):    
00378                                 item.child(i_item).setStatus(value_)
00379                         self._update_tree_view(tree_view, item.child(i_item))
00380                         
00381     def _clear_tree_view(self):
00382         self._tree_view_dict = None
00383         self._tree_view = False
00384         self._scxml_model.clear() 
00385         
00386     def onPause(self):
00387         pass
00388     
00389     def onResume(self):
00390         if(self._ssm_loaded == False):
00391              self._load_SSM()
00392         
00393         
00394     def onControlModeChanged(self, mode):
00395         
00396         if mode == ControlMode.AUTOMATIC:
00397             self.setEnabled(False)
00398         else:
00399             self.setEnabled(True)
00400         
00401     def onUserChanged(self, user_info):
00402         pass
00403     
00404     def onTranslate(self, lng):
00405         pass
00406     
00407     def onEmergencyStop(self, state):
00408         self.onPause()
00409         
00410     def onDestroy(self):
00411         self._preempt_ssm()
00412 
00413 
00414     
00415     


airbus_ssm_plugin
Author(s): Ludovic Delval
autogenerated on Thu Jun 6 2019 17:59:30