00001
00002
00003 import numpy as np
00004 import cPickle as pickle
00005 from threading import Lock
00006 import copy
00007
00008 import roslib
00009 roslib.load_manifest("hrl_pr2_traj_playback")
00010 import rospy
00011 from std_msgs.msg import String
00012 from std_srvs.srv import Empty, EmptyResponse
00013 import roslaunch.substitution_args
00014 import actionlib
00015
00016 from hrl_pr2_arms.pr2_arm_joint_traj import create_ep_arm, PR2ArmJointTraj
00017 from hrl_pr2_arms.pr2_controller_switcher import ControllerSwitcher
00018 from msg import TrajectoryPlayAction, TrajectoryPlayGoal
00019
00020 RATE = 20
00021 JOINT_TOLERANCES = [0.03, 0.1, 0.1, 0.1, 0.17, 0.15, 0.12]
00022 JOINT_VELOCITY_WEIGHT = [3.0, 1.7, 1.7, 1.0, 1.0, 1.0, 0.5]
00023
00024 CTRL_NAME_LOW = '%s_joint_controller_low'
00025 PARAM_FILE_LOW = '$(find hrl_pr2_arms)/params/joint_traj_params_electric_low.yaml'
00026 CTRL_NAME_NONE = '%s_joint_controller_none'
00027 PARAM_FILE_NONE = '$(find hrl_pr2_arms)/params/joint_traj_params_electric_none.yaml'
00028
00029
00030
00031
00032 class TrajPlayback(object):
00033
00034
00035
00036
00037
00038 def __init__(self, arm_char, ctrl_name="%s_arm_controller", param_file=None):
00039 self.arm_char = arm_char
00040 self.ctrl_name = ctrl_name
00041 self.param_file = param_file
00042 self.cur_joint_traj = None
00043 self.running = False
00044 self.is_paused = False
00045 self.ctrl_switcher = ControllerSwitcher()
00046 rospy.loginfo('[trajectory_playback] Started Traj Playback for %s arm with %s controller.' %(self.arm_char, self.ctrl_name))
00047
00048
00049
00050 def load_arm(self):
00051 self.ctrl_switcher.carefree_switch(self.arm_char, self.ctrl_name,
00052 self.param_file, reset=False)
00053 return create_ep_arm(self.arm_char, PR2ArmJointTraj,
00054 controller_name=self.ctrl_name, timeout=8)
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 def execute(self, joint_trajectory, rate, blocking=True):
00065 if len(joint_trajectory) == 0:
00066 return True
00067 if self.running:
00068 rospy.logerr("[arm_pose_move_controller] Trajectory already in motion.")
00069 return False
00070 self.cur_arm = self.load_arm()
00071 if not self.can_exec_traj(joint_trajectory):
00072 rospy.logwarn("[arm_pose_move_controller] Arm not at trajectory start.")
00073 return False
00074 def exec_traj(te):
00075 self.cur_idx = 0
00076 self.stop_traj = False
00077 self.is_paused = False
00078 self.running = True
00079 rospy.loginfo("[arm_pose_move_controller] Starting trajectory.")
00080 r = rospy.Rate(rate)
00081 while (not rospy.is_shutdown() and not self.stop_traj and
00082 self.cur_idx < len(joint_trajectory)):
00083 self.cur_arm.set_ep(joint_trajectory[self.cur_idx], 1./rate)
00084 self.cur_idx += 1
00085 r.sleep()
00086 self.cur_arm.set_ep(self.cur_arm.get_ep(), 0.3)
00087 if self.cur_idx < len(joint_trajectory):
00088 self.cur_joint_traj = joint_trajectory[self.cur_idx:]
00089 successful = False
00090 else:
00091 self.cur_joint_traj = None
00092 self.is_paused = False
00093 successful = True
00094 self.last_rate = rate
00095 self.running = False
00096 return successful
00097 if blocking:
00098 return exec_traj(None)
00099 else:
00100 self.exec_traj_timer = rospy.Timer(rospy.Duration(0.1), exec_traj, oneshot=True)
00101 return True
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 def move_to_angles(self, q_goal, rate=RATE, velocity=0.1, blocking=True):
00114 traj = self.get_angle_traj(q_goal, rate, velocity)
00115 if len(traj) == 0:
00116 return True
00117 return self.execute(traj, rate, blocking)
00118
00119 def get_angle_traj(self, q_goal, rate=RATE, velocity=0.1):
00120 self.cur_arm = self.load_arm()
00121 q_cur = self.cur_arm.get_ep()
00122 diff = self.cur_arm.difference_joints(q_goal, q_cur)
00123 max_ang = np.max(np.fabs(diff) * JOINT_VELOCITY_WEIGHT)
00124 time_traj = max_ang / velocity
00125 steps = np.round(rate * time_traj)
00126 if steps == 0:
00127 return []
00128 t_vals = np.linspace(0., 1., steps)
00129 return [q_cur + diff * t for t in t_vals]
00130
00131
00132
00133
00134
00135
00136 def can_exec_traj(self, joint_trajectory):
00137 if len(joint_trajectory) == 0:
00138 return True
00139 q_cur = self.cur_arm.get_ep()
00140 q_init = joint_trajectory[0]
00141 diff = self.cur_arm.difference_joints(q_cur, q_init)
00142 return np.all(np.fabs(diff) < JOINT_TOLERANCES)
00143
00144 def is_moving(self):
00145 return self.running
00146
00147
00148
00149 def pause_moving(self):
00150 if self.is_moving():
00151 self.stop_traj = True
00152 while not rospy.is_shutdown() and self.running:
00153 rospy.sleep(0.01)
00154 self.is_paused = True
00155 return True
00156 return False
00157
00158
00159
00160 def restart_moving(self, blocking=True):
00161 if not self.is_paused or self.cur_joint_traj is None:
00162 return False
00163 self.execute(self.cur_joint_traj, self.last_rate, blocking=blocking)
00164 return True
00165
00166
00167
00168 def stop_moving(self):
00169 self.stop_traj = True
00170 self.is_paused = False
00171 self.cur_joint_traj = None
00172 while not rospy.is_shutdown() and self.running:
00173 rospy.sleep(0.01)
00174
00175 def preempt(self):
00176 self.stop_moving()
00177
00178 def load_arm_file(filename):
00179 try:
00180 directory = rospy.get_param("~traj_directory", "")
00181 if directory[-1] != '/':
00182 directory = directory + "/"
00183 f = file(roslaunch.substitution_args.resolve_args(directory + filename), "r")
00184 traj, arm_char, rate = pickle.load(f)
00185 if arm_char not in ['r', 'l']:
00186 raise Exception("arm_char not r or l")
00187 return traj, arm_char, rate
00188 except Exception as e:
00189 print "Cannot open file."
00190 print "Error:", e
00191 return None, None, None
00192
00193 def move_to_setup_from_file(filename, ctrl_name=CTRL_NAME_LOW, param_file=PARAM_FILE_LOW,
00194 velocity=0.1, rate=RATE, reverse=False, blocking=True):
00195 traj, arm_char, rate = load_arm_file(filename)
00196 if traj is None:
00197 return None
00198 if not reverse:
00199 q = traj[0]
00200 else:
00201 q = traj[-1]
00202 traj_ctrl = TrajPlayback(arm_char, ctrl_name, param_file)
00203 traj_ctrl.load_arm()
00204 rospy.sleep(0.1)
00205 traj_ctrl.move_to_angles(q, velocity=velocity,
00206 rate=rate, blocking=blocking)
00207
00208 def can_exec_traj_from_file(filename, reverse=False):
00209 traj, arm_char, rate = load_arm_file(filename)
00210 if traj is None:
00211 return None
00212 traj_ctrl = TrajPlayback(arm_char)
00213 traj_ctrl.load_arm()
00214 rospy.sleep(0.1)
00215 return traj_ctrl.can_exec_traj(traj)
00216
00217 def exec_traj_from_file(filename, ctrl_name=CTRL_NAME_LOW, param_file=PARAM_FILE_LOW,
00218 reverse=False, rate_mult=0.8, blocking=True):
00219 traj, arm_char, rate = load_arm_file(filename)
00220 if traj is None:
00221 return
00222 if reverse:
00223 traj.reverse()
00224 traj_ctrl = TrajPlayback(arm_char, ctrl_name, param_file)
00225 traj_ctrl.load_arm()
00226 rospy.sleep(0.1)
00227 return traj_ctrl.execute(traj, rate * rate_mult, blocking)
00228
00229 class TrajectorySaver(object):
00230 def __init__(self, rate):
00231 self.rate = rate
00232
00233 def record_trajectory(self, arm_char, blocking=True):
00234 self.traj = []
00235 self.stop_recording = False
00236 self.is_recording = True
00237 self.cur_arm = create_ep_arm(arm_char, timeout=5)
00238 def rec_traj(te):
00239 rospy.loginfo("[arm_pose_move_controller] Recording trajectory.")
00240 r = rospy.Rate(self.rate)
00241 while not rospy.is_shutdown() and not self.stop_recording:
00242 q = self.cur_arm.get_joint_angles()
00243 self.traj.append(q)
00244 r.sleep()
00245 rospy.loginfo("[arm_pose_move_controller] Stopped recording trajectory.")
00246 self.is_recording = False
00247 if blocking:
00248 rec_traj(None)
00249 else:
00250 self.rec_traj_timer = rospy.Timer(rospy.Duration(0.1), rec_traj, oneshot=True)
00251
00252 def stop_record(self, save_file):
00253 self.stop_recording = True
00254 while not rospy.is_shutdown() and self.is_recording:
00255 rospy.sleep(0.1)
00256 f = file(save_file, "w")
00257 pickle.dump((self.traj, self.cur_arm.arm_side, self.rate), f)
00258 f.close()
00259
00260 class TrajectoryServer(object):
00261 def __init__(self, arm_char, as_name, ctrl_name, param_file):
00262 self.traj_ctrl = TrajPlayback(arm_char, ctrl_name, param_file)
00263 self.arm_dict = {'r' : "right", 'l' : "left"}
00264
00265 def pause_cb(req):
00266 if not self.traj_ctrl.is_paused:
00267 if self.traj_ctrl.pause_moving():
00268 self.publish_feedback("Trajectory playback on the %s arm paused." %
00269 self.arm_dict[self.traj_ctrl.arm_char])
00270 else:
00271 self.traj_ctrl.restart_moving(blocking=False)
00272 self.publish_feedback("Trajectory playback on the %s arm restarted." %
00273 self.arm_dict[self.traj_ctrl.arm_char])
00274 return EmptyResponse()
00275 self.traj_pause_srv = rospy.Service(as_name + "_pause", Empty, pause_cb)
00276
00277 def stop_cb(req):
00278 self.publish_feedback("Trajectory playback on the %s arm stopping." %
00279 self.arm_dict[self.traj_ctrl.arm_char])
00280 self.traj_ctrl.stop_moving()
00281 return EmptyResponse()
00282 self.traj_stop_srv = rospy.Service(as_name + "_stop", Empty, stop_cb)
00283 self.feedback_pub = rospy.Publisher(as_name + "/feedback", String)
00284
00285 self.traj_srv = actionlib.SimpleActionServer(as_name, TrajectoryPlayAction,
00286 self.traj_play_cb, False)
00287 self.traj_srv.register_preempt_callback(self.traj_cancel_cb)
00288 self.traj_srv.start()
00289 self.last_goal = None
00290
00291 def same_goal_as_last(self, new_goal):
00292 if self.last_goal is None:
00293 self.last_goal = copy.copy(new_goal)
00294 return False
00295 ret_val = (new_goal.filepath == self.last_goal.filepath and
00296 new_goal.reverse == self.last_goal.reverse and
00297 new_goal.mode == self.last_goal.mode)
00298 self.last_goal = copy.copy(new_goal)
00299 return ret_val
00300
00301 def publish_feedback(self, msg):
00302 rospy.loginfo("[arm_pose_move_controller] %s" % msg)
00303 self.feedback_pub.publish(msg)
00304
00305 def traj_play_cb(self, goal):
00306 traj, arm_char, rate = load_arm_file(goal.filepath)
00307 if traj is None:
00308 self.traj_srv.set_aborted(text="Failed to open file.")
00309 return
00310 if arm_char != self.traj_ctrl.arm_char:
00311 self.traj_srv.set_aborted(text="File contains wrong arm.")
00312 return
00313 self.publish_feedback("Trajectory playback on the %s arm starting." %
00314 self.arm_dict[self.traj_ctrl.arm_char])
00315 if goal.reverse:
00316 traj.reverse()
00317 if self.same_goal_as_last(goal) and self.traj_ctrl.is_paused:
00318 self.publish_feedback("Trajectory playback on the %s arm restarted." %
00319 self.arm_dict[self.traj_ctrl.arm_char])
00320 self.traj_ctrl.restart_moving(blocking=True)
00321 else:
00322 if goal.mode == goal.MOVE_SETUP or goal.mode == goal.SETUP_AND_TRAJ:
00323 setup_traj = self.traj_ctrl.get_angle_traj(traj[0], velocity=goal.setup_velocity,
00324 rate=RATE)
00325 if goal.mode == goal.MOVE_SETUP:
00326 full_traj = setup_traj
00327 else:
00328 full_traj = setup_traj + traj
00329 elif goal.mode == goal.TRAJ_ONLY:
00330 full_traj = traj
00331 else:
00332 self.traj_srv.set_aborted(text="Unknown goal mode.")
00333 return
00334 if self.traj_ctrl.execute(full_traj, rate * goal.traj_rate_mult, blocking=True):
00335 self.publish_feedback("Trajectory playback on the %s arm successful." %
00336 self.arm_dict[self.traj_ctrl.arm_char])
00337 self.traj_srv.set_succeeded()
00338
00339 def traj_cancel_cb(self):
00340 self.traj_ctrl.stop_moving()
00341
00342 def main():
00343
00344 from optparse import OptionParser
00345 p = OptionParser()
00346 p.add_option('-f', '--filename', dest="filename", default="",
00347 help="File to save trajectory to or load from.")
00348 p.add_option('-l', '--left_arm', dest="left_arm",
00349 action="store_true", default=False,
00350 help="Use left arm.")
00351 p.add_option('-r', '--right_arm', dest="right_arm",
00352 action="store_true", default=False,
00353 help="Use right arm.")
00354 p.add_option('-s', '--save_mode', dest="save_mode",
00355 action="store_true", default=False,
00356 help="Saving mode.")
00357 p.add_option('-t', '--traj_mode', dest="traj_mode",
00358 action="store_true", default=False,
00359 help="Trajectory mode.")
00360 p.add_option('-c', '--ctrl_name', dest="ctrl_name", default=None,
00361 help="Controller to run the playback with.")
00362 p.add_option('-p', '--params', dest="param_file", default=None,
00363 help="YAML file to save parameters in or load from.")
00364 p.add_option('-v', '--srv_mode', dest="srv_mode",
00365 action="store_true", default=False,
00366 help="Server mode.")
00367 p.add_option('-y', '--playback_mode', dest="playback_mode",
00368 action="store_true", default=False,
00369 help="Plays back trajectory immediately.")
00370 p.add_option('-z', '--reverse', dest="reverse",
00371 action="store_true", default=False,
00372 help="Plays back trajectory in reverse.")
00373 (opts, args) = p.parse_args()
00374
00375 if opts.right_arm:
00376 arm_char = 'r'
00377 elif opts.left_arm:
00378 arm_char = 'l'
00379 else:
00380 print "Must select arm with -r or -l."
00381 return
00382 filename = opts.filename
00383
00384 rospy.init_node("arm_pose_move_controller_%s" % arm_char)
00385 if opts.save_mode:
00386 assert(opts.right_arm + opts.left_arm == 1)
00387 if opts.traj_mode:
00388 ctrl_switcher = ControllerSwitcher()
00389 ctrl_switcher.carefree_switch(arm_char, CTRL_NAME_NONE, PARAM_FILE_NONE, reset=False)
00390 traj_saver = TrajectorySaver(RATE)
00391 raw_input("Press enter to start recording")
00392 traj_saver.record_trajectory(arm_char, blocking=False)
00393
00394 import curses
00395 def wait_for_key(stdscr):
00396 curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
00397 stdscr.addstr(0,0, "Press any key to stop!", curses.color_pair(1) )
00398 stdscr.refresh()
00399 c = 0
00400 while not rospy.is_shutdown() and c == 0:
00401 c = stdscr.getch()
00402 curses.wrapper(wait_for_key)
00403
00404 traj_saver.stop_record(roslaunch.substitution_args.resolve_args(opts.filename))
00405 ctrl_switcher.carefree_switch(arm_char, opts.ctrl_name, PARAM_FILE_LOW, reset=False)
00406 return
00407 else:
00408 print "FIX"
00409 return
00410 elif opts.srv_mode:
00411 traj_srv = TrajectoryServer(arm_char, "/trajectory_playback_" + arm_char,
00412 opts.ctrl_name, opts.param_file)
00413 rospy.spin()
00414 return
00415 elif opts.playback_mode:
00416 raw_input("Press enter to continue")
00417 if opts.traj_mode:
00418 exec_traj_from_file(opts.filename,
00419 ctrl_name=opts.ctrl_name,
00420 param_file=opts.param_file,
00421 reverse=opts.reverse,
00422 blocking=True)
00423 else:
00424 move_to_setup_from_file(opts.filename,
00425 ctrl_name=opts.ctrl_name,
00426 param_file=opts.param_file,
00427 reverse=opts.reverse,
00428 blocking=True)
00429
00430 if __name__ == "__main__":
00431 main()