00001 import tool_utils as tu
00002 from PyQt4.QtGui import *
00003 from PyQt4.QtCore import *
00004 import numpy as np
00005 import geometry_msgs.msg as geo
00006 import smach
00007 import rospy
00008 import tf.transformations as tr
00009 from tf_broadcast_server.srv import BroadcastTransform, GetTransforms, ClearTransforms
00010
00011 import tf_utils as tfu
00012
00013
00014 class PointCloudClickTool(tu.ToolBase):
00015
00016 def __init__(self, rcommander):
00017 tu.ToolBase.__init__(self, rcommander, 'create_origin', 'Create Origin', Point3DState)
00018 self.default_frame = '/base_link'
00019 self.tf_listener = rcommander.tf_listener
00020 self.frames_service = rospy.ServiceProxy('get_transforms', GetTransforms)
00021 self.clear_frames_service = rospy.ServiceProxy('clear_all_transforms', ClearTransforms)
00022
00023 def fill_property_box(self, pbox):
00024 formlayout = pbox.layout()
00025
00026 self.xline = QLineEdit(pbox)
00027 self.yline = QLineEdit(pbox)
00028 self.zline = QLineEdit(pbox)
00029
00030 self.time_out_box = QDoubleSpinBox(pbox)
00031 self.time_out_box.setMinimum(1.)
00032 self.time_out_box.setMaximum(1000.)
00033 self.time_out_box.setSingleStep(1.)
00034
00035 self.frame_box = tu.FrameBox(self.frames_service)
00036
00037
00038 self.orientation_frame_box = tu.FrameBox(self.frames_service)
00039
00040
00041
00042
00043
00044 self.pose_button = QPushButton(pbox)
00045 self.pose_button.setText('Get Point')
00046
00047 self.clear_frames_button = QPushButton(pbox)
00048 self.clear_frames_button.setText('Clear Frames')
00049
00050 self.wait_check = QCheckBox(pbox)
00051 self.wait_check.setTristate(False)
00052
00053 pos_group = QGroupBox('Position', pbox)
00054 pos_layout = QFormLayout(pos_group)
00055 pos_group.setLayout(pos_layout)
00056 pos_layout.addRow("&Frame", self.frame_box.create_box(pbox))
00057 pos_layout.addRow("&X", self.xline)
00058 pos_layout.addRow("&Y", self.yline)
00059 pos_layout.addRow("&Z", self.zline)
00060 formlayout.addRow(pos_group)
00061
00062 ori_group = QGroupBox("Orientation", pbox)
00063 ori_layout = QFormLayout(ori_group)
00064 ori_layout.addRow("Frame", self.orientation_frame_box.create_box(pbox))
00065 formlayout.addRow(ori_group)
00066
00067 formlayout.addRow('Wait For Point', self.wait_check)
00068 formlayout.addRow('Wait Time Out', self.time_out_box)
00069 formlayout.addRow(self.pose_button)
00070 formlayout.addRow(self.clear_frames_button)
00071
00072 self.rcommander.connect(self.pose_button, SIGNAL('clicked()'), self.get_current_pose)
00073 self.rcommander.connect(self.wait_check, SIGNAL('stateChanged(int)'), self.box_checked)
00074 self.rcommander.connect(self.clear_frames_button, SIGNAL('clicked()'), self.clear_frames_button_cb)
00075
00076 self.reset()
00077 pbox.update()
00078
00079 def clear_frames_button_cb(self):
00080 self.clear_frames_service()
00081
00082 def new_node(self, name=None):
00083 point = [float(str(self.xline.text())), float(str(self.yline.text())), float(str(self.zline.text()))]
00084
00085 point_frame = self.frame_box.text()
00086
00087 orientation_frame = self.orientation_frame_box.text()
00088 if name == None:
00089 nname = self.name + str(self.counter)
00090 else:
00091 nname = name
00092
00093 wait_for_msg = self.wait_check.isChecked()
00094 time_out = self.time_out_box.value()
00095 return Point3DState(nname, point,
00096 point_frame, orientation_frame,
00097 wait_for_msg=wait_for_msg, time_out=time_out)
00098
00099 def box_checked(self, state):
00100 if state == 0:
00101 self.xline.setEnabled(True)
00102 self.yline.setEnabled(True)
00103 self.zline.setEnabled(True)
00104
00105 self.frame_box.setEnabled(True)
00106 self.pose_button.setEnabled(True)
00107
00108 if state == 2:
00109 self.xline.setEnabled(False)
00110 self.yline.setEnabled(False)
00111 self.zline.setEnabled(False)
00112
00113 self.frame_box.setEnabled(False)
00114 self.pose_button.setEnabled(False)
00115
00116 def set_node_properties(self, node):
00117 self.xline.setText(str(node.point[0]))
00118 self.yline.setText(str(node.point[1]))
00119 self.zline.setText(str(node.point[2]))
00120 self.frame_box.set_text(node.point_frame)
00121 self.orientation_frame_box.set_text(node.orientation_frame)
00122 self.time_out_box.setValue(node.time_out)
00123 if node.wait_for_msg:
00124 self.wait_check.setCheckState(2)
00125
00126
00127 def reset(self):
00128 self.xline.setText(str(0.))
00129 self.yline.setText(str(0.))
00130 self.zline.setText(str(0.))
00131
00132 self.time_out_box.setValue(120.)
00133 self.wait_check.setCheckState(False)
00134 self.frame_box.set_text(self.default_frame, create=False)
00135 self.orientation_frame_box.set_text(self.default_frame, create=False)
00136
00137
00138 def get_current_pose(self):
00139 pose_stamped = rospy.wait_for_message('/cloud_click_point', geo.PoseStamped, 5.)
00140 self.xline.setText('%.3f' % pose_stamped.pose.position.x)
00141 self.yline.setText('%.3f' % pose_stamped.pose.position.y)
00142 self.zline.setText('%.3f' % pose_stamped.pose.position.z)
00143
00144 q = pose_stamped.pose.orientation
00145 phi, theta, psi = tr.euler_from_quaternion([q.x, q.y, q.z, q.w])
00146 self.psi_line.setText('%.3f' % phi)
00147 self.theta_line.setText('%.3f' % theta)
00148 self.psi_line.setText('%.3f' % psi)
00149 self.frame_box.set_text(pose_stamped.header.frame_id)
00150 self.orientation_frame_box.set_text(pose_stamped.header.frame_id)
00151
00152
00153
00154 class WaitForMessage:
00155
00156 def __init__(self, topic, message_type):
00157 self.subscriber = rospy.Subscriber(topic, message_type, self.message_cb)
00158 self.msg = None
00159
00160 def message_cb(self, message):
00161 self.msg = message
00162
00163 def get_message(self):
00164 return self.msg
00165
00166 def __del__(self):
00167 self.subscriber.unregister()
00168
00169
00170 class Point3DState(tu.StateBase):
00171
00172 def __init__(self, name, point,
00173 point_frame, orientation_frame, wait_for_msg, time_out):
00174 tu.StateBase.__init__(self, name)
00175 self.point = point
00176 self.point_frame = point_frame
00177 self.orientation_frame = orientation_frame
00178 self.time_out = time_out
00179 self.wait_for_msg = wait_for_msg
00180
00181 def get_smach_state(self):
00182 if self.wait_for_msg:
00183 return Point3DStateSmach(self.get_name(), self.orientation_frame, message = None, time_out = self.time_out)
00184 else:
00185 ps = geo.PointStamped()
00186 ps.header.frame_id = self.point_frame
00187 ps.header.stamp = rospy.Time.now()
00188 ps.point.x = self.point[0]
00189 ps.point.y = self.point[1]
00190 ps.point.z = self.point[2]
00191
00192 return Point3DStateSmach(self.get_name(), self.orientation_frame, message = ps, time_out = None)
00193
00194
00195 class Point3DStateSmach(smach.State):
00196
00197
00198
00199
00200 def __init__(self, frame_name, orientation_frame, message = None, time_out = None):
00201 smach.State.__init__(self,
00202 outcomes = ['succeeded', 'preempted', 'timed_out'],
00203 input_keys = [], output_keys = [])
00204
00205 self.frame_name = frame_name
00206 self.orientation_frame = orientation_frame
00207 self.time_out = time_out
00208 self.message = message
00209 self.broadcast_transform_srv = rospy.ServiceProxy('broadcast_transform', BroadcastTransform)
00210
00211 def set_robot(self, robot):
00212 self.robot = robot
00213
00214 def execute(self, userdata):
00215
00216 point_stamped = self.message
00217 t_start = rospy.get_time()
00218 r = rospy.Rate(10)
00219 waitobj = WaitForMessage('/cloud_click_point', geo.PoseStamped)
00220 pose_stamped = None
00221 while point_stamped == None:
00222 try:
00223 pose_stamped = waitobj.get_message()
00224 if pose_stamped != None:
00225 point_stamped = geo.PointStamped()
00226 point_stamped.header = pose_stamped.header
00227 point_stamped.point = pose_stamped.pose.position
00228
00229 r.sleep()
00230 except rospy.ROSException, e:
00231 pass
00232
00233 if self.preempt_requested():
00234 self.service_preempt()
00235 return 'preempted'
00236
00237 if (self.time_out != None) and ((rospy.get_time() - t_start) > self.time_out):
00238 return 'timed_out'
00239 del waitobj
00240
00241
00242
00243 frame_id_T_frame_name = tfu.origin_to_frame(point_stamped, self.orientation_frame,
00244 self.robot.tf_listener, point_stamped.header.frame_id)
00245 pose = tfu.stamp_pose(tfu.mat_to_pose(frame_id_T_frame_name), point_stamped.header.frame_id)
00246
00247
00248
00249 self.broadcast_transform_srv(self.frame_name, pose)
00250
00251
00252 return 'succeeded'
00253
00254
00255
00256