00001 import roslib; roslib.load_manifest('rcommander')
00002 import rospy
00003 from PyQt4.QtGui import *
00004 from PyQt4.QtCore import *
00005 import tool_utils as tu
00006 import pr2_utils as pu
00007 import numpy as np
00008 import actionlib_msgs.msg as am
00009 import smach
00010
00011
00012 class JointSequenceTool(tu.ToolBase):
00013
00014 def __init__(self, rcommander):
00015 tu.ToolBase.__init__(self, rcommander, 'joint_sequence', 'Joint Sequence')
00016 self.joint_name_fields = ["shoulder_pan_joint", "shoulder_lift_joint", "upper_arm_roll_joint",
00017 "elbow_flex_joint", "forearm_roll_joint", "wrist_flex_joint", "wrist_roll_joint"]
00018 self.joint_angs_list = None
00019
00020 def fill_property_box(self, pbox):
00021 formlayout = pbox.layout()
00022 self.arm_box = QComboBox(pbox)
00023 self.arm_box.addItem('left')
00024 self.arm_box.addItem('right')
00025 formlayout.addRow('&Arm', self.arm_box)
00026
00027
00028 for name in self.joint_name_fields:
00029 exec("self.%s = QLineEdit(pbox)" % name)
00030 exec("formlayout.addRow(\"&\" + name, self.%s)" % name)
00031
00032 self.time_box = QDoubleSpinBox(pbox)
00033 self.time_box.setMinimum(0)
00034 self.time_box.setMaximum(1000.)
00035 self.time_box.setSingleStep(.2)
00036 self.time_box.setValue(1.)
00037 formlayout.addRow('&Time', self.time_box)
00038
00039
00040 self.joint_angs_list = []
00041 self.list_widget = QListWidget(pbox)
00042 self.rcommander.connect(self.list_widget, SIGNAL('itemSelectionChanged()'), self.item_selection_changed_cb)
00043 self.list_widget_buttons = QWidget(pbox)
00044 self.lbb_hlayout = QHBoxLayout(self.list_widget_buttons)
00045
00046 self.add_joint_set_button = QPushButton(self.list_widget_buttons)
00047 self.add_joint_set_button.setText('Add')
00048 self.rcommander.connect(self.add_joint_set_button, SIGNAL('clicked()'), self.add_joint_set_cb)
00049
00050 self.remove_joint_set_button = QPushButton(self.list_widget_buttons)
00051 self.remove_joint_set_button.setText('Remove')
00052 self.rcommander.connect(self.remove_joint_set_button, SIGNAL('clicked()'), self.remove_pose_cb)
00053
00054 self.pose_button = QPushButton(self.list_widget_buttons)
00055 self.pose_button.setText('Pose')
00056 self.rcommander.connect(self.pose_button, SIGNAL('clicked()'), self.get_current_joint_angles)
00057
00058 self.lbb_hlayout.addWidget(self.add_joint_set_button)
00059 self.lbb_hlayout.addWidget(self.remove_joint_set_button)
00060 self.lbb_hlayout.addWidget(self.pose_button)
00061 self.lbb_hlayout.setContentsMargins(2, 2, 2, 2)
00062
00063 formlayout.addRow(self.list_widget)
00064 formlayout.addRow(self.list_widget_buttons)
00065 self.reset()
00066
00067 def get_current_joint_angles(self):
00068 if ('left' == str(self.arm_box.currentText())):
00069 arm_obj = self.rcommander.pr2.left
00070 else:
00071 arm_obj = self.rcommander.pr2.right
00072
00073 pose_mat = arm_obj.pose()
00074 for idx, name in enumerate(self.joint_name_fields):
00075 deg = np.degrees(pose_mat[idx, 0])
00076 exec('line_edit = self.%s' % name)
00077 line_edit.setText(str(deg))
00078
00079 def _has_name(self, test_name):
00080 for rec in self.joint_angs_list:
00081 if rec['name'] == test_name:
00082 return True
00083 else:
00084 return False
00085
00086 def _create_name(self):
00087 idx = len(self.joint_angs_list)
00088 tentative_name = 'point%d' % idx
00089
00090 while self._has_name(tentative_name):
00091 idx = idx + 1
00092 tentative_name = 'point%d' % idx
00093
00094 return tentative_name
00095
00096 def item_selection_changed_cb(self):
00097 selected = self.list_widget.selectedItems()
00098 if len(selected) == 0:
00099 return
00100 idx = self._find_index_of(str(selected[0].text()))
00101 joint_angs = self.joint_angs_list[idx]['angs']
00102 self._set_joints_to_fields(joint_angs)
00103 self.time_box.setValue(self.joint_angs_list[idx]['time'])
00104
00105 def add_joint_set_cb(self):
00106
00107 name = self._create_name()
00108 self.list_widget.addItem(name)
00109 self.joint_angs_list.append({'name':name, 'time': self.time_box.value(), 'angs': self._read_joints_from_fields()})
00110
00111 def _find_index_of(self, name):
00112 for idx, tup in enumerate(self.joint_angs_list):
00113 if tup['name'] == name:
00114 return idx
00115 return None
00116
00117 def remove_pose_cb(self):
00118
00119 selected = self.list_widget.selectedItems()
00120 if len(selected) == 0:
00121 return
00122 sname = str(selected[0].text())
00123
00124
00125 idx = self._find_index_of(sname)
00126 self.list_widget.takeItem(idx)
00127
00128 if idx == None:
00129 raise RuntimeError('Inconsistency detected in list')
00130 else:
00131 self.joint_angs_list.pop(idx)
00132
00133 def _read_joints_from_fields(self):
00134 joints = []
00135 for name in self.joint_name_fields:
00136 exec('rad = np.radians(float(str(self.%s.text())))' % name)
00137 joints.append(rad)
00138 return joints
00139
00140 def _set_joints_to_fields(self, joints):
00141 for idx, name in enumerate(self.joint_name_fields):
00142 deg = np.degrees(joints[idx])
00143 exec('line_edit = self.%s' % name)
00144 line_edit.setText(str(deg))
00145
00146 def _create_node(self, name=None):
00147 if name == None:
00148 nname = self.name + str(self.counter)
00149 else:
00150 nname = name
00151
00152
00153 sstate = JointSequenceState(nname, str(self.arm_box.currentText()), self.joint_angs_list)
00154 sstate.set_robot(self.rcommander.pr2)
00155 return sstate
00156
00157 def _node_selected(self, my_node):
00158 self.joint_angs_list = my_node.joint_waypoints
00159 for d in self.joint_angs_list:
00160 self.list_widget.addItem(d['name'])
00161 self.arm_box.setCurrentIndex(self.arm_box.findText(my_node.arm))
00162 self.list_widget.setCurrentItem(self.list_widget.item(0))
00163
00164 def reset(self):
00165 self.arm_box.setCurrentIndex(self.arm_box.findText('left'))
00166 for name in self.joint_name_fields:
00167 exec('self.%s.setText(str(0.))' % name)
00168
00169 def get_smach_class(self):
00170 return JointSequenceState
00171
00172
00173 class JointSequenceState(smach.State, tu.StateBase):
00174
00175 TIME_OUT_FACTOR = 2.
00176
00177 def __init__(self, name, arm, joint_waypoints):
00178 self.name = name
00179 tu.StateBase.__init__(self, self.name)
00180 self.arm = arm
00181 self.joint_waypoints = joint_waypoints
00182 self.arm_obj = None
00183 self.__init_unpicklables__()
00184
00185 def execute(self, userdata):
00186
00187 times = []
00188 wps = []
00189 for d in self.joint_waypoints:
00190 wps.append(np.matrix(d['angs']).T)
00191 times.append(d['time'])
00192
00193 self.arm_obj.set_poses(np.column_stack(wps), np.cumsum(np.array(times)), block=False)
00194 client = self.arm_obj.client
00195 state = client.get_state()
00196 print 'goal status', tu.goal_status_to_string(state)
00197
00198
00199 trajectory_time_out = JointSequenceState.TIME_OUT_FACTOR * np.sum(times)
00200 succeeded = False
00201 preempted = False
00202 r = rospy.Rate(30)
00203 start_time = rospy.get_time()
00204 while True:
00205
00206 if self.preempt_requested():
00207 rospy.loginfo('JointSequenceState: preempt requested')
00208 client.cancel_goal()
00209 self.service_preempt()
00210 preempted = True
00211 break
00212
00213 if (rospy.get_time() - start_time) > trajectory_time_out:
00214 client.cancel_goal()
00215 rospy.loginfo('JointSequenceState: timed out!')
00216 succeeded = True
00217 break
00218
00219
00220 if (state not in [am.GoalStatus.ACTIVE, am.GoalStatus.PENDING]):
00221 if state == am.GoalStatus.SUCCEEDED:
00222 rospy.loginfo('JointSequenceState: Succeeded!')
00223 succeeded = True
00224 break
00225
00226 r.sleep()
00227
00228 if preempted:
00229 return 'preempted'
00230
00231 if succeeded:
00232 return 'succeeded'
00233
00234 return 'failed'
00235
00236 def set_robot(self, pr2):
00237 if self.arm == 'left':
00238 self.arm_obj = pr2.left
00239
00240 if self.arm == 'right':
00241 self.arm_obj = pr2.right
00242
00243 def __init_unpicklables__(self):
00244 smach.State.__init__(self, outcomes = ['succeeded', 'preempted', 'failed'], input_keys = [], output_keys = [])
00245
00246 def __getstate__(self):
00247 state = tu.StateBase.__getstate__(self)
00248 my_state = [self.name, self.arm, self.joint_waypoints]
00249 return {'state_base': state, 'self': my_state}
00250
00251 def __setstate__(self, state):
00252 tu.StateBase.__setstate__(self, state['state_base'])
00253 self.name, self.arm, self.joint_waypoints = state['self']
00254 self.__init_unpicklables__()
00255
00256