00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00111
00112 self._ssm_runnable = SSMRunnable(self)
00113 self._ssm_runnable.start()
00114
00115
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
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
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:
00239 self._ready_state()
00240 elif status == 2:
00241 self._running_state()
00242 elif status == -1:
00243 self._pause_state()
00244 elif status == -2:
00245 self._preempt_state()
00246 elif status == -10:
00247 self._not_loaded()
00248 elif status == 10:
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
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