00001
00002
00003 import sys
00004 import numpy as np
00005
00006 import roslib
00007 roslib.load_manifest('hrl_ellipsoidal_control')
00008
00009 import rospy
00010 from geometry_msgs.msg import PoseStamped
00011
00012 from ellipsoid_space import EllipsoidSpace
00013 from msg import EllipsoidMoveAction, EllipsoidMoveResult
00014 from msg import EllipsoidParams
00015 from hrl_ellipsoidal_control.controller_base import CartesianStepController, min_jerk_traj
00016 from pykdl_utils.joint_kinematics import create_joint_kin
00017 import hrl_geom.transformations as trans
00018 from hrl_geom.pose_converter import PoseConv
00019
00020 class EllipsoidParamServer(object):
00021
00022 def __init__(self):
00023 self.ell_param_sub = rospy.Subscriber("/ellipsoid_params", EllipsoidParams,
00024 self.load_params)
00025 self.kinect_frame = rospy.get_param("~kinect_frame", "head_mount_kinect_rgb_optical_frame")
00026 self.kin_head = create_joint_kin("base_link", self.kinect_frame)
00027 self.ell_space = None
00028 self.head_center = None
00029 self.head_center_pub = rospy.Publisher("/head_center", PoseStamped)
00030 def pub_head_center(te):
00031 if self.head_center is not None:
00032 self.head_center_pub.publish(self.head_center)
00033 rospy.Timer(rospy.Duration(0.2), pub_head_center)
00034
00035 def load_params(self, params):
00036 kinect_B_head = PoseConv.to_homo_mat(params.e_frame)
00037 base_B_kinect = self.kin_head.forward(base_link="base_link",
00038 end_link=self.kinect_frame)
00039 base_B_head = base_B_kinect * kinect_B_head
00040 self.head_center = PoseConv.to_pose_stamped_msg("/base_link",base_B_head)
00041 self.ell_space = EllipsoidSpace()
00042 self.ell_space.load_ell_params(params.E, params.is_oblate, params.height)
00043 rospy.loginfo("Loaded ellispoidal parameters.")
00044
00045 def params_loaded(self):
00046 return self.ell_space is not None
00047
00048 def get_ell_pose(self, pose):
00049 torso_B_kinect = self.kin_head.forward(base_link="/torso_lift_link")
00050 torso_B_ee = PoseConv.to_homo_mat(pose)
00051 kinect_B_ee = torso_B_kinect**-1 * torso_B_ee
00052 ell_B_pose = self.get_ell_frame(self.kinect_frame)**-1 * kinect_B_ee
00053 return self.ell_space.pose_to_ellipsoidal(ell_B_pose)
00054
00055
00056 def robot_ellipsoidal_pose(self, lat, lon, height, orient_quat, kinect_frame_mat=None):
00057 if kinect_frame_mat is None:
00058 kinect_frame_mat = self.get_ell_frame()
00059 pos, quat = self.ell_space.ellipsoidal_to_pose(lat, lon, height)
00060 quat_rotated = trans.quaternion_multiply(quat, orient_quat)
00061 ell_pose_mat = PoseConv.to_homo_mat(pos, quat_rotated)
00062 return PoseConv.to_pos_rot(kinect_frame_mat * ell_pose_mat)
00063
00064 def get_ell_frame(self, frame="/torso_lift_link"):
00065
00066 base_B_head = PoseConv.to_homo_mat(self.head_center)
00067 target_B_base = self.kin_head.forward(end_link=frame)
00068 return target_B_base**-1 * base_B_head
00069
00070 class EllipsoidController(CartesianStepController):
00071
00072 def __init__(self):
00073 super(EllipsoidController, self).__init__()
00074 self.ell_server = EllipsoidParamServer()
00075 self._lat_bounds = None
00076 self._lon_bounds = None
00077 self._height_bounds = None
00078 self._no_bounds = True
00079
00080 def get_ell_ep(self):
00081 ell_ep, ell_rot = self.ell_server.get_ell_pose(self.arm.get_ep())
00082 return ell_ep
00083
00084 def execute_ell_move(self, change_ep, abs_sel, orient_quat=[0., 0., 0., 1.],
00085 velocity=0.001, blocking=True):
00086 if not self.cmd_lock.acquire(False):
00087 return False
00088 ell_f, rot_mat_f = self._parse_ell_move(change_ep, abs_sel, orient_quat)
00089 traj = self._create_ell_trajectory(ell_f, rot_mat_f, orient_quat, velocity)
00090 if traj is None:
00091 rospy.logerr("[ellipsoid_controller] Bad trajectory.")
00092 self.cmd_lock.release()
00093 return False
00094 retval = self._run_traj(traj, blocking=blocking)
00095 self.cmd_lock.release()
00096 return retval
00097
00098 def set_bounds(self, lat_bounds=None, lon_bounds=None, height_bounds=None):
00099 if lat_bounds is None and lon_bounds is None and height_bounds is None:
00100 self._no_bounds = True
00101 self._no_bounds = False
00102 assert lon_bounds[1] >= 0
00103 self._lat_bounds = lat_bounds
00104 self._lon_bounds = lon_bounds
00105 self._height_bounds = height_bounds
00106
00107 def _clip_ell_ep(self, ell_ep):
00108 if self._no_bounds:
00109 return ell_ep
00110 lat = np.clip(ell_ep[0], self._lat_bounds[0], self._lat_bounds[1])
00111 if self._lon_bounds[0] >= 0:
00112 lon = np.clip(ell_ep[1], self._lon_bounds[0], self._lon_bounds[1])
00113 else:
00114 ell_ep_1 = np.mod(ell_ep[1], 2 * np.pi)
00115 min_lon = np.mod(self._lon_bounds[0], 2 * np.pi)
00116 if ell_ep_1 >= min_lon or ell_ep_1 <= self._lon_bounds[1]:
00117 lon = ell_ep[1]
00118 else:
00119 if min_lon - ell_ep_1 < ell_ep_1 - self._lon_bounds[1]:
00120 lon = min_lon
00121 else:
00122 lon = self._lon_bounds[1]
00123 height = np.clip(ell_ep[2], self._height_bounds[0], self._height_bounds[1])
00124 return np.array([lat, lon, height])
00125
00126 def arm_in_bounds(self):
00127 if self._no_bounds:
00128 return True
00129 ell_ep = self.get_ell_ep()
00130 equals = ell_ep == self._clip_ell_ep(ell_ep)
00131 print ell_ep, equals
00132 if self._lon_bounds[0] >= 0 and ell_ep[1] >= 0:
00133 return np.all(equals)
00134 else:
00135 ell_ep_1 = np.mod(ell_ep[1], 2 * np.pi)
00136 min_lon = np.mod(self._lon_bounds[0], 2 * np.pi)
00137 return (equals[0] and equals[2] and
00138 (ell_ep_1 >= min_lon or ell_ep_1 <= self._lon_bounds[1]))
00139
00140 def _parse_ell_move(self, change_ep, abs_sel, orient_quat):
00141
00142
00143 change_ell_ep, change_rot_ep = change_ep
00144
00145
00146
00147 abs_ell_ep_sel, is_abs_rot = abs_sel
00148 ell_f = np.where(abs_ell_ep_sel,
00149 change_ell_ep,
00150 np.array(self.get_ell_ep()) + np.array(change_ell_ep))
00151
00152 print "old", ell_f
00153 if ell_f[0] > np.pi:
00154 ell_f[0] = 2 * np.pi - ell_f[0]
00155 ell_f[1] *= -1
00156 if ell_f[0] < 0.:
00157 ell_f[0] *= -1
00158 ell_f[1] *= -1
00159 ell_f[1] = np.mod(ell_f[1], 2 * np.pi)
00160 ell_f = self._clip_ell_ep(ell_f)
00161 print "new", ell_f
00162 if is_abs_rot:
00163
00164
00165 rot_change_mat = change_rot_ep
00166 _, ell_final_rot = self.ell_server.robot_ellipsoidal_pose(ell_f[0], ell_f[1], ell_f[2],
00167 orient_quat)
00168 rot_mat_f = ell_final_rot * rot_change_mat
00169 else:
00170
00171
00172 quat = change_rot_ep
00173 _, cur_rot = PoseConv.to_pos_rot(self.arm.get_ep())
00174 rot_mat = np.mat(trans.quaternion_matrix(quat))[:3,:3]
00175 rot_mat_f = cur_rot * rot_mat
00176 return ell_f, rot_mat_f
00177
00178 def _create_ell_trajectory(self, ell_f, rot_mat_f, orient_quat=[0., 0., 0., 1.], velocity=0.001):
00179 _, cur_rot = PoseConv.to_pos_rot(self.arm.get_ep())
00180
00181 rpy = trans.euler_from_matrix(cur_rot.T * rot_mat_f)
00182
00183 ell_f[1] = np.mod(ell_f[1], 2 * np.pi)
00184
00185
00186 ell_init = np.mat(self.get_ell_ep()).T
00187 ell_final = np.mat(ell_f).T
00188
00189
00190 if np.fabs(2 * np.pi + ell_final[1,0] - ell_init[1,0]) < np.pi:
00191 ell_final[1,0] += 2 * np.pi
00192 elif np.fabs(-2 * np.pi + ell_final[1,0] - ell_init[1,0]) < np.pi:
00193 ell_final[1,0] -= 2 * np.pi
00194
00195 if np.any(np.isnan(ell_init)) or np.any(np.isnan(ell_final)):
00196 rospy.logerr("[ellipsoid_controller] Nan values in ellipsoid EPs. " +
00197 "ell_init: %f, %f, %f; " % (ell_init[0,0], ell_init[1,0], ell_init[2,0]) +
00198 "ell_final: %f, %f, %f; " % (ell_final[0,0], ell_final[1,0], ell_final[2,0]))
00199 return None
00200
00201 num_samps = np.max([2, int(np.linalg.norm(ell_final - ell_init) / velocity),
00202 int(np.linalg.norm(rpy) / velocity)])
00203 t_vals = min_jerk_traj(num_samps)
00204
00205
00206 ell_traj = np.array(ell_init) + np.array(np.tile(ell_final - ell_init,
00207 (1, num_samps))) * np.array(t_vals)
00208
00209 ell_frame_mat = self.ell_server.get_ell_frame()
00210
00211 ell_pose_traj = [self.ell_server.robot_ellipsoidal_pose(
00212 ell_traj[0,i], ell_traj[1,i], ell_traj[2,i], orient_quat, ell_frame_mat)
00213 for i in range(ell_traj.shape[1])]
00214
00215
00216 _, ell_init_rot = self.ell_server.robot_ellipsoidal_pose(
00217 ell_init[0,0], ell_init[1,0], ell_init[2,0], orient_quat, ell_frame_mat)
00218 rot_adjust_traj = self.arm.interpolate_ep([np.mat([0]*3).T, cur_rot],
00219 [np.mat([0]*3).T, rot_mat_f],
00220 min_jerk_traj(num_samps))
00221 ell_pose_traj = [(ell_pose_traj[i][0],
00222 ell_pose_traj[i][1] * ell_init_rot.T * rot_adjust_traj[i][1])
00223 for i in range(num_samps)]
00224
00225 return ell_pose_traj
00226
00227 def main():
00228 rospy.init_node("ellipsoid_controller", sys.argv)
00229 cart_arm = create_pr2_arm('l', PR2ArmJTransposeTask,
00230 controller_name='%s_cart_jt_task',
00231 end_link="%s_gripper_shaver45_frame", timeout=0)
00232
00233 rospy.sleep(1)
00234 ell_controller = EllipsoidController()
00235 ell_controller.set_arm(cart_arm)
00236 rospy.spin()
00237
00238
00239 if __name__ == "__main__":
00240 main()