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 Tool to tuck/untuck Baxter's arms to/from the shipping pose
00032 """
00033 import argparse
00034
00035 from copy import deepcopy
00036
00037 import rospy
00038
00039 from std_msgs.msg import (
00040 Empty,
00041 Bool,
00042 )
00043
00044 import baxter_interface
00045
00046 from baxter_core_msgs.msg import (
00047 CollisionAvoidanceState,
00048 )
00049 from baxter_interface import CHECK_VERSION
00050
00051
00052 class Tuck(object):
00053 def __init__(self, tuck_cmd):
00054 self._done = False
00055 self._limbs = ('left', 'right')
00056 self._arms = {
00057 'left': baxter_interface.Limb('left'),
00058 'right': baxter_interface.Limb('right'),
00059 }
00060 self._tuck = tuck_cmd
00061 self._tuck_rate = rospy.Rate(20.0)
00062 self._tuck_threshold = 0.2
00063 self._peak_angle = -1.6
00064 self._arm_state = {
00065 'tuck': {'left': 'none', 'right': 'none'},
00066 'collide': {'left': False, 'right': False},
00067 'flipped': {'left': False, 'right': False}
00068 }
00069 self._joint_moves = {
00070 'tuck': {
00071 'left': [-1.0, -2.07, 3.0, 2.55, 0.0, 0.01, 0.0],
00072 'right': [1.0, -2.07, -3.0, 2.55, -0.0, 0.01, 0.0]
00073 },
00074 'untuck': {
00075 'left': [-0.08, -1.0, -1.19, 1.94, 0.67, 1.03, -0.50],
00076 'right': [0.08, -1.0, 1.19, 1.94, -0.67, 1.03, 0.50]
00077 }
00078 }
00079 self._collide_lsub = rospy.Subscriber(
00080 'robot/limb/left/collision_avoidance_state',
00081 CollisionAvoidanceState,
00082 self._update_collision, 'left')
00083 self._collide_rsub = rospy.Subscriber(
00084 'robot/limb/right/collision_avoidance_state',
00085 CollisionAvoidanceState,
00086 self._update_collision, 'right')
00087 self._disable_pub = {
00088 'left': rospy.Publisher(
00089 'robot/limb/left/suppress_collision_avoidance',
00090 Empty),
00091 'right': rospy.Publisher(
00092 'robot/limb/right/suppress_collision_avoidance',
00093 Empty)
00094 }
00095 self._rs = baxter_interface.RobotEnable(CHECK_VERSION)
00096 self._enable_pub = rospy.Publisher('robot/set_super_enable', Bool)
00097
00098 def _update_collision(self, data, limb):
00099 self._arm_state['collide'][limb] = len(data.collision_object) > 0
00100 self._check_arm_state()
00101
00102 def _check_arm_state(self):
00103 """
00104 Check for goals and behind collision field.
00105
00106 If s1 joint is over the peak, collision will need to be disabled
00107 to get the arm around the head-arm collision force-field.
00108 """
00109 diff_check = lambda a, b: abs(a - b) <= self._tuck_threshold
00110 for limb in self._limbs:
00111 angles = [self._arms[limb].joint_angle(joint)
00112 for joint in self._arms[limb].joint_names()]
00113
00114
00115 untuck_goal = map(diff_check, angles,
00116 self._joint_moves['untuck'][limb])
00117 tuck_goal = map(diff_check, angles[0:2],
00118 self._joint_moves['tuck'][limb][0:2])
00119 if all(untuck_goal):
00120 self._arm_state['tuck'][limb] = 'untuck'
00121 elif all(tuck_goal):
00122 self._arm_state['tuck'][limb] = 'tuck'
00123 else:
00124 self._arm_state['tuck'][limb] = 'none'
00125
00126
00127 self._arm_state['flipped'][limb] = (
00128 self._arms[limb].joint_angle(limb + '_s1') <= self._peak_angle)
00129
00130 def _prepare_to_tuck(self):
00131
00132
00133 head = baxter_interface.Head()
00134 start_disabled = not self._rs.state().enabled
00135 at_goal = lambda: (abs(head.pan()) <=
00136 baxter_interface.settings.HEAD_PAN_ANGLE_TOLERANCE)
00137
00138 rospy.loginfo("Moving head to neutral position")
00139 while not at_goal() and not rospy.is_shutdown():
00140 if start_disabled:
00141 [pub.publish(Empty()) for pub in self._disable_pub.values()]
00142 if not self._rs.state().enabled:
00143 self._enable_pub.publish(True)
00144 head.set_pan(0.0, 50.0, timeout=0)
00145 self._tuck_rate.sleep()
00146
00147 if start_disabled:
00148 while self._rs.state().enabled == True and not rospy.is_shutdown():
00149 [pub.publish(Empty()) for pub in self._disable_pub.values()]
00150 self._enable_pub.publish(False)
00151 self._tuck_rate.sleep()
00152
00153 def _move_to(self, tuck, disabled):
00154 if any(disabled.values()):
00155 [pub.publish(Empty()) for pub in self._disable_pub.values()]
00156 while (any(self._arm_state['tuck'][limb] != goal
00157 for limb, goal in tuck.viewitems())
00158 and not rospy.is_shutdown()):
00159 if self._rs.state().enabled == False:
00160 self._enable_pub.publish(True)
00161 for limb in self._limbs:
00162 if disabled[limb]:
00163 self._disable_pub[limb].publish(Empty())
00164 if limb in tuck:
00165 self._arms[limb].set_joint_positions(dict(zip(
00166 self._arms[limb].joint_names(),
00167 self._joint_moves[tuck[limb]][limb])))
00168 self._check_arm_state()
00169 self._tuck_rate.sleep()
00170
00171 if any(self._arm_state['collide'].values()):
00172 self._rs.disable()
00173 return
00174
00175 def supervised_tuck(self):
00176
00177 self._prepare_to_tuck()
00178 self._check_arm_state()
00179
00180 if self._tuck == True:
00181
00182 if all(self._arm_state['tuck'][limb] == 'tuck'
00183 for limb in self._limbs):
00184 rospy.loginfo("Tucking: Arms already in 'Tucked' position.")
00185 self._done = True
00186 return
00187 else:
00188 rospy.loginfo("Tucking: One or more arms not Tucked.")
00189 any_flipped = not all(self._arm_state['flipped'].values())
00190 if any_flipped:
00191 rospy.loginfo(
00192 "Moving to neutral start position with collision %s.",
00193 "on" if any_flipped else "off")
00194
00195 self._check_arm_state()
00196 actions = dict()
00197 disabled = {'left': True, 'right': True}
00198 for limb in self._limbs:
00199 if not self._arm_state['flipped'][limb]:
00200 actions[limb] = 'untuck'
00201 disabled[limb] = False
00202 self._move_to(actions, disabled)
00203
00204
00205 rospy.loginfo("Tucking: Tucking with collision avoidance off.")
00206 actions = {'left': 'tuck', 'right': 'tuck'}
00207 disabled = {'left': True, 'right': True}
00208 self._move_to(actions, disabled)
00209 self._done = True
00210 return
00211
00212
00213 else:
00214
00215 if any(self._arm_state['flipped'].values()):
00216 rospy.loginfo("Untucking: One or more arms Tucked;"
00217 " Disabling Collision Avoidance and untucking.")
00218 self._check_arm_state()
00219 suppress = deepcopy(self._arm_state['flipped'])
00220 actions = {'left': 'untuck', 'right': 'untuck'}
00221 self._move_to(actions, suppress)
00222 self._done = True
00223 return
00224
00225 else:
00226 rospy.loginfo("Untucking: Arms already Untucked;"
00227 " Moving to neutral position.")
00228 self._check_arm_state()
00229 suppress = deepcopy(self._arm_state['flipped'])
00230 actions = {'left': 'untuck', 'right': 'untuck'}
00231 self._move_to(actions, suppress)
00232 self._done = True
00233 return
00234
00235 def clean_shutdown(self):
00236 """Handles ROS shutdown (Ctrl-C) safely."""
00237 if not self._done:
00238 rospy.logwarn('Aborting: Shutting down safely...')
00239 if any(self._arm_state['collide'].values()):
00240 while self._rs.state().enabled != False:
00241 [pub.publish(Empty()) for pub in self._disable_pub.values()]
00242 self._enable_pub.publish(False)
00243 self._tuck_rate.sleep()
00244
00245
00246 def main():
00247 parser = argparse.ArgumentParser()
00248 tuck_group = parser.add_mutually_exclusive_group(required=True)
00249 tuck_group.add_argument("-t", "--tuck", dest="tuck",
00250 action='store_true', default=False, help="tuck arms")
00251 tuck_group.add_argument("-u", "--untuck", dest="untuck",
00252 action='store_true', default=False, help="untuck arms")
00253 args = parser.parse_args(rospy.myargv()[1:])
00254 tuck = args.tuck
00255
00256 rospy.loginfo("Initializing node... ")
00257 rospy.init_node("rsdk_tuck_arms")
00258 rospy.loginfo("%sucking arms" % ("T" if tuck else "Unt",))
00259 tucker = Tuck(tuck)
00260 rospy.on_shutdown(tucker.clean_shutdown)
00261 tucker.supervised_tuck()
00262 rospy.loginfo("Finished tuck")
00263
00264 if __name__ == "__main__":
00265 main()