tuck_arms.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Copyright (c) 2013-2014, Rethink Robotics
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions are met:
00008 #
00009 # 1. Redistributions of source code must retain the above copyright notice,
00010 #    this list of conditions and the following disclaimer.
00011 # 2. Redistributions in binary form must reproduce the above copyright
00012 #    notice, this list of conditions and the following disclaimer in the
00013 #    documentation and/or other materials provided with the distribution.
00014 # 3. Neither the name of the Rethink Robotics nor the names of its
00015 #    contributors may be used to endorse or promote products derived from
00016 #    this software without specific prior written permission.
00017 #
00018 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 # POSSIBILITY OF SUCH DAMAGE.
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)  # Hz
00062         self._tuck_threshold = 0.2  # radians
00063         self._peak_angle = -1.6  # radians
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             # Check if in a goal position
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             # Check if shoulder is flipped over peak
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         # If arms are in "tucked" state, disable collision avoidance
00132         # before enabling robot, to avoid arm jerking from "force-field".
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         # Update our starting state to check if arms are tucked
00177         self._prepare_to_tuck()
00178         self._check_arm_state()
00179         # Tuck Arms
00180         if self._tuck == True:
00181             # If arms are already tucked, report this to user and exit.
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                 # Move to neutral pose before tucking arms to avoid damage
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                 # Disable collision and Tuck Arms
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         # Untuck Arms
00213         else:
00214             # If arms are tucked disable collision and untuck arms
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             # If arms already untucked, move to neutral location
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()


baxter_tools
Author(s): Rethink Robotics Inc.
autogenerated on Sun Oct 5 2014 22:29:27