00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import os
00036 import sys
00037 from threading import Thread
00038 import time
00039
00040 from python_qt_binding import loadUi
00041 from python_qt_binding.QtCore import QModelIndex, QTimer, Signal
00042 from python_qt_binding.QtGui import QStandardItem, QStandardItemModel, QWidget
00043 import rospkg
00044
00045
00046 import rospy
00047 import rostopic
00048 from rqt_py_common.rqt_roscomm_util import RqtRoscommUtil
00049 from rqt_topic.topic_widget import TopicWidget
00050
00051
00052 class MoveitWidget(QWidget):
00053 """#TODO: comment
00054 """
00055
00056 sig_sysmsg = None
00057 sig_param = Signal(bool, str)
00058 sig_node = Signal(bool, str)
00059
00060 _SPLITTER_H = 'splitter_horizontal'
00061
00062 def __init__(self, parent, plugin_context):
00063 """
00064 @type parent: MoveitMain
00065 """
00066
00067 self._nodes_monitored = ['/move_group']
00068 self._selected_topics = [('/pointcloud', 'sensor_msgs/PointCloud'),
00069 ('/pointcloud2', 'sensor_msgs/PointCloud2'),
00070 ('/image', 'sensor_msgs/Image'),
00071 ('/camera_info', 'sensor_msgs/CameraInfo')]
00072 self._params_monitored = ['/robot_description',
00073 '/robot_description_semantic']
00074
00075 super(MoveitWidget, self).__init__()
00076 self._parent = parent
00077 self._plugin_context = plugin_context
00078 self._refresh_rate = 5
00079
00080 self._rospack = rospkg.RosPack()
00081 ui_file = os.path.join(self._rospack.get_path('rqt_moveit'),
00082 'resource', 'moveit_top.ui')
00083 loadUi(ui_file, self, {'TopicWidget': TopicWidget})
00084
00085
00086
00087
00088 self._splitter.addWidget(self._widget_topic)
00089
00090 self._spinbox_refreshrate.valueChanged.connect(
00091 self._update_refreshrate)
00092
00093 self._spinbox_refreshrate.setValue(self._refresh_rate)
00094
00095
00096 self._is_checking_nodes = True
00097 self._node_qitems = {}
00098 self._node_monitor_thread = self._init_monitor_nodes(
00099 self._nodes_monitored)
00100 self._node_monitor_thread.start()
00101
00102
00103
00104
00105 self._widget_topic.set_selected_topics(self._selected_topics)
00106 self._widget_topic.set_topic_specifier(TopicWidget.SELECT_BY_MSGTYPE)
00107 self._widget_topic.start()
00108
00109
00110
00111 self.sig_sysmsg = self._widget_topic.sig_sysmsg
00112
00113
00114 self._is_checking_params = True
00115 self._param_qitems = {}
00116 _col_names_paramtable = ['Param name', 'Found on Parameter Server?']
00117 self._param_check_thread = self._init_monitor_parameters(
00118 self._params_monitored,
00119 _col_names_paramtable)
00120 self._param_check_thread.start()
00121
00122 def _init_monitor_nodes(self, nodes_monitored):
00123 """
00124 @type params_monitored: str[]
00125 @rtype: Thread
00126 """
00127 self._node_datamodel = QStandardItemModel(0, 2)
00128 self._root_qitem = self._node_datamodel.invisibleRootItem()
00129 self._view_nodes.setModel(self._node_datamodel)
00130
00131 node_monitor_thread = Thread(target=self._check_nodes_alive,
00132 args=(self.sig_node,
00133 self._nodes_monitored))
00134
00135
00136 self.sig_node.connect(self._update_output_nodes)
00137 return node_monitor_thread
00138
00139 def _check_nodes_alive(self, signal, nodes_monitored):
00140 """
00141 Working as a callback of Thread class, this method keeps looping to
00142 watch if the nodes whose names are passed exist and emits signal per
00143 each node.
00144
00145 Notice that what MoveitWidget._check_nodes_alive &
00146 MoveitWidget._check_params_alive do is very similar, but since both of
00147 them are supposed to be passed to Thread class, there might not be
00148 a way to generalize these 2.
00149
00150 @param signal: Signal(bool, str)
00151 @type nodes_monitored: str[]
00152 """
00153 while self._is_checking_nodes:
00154 rosnode_dynamically_loaded = __import__('rosnode')
00155
00156 for nodename in nodes_monitored:
00157
00158
00159 try:
00160
00161 is_node_running = rosnode_dynamically_loaded.rosnode_ping(
00162 nodename, 1)
00163 except rosnode_dynamically_loaded.ROSNodeIOException as e:
00164
00165
00166 rospy.logerr(e.message)
00167 is_node_running = False
00168
00169 signal.emit(is_node_running, nodename)
00170 rospy.logdebug('_update_output_nodes')
00171 del rosnode_dynamically_loaded
00172 time.sleep(self._refresh_rate)
00173
00174 def _init_monitor_parameters(self, params_monitored,
00175 _col_names_paramtable=None):
00176 """
00177 @type params_monitored: str[]
00178 """
00179 self._params_monitored = params_monitored
00180
00181 self._param_datamodel = QStandardItemModel(0, 2)
00182 self._root_qitem = self._param_datamodel.invisibleRootItem()
00183 self._view_params.setModel(self._param_datamodel)
00184
00185
00186 if not _col_names_paramtable:
00187 _col_names_paramtable = ['Param name',
00188 'Found on Parameter Server?']
00189 self._param_datamodel.setHorizontalHeaderLabels(_col_names_paramtable)
00190
00191 self.sig_param.connect(self._update_output_parameters)
00192
00193 param_check_thread = Thread(target=self._check_params_alive,
00194 args=(self.sig_param,
00195 self._params_monitored))
00196 return param_check_thread
00197
00198 def _update_output_nodes(self, is_node_running, node_name):
00199 """
00200 Slot for signals that tell nodes existence.
00201
00202 @type is_node_running: bool
00203 @type node_name: str
00204 """
00205
00206
00207
00208 rospy.logdebug('is_node_running={} par_name={}'.format(is_node_running,
00209 node_name))
00210 node_name = str(node_name)
00211 node_qitem = None
00212 if not node_name in self._node_qitems:
00213 node_qitem = QStandardItem(node_name)
00214 self._node_qitems[node_name] = node_qitem
00215 self._node_datamodel.appendRow(node_qitem)
00216 else:
00217 node_qitem = self._node_qitems[str(node_name)]
00218
00219 qindex = self._node_datamodel.indexFromItem(node_qitem)
00220 _str_node_running = 'Not running'
00221 if is_node_running:
00222 _str_node_running = 'Running'
00223 qitem_node_status = QStandardItem(_str_node_running)
00224 self._node_datamodel.setItem(qindex.row(), 1, qitem_node_status)
00225
00226 def _check_params_alive(self, signal, params_monitored):
00227 """
00228 Working as a callback of Thread class, this method keeps looping to
00229 watch if the params whose names are passed exist and emits signal per
00230 each node.
00231
00232 Notice that what MoveitWidget._check_nodes_alive &
00233 MoveitWidget._check_params_alive do is very similar, but since both of
00234 them are supposed to be passed to Thread class, there might not be
00235 a way to generalize these 2.
00236
00237 @type signal: Signal(bool, str)
00238 @param_name signal: emitting a name of the parameter that's found.
00239 @type params_monitored: str[]
00240 """
00241
00242 while self._is_checking_params:
00243
00244
00245
00246 has_param = False
00247
00248 for param_name in params_monitored:
00249 is_rosmaster_running = RqtRoscommUtil.is_roscore_running()
00250
00251 try:
00252 if is_rosmaster_running:
00253
00254
00255 has_param = rospy.has_param(param_name)
00256 except rospy.exceptions.ROSException as e:
00257 self.sig_sysmsg.emit(
00258 'Exception upon rospy.has_param {}'.format(e.message))
00259 signal.emit(has_param, param_name)
00260 rospy.loginfo('has_param {}, check_param_alive: {}'.format(
00261 has_param, param_name))
00262 time.sleep(self._refresh_rate)
00263
00264 def _update_output_parameters(self, has_param, param_name):
00265 """
00266 Slot
00267
00268 @type has_param: bool
00269 @type param_name: str
00270 """
00271 rospy.logdebug('has_param={} par_name={}'.format(has_param,
00272 param_name))
00273 param_name = str(param_name)
00274 param_qitem = None
00275 if not param_name in self._param_qitems:
00276 param_qitem = QStandardItem(param_name)
00277 self._param_qitems[param_name] = param_qitem
00278 self._param_datamodel.appendRow(param_qitem)
00279 else:
00280 param_qitem = self._param_qitems[str(param_name)]
00281
00282 qindex = self._param_datamodel.indexFromItem(param_qitem)
00283 _str_param_found = 'No'
00284 if has_param:
00285 _str_param_found = 'Yes'
00286 qitem_param_status = QStandardItem(_str_param_found)
00287 self._param_datamodel.setItem(qindex.row(), 1, qitem_param_status)
00288 self._view_params.resizeColumnsToContents()
00289
00290 def _update_refreshrate(self, refresh_rate):
00291 """
00292 Slot
00293
00294 @type refresh_rate: int
00295 """
00296 self._refresh_rate = refresh_rate
00297
00298 def save_settings(self, plugin_settings, instance_settings):
00299 instance_settings.set_value(self._SPLITTER_H,
00300 self._splitter.saveState())
00301
00302 def restore_settings(self, plugin_settings, instance_settings):
00303 if instance_settings.contains(self._SPLITTER_H):
00304 self._splitter.restoreState(instance_settings.value(
00305 self._SPLITTER_H))
00306 else:
00307 self._splitter.setSizes([100, 100, 200])
00308 pass
00309
00310 def shutdown(self):
00311 """
00312 Overridden.
00313
00314 Close threads.
00315
00316 @raise RuntimeError:
00317 """
00318 try:
00319
00320 self._is_checking_nodes = False
00321 self._node_monitor_thread = None
00322
00323
00324 self._is_checking_params = False
00325 self._param_check_thread = None
00326 except RuntimeError as e:
00327 rospy.logerr(e)
00328 raise e
00329
00330
00331 if __name__ == '__main__':
00332
00333
00334 from rqt_gui.main import Main
00335
00336 main = Main()
00337 sys.exit(main.main(sys.argv, standalone='rqt_moveit'))