waypoint_generator.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 #   Copyright 2013 Georgia Tech Research Corporation
00004 #
00005 #   Licensed under the Apache License, Version 2.0 (the "License");
00006 #   you may not use this file except in compliance with the License.
00007 #   You may obtain a copy of the License at
00008 #
00009 #     http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 #   Unless required by applicable law or agreed to in writing, software
00012 #   distributed under the License is distributed on an "AS IS" BASIS,
00013 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 #   See the License for the specific language governing permissions and
00015 #   limitations under the License.
00016 #
00017 #  http://healthcare-robotics.com/
00018 
00019 ## @package hrl_haptic_mpc
00020 #
00021 # @author Jeff Hawke 
00022 # @version 0.1
00023 # @copyright Apache 2.0
00024 
00025 import sys, os
00026 import numpy, math
00027 import copy, threading
00028 import collections
00029 
00030 import roslib; roslib.load_manifest('hrl_haptic_mpc')
00031 import rospy
00032 import tf
00033 
00034 import hrl_lib.util as ut
00035 import hrl_lib.transforms as tr
00036 
00037 import trajectory_msgs.msg
00038 import geometry_msgs.msg
00039 import trajectory_msgs.msg
00040 import std_msgs.msg
00041 import hrl_haptic_manipulation_in_clutter_msgs.msg as haptic_msgs
00042 import hrl_msgs.msg
00043 
00044 import haptic_mpc_util
00045 
00046 ## @class WaypointGenerator Node which takes either a goal pose or a trajectory and passes
00047 # local goals to the MPC controller to try to make the controller follow it.
00048 class WaypointGenerator():
00049   node_name = None # ROS node name
00050   opt = None  # Options - should be specified by the optparser when run from the console.
00051   rate = 25.0 # Publish rate. By default, 25Hz
00052   msg_seq = 0 # Sequence counter
00053 
00054   # ROS Parameter paths - robot dependent.
00055   param_path = ""
00056   base_path = "/haptic_mpc"
00057   cody_param_path = "/cody"
00058   pr2_param_path = "/pr2"
00059   sim_param_path = "/sim3"
00060   simcody_param_path = "/simcody"
00061   crona_param_path = "/crona"
00062 
00063   # ROS Topics. TODO: Move these to param server to allow easy changes across all modules.
00064   current_pose_topic = "/haptic_mpc/robot_state"
00065   goal_pose_topic = "/haptic_mpc/goal_pose"
00066   goal_pose_array_topic = "/haptic_mpc/goal_pose_array"
00067   waypoint_pose_topic = "/haptic_mpc/traj_pose"
00068 
00069   # Member variables
00070   robot = None # Robot object
00071   robot_name = None # Robot name
00072   sensor = None # Sensor object
00073   eq_gen_type = None
00074   default_eq_gen_type = 'mpc_qs_1'
00075 
00076   skin_topic_list = None
00077   scl = None # skin client
00078   epcon = None
00079 
00080   # Trajectory pose parameters.
00081   max_pos_step = 0.05 # 50mm steps at largest
00082   #max_pos_step = 0.0 # changed
00083   max_ang_step = 0.02 # 0.02 rad. Slightly over 1 degree
00084   at_waypoint_threshold = 0.02 # tolerance for being at the goal and moving to the next waypoint.
00085   at_waypoint_ang_threshold = numpy.radians(5.0)
00086   
00087   max_posture_step = numpy.radians(5.0)
00088   at_posture_threshold = numpy.radians(2.0)
00089   
00090   mode = "none" # Set to "posture", "pose", or potentially "both"
00091 
00092   current_trajectory_deque = collections.deque()
00093   gripper_pose = None
00094   goal_pose = None
00095   current_gripper_waypoint = None
00096 
00097   traj_lock = threading.RLock()
00098   goal_lock = threading.RLock()
00099   state_lock = threading.RLock()
00100 
00101 
00102   ## Constructor. Calls functions to initialise robot specific parameters, then initialises all publishers/subscribers.
00103   def __init__(self, node_name, opt):
00104     rospy.loginfo("Initialising trajectory generator for Haptic MPC")
00105     self.opt = opt
00106     self.node_name = node_name
00107     rospy.init_node(node_name)
00108 
00109     # Set up the relevant robot parameters
00110     if (self.opt.robot == "cody"):
00111       self.initCody()
00112     elif (self.opt.robot == "pr2"):
00113       self.initPR2()
00114     elif(self.opt.robot == "sim3" or self.opt.robot == "sim3_nolim"):
00115       self.initSim3()
00116     elif(self.opt.robot == "simcody"):
00117       self.initSimCody()
00118     elif(self.opt.robot == "crona"):
00119       self.initCrona()
00120     else:
00121       rospy.logerr("Invalid Robot type: %s" % robot)
00122 
00123     # Set up the publishers/subscribers and their callbacks.
00124     self.initComms()
00125 
00126     return
00127 
00128   ## Initialise 3DOF Sim kinematics. NB: This doesn't actually do anything and is added mostly for structural consistency.
00129   def initCody(self):
00130     rospy.loginfo("Trajectory generator for: Cody")
00131     #TODO:
00132     #sys.exit()
00133 
00134   ## Initialise PR2 kinematics. NB: Only used for joint limits, will eventually be removed once these are passed with the robot state.
00135   def initPR2(self):
00136     from pykdl_utils.kdl_kinematics import create_kdl_kin
00137     
00138     rospy.loginfo("Trajectory generator for: PR2")
00139     if not self.opt.arm:
00140       rospy.logerr('Arm not specified for PR2')
00141       sys.exit()
00142     
00143     self.robot_kinematics = create_kdl_kin('torso_lift_link', self.opt.arm+'_gripper_tool_frame')
00144     self.tf_listener = tf.TransformListener()
00145 
00146     if self.opt.arm == None:
00147         rospy.logerr('Need to specify --arm_to_use.\nExiting...')
00148         sys.exit()
00149 
00150   ## Initialise 3DOF Sim kinematics. NB: This doesn't actually do anything and is added mostly for structural consistency.
00151   def initSim3(self):
00152     rospy.loginfo("Trajectory generator for: Simulation 3DOF")
00153     # Nothing to initialise for this.
00154    
00155   def initCrona(self):
00156     from pykdl_utils.kdl_kinematics import create_kdl_kin
00157 
00158     rospy.loginfo("Trajectory generator for: cRoNA")
00159     if not self.opt.arm:
00160       rospy.logerr('Arm not specified for cRoNA')
00161       sys.exit()
00162 
00163     #self.robot_kinematics = create_kdl_kin('torso_chest_link', self.opt.arm+'_hand_link')
00164     self.robot_kinematics = create_kdl_kin('base_link', self.opt.arm+'_hand_link') # testing
00165     self.tf_listener = tf.TransformListener()
00166 
00167     if self.opt.arm == None:
00168         rospy.logerr('Need to specify --arm_to_use.\nExiting...')
00169         sys.exit()
00170 
00171   ## Initialise all publishers/subscribers used by the waypoint generator.
00172   def initComms(self):        
00173     # Publish to a waypoint pose topic
00174     self.pose_waypoint_pub = rospy.Publisher(self.waypoint_pose_topic, geometry_msgs.msg.PoseStamped) # Pose waypoint publishing      
00175     self.goal_posture_pub = rospy.Publisher("/haptic_mpc/goal_posture", hrl_msgs.msg.FloatArray)
00176     self.mpc_weights_pub = rospy.Publisher("/haptic_mpc/weights", haptic_msgs.HapticMpcWeights)
00177     
00178     # Subscribe to the a goal pose topic. 
00179     rospy.Subscriber(self.goal_pose_topic, geometry_msgs.msg.PoseStamped, self.goalPoseCallback)
00180     # Subscribe to the current robot state 
00181     rospy.Subscriber(self.current_pose_topic, haptic_msgs.RobotHapticState, self.robotStateCallback)
00182     # OpenRave planner for the PR2
00183     rospy.Subscriber('/haptic_mpc/joint_trajectory', trajectory_msgs.msg.JointTrajectory, self.jointTrajectoryCallback)
00184     # Subscribe to the goal pose array topic.
00185     rospy.Subscriber(self.goal_pose_array_topic, geometry_msgs.msg.PoseArray, self.poseTrajectoryCallback)
00186     self.pose_traj_viz_pub = rospy.Publisher('/haptic_mpc/current_pose_traj', geometry_msgs.msg.PoseArray, latch=True) 
00187 
00188  
00189   ## Update goal pose.
00190   # @param msg A geometry_msgs.msg.PoseStamped object.
00191   def goalPoseCallback(self, msg):
00192     rospy.loginfo("Got new goal pose")
00193     if (not 'torso_lift_link' in msg.header.frame_id) and (not '/torso_chest_link' in msg.header.frame_id) and (not '/base_link' in msg.header.frame_id):
00194       print "msg.header.frame_id"
00195       print msg.header.frame_id
00196       try:
00197         self.tf_listener.waitForTransform(msg.header.frame_id, '/torso_lift_link', msg.header.stamp, rospy.Duration(5.0))
00198       except (tf.ConnectivityException, tf.LookupException, tf.ExtrapolationException) as e:
00199         rospy.logerr('[arm_trajectory_generator]: TF Exception: %s' %e)
00200       ps = geometry_msgs.msg.PoseStamped(msg.header, msg.pose)
00201       ps.header.stamp = rospy.Time(0)
00202       new_pose_stamped = self.tf_listener.transformPose('/torso_lift_link', ps)
00203       msg = new_pose_stamped
00204 
00205     with self.goal_lock:
00206       self.goal_pose = msg.pose
00207 
00208     with self.traj_lock:
00209       self.current_trajectory_deque.clear()
00210   
00211   ## Store the current pose from the haptic state publisher
00212   # @param msg RobotHapticState messge object
00213   def robotStateCallback(self, msg):
00214     with self.state_lock:
00215       self.gripper_pose = msg.hand_pose
00216       self.joint_angles = msg.joint_angles
00217      
00218   ## Store a trajectory of poses in the deque. Converts it to the 'torso_frame' if required.
00219   # @param msg A geometry_msgs.msg.PoseArray object
00220   def poseTrajectoryCallback(self, msg):
00221     rospy.loginfo("Got new pose trajectory")
00222     self.goal_pose = None
00223     with self.traj_lock:
00224       self.current_trajectory_msg = msg
00225       self.current_trajectory_deque.clear()
00226       # if we have an empty array, clear the deque and do nothing else.
00227       if len(msg.poses) == 0:
00228         rospy.logwarn("Received empty pose array. Clearing trajectory buffer")
00229         return        
00230 
00231       #Check if pose array is in torso_lift_link.  If not, transform.
00232       if not 'torso_lift_link' in msg.header.frame_id:
00233         print "msg.header.frame_id"
00234         print msg.header.frame_id
00235         try:
00236           self.tf_listener.waitForTransform(msg.header.frame_id, '/torso_lift_link',
00237                                             msg.header.stamp, rospy.Duration(5.0))
00238         except (tf.ConnectivityException, tf.LookupException, tf.ExtrapolationException) as e:
00239           rospy.logerr('[arm_trajectory_generator]: TF Exception: %s' %e)
00240         
00241       pose_array = []
00242       for pose in msg.poses:
00243         ps = geometry_msgs.msg.PoseStamped(msg.header, pose)
00244         ps.header.stamp = rospy.Time(0)
00245         new_pose_stamped = self.tf_listener.transformPose('/torso_lift_link', ps)
00246         pose_array.append(new_pose_stamped.pose)
00247 
00248       # visualisation message
00249       pose_array_msg = geometry_msgs.msg.PoseArray()
00250       pose_array_msg.header.frame_id = "/torso_lift_link"
00251       pose_array_msg.poses = pose_array
00252       self.pose_traj_viz_pub.publish(pose_array_msg)
00253       #Append the list of poses to the recently cleared deque
00254       self.current_trajectory_deque.extend(pose_array)
00255       
00256       with self.goal_lock: # Invalidate previous goal poses.
00257         self.goal_pose = None
00258       
00259 
00260   ## Store a joint angle trajectory in the deque. Performs forward kinematics to convert it to end effector poses in the torso frame.
00261   # @param msg A trajectory_msgs.msg.JointTrajectory object.
00262   def jointTrajectoryCallback(self, msg):    
00263     rospy.loginfo("Got new joint trajectory")
00264     with self.traj_lock:
00265       self.current_trajectory_msg = msg
00266       self.current_trajectory_deque.clear()
00267       
00268       for point in msg.points:
00269         # Calculate pose for this point using FK
00270         # Append pose to deque
00271 #        joint_angles = point.positions
00272 #        end_effector_position, end_effector_orient_cart = self.robot_kinematics.FK(joint_angles, len(joint_angles))
00273 #        end_effector_orient_quat = tr.matrix_to_quaternion(end_effector_orient_cart)
00274 #        
00275 #        pose = geometry_msgs.msg.Pose()
00276 #        ee_pos = end_effector_position.A1
00277 #        pose.position.x = ee_pos[0]
00278 #        pose.position.y = ee_pos[1]
00279 #        pose.position.z = ee_pos[2]
00280 #        pose.orientation.x = end_effector_orient_quat[0]
00281 #        pose.orientation.y = end_effector_orient_quat[1]
00282 #        pose.orientation.z = end_effector_orient_quat[2]
00283 #        pose.orientation.w = end_effector_orient_quat[3]
00284         
00285         self.current_trajectory_deque.append(point) # Check type of current value when pulling from the deque
00286     
00287     # Clear goal pose so the waypoints come from the trajectory
00288     with self.goal_lock:
00289       self.goal_pose = None
00290         
00291   ## Update the weights used by the MPC.  
00292   def setControllerWeights(self, position_weight, orient_weight, posture_weight):
00293     weights_msg = haptic_msgs.HapticMpcWeights()
00294     weights_msg.header.stamp = rospy.Time.now()
00295     weights_msg.position_weight = position_weight
00296     weights_msg.orient_weight = orient_weight
00297     weights_msg.posture_weight = posture_weight
00298     self.mpc_weights_pub.publish(weights_msg) # Enable position tracking only - disable orientation by setting the weight to 0  
00299  
00300    
00301   ## Returns the next waypoint along a straight line trajectory from the current gripper pose to the goal pose.
00302   # The step size towards the goal is configurable through the parameters passed in.
00303   # @param current_pose geometry_msgs.msg.Pose
00304   # @param goal_pose geometry_msgs.msg.Pose
00305   # @param max_pos_step = scalar float for position step size to take (metres)
00306   # @param max_ang_step = scalar float for orientation step size to take (radians)
00307   # @return A geometry_msgs.msg.Pose to send to the MPC 
00308   def straightLineTrajectory(self, current_pose, goal_pose, max_pos_step, max_ang_step):
00309     desired_pose = geometry_msgs.msg.Pose() # Create the Pose for the desired waypoint
00310     
00311     current_pos_vector = numpy.array([current_pose.position.x, current_pose.position.y, current_pose.position.z])
00312     goal_pos_vector = numpy.array([goal_pose.position.x, goal_pose.position.y, goal_pose.position.z])
00313     
00314     position_waypoint = self.getPositionStep(current_pos_vector, goal_pos_vector, max_pos_step)
00315   
00316     desired_pose.position.x = position_waypoint[0]
00317     desired_pose.position.y = position_waypoint[1]
00318     desired_pose.position.z = position_waypoint[2]
00319     
00320     # Calculate the new orientation. Use slerp - spherical interpolation on quaternions
00321     current_orientation = [current_pose.orientation.x, current_pose.orientation.y, current_pose.orientation.z, current_pose.orientation.w]
00322     goal_orientation = [goal_pose.orientation.x, goal_pose.orientation.y, goal_pose.orientation.z, goal_pose.orientation.w]
00323     
00324     orientation_waypoint = goal_orientation#self.getOrientationStep(current_orientation, goal_orientation, max_ang_step)
00325 
00326     desired_pose.orientation.x = orientation_waypoint[0]
00327     desired_pose.orientation.y = orientation_waypoint[1]
00328     desired_pose.orientation.z = orientation_waypoint[2]
00329     desired_pose.orientation.w = orientation_waypoint[3]
00330     
00331     # Return completed pose data structure
00332     return desired_pose
00333   
00334   ## Returns a linearly interpolated step towards the goal pos from the current pos
00335   # @param current_pos Current position as a numpy array (assumed to be [x,y,z])
00336   # @param goal_pos Goal position as a numpy array (assumed to be [x,y,z])
00337   # @param max_pos_step A scalar max step size for position (in metres).
00338   # @return An interpolated step in position towards the goal.
00339   def getPositionStep(self, current_pos, goal_pos, max_pos_step):
00340     difference_to_goal = goal_pos - current_pos
00341     dist_to_goal = numpy.sqrt(numpy.vdot(difference_to_goal, difference_to_goal))
00342     
00343     if dist_to_goal > max_pos_step:
00344       step_vector = difference_to_goal / dist_to_goal * max_pos_step # Generate a linear step towards the goal position.
00345     else:
00346       step_vector = difference_to_goal # The distance remaining to the goal is less than the step size used.
00347     desired_position = current_pos + step_vector
00348     
00349     return desired_position
00350   
00351   ## Returns a linearly interpolated step towards the goal orientation from the current orientation (using SLERP)
00352   # @param q_h_orient Current hand orientation as a quaternion in numpy array form (assumed to be [x,y,z,w])
00353   # @param q_g_orient Current goal orientation as a quaternion in numpy array form (assumed to be [x,y,z,w])
00354   # @param max_ang_step A scalar max step size for orientation (in radians).  
00355   # @return An interpolated step in orientation towards the goal.
00356   def getOrientationStep(self, q_h_orient, q_g_orient, max_ang_step):
00357     ang = ut.quat_angle(q_h_orient, q_g_orient)
00358 
00359     ang_mag = abs(ang)
00360     step_fraction = 0.001
00361     if step_fraction * ang_mag > max_ang_step:
00362       # this is pretty much always true, can clean up the code.
00363       step_fraction = max_ang_step / ang_mag
00364 
00365     interp_q_goal = tr.tft.quaternion_slerp(q_h_orient, q_g_orient, step_fraction)
00366     return interp_q_goal
00367         
00368   ## Returns a message header (std_msgs object), populated with the time, frame_id and sequence number
00369   def getMessageHeader(self):
00370     header = std_msgs.msg.Header()
00371     header.seq = self.msg_seq
00372     self.msg_seq += 1
00373     header.stamp = rospy.get_rostime()
00374     #header.frame_id = "/torso_lift_link"
00375     header.frame_id = "/base_link"
00376     return header
00377   
00378   ## Max absolute distance between joints postures.  
00379   def distanceBetweenPostures(self, postureA, postureB):
00380     max_dist = 0.0
00381     
00382     for i in range(1, len(postureA)):
00383       dist = abs(postureA[i] - postureB[i])
00384       if dist > max_dist:
00385         max_dist = dist
00386         
00387     return max_dist
00388     
00389   ## Euclidian distance between two poses. Ignores differences in orientation.
00390   # @param poseA geometry_msgs.msg.Pose
00391   # @param poseB geometry_msgs.msg.Pose
00392   # @return The euclidian distance between the two pose positions.
00393   def distanceBetweenPoses(self, poseA, poseB):
00394     xdiff = poseA.position.x - poseB.position.x
00395     ydiff = poseA.position.y - poseB.position.y
00396     zdiff = poseA.position.z - poseB.position.z
00397     return numpy.sqrt(xdiff**2 + ydiff **2 + zdiff**2)      
00398 
00399   ## Return the angle between two quaternions (axis-angle representation)
00400   # @param poseA geometry_msgs.msg.Pose
00401   # @param poseB geometry_msgs.msg.Pose
00402   # @return The angular distance between the two pose orientations.
00403   def angularDistanceBetweenPoses(self, poseA, poseB):
00404     quatA = [poseA.orientation.x, poseA.orientation.y, poseA.orientation.z, poseA.orientation.w]
00405     quatB = [poseB.orientation.x, poseB.orientation.y, poseB.orientation.z, poseB.orientation.w]
00406     ang_diff = ut.quat_angle(quatA, quatB)
00407     return ang_diff
00408   
00409   ## Try to get a waypoint pose from the trajectory deque. 
00410   # 
00411   # Also trims the trajectory to reduce the number of waypoint. 
00412   # Scans through the trajectory to find the next pose that is at least max_pos_step away (or the last pose in the deque).
00413   # @return A Pose object if there is a currently stored trajectory, otherwise None.
00414   def getWaypointFromTrajectory(self):      
00415     with self.state_lock:
00416       curr_gripper_pose = copy.copy(self.gripper_pose)
00417     with self.traj_lock:
00418       # If we have a current trajectory, represented as a sequence of Pose objects in a deque  
00419       if len(self.current_trajectory_deque) > 0:
00420         # Check if we need to trim the list
00421         if len(self.current_trajectory_deque) > 1:
00422           # Return the next point closest along the trajectory if we're close enough to it (eg within 5mm of it)
00423           if self.distanceBetweenPoses(curr_gripper_pose, self.current_trajectory_deque[0]) < self.at_waypoint_threshold:# \
00424 #            and self.angularDistanceBetweenPoses(curr_gripper_pose, self.current_trajectory_deque[0]) < self.at_waypoint_ang_threshold:      
00425             # Trim the trajectory so that the current waypoint is a reasonable distance away - too fine steps make the controller unhappy.
00426             # Discard trajectory points that are within the min distance unless this the last point in the trajectory.
00427             # Adjust this by increasing or decreasing max_pos_step
00428             while self.distanceBetweenPoses(curr_gripper_pose, self.current_trajectory_deque[0]) < self.max_pos_step and len(self.current_trajectory_deque) > 1:
00429               print "Trimming trajectory - dist: %s, len(deque): %s" %  (self.distanceBetweenPoses(self.gripper_pose, self.current_trajectory_deque[0]), len(self.current_trajectory_deque))
00430               self.current_trajectory_deque.popleft()
00431         
00432         desired_pose = self.current_trajectory_deque[0]#self.straightLineTrajectory(curr_gripper_pose, self.current_trajectory_deque[0], self.max_pos_step, self.max_ang_step)
00433         return desired_pose
00434      
00435       else: # We haven't got a valid trajectory. Return None. 
00436         return None  
00437   
00438   ## Pull postures from the trajectory deque    
00439   def getPostureFromTrajectory(self):
00440     with self.state_lock:
00441       curr_posture = copy.copy(self.joint_angles)
00442     with self.traj_lock:
00443       # If we have a current trajectory, represented as a sequence of Pose OR JointTrajectoryPoint objects in a deque  
00444       if len(self.current_trajectory_deque) > 0:
00445         # Check if we need to trim the list
00446         if len(self.current_trajectory_deque) > 1:
00447           # Return the next point closest along the trajectory if we're close enough to it (eg within 5mm of it)
00448           if self.distanceBetweenPostures(curr_posture, self.current_trajectory_deque[0].positions) < self.at_posture_threshold:# \    
00449             # Trim the trajectory so that the current waypoint is a reasonable distance away - too fine steps make the controller unhappy.
00450             # Discard trajectory points that are within the min distance unless this the last point in the trajectory.
00451             # Adjust this by increasing or decreasing max_pos_step
00452 #            while self.distanceBetweenPostures(curr_posture, self.current_trajectory_deque[0].positions) < self.at_posture_threshold and len(self.current_trajectory_deque) > 1:
00453 #              print "Trimming trajectory - dist: %s, len(deque): %s" %  (self.distanceBetweenPostures(curr_posture, self.current_trajectory_deque[0].positions), len(self.current_trajectory_deque))
00454             self.current_trajectory_deque.popleft()
00455             print "Moving to next waypoint."
00456             print numpy.degrees(self.current_trajectory_deque[0].positions)
00457         
00458         desired_posture = self.current_trajectory_deque[0]#self.straightLineTrajectory(curr_gripper_pose, self.current_trajectory_deque[0], self.max_pos_step, self.max_ang_step)
00459         return desired_posture
00460      
00461       else: # We haven't got a valid trajectory. Return None. 
00462         return None 
00463         
00464   
00465   ## Publishes the next waypoint for the control to try to achieve.
00466   #
00467   # If we have a valid trajectory, get the next waypoint from that. 
00468   # If not and we have a valid end goal pose instead, move in a straight line towards it.
00469   # If we have neither, don't publish anything.   
00470   def generateWaypoint(self):   
00471     # TODO: Work out which way to generate the next waypoint. Currently always do a straight line 
00472     # update waypoint if we've achieved this waypoint, else keep current waypoint.
00473     with self.state_lock:
00474       tmp_curr_pose = copy.copy(self.gripper_pose)
00475     with self.goal_lock:
00476       tmp_goal_pose = copy.copy(self.goal_pose)  
00477    
00478     if tmp_curr_pose == None: # If we haven't heard robot state yet, don't act.
00479       return
00480 
00481     # Logic flow changed so that the deque can store either geometry_msgs.msg.Pose or trajectory_msgs.msg.JointTrajectoryPoint     
00482     if tmp_goal_pose != None:
00483       desired_pose = self.straightLineTrajectory(tmp_curr_pose, tmp_goal_pose, self.max_pos_step, self.max_ang_step)
00484       waypoint_msg = geometry_msgs.msg.PoseStamped()
00485       waypoint_msg.header = self.getMessageHeader()
00486       waypoint_msg.pose = desired_pose
00487       self.pose_waypoint_pub.publish(waypoint_msg)
00488     elif len(self.current_trajectory_deque) > 0: # We have some valid trajectory.
00489       # If the deque has poses
00490       if type(self.current_trajectory_deque[0]) == geometry_msgs.msg.Pose:
00491         if self.mode != "pose":
00492           self.setControllerWeights(5.0, 4.0, 0.0)
00493         self.mode = "pose"
00494         desired_pose = self.getWaypointFromTrajectory() # If we have a trajectory, return a valid pose (else None)
00495         if desired_pose == None and tmp_goal_pose != None: # If we have a teleop goal but don't have a trajectory, go in a straight line to the goal
00496           desired_pose = self.straightLineTrajectory(tmp_curr_pose, tmp_goal_pose, self.max_pos_step, self.max_ang_step)
00497         
00498         # Don't publish invalid waypoints. If we still didn't get a good pose from the straight line interpolation, something is wrong.
00499         if desired_pose == None:
00500           return  
00501      
00502         # Publish a waypoint every cycle.
00503         waypoint_msg = geometry_msgs.msg.PoseStamped()
00504         waypoint_msg.header = self.getMessageHeader()
00505         waypoint_msg.pose = desired_pose
00506         self.pose_waypoint_pub.publish(waypoint_msg)
00507       # If the deque has joint postures rather than poses.
00508       elif type(self.current_trajectory_deque[0]) == trajectory_msgs.msg.JointTrajectoryPoint:
00509         if self.mode != "posture":
00510           self.setControllerWeights(0.0, 0.0, 1.0)
00511         self.mode = "posture"
00512         desired_posture = self.getPostureFromTrajectory() # If we have a trajectory, return a valid posture
00513         if desired_posture == None:
00514           rospy.loginfo("desired_posture is none")
00515           return
00516         
00517         waypoint_msg = hrl_msgs.msg.FloatArray()
00518         #print desired_posture.positions
00519         waypoint_msg.data = list(desired_posture.positions)
00520         
00521         self.goal_posture_pub.publish(waypoint_msg)
00522       else:
00523         rospy.loginfo("Object in the waypoint deque is neither geometry_msgs.msg.Pose or trajectory_msgs.msg.JointTrajectoryPoint. Who broke it?!")
00524           
00525            
00526 
00527   ## Start the waypoint generator publishing waypoints.  
00528   def start(self):
00529     rate = rospy.Rate(self.rate) # 25Hz, nominally.
00530     rospy.loginfo("Beginning publishing waypoints")
00531     while not rospy.is_shutdown():
00532       self.generateWaypoint()
00533       #print rospy.Time()
00534       rate.sleep()
00535 
00536 if __name__ == '__main__':
00537     # Set up input arg parser
00538     import optparse
00539     p = optparse.OptionParser()
00540 
00541     haptic_mpc_util.initialiseOptParser(p)
00542     opt = haptic_mpc_util.getValidInput(p)
00543 
00544     # Create and start the trajectory manager module. 
00545     traj_mgr = WaypointGenerator('mpc_traj_gen', opt) # loads all parameter sets on init
00546     traj_mgr.start()
00547     
00548 
00549 
00550 
00551 


hrl_haptic_mpc
Author(s): Jeff Hawke, Phillip Grice, Marc Killpack, Advait Jain. Advisor and Co-author: Prof. Charlie Kemp. Healthcare Robotics Lab, Georgia Tech
autogenerated on Wed Nov 27 2013 12:27:09