00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 PKG = 'life_test'
00034 import roslib; roslib.load_manifest(PKG)
00035 import rospy
00036 import actionlib
00037 import random
00038 random.seed()
00039
00040 from pr2_controllers_msgs.msg import JointTrajectoryGoal, JointTrajectoryAction
00041 from trajectory_msgs.msg import JointTrajectoryPoint
00042 from actionlib_msgs.msg import GoalStatus
00043
00044 FAILED_OUT = 5
00045
00046
00047
00048
00049
00050 def _get_recovery_goal(recovery):
00051 point = JointTrajectoryPoint()
00052 point.time_from_start = rospy.Duration.from_sec(5)
00053
00054 goal = JointTrajectoryGoal()
00055 goal.trajectory.points.append(point)
00056 goal.trajectory.header.stamp = rospy.get_rostime()
00057
00058 for joint, pos in recovery.iteritems():
00059 goal.trajectory.joint_names.append(joint)
00060 goal.trajectory.points[0].positions.append(pos)
00061 goal.trajectory.points[0].velocities.append(0.0)
00062
00063 return goal
00064
00065 class ArmCmder(object):
00066 """
00067 This class sends commands random to an arm using a JointTrajectoryAction.
00068 It sends "safe" commands by default. If the arm fails to move after a few tries,
00069 it sends an unsafe, predefined recovery command.
00070 """
00071 def __init__(self, arm_client, ranges, recovery_client, recovery_positions):
00072 """
00073 \param arm_client SimpleActionClient : Client to collision free arm commands
00074 \param ranges { str : (float, float) } : Position ranges for each joint.
00075 \param recovery_client SimpleActionClient : Client to unsafe arm controller
00076 \param recovery_positions { str : float } : Recovery positions for each joint
00077 """
00078 self._arm_client = arm_client
00079 self._ranges = ranges
00080 self._recovery_client = recovery_client
00081 self._recovery_positions = recovery_positions
00082
00083 self._fail_count = 0
00084
00085
00086
00087 def command_goal(self, goal, duration = 15):
00088 self._arm_client.send_goal(goal)
00089 self._arm_client.wait_for_result(rospy.Duration.from_sec(duration))
00090
00091 rv = self._arm_client.get_state()
00092 self._arm_client.cancel_goal()
00093
00094 return rv
00095
00096
00097
00098 def command_recovery(self):
00099 recovery_goal = _get_recovery_goal(self._recovery_positions)
00100 self._recovery_client.cancel_all_goals()
00101 self._recovery_client.send_goal(recovery_goal)
00102 rospy.loginfo('Sent recovery goal')
00103 self._recovery_client.wait_for_result(rospy.Duration.from_sec(10))
00104
00105 rv = self._recovery_client.get_state()
00106 rospy.loginfo('Got recovery result: %d' % rv)
00107
00108 self._recovery_client.cancel_goal()
00109
00110 return rv
00111
00112 def _get_random_goal(self):
00113 goal = JointTrajectoryGoal()
00114 point = JointTrajectoryPoint()
00115 point.time_from_start = rospy.Duration.from_sec(5)
00116
00117 goal.trajectory.points.append(point)
00118
00119 for joint, rng in self._ranges.iteritems():
00120 goal.trajectory.joint_names.append(joint)
00121
00122 goal.trajectory.points[0].positions.append(random.uniform(rng[0], rng[1]))
00123
00124 return goal
00125
00126
00127 def send_cmd(self):
00128 goal = self._get_random_goal()
00129 my_result = self.command_goal(goal)
00130
00131 if my_result == GoalStatus.SUCCEEDED:
00132 self._fail_count = 0
00133 else:
00134 self._fail_count += 1
00135
00136 if self._fail_count > FAILED_OUT:
00137 rospy.logwarn('Arm may be stuck. Sending recovery goal to free it')
00138 self._fail_count = 0
00139 self._arm_client.cancel_goal()
00140 self.command_recovery()
00141