00001
00002
00003 import math
00004 import new
00005 import os
00006 import random
00007 import signal
00008 from StringIO import StringIO
00009 import sys
00010 import tempfile
00011
00012 import roslib
00013 roslib.load_manifest('python_qt_binding')
00014 roslib.load_manifest('rviz')
00015 roslib.load_manifest('rviz_backdrop')
00016 roslib.load_manifest('slider_gui')
00017 import rospy;
00018
00019
00020 from python_qt_binding.QtBindingHelper import loadUi
00021 from QtCore import QEvent, qFatal, QModelIndex, QObject, QRect, QRegExp, QSignalMapper, Qt, QTimer, Signal
00022 from QtGui import QApplication, QColor, QDialog, QFileDialog, QIcon, QItemSelectionModel, QKeyEvent, QMainWindow, QMessageBox, QPalette, QPixmap, QSplitter, QTableView, QVBoxLayout, QWidget
00023 from actions.DefaultAction import DefaultAction
00024 from CollisionChecker import CollisionChecker
00025 from DoubleSpinBoxDelegate import DoubleSpinBoxDelegate
00026 from KontrolSubscriber import KontrolSubscriber
00027 from PosesDataModel import PosesDataModel
00028 from actions.ActionSet import ActionSet
00029 from actions.Pr2LookAtFace import Pr2LookAtFace
00030 from actions.Pr2MoveHeadAction import Pr2MoveHeadAction
00031 from actions.Pr2MoveLeftArmAction import Pr2MoveLeftArmAction
00032 from actions.Pr2MoveRightArmAction import Pr2MoveRightArmAction
00033 from pr2_controllers_msgs.msg import *
00034 import pr2_mechanism_msgs.srv._ListControllers
00035 import pr2_mechanism_msgs.srv._LoadController
00036 import pr2_mechanism_msgs.srv._SwitchController
00037 from ProgramQueue import ProgramQueue
00038 from Ps3Subscriber import Ps3Subscriber
00039 import rviz
00040 from sensor_msgs.msg import CompressedImage
00041 from sensor_msgs.msg import Image
00042 from sensor_msgs.msg import JointState
00043 from SimpleFormat import SimpleFormat
00044 import std_srvs.srv._Empty
00045 from trajectory_msgs.msg import *
00046
00047 app = QApplication(sys.argv)
00048
00049 check_collisions = '--no-collision' not in sys.argv
00050 show_point_clouds = '--with-point-clouds' in sys.argv
00051
00052 main_window = QMainWindow()
00053 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'slider_simple.ui')
00054 loadUi(ui_file, main_window)
00055
00056
00057 icons = {
00058 0: 'square.png',
00059 1: 'triangle.png',
00060 2: 'circle.png',
00061 3: 'cross.png',
00062 }
00063 for index, filename in icons.iteritems():
00064 filename = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'icons', filename))
00065 icon = QIcon(filename)
00066 if not icon.isNull():
00067 main_window.PoseList_tabWidget.setTabText(index, '')
00068 main_window.PoseList_tabWidget.setTabIcon(index, icon)
00069
00070
00071
00072
00073 sigint_called = False
00074 def sigint_handler(*args):
00075 global sigint_called
00076 print('\nsigint_handler()')
00077 sigint_called = True
00078 main_window.close()
00079 signal.signal(signal.SIGINT, sigint_handler)
00080
00081 timer = QTimer()
00082 timer.start(500)
00083 timer.timeout.connect(lambda: None)
00084
00085
00086 index = main_window.robot_view_verticalLayout.indexOf(main_window.robot_view_widget)
00087 stretch = main_window.robot_view_verticalLayout.stretch(index)
00088 main_window.robot_view_verticalLayout.removeWidget(main_window.robot_view_widget)
00089 robot_view = rviz.VisualizationPanel()
00090
00091 robot_view.children()[1].hide()
00092 main_window.robot_view_verticalLayout.insertWidget(index, robot_view, stretch)
00093 robot_view.setSizes([0])
00094
00095 config = tempfile.NamedTemporaryFile('w')
00096 if not show_point_clouds:
00097 config.write("""Backdrop.Enabled=1
00098 Backdrop.Scale=4
00099 Backdrop.Topic=/backdrop
00100 Background\ ColorB=0
00101 Background\ ColorG=0
00102 Background\ ColorR=0
00103 Camera\ Config=0.905202 5.83579 18.0278 0 -1.90735e-06 1.90735e-06
00104 Camera\ Type=rviz::OrbitViewController
00105 Fixed\ Frame=/base_link
00106 Grid.Alpha=0.5
00107 Grid.Cell\ Size=1
00108 Grid.ColorB=0.5
00109 Grid.ColorG=0.5
00110 Grid.ColorR=0.5
00111 Grid.Enabled=1
00112 Grid.Line\ Style=0
00113 Grid.Line\ Width=0.03
00114 Grid.Normal\ Cell\ Count=0
00115 Grid.OffsetX=0
00116 Grid.OffsetY=0
00117 Grid.OffsetZ=0
00118 Grid.Plane=0
00119 Grid.Plane\ Cell\ Count=8
00120 Grid.Reference\ Frame=<Fixed Frame>
00121 RobotModel.Alpha=1
00122 RobotModel.Collision\ Enabled=0
00123 RobotModel.Enabled=1
00124 RobotModel.Robot\ Description=robot_description
00125 RobotModel.TF\ Prefix=
00126 RobotModel.Update\ Interval=0
00127 RobotModel.Visual\ Enabled=1
00128 Target\ Frame=<Fixed Frame>
00129 [Display0]
00130 ClassName=rviz::GridDisplay
00131 Name=Grid
00132 [Display1]
00133 ClassName=rviz_backdrop::BackdropDisplay
00134 Name=Backdrop
00135 [Display2]
00136 ClassName=rviz::RobotModelDisplay
00137 Name=RobotModel
00138 """)
00139 else:
00140 config.write("""Backdrop.Enabled=1
00141 Backdrop.Scale=4
00142 Backdrop.Topic=/backdrop
00143 Background\ ColorB=0
00144 Background\ ColorG=0
00145 Background\ ColorR=0
00146 Camera\ Config=0.905202 5.83579 18.0278 0 -1.90735e-06 1.90735e-06
00147 Camera\ Type=rviz::OrbitViewController
00148 Fixed\ Frame=/base_link
00149 Grid.Alpha=0.5
00150 Grid.Cell\ Size=1
00151 Grid.ColorB=0.5
00152 Grid.ColorG=0.5
00153 Grid.ColorR=0.5
00154 Grid.Enabled=1
00155 Grid.Line\ Style=0
00156 Grid.Line\ Width=0.03
00157 Grid.Normal\ Cell\ Count=0
00158 Grid.OffsetX=0
00159 Grid.OffsetY=0
00160 Grid.OffsetZ=0
00161 Grid.Plane=0
00162 Grid.Plane\ Cell\ Count=8
00163 Grid.Reference\ Frame=<Fixed Frame>
00164 PointCloud2..AxisColorAutocompute\ Value\ Bounds=1
00165 PointCloud2..AxisColorAxis=2
00166 PointCloud2..AxisColorMax\ Value=0.919509
00167 PointCloud2..AxisColorMin\ Value=-0.0470135
00168 PointCloud2..AxisColorUse\ Fixed\ Frame=1
00169 PointCloud2..FlatColorColorB=1
00170 PointCloud2..FlatColorColorG=1
00171 PointCloud2..FlatColorColorR=1
00172 PointCloud2..IntensityAutocompute\ Intensity\ Bounds=1
00173 PointCloud2..IntensityChannel\ Name=intensity
00174 PointCloud2..IntensityMax\ ColorB=1
00175 PointCloud2..IntensityMax\ ColorG=1
00176 PointCloud2..IntensityMax\ ColorR=1
00177 PointCloud2..IntensityMax\ Intensity=4096
00178 PointCloud2..IntensityMin\ ColorB=0
00179 PointCloud2..IntensityMin\ ColorG=0
00180 PointCloud2..IntensityMin\ ColorR=0
00181 PointCloud2..IntensityMin\ Intensity=0
00182 PointCloud2..IntensityUse\ full\ RGB\ spectrum=0
00183 PointCloud2.Alpha=1
00184 PointCloud2.Billboard\ Size=0.003
00185 PointCloud2.Color\ Transformer=RGB8
00186 PointCloud2.Decay\ Time=0
00187 PointCloud2.Enabled=1
00188 PointCloud2.Position\ Transformer=XYZ
00189 PointCloud2.Queue\ Size=10
00190 PointCloud2.Selectable=1
00191 PointCloud2.Style=1
00192 PointCloud2.Topic=/head_mount_kinect/depth_registered/points
00193 RobotModel.Alpha=1
00194 RobotModel.Collision\ Enabled=0
00195 RobotModel.Enabled=1
00196 RobotModel.Robot\ Description=robot_description
00197 RobotModel.TF\ Prefix=
00198 RobotModel.Update\ Interval=0
00199 RobotModel.Visual\ Enabled=1
00200 Target\ Frame=<Fixed Frame>
00201 [Display0]
00202 ClassName=rviz::GridDisplay
00203 Name=Grid
00204 [Display1]
00205 ClassName=rviz_backdrop::BackdropDisplay
00206 Name=Backdrop
00207 [Display2]
00208 ClassName=rviz::RobotModelDisplay
00209 Name=RobotModel
00210 [Display3]
00211 ClassName=rviz::PointCloud2Display
00212 Name=PointCloud2
00213 """)
00214
00215 config.flush()
00216 robot_view.loadDisplayConfig(config.name)
00217 config.close
00218
00219
00220
00221 views = []
00222 view_mapper = QSignalMapper(main_window)
00223 def set_view(index):
00224 robot_view.setViewString(views[index])
00225 view_mapper.mapped.connect(set_view)
00226 def view_selected(checked):
00227 if checked:
00228 view_mapper.map()
00229 def add_view(button, view_str):
00230 view_mapper.setMapping(button, len(views))
00231 views.append(view_str)
00232 if button.isChecked():
00233 set_view(len(views) - 1)
00234 button.clicked.connect(view_mapper.map)
00235 add_view(main_window.front_view_radioButton, '0.0402028 6.2758 2.24508 0.00208002 -0.0024735 0.753009')
00236 add_view(main_window.side_view_radioButton, '-0.0747972 4.83578 2.81623 -0.0104112 -0.00416593 0.984444')
00237 add_view(main_window.angled_view_radioButton, '0.175202 5.59079 2.81623 -0.0104112 -0.00416593 0.984444')
00238
00239 rospy.init_node('proto_simple', disable_signals=True)
00240 try:
00241 use_sim_time = rospy.get_param('use_sim_time')
00242 except KeyError:
00243 use_sim_time = False
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 backdrop_publisher = rospy.Publisher('/backdrop/compressed', CompressedImage, latch=True)
00259 scenes = []
00260 def set_scene(index):
00261 image = CompressedImage()
00262
00263
00264
00265 image.header.frame_id = '/base_link'
00266 image.format = 'jpeg'
00267 try:
00268 scene = scenes[index]
00269 except TypeError:
00270 index = main_window.scene_comboBox.findText(index)
00271 scene = scenes[index]
00272 image.data = open(scene).read()
00273 image.header.stamp = rospy.Time.now()
00274 backdrop_publisher.publish(image)
00275 path = os.path.join(os.path.dirname(__file__), '..', 'images')
00276 for filename in os.listdir(path):
00277 (root, ext) = os.path.splitext(filename)
00278 if ext in ['.jpg']:
00279 filename = os.path.join(path, filename)
00280 scenes.append(filename)
00281 scenes.sort()
00282 for index, filename in enumerate(scenes):
00283 (root, ext) = os.path.splitext(filename)
00284 text = os.path.basename(root)
00285 main_window.scene_comboBox.insertItem(index, text)
00286 main_window.scene_comboBox.currentIndexChanged.connect(set_scene)
00287 index = main_window.scene_comboBox.findText('None')
00288 if index != -1:
00289 main_window.scene_comboBox.setCurrentIndex(index)
00290
00291
00292
00293 def reset_sim():
00294 print 'reset_sim()'
00295 service = '/gazebo/reset_simulation'
00296 rospy.wait_for_service(service)
00297 reset_sim_service = rospy.ServiceProxy(service, std_srvs.srv._Empty.Empty)
00298 try:
00299 reset_sim_service()
00300 except rospy.ServiceException, e:
00301 print "Service did not process request: %s" % str(e)
00302
00303 main_window.reset_sim_pushButton.clicked.connect(reset_sim)
00304 if not show_point_clouds:
00305 main_window.reset_sim_pushButton.setVisible(False)
00306
00307 def autosave_program():
00308 print 'autosave_program()'
00309 save_to_filename(os.path.expanduser('~/_autosave.pt'))
00310
00311 def update_sequence_duration():
00312 print 'update_sequence_duration()'
00313 model = get_current_model()
00314 main_window.sequence_duration_label.setText('%.1f' % model.action_sequence().get_duration())
00315
00316 def current_tab_changed(index):
00317 update_sequence_duration()
00318 main_window.PoseList_tabWidget.currentChanged.connect(current_tab_changed)
00319
00320
00321 class TrajectoryLock():
00322 def __init__(self, ns, joint_bounds):
00323 self._ns = ns
00324 self._subscriber = None
00325 self._joint_bounds = [float(x) for x in joint_bounds]
00326 self._publisher = rospy.Publisher('/%s/command' % ns, trajectory_msgs.msg.JointTrajectory)
00327
00328 def start(self):
00329 print 'TrajectoryLock.start()'
00330 if self._subscriber is not None:
00331 self._subscriber.unregister()
00332 self._subscriber = rospy.Subscriber('/%s/state' % self._ns, pr2_controllers_msgs.msg.JointTrajectoryControllerState, self._receive_state)
00333
00334 def stop(self):
00335 print 'TrajectoryLock.stop()'
00336 if self._subscriber is not None:
00337 self._subscriber.unregister()
00338 self._subscriber = None
00339
00340 def _receive_state(self, msg):
00341 max_error = max([abs(x) for x in msg.error.positions])
00342
00343 exceeded = [abs(x) > y for x,y in zip(msg.error.positions, self._joint_bounds)]
00344
00345
00346
00347 if any(exceeded):
00348
00349
00350
00351 cmd = trajectory_msgs.msg.JointTrajectory()
00352 cmd.header.stamp = msg.header.stamp
00353 cmd.joint_names = msg.joint_names
00354 cmd.points.append(trajectory_msgs.msg.JointTrajectoryPoint())
00355 cmd.points[0].time_from_start = rospy.Duration(.125)
00356 cmd.points[0].positions = msg.actual.positions
00357 self._publisher.publish(cmd)
00358
00359
00360
00361
00362 class JointObserver(QObject):
00363 current_values_changed = Signal(str)
00364 _update_current_value_signal = Signal()
00365 def __init__(self):
00366 super(JointObserver, self).__init__()
00367 self.action_set = None
00368 self._latest_joint_state = None
00369 self._update_current_value_signal.connect(self._update_current_value)
00370 self._subscriber = None
00371 self._trajectory_locks = []
00372 self._trajectory_locks.append(TrajectoryLock('head_traj_controller_loose', [.08, .08]))
00373 self._trajectory_locks.append(TrajectoryLock('l_arm_controller_loose', [.02, .02, .02, .02, .02, .06, .06]))
00374 self._trajectory_locks.append(TrajectoryLock('r_arm_controller_loose', [.02, .02, .02, .02, .02, .06, .06]))
00375
00376 def start(self):
00377 print 'JointObserver.start()'
00378 if self._subscriber is not None:
00379 self._subscriber.unregister()
00380 self._subscriber = rospy.Subscriber('/joint_states', JointState, self._receive_joint_states)
00381 for trajectory_lock in self._trajectory_locks:
00382 trajectory_lock.start()
00383
00384 def stop(self):
00385 print 'JointObserver.stop()'
00386 if self._subscriber is not None:
00387 self._subscriber.unregister()
00388 self._subscriber = None
00389 for trajectory_lock in self._trajectory_locks:
00390 trajectory_lock.stop()
00391
00392 def _receive_joint_states(self, joint_state_msg):
00393 self._latest_joint_state = joint_state_msg
00394 self._update_current_value_signal.emit()
00395
00396 def _update_current_value(self):
00397 self.action_set = ActionSet()
00398 self.action_set.add_action(Pr2MoveHeadAction())
00399 self.action_set.add_action(Pr2MoveLeftArmAction())
00400 self.action_set.add_action(Pr2MoveRightArmAction())
00401
00402 labels = self.action_set.get_labels()
00403
00404 for label in labels:
00405 value = self._latest_joint_state.position[self._latest_joint_state.name.index(label)]
00406 value *= 180.0 / math.pi
00407 try:
00408 self.action_set.update_value(label, value)
00409 except KeyError, e:
00410 print 'JointObserver._update_current_value() label "%s" not found' % label
00411 pass
00412
00413 value = self.action_set.to_string()
00414 self.current_values_changed.emit(value)
00415
00416 joint_observer = JointObserver()
00417 joint_observer.current_values_changed.connect(main_window.lineEdit.setText)
00418
00419
00420 INPUT_METHOD_SLIDERS = 0
00421 INPUT_METHOD_INTERACTIVE_MARKERS = 1
00422 INPUT_METHOD_ROBOT = 2
00423 main_window.input_method_comboBox.addItem('Sliders', INPUT_METHOD_SLIDERS)
00424
00425 if not use_sim_time:
00426 main_window.input_method_comboBox.addItem('Robot', INPUT_METHOD_ROBOT)
00427 def is_in_slider_mode():
00428 return main_window.input_method_comboBox.currentIndex() == INPUT_METHOD_SLIDERS
00429
00430 def load_controllers(controllers):
00431 service = '/pr2_controller_manager/list_controllers'
00432 rospy.wait_for_service(service)
00433 service_proxy = rospy.ServiceProxy(service, pr2_mechanism_msgs.srv._ListControllers.ListControllers)
00434 try:
00435 request = pr2_mechanism_msgs.srv._ListControllers.ListControllersRequest()
00436 response = service_proxy(request)
00437 loaded_controllers = response.controllers
00438 except rospy.ServiceException, e:
00439 print 'Service did not process request: %s' % str(e)
00440 return False
00441
00442 service = '/pr2_controller_manager/load_controller'
00443 rospy.wait_for_service(service)
00444 for name in controllers:
00445 if name in loaded_controllers:
00446 print 'load_controllers()', 'skip already loaded', name
00447 continue
00448 print 'load_controllers()', name
00449 service_proxy = rospy.ServiceProxy(service, pr2_mechanism_msgs.srv._LoadController.LoadController)
00450 try:
00451 request = pr2_mechanism_msgs.srv._LoadController.LoadControllerRequest()
00452 request.name = name
00453 response = service_proxy(request)
00454 if not response.ok:
00455 return False
00456 except rospy.ServiceException, e:
00457 print 'Service did not process request: %s' % str(e)
00458 return False
00459 return True
00460
00461 def switch_controllers(start_controllers, stop_controllers):
00462 print 'switch_controllers()'
00463 service = '/pr2_controller_manager/switch_controller'
00464 rospy.wait_for_service(service)
00465 service_proxy = rospy.ServiceProxy(service, pr2_mechanism_msgs.srv._SwitchController.SwitchController)
00466 try:
00467 request = pr2_mechanism_msgs.srv._SwitchController.SwitchControllerRequest()
00468 request.start_controllers = start_controllers
00469 request.stop_controllers = stop_controllers
00470 response = service_proxy(request)
00471 if not response.ok:
00472 return False
00473 except rospy.ServiceException, e:
00474 print 'Service did not process request: %s' % str(e)
00475 return False
00476 return True
00477
00478 manniquin_controllers_loaded = False
00479 def change_input_method():
00480 global manniquin_controllers_loaded
00481 global joint_observer
00482 index = main_window.input_method_comboBox.currentIndex()
00483 input_method = main_window.input_method_comboBox.itemData(index)
00484 print 'change_input_method()', index
00485
00486 manniquin_controllers = ['r_arm_controller_loose', 'l_arm_controller_loose', 'head_traj_controller_loose']
00487 standard_controllers = ['r_arm_controller', 'l_arm_controller', 'head_traj_controller']
00488 if input_method == INPUT_METHOD_ROBOT:
00489
00490 if not manniquin_controllers_loaded:
00491
00492 print 'change_input_method()', 'load manniquin controllers'
00493 manniquin_controllers_loaded = load_controllers(manniquin_controllers)
00494 if not manniquin_controllers_loaded:
00495 QMessageBox.critical(main_window, main_window.tr('Loading controllers failed'), main_window.tr('Could not load manniquin controllers.'))
00496
00497 success = switch_controllers(manniquin_controllers, standard_controllers)
00498 if success:
00499 joint_observer.start()
00500 else:
00501
00502 success = switch_controllers(standard_controllers, manniquin_controllers)
00503 if success:
00504 joint_observer.stop()
00505 if not success:
00506 QMessageBox.critical(main_window, main_window.tr('Switching controllers failed'), main_window.tr('Could not switch controllers.'))
00507
00508 main_window.input_method_comboBox.setCurrentIndex(INPUT_METHOD_SLIDERS)
00509 main_window.input_method_comboBox.currentIndexChanged.connect(change_input_method)
00510 if main_window.input_method_comboBox.count() <= 1:
00511 main_window.input_method_label.setVisible(False)
00512 main_window.input_method_comboBox.setVisible(False)
00513 main_window.input_method_horizontalLayout.parent().removeItem(main_window.input_method_horizontalLayout)
00514
00515
00516 kontrol_subscriber = KontrolSubscriber()
00517 if check_collisions:
00518 collision_checker = CollisionChecker()
00519 currently_in_collision = False
00520 default_color = main_window.lineEdit.palette().text().color()
00521
00522
00523 class Foo(QObject):
00524 current_values_changed = Signal(str)
00525 current_duration_changed = Signal(float)
00526 _update_current_value_signal = Signal()
00527 _show_input_notification_signal = Signal()
00528 _hide_input_notification_signal = Signal()
00529 _show_scene_notification_signal = Signal()
00530 _hide_scene_notification_signal = Signal()
00531 _update_color_of_line_edit_signal = Signal()
00532 def __init__(self):
00533 super(Foo, self).__init__()
00534 self._action_set = None
00535 self._update_current_value_signal.connect(self._update_current_value)
00536
00537 self._scene_notification = QDialog(main_window)
00538 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_scene_dialog.ui')
00539 loadUi(ui_file, self._scene_notification)
00540 self._scene_notification_timer = QTimer(main_window)
00541 self._scene_notification_timer.setInterval(5000)
00542 self._scene_notification_timer.setSingleShot(True)
00543 self._scene_notification_timer.timeout.connect(self._hide_scene_notification)
00544 self._scene_notification.finished.connect(self._hide_scene_notification)
00545
00546 self._input_notification = QDialog(main_window)
00547 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_input_method_dialog.ui')
00548 loadUi(ui_file, self._input_notification)
00549 self._input_notification_timer = QTimer(main_window)
00550 self._input_notification_timer.setInterval(5000)
00551 self._input_notification_timer.setSingleShot(True)
00552 self._input_notification_timer.timeout.connect(self._hide_input_method_notification)
00553 self._input_notification.finished.connect(self._hide_input_method_notification)
00554
00555 self._show_input_notification_signal.connect(self._show_input_notification)
00556 self._hide_input_notification_signal.connect(self._hide_input_method_notification)
00557 self._show_input_notification_signal.connect(self._show_scene_notification)
00558 self._hide_input_notification_signal.connect(self._hide_scene_notification)
00559 self._update_color_of_line_edit_signal.connect(self._update_color_of_line_edit)
00560
00561 def _hide_scene_notification(self, result=None):
00562 self._scene_notification_timer.stop()
00563 self._scene_notification.hide()
00564
00565 def _hide_input_method_notification(self, result=None):
00566 self._input_notification_timer.stop()
00567 self._input_notification.hide()
00568
00569
00570 def update_current_value(self):
00571 global check_collisions
00572 global currently_in_collision
00573
00574 if self._action_set is not None:
00575 self._action_set.stop()
00576 self._action_set = kontrol_subscriber.get_action_set()
00577 if self._action_set is not None:
00578 self.current_duration_changed.emit(self._action_set.get_duration())
00579
00580 if not is_in_slider_mode():
00581 currently_in_collision = False
00582 self._show_input_notification_signal.emit()
00583 return
00584 if self._input_notification_timer.isActive():
00585 self._hide_input_notification_signal.emit()
00586
00587
00588 if not kontrol_subscriber.is_valid_action_set():
00589 self._show_scene_notification_signal.emit()
00590 return
00591 if self._scene_notification_timer.isActive():
00592 self._hide_scene_notification_signal.emit()
00593
00594 joint_values = kontrol_subscriber.get_joint_values()
00595 if check_collisions:
00596 in_collision = collision_checker.is_in_collision(joint_values)
00597 else:
00598 in_collision = False
00599
00600 collision_toggled = (currently_in_collision != in_collision)
00601 currently_in_collision = in_collision
00602
00603 if collision_toggled:
00604 self._update_color_of_line_edit_signal.emit()
00605
00606 self._update_current_value_signal.emit()
00607
00608 def _show_input_notification(self):
00609
00610 self._input_notification.show()
00611 self._input_notification_timer.start()
00612
00613 def _show_scene_notification(self):
00614
00615 self._scene_notification.show()
00616 self._scene_notification_timer.start()
00617
00618 def _update_color_of_line_edit(self):
00619 global currently_in_collision
00620 palette = main_window.lineEdit.palette()
00621 if currently_in_collision:
00622 palette.setColor(QPalette.Text, QColor(255, 0, 0))
00623 else:
00624 palette.setColor(QPalette.Text, default_color)
00625 main_window.lineEdit.setPalette(palette)
00626
00627 def _update_current_value(self):
00628 global currently_in_collision
00629 main_window.append_pushButton.setEnabled(not currently_in_collision)
00630 main_window.insert_before_pushButton.setEnabled(not currently_in_collision)
00631
00632 value = self._action_set.to_string()
00633 self.current_values_changed.emit(value)
00634 for action in self._action_set._actions:
00635 action._duration = 0.1 if use_sim_time else 0.5
00636 self._action_set.execute()
00637 foo = Foo()
00638
00639 kontrol_subscriber.axes_changed.connect(foo.update_current_value)
00640 foo.current_values_changed.connect(main_window.lineEdit.setText)
00641 foo.current_duration_changed.connect(main_window.duration_doubleSpinBox.setValue)
00642
00643 def get_tab_widget(index):
00644 return main_window.PoseList_tabWidget.widget(index)
00645
00646 def get_table_view(index):
00647 tab_widget = get_tab_widget(index)
00648 return tab_widget.findChildren(QTableView, QRegExp('.*_tableView'))[0]
00649
00650 def get_current_tab_index():
00651 return main_window.PoseList_tabWidget.currentIndex()
00652
00653 def test_clicked(index):
00654 try:
00655 row = index.row()
00656 except:
00657 row = int(index)
00658 model = get_current_model()
00659 print 'execute %d' % row
00660 model.action_sequence().actions()[row].execute()
00661
00662
00663 def custom_focusNextPrevChild(self, next, old_focusNextPrevChild=QTableView.focusNextPrevChild):
00664 rc = old_focusNextPrevChild(self, next)
00665 if self.tabKeyNavigation() and self.currentIndex().isValid() and not(self.currentIndex().flags() & Qt.ItemIsEditable):
00666
00667 event = QKeyEvent(QEvent.KeyPress, Qt.Key_Tab, Qt.ShiftModifier if next else Qt.NoModifier)
00668 self.keyPressEvent(event)
00669 if event.isAccepted():
00670 return True
00671 return rc
00672
00673
00674 def custom_keyPressEvent(self, event, old_keyPressEvent=QTableView.keyPressEvent):
00675 if event.key() == Qt.Key_Delete and event.modifiers() == Qt.NoModifier:
00676 if delete_selected():
00677 print 'custom_keyPressEvent()', 'delete row'
00678 event.accept()
00679 return True
00680 return old_keyPressEvent(self, event)
00681
00682 for i in range(main_window.PoseList_tabWidget.count()):
00683 table_view = get_table_view(i)
00684 table_view.focusNextPrevChild = new.instancemethod(custom_focusNextPrevChild, table_view, None)
00685 table_view.keyPressEvent = new.instancemethod(custom_keyPressEvent, table_view, None)
00686
00687
00688 models = []
00689
00690 delegates = []
00691 for i in range(main_window.PoseList_tabWidget.count()):
00692 table_view = get_table_view(i)
00693 model = PosesDataModel(main_window.edit_model_radioButton.isChecked())
00694 model.actions_changed.connect(autosave_program)
00695 model.duration_modified.connect(update_sequence_duration)
00696 table_view.setModel(model)
00697 table_view.resizeColumnsToContents()
00698 duration_delegate = DoubleSpinBoxDelegate()
00699 duration_delegate.setMinimum(main_window.duration_doubleSpinBox.minimum())
00700 duration_delegate.setMaximum(main_window.duration_doubleSpinBox.maximum())
00701 duration_delegate.setSuffix(main_window.duration_doubleSpinBox.suffix())
00702 duration_delegate.setSingleStep(main_window.duration_doubleSpinBox.singleStep())
00703 table_view.setItemDelegateForColumn(0, duration_delegate)
00704 delegates.append(duration_delegate)
00705 model.add_delegates(table_view)
00706 table_view.clicked.connect(test_clicked)
00707 table_view.verticalHeader().sectionClicked.connect(test_clicked)
00708 models.append(model)
00709
00710 def toggle_model_editable():
00711 for i in range(main_window.PoseList_tabWidget.count()):
00712 models[i].set_editable(main_window.edit_model_radioButton.isChecked())
00713 table_view = get_table_view(i)
00714 table_view.resizeColumnsToContents()
00715
00716 main_window.read_only_model_radioButton.clicked.connect(toggle_model_editable)
00717 main_window.edit_model_radioButton.clicked.connect(toggle_model_editable)
00718
00719 def get_current_model():
00720 index = get_current_tab_index()
00721 return models[index]
00722
00723
00724 def get_action_set():
00725 if is_in_slider_mode():
00726 action_set = kontrol_subscriber.get_action_set()
00727 if action_set is not None:
00728 action_set.set_duration(main_window.duration_doubleSpinBox.value())
00729 else:
00730 action_set = joint_observer.action_set.deepcopy()
00731 return action_set
00732
00733 def append_current():
00734 if currently_in_collision:
00735 return
00736
00737 model = get_current_model()
00738
00739 action_set = get_action_set()
00740 if action_set is None:
00741 return
00742 model.add_action(action_set)
00743
00744 table_view = get_table_view(get_current_tab_index())
00745 rows = len(model.action_sequence().actions())
00746 table_view.resizeColumnsToContents()
00747 table_view.selectRow(rows - 1)
00748
00749 main_window.append_pushButton.clicked.connect(append_current)
00750
00751
00752 def insert_current_before_selected():
00753 if currently_in_collision:
00754 return
00755
00756 row = get_selected_row()
00757 if row is None:
00758 append_current()
00759 return
00760
00761 model = get_current_model()
00762
00763 action_set = get_action_set()
00764 if action_set is None:
00765 return
00766 model.add_action(action_set, row)
00767
00768 table_view = get_table_view(get_current_tab_index())
00769 table_view.resizeColumnsToContents()
00770 table_view.selectRow(row + 1)
00771
00772 main_window.insert_before_pushButton.clicked.connect(insert_current_before_selected)
00773
00774
00775 def insert_find_face():
00776 model = get_current_model()
00777 action_set = ActionSet()
00778 action = Pr2LookAtFace()
00779 action_set.add_action(action)
00780 action_set.set_duration(main_window.duration_doubleSpinBox.value())
00781 model.add_action(action_set)
00782
00783 main_window.find_face_pushButton.clicked.connect(insert_find_face)
00784
00785
00786 def delete_selected():
00787 row = get_selected_row()
00788 if row is None:
00789 return False
00790
00791 model = get_current_model()
00792 model.remove_action(row)
00793
00794 table_view = get_table_view(get_current_tab_index())
00795 rows = len(model.action_sequence().actions())
00796 if row >= rows:
00797 row = row - 1
00798 table_view.resizeColumnsToContents()
00799 table_view.selectRow(row)
00800 return True
00801
00802 main_window.delete_selected_pushButton.clicked.connect(delete_selected)
00803
00804
00805 def clone_selected():
00806 row = get_selected_row()
00807 if row is None:
00808 return
00809
00810 model = get_current_model()
00811 action = model.action_sequence().actions()[row]
00812 clone = action.deepcopy()
00813 model.add_action(clone, row + 1)
00814
00815 main_window.clone_selected_pushButton.clicked.connect(clone_selected)
00816
00817
00818 def get_row_count():
00819 model = get_current_model()
00820 return model.rowCount()
00821 def get_selected_row():
00822 table_view = get_table_view(get_current_tab_index())
00823 selection_model = table_view.selectionModel()
00824 if selection_model.hasSelection():
00825 row = selection_model.selectedRows()[0].row()
00826
00827 return row
00828
00829 return None
00830 def execute_selected():
00831 row = get_selected_row()
00832 if row is not None:
00833 model = get_current_model()
00834 print 'execute %d' % row
00835 model.action_sequence().actions()[row].execute()
00836
00837
00838 def set_selected_row(row):
00839
00840 rows = get_row_count()
00841 if rows == 0:
00842 return
00843 if row < 0:
00844 row = 0
00845 if row >= rows:
00846 row = rows - 1
00847 table_view = get_table_view(get_current_tab_index())
00848
00849 table_view.selectRow(row)
00850
00851 class RelaySignalInt(QObject):
00852 relay_signal = Signal(int)
00853 def __init__(self):
00854 super(RelaySignalInt, self).__init__()
00855 def emit(self, row):
00856 self.relay_signal.emit(row)
00857
00858 set_selected_row_signal = RelaySignalInt()
00859 set_selected_row_signal.relay_signal.connect(set_selected_row)
00860
00861 running_sequence = None
00862
00863 def set_tab(index):
00864 if get_current_tab_index() != index:
00865 main_window.PoseList_tabWidget.setCurrentIndex(index)
00866
00867 def finished_executing_current_sequence():
00868 global running_sequence
00869 print 'finished_executing_current_sequence()'
00870 model = get_current_model()
00871 action_sequence = model.action_sequence()
00872 action_sequence.executing_action_signal.disconnect(set_selected_row_signal.emit)
00873 action_sequence.execute_sequence_finished_signal.disconnect(finished_executing_current_sequence)
00874 running_sequence = None
00875
00876 def stop_sequence():
00877 global running_sequence
00878 if running_sequence is None:
00879 print 'stop_sequence() skipped - not running'
00880 return
00881 print 'stop_sequence()', running_sequence
00882 model = models[running_sequence]
00883 action_sequence = model.action_sequence()
00884 action_sequence.executing_action_signal.disconnect(set_selected_row_signal.emit)
00885 action_sequence.execute_sequence_finished_signal.disconnect(finished_executing_current_sequence)
00886 action_sequence.stop()
00887 running_sequence = None
00888
00889 def execute_sequence(index, first_action = None):
00890 global running_sequence
00891 if running_sequence == -1:
00892 print 'execute_sequence() skip execute due to running sequence'
00893 return
00894 if running_sequence is not None:
00895 stop_sequence()
00896 print 'execute_sequence()', index
00897 running_sequence = index
00898 set_tab(index)
00899 model = models[index]
00900 action_sequence = model.action_sequence()
00901 action_sequence.executing_action_signal.connect(set_selected_row_signal.emit)
00902 action_sequence.execute_sequence_finished_signal.connect(finished_executing_current_sequence)
00903 action_sequence.execute_all(first_action)
00904
00905 def execute_current_sequence():
00906 execute_sequence(get_current_tab_index())
00907
00908 def execute_current_sequence_from_selection():
00909 row = get_selected_row()
00910 if row == get_row_count() - 1:
00911 row = None
00912 execute_sequence(get_current_tab_index(), row)
00913
00914 main_window.run_sequence_from_selection_pushButton.clicked.connect(execute_current_sequence_from_selection)
00915
00916
00917 select_row_signal = RelaySignalInt()
00918 select_row_signal.relay_signal.connect(set_selected_row)
00919
00920 collision_notification = QDialog(main_window)
00921 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'collision_dialog.ui')
00922 loadUi(ui_file, collision_notification)
00923 collision_notification_timer = QTimer(main_window)
00924 collision_notification_timer.setInterval(3000)
00925 collision_notification_timer.setSingleShot(True)
00926 def hide_collision_notification(result=None):
00927 collision_notification_timer.stop()
00928 collision_notification.hide()
00929 collision_notification_timer.timeout.connect(hide_collision_notification)
00930 collision_notification.finished.connect(hide_collision_notification)
00931
00932 def check_buttons():
00933 triggered_buttons = kontrol_subscriber.get_triggered_buttons()
00934
00935 if KontrolSubscriber.previous_button in triggered_buttons:
00936 if get_selected_row() is not None:
00937 select_row_signal.emit(get_selected_row() - 1)
00938 else:
00939 select_row_signal.emit(0)
00940 elif KontrolSubscriber.play_button in triggered_buttons:
00941 execute_selected()
00942 elif KontrolSubscriber.next_button in triggered_buttons:
00943 if get_selected_row() is not None:
00944 select_row_signal.emit(get_selected_row() + 1)
00945 else:
00946 select_row_signal.emit(get_row_count() - 1)
00947
00948 elif KontrolSubscriber.repeat_button in triggered_buttons:
00949 execute_current_sequence()
00950 elif KontrolSubscriber.stop_button in triggered_buttons:
00951 stop_sequence()
00952 elif KontrolSubscriber.record_button in triggered_buttons:
00953 if currently_in_collision:
00954
00955 collision_notification.show()
00956 collision_notification_timer.start()
00957 append_current()
00958
00959 elif KontrolSubscriber.top1_button in triggered_buttons:
00960 set_tab(0)
00961 elif KontrolSubscriber.bottom1_button in triggered_buttons:
00962 set_tab(3)
00963 elif KontrolSubscriber.top2_button in triggered_buttons:
00964 set_tab(1)
00965 elif KontrolSubscriber.bottom2_button in triggered_buttons:
00966 set_tab(2)
00967
00968 elif KontrolSubscriber.top6_button in triggered_buttons:
00969 execute_sequence(0)
00970 elif KontrolSubscriber.bottom6_button in triggered_buttons:
00971 execute_sequence(3)
00972 elif KontrolSubscriber.top7_button in triggered_buttons:
00973 execute_sequence(1)
00974 elif KontrolSubscriber.bottom7_button in triggered_buttons:
00975 execute_sequence(2)
00976
00977 class RelaySignal(QObject):
00978 relay_signal = Signal()
00979 def __init__(self):
00980 super(RelaySignal, self).__init__()
00981 def emit(self):
00982 self.relay_signal.emit()
00983
00984 check_buttons_signal = RelaySignal()
00985 check_buttons_signal.relay_signal.connect(check_buttons)
00986 kontrol_subscriber.buttons_changed.connect(check_buttons_signal.emit)
00987
00988
00989 def check_ps3_buttons():
00990 triggered_buttons = ps3_subscriber.get_triggered_buttons()
00991
00992 if Ps3Subscriber.select_button in triggered_buttons:
00993
00994 pass
00995 elif Ps3Subscriber.start_button in triggered_buttons:
00996
00997 pass
00998
00999 elif Ps3Subscriber.square_button in triggered_buttons:
01000 execute_sequence(0)
01001 elif Ps3Subscriber.triangle_button in triggered_buttons:
01002 execute_sequence(1)
01003 elif Ps3Subscriber.circle_button in triggered_buttons:
01004 execute_sequence(2)
01005 elif Ps3Subscriber.cross_button in triggered_buttons:
01006 execute_sequence(3)
01007
01008 ps3_subscriber = Ps3Subscriber()
01009 check_ps3_buttons_signal = RelaySignal()
01010 check_ps3_buttons_signal.relay_signal.connect(check_ps3_buttons)
01011 ps3_subscriber.buttons_changed.connect(check_ps3_buttons_signal.emit)
01012
01013
01014 current_name = None
01015
01016 def load_from_file():
01017 global current_name
01018 file_name, _ = QFileDialog.getOpenFileName(main_window, main_window.tr('Load program from file'), None, main_window.tr('Puppet Talk (*.pt)'))
01019 if file_name is None or file_name == '':
01020 return
01021
01022 print 'load_from_file', file_name
01023 handle = open(file_name, 'rb')
01024 storage = SimpleFormat(handle)
01025
01026 count = storage.deserialize_data()
01027 tabs = main_window.PoseList_tabWidget.count()
01028 for index in range(tabs):
01029 model = models[index]
01030 if index < count:
01031 model.action_sequence().deserialize(storage)
01032 model.reset()
01033 else:
01034 model.remove_all_actions()
01035 handle.close()
01036
01037 current_name = os.path.splitext(os.path.basename(file_name))[0]
01038
01039 update_sequence_duration()
01040
01041 main_window.actionOpen.triggered.connect(load_from_file)
01042
01043
01044 def serialize(storage):
01045 count = main_window.PoseList_tabWidget.count()
01046 storage.serialize_data(count)
01047 for index in range(count):
01048 model = models[index]
01049 model.action_sequence().serialize(storage)
01050
01051 def save_to_file():
01052 file_name, _ = QFileDialog.getSaveFileName(main_window, main_window.tr('Save program to file'), 'example.pt', main_window.tr('Puppet Talk (*.pt)'))
01053 if file_name is None or file_name == '':
01054 return False
01055
01056 save_to_filename(file_name)
01057 return True
01058
01059 def save_to_filename(file_name):
01060 global current_name
01061 print 'save_to_filename', file_name
01062 handle = open(file_name, 'wb')
01063 storage = SimpleFormat(handle)
01064 serialize(storage)
01065 handle.close()
01066
01067 current_name = os.path.splitext(os.path.basename(file_name))[0]
01068
01069 main_window.actionSave_As.triggered.connect(save_to_file)
01070
01071
01072 def save_screenshot():
01073 path = os.path.expanduser('~')
01074 filename_template = 'robot-%d.png'
01075 serial = 1
01076 while True:
01077 filename = os.path.join(path, filename_template % serial)
01078 if not os.path.exists(filename):
01079 break
01080 serial += 1
01081 widget = robot_view.children()[0]
01082 pixmap = QPixmap.grabWindow(widget.winId())
01083 rc = pixmap.save(filename)
01084 if rc:
01085 QMessageBox.information(main_window, main_window.tr('Saved screenshot'), main_window.tr('Screenshot saved in file: %s') % filename)
01086 else:
01087 QMessageBox.critical(main_window, main_window.tr('Saving screenshot failed'), main_window.tr('Could not save screenshot.'))
01088
01089 main_window.actionSave_Screenshot.triggered.connect(save_screenshot)
01090
01091
01092 def clear_all():
01093 global current_name
01094 confirmed = True
01095 if current_name is None:
01096 button = QMessageBox.question(main_window, main_window.tr('Clear all poses'), main_window.tr('Do you really want to delete all poses?'), QMessageBox.No | QMessageBox.Yes)
01097 confirmed = button == QMessageBox.Yes
01098 if confirmed:
01099 print 'clear_all()'
01100 for index in range(main_window.PoseList_tabWidget.count()):
01101 model = models[index]
01102 model.remove_all_actions()
01103 current_name = None
01104 set_tab(0)
01105 main_window.angled_view_radioButton.click()
01106
01107 main_window.actionClear_All.triggered.connect(clear_all)
01108
01109
01110 default_pose = DefaultAction()
01111 default_pose.set_duration(8.0)
01112
01113 def finished_executing_default_pose():
01114 global running_sequence
01115 print 'finished_executing_default_pose()'
01116 running_sequence = None
01117
01118 def execute_default_pose():
01119 global running_sequence
01120 if running_sequence is not None:
01121 stop_sequence()
01122 print 'execute_default_pose()'
01123 running_sequence = -1
01124 default_pose.execute()
01125
01126 default_pose.execute_finished_signal.connect(finished_executing_default_pose)
01127
01128 def add_default_pose():
01129 model = get_current_model()
01130 action_set = ActionSet()
01131 action = DefaultAction()
01132 action_set.add_action(action)
01133 action_set.set_duration(main_window.duration_doubleSpinBox.value())
01134 model.add_action(action_set)
01135
01136 table_view = get_table_view(get_current_tab_index())
01137 rows = len(model.action_sequence().actions())
01138 table_view.resizeColumnsToContents()
01139 table_view.selectRow(rows - 1)
01140
01141 main_window.actionDefault_Pose.triggered.connect(add_default_pose)
01142
01143
01144 main_window.actionTest_Program.triggered.connect(execute_current_sequence)
01145
01146
01147 queue_default_username = 'admin'
01148 queue_default_password = 'admin'
01149
01150 def queue_dialog():
01151 dialog = QDialog()
01152 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'queue_dialog.ui')
01153 loadUi(ui_file, dialog)
01154
01155 if current_name is not None:
01156 dialog.label_lineEdit.setText(current_name)
01157 dialog.username_lineEdit.setText(queue_default_username)
01158 dialog.password_lineEdit.setText(queue_default_password)
01159
01160 rc = dialog.exec_()
01161 if rc == QDialog.Rejected:
01162 return
01163
01164 queue_program(dialog.username_lineEdit.text(), dialog.password_lineEdit.text(), dialog.label_lineEdit.text())
01165
01166 def save_and_queue_program():
01167 rc = save_to_file()
01168 if rc:
01169 queue_program(queue_default_username, queue_default_password, current_name)
01170
01171 def queue_program(username, password, label):
01172 queue = ProgramQueue(username, password)
01173 try:
01174 rc = queue.login()
01175 except:
01176 rc = False
01177 if not rc:
01178 QMessageBox.critical(main_window, main_window.tr('Login failed'), main_window.tr('Could not log in to the program queue.'))
01179 return
01180
01181 output = StringIO()
01182 storage = SimpleFormat(output)
01183 serialize(storage)
01184 program_data = output.getvalue()
01185 output.close()
01186
01187 try:
01188 id = queue.upload_program(program_data, label)
01189 except:
01190 id = False
01191 if not id:
01192 QMessageBox.critical(main_window, main_window.tr('Upload failed'), main_window.tr('Could not upload program to queue.'))
01193 return
01194 try:
01195 queue.logout()
01196 except:
01197 pass
01198 QMessageBox.information(main_window, main_window.tr('Uploaded program'), main_window.tr('Uploaded program (%d) successfully.') % id)
01199
01200 main_window.actionQueue_Program.triggered.connect(queue_dialog)
01201 main_window.save_and_queue_program_pushButton.clicked.connect(save_and_queue_program)
01202
01203
01204 main_window.actionExit.triggered.connect(main_window.close)
01205
01206
01207 def closeEvent(event):
01208 if not sigint_called:
01209 button = QMessageBox.question(main_window, main_window.tr('Close application'), main_window.tr('Do you really want to close the application?'), QMessageBox.Cancel | QMessageBox.Close)
01210 else:
01211 button = QMessageBox.Close
01212 if button == QMessageBox.Close:
01213 event.accept()
01214 else:
01215 event.ignore()
01216 main_window.closeEvent = closeEvent
01217
01218
01219
01220 main_window.showMaximized()
01221
01222 execute_default_pose()
01223
01224 sys.exit(app.exec_())