ellipsoid_controller.py
Go to the documentation of this file.
00001 #! /usr/bin/python
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     # Get pose in robot's frame of ellipsoidal coordinates
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         # find the current ellipsoid frame location in this frame
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         #change_ell_ep = [lat, lon, height], change_rot_ep = Rotation in matrix or quat form (3x3 rotation mat, 1x4 quat)
00142         #Provides new position and orientation goals (in relative or abs manner, determined next).
00143         change_ell_ep, change_rot_ep = change_ep
00144         #abs_ell_ep_sel = 1x3 list of 0/1, is_abs_rot = 0/1 (Bool)
00145         #abs_ell_ep_sel: selects lat, long, height absolute vs relative position command
00146         #change_rot_ep: selects abs vs relative use of orientation.
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             #Apply rotation from change_rot_ep as final orientation of pose
00164             #Expects rotation matrix in change_rot_ep
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             #Apply rotation from change_rot_ep as change to current rotation
00171             #Expects quaternion in change_rot_ep
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) # get roll, pitch, yaw of angle diff
00182 
00183         ell_f[1] = np.mod(ell_f[1], 2 * np.pi) # wrap longitude value
00184 
00185         # get the current ellipsoidal location of the end effector
00186         ell_init = np.mat(self.get_ell_ep()).T 
00187         ell_final = np.mat(ell_f).T
00188 
00189         # find the closest longitude angle to interpolate to
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) # makes movement smooth
00204             
00205         # smoothly interpolate from init to final
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         # modify rotation of trajectory
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()


hrl_ellipsoidal_control
Author(s): Kelsey Hawkins
autogenerated on Wed Nov 27 2013 11:41:49