joy_footstep_planner.py
Go to the documentation of this file.
00001 import rospy
00002 
00003 import imp
00004 try:
00005   imp.find_module("actionlib")
00006 except:
00007   import roslib; roslib.load_manifest('jsk_teleop_joy')
00008 import threading
00009 import actionlib
00010 from joy_pose_6d import JoyPose6D
00011 from actionlib_msgs.msg import GoalStatusArray
00012 from jsk_footstep_msgs.msg import PlanFootstepsAction, PlanFootstepsGoal, Footstep, FootstepArray, ExecFootstepsAction, ExecFootstepsGoal
00013 from jsk_rviz_plugins.msg import OverlayMenu
00014 from std_msgs.msg import UInt8, Empty
00015 import tf
00016 from tf.transformations import *
00017 from geometry_msgs.msg import PoseStamped
00018 import jsk_teleop_joy.tf_ext as tf_ext
00019 
00020 class JoyFootstepPlanner(JoyPose6D):
00021   EXECUTING = 1
00022   PLANNING = 2
00023   WAIT_FOR_CANCEL = 3
00024   CANCELED = 4
00025   CANCELED_MENUS = ["Cancel", 
00026                     "Ignore and proceed",
00027                     "Use larger footsteps",
00028                     "Use middle footsteps",
00029                     "Use smaller footsteps"]
00030   def __init__(self, name, args):
00031     JoyPose6D.__init__(self, name, args)
00032     self.supportFollowView(True)
00033     self.mode = self.PLANNING
00034     self.snapped_pose = None
00035     self.ignore_next_status_flag = False
00036     self.prev_mode = self.PLANNING
00037     self.frame_id = self.getArg('frame_id', '/map')
00038     self.lfoot_frame_id = rospy.get_param('~lfoot_frame_id', '/LLEG_LINK5')
00039     self.rfoot_frame_id = rospy.get_param('~rfoot_frame_id', '/RLEG_LINK5')
00040     self.lfoot_offset = tf_ext.xyzxyzwToMatrix(rospy.get_param('~lfoot_offset'))
00041     self.rfoot_offset = tf_ext.xyzxyzwToMatrix(rospy.get_param('~rfoot_offset'))
00042     
00043     self.command_pub = rospy.Publisher('/menu_command', UInt8)
00044     self.execute_pub = rospy.Publisher(self.getArg('execute', 'execute'), Empty)
00045     self.resume_pub = rospy.Publisher(self.getArg('resume', 'resume'), Empty)
00046     self.tf_listener = tf.TransformListener()
00047     self.menu_pub = rospy.Publisher("/overlay_menu", OverlayMenu)
00048     # initialize self.pre_pose
00049     rospy.loginfo("waiting %s" % (self.lfoot_frame_id))
00050     self.tf_listener.waitForTransform(self.frame_id, self.lfoot_frame_id,
00051                                       rospy.Time(0.0), rospy.Duration(100.0))
00052     rospy.loginfo("waiting %s" % (self.rfoot_frame_id))
00053     self.tf_listener.waitForTransform(self.frame_id, self.rfoot_frame_id, 
00054                                       rospy.Time(0.0), rospy.Duration(100.0))
00055     self.exec_client = actionlib.SimpleActionClient('/footstep_controller',
00056                                                     ExecFootstepsAction)
00057     self.status_sub = rospy.Subscriber("/footstep_controller/status", GoalStatusArray,
00058                                        self.statusCB, queue_size=1)
00059     self.snap_sub = rospy.Subscriber(self.getArg("snapped_pose", "/footstep_marker/snapped_pose"), 
00060                                      PoseStamped,
00061                                      self.snapCB,
00062                                      queue_size=1)
00063     self.status_lock = threading.Lock()
00064     self.current_selecting_index = 0
00065     self.resetGoalPose()
00066   def snapCB(self, msg):
00067     self.snapped_pose = msg
00068   def statusCB(self, msg):
00069     if len(msg.status_list) == 0:
00070       return                    # do nothing
00071     self.status_lock.acquire()
00072     # msg.status_list[0].status == 0 -> done
00073     if self.mode == self.EXECUTING and msg.status_list[0].status == 0: # ???
00074       # done
00075       if self.ignore_next_status_flag: # hack!!
00076         self.ignore_next_status_flag = False
00077       else:
00078         self.mode = self.PLANNING
00079     elif self.mode == self.WAIT_FOR_CANCEL and msg.status_list[0].status == 0:
00080       self.mode = self.CANCELED
00081     self.status_lock.release()
00082   def resetGoalPose(self):
00083     # initial pose will be the center 
00084     # of self.lfoot_frame_id and self.rfoot_frame_id
00085     lfoot_pose = tf_ext.transformToMatrix(self.tf_listener.lookupTransform(
00086       self.frame_id, 
00087       self.lfoot_frame_id,
00088       rospy.Time(0.0)))
00089     rfoot_pose = tf_ext.transformToMatrix(self.tf_listener.lookupTransform(
00090       self.frame_id, 
00091       self.rfoot_frame_id,
00092       rospy.Time(0.0)))
00093     # apply offset
00094     lfoot_with_offset = numpy.dot(lfoot_pose, self.lfoot_offset)
00095     rfoot_with_offset = numpy.dot(rfoot_pose, self.rfoot_offset)
00096     (lfoot_pos, lfoot_q) = tf_ext.decomposeMatrix(lfoot_with_offset)
00097     (rfoot_pos, rfoot_q) = tf_ext.decomposeMatrix(rfoot_with_offset)
00098     # compute the center of the two transformations
00099     mid_pos = (lfoot_pos + rfoot_pos) / 2.0
00100     mid_quaternion = quaternion_slerp(lfoot_q, rfoot_q,
00101                                       0.5)
00102     self.pre_pose.pose.position.x = mid_pos[0]
00103     self.pre_pose.pose.position.y = mid_pos[1]
00104     self.pre_pose.pose.position.z = mid_pos[2]
00105     self.pre_pose.pose.orientation.x = mid_quaternion[0]
00106     self.pre_pose.pose.orientation.y = mid_quaternion[1]
00107     self.pre_pose.pose.orientation.z = mid_quaternion[2]
00108     self.pre_pose.pose.orientation.w = mid_quaternion[3]
00109   def executePlan(self):
00110     # publish execute with std_msgs/empty 
00111     self.execute_pub.publish(Empty())
00112   def resumePlan(self):
00113     # publish execute with std_msgs/empty 
00114     self.resume_pub.publish(Empty())
00115   def publishMenu(self, close=False):
00116     menu = OverlayMenu()
00117     menu.menus = self.CANCELED_MENUS
00118     menu.current_index = self.current_selecting_index
00119     menu.title = "Canceled"
00120     if close:
00121       menu.action = OverlayMenu.ACTION_CLOSE
00122     self.menu_pub.publish(menu)
00123   def procCancelMenu(self, index):
00124     selected_title = self.CANCELED_MENUS[index]
00125     if selected_title == "Cancel":
00126       self.status_lock.acquire()
00127       self.mode = self.PLANNING
00128       self.status_lock.release()
00129       self.publishMenu(close=True)
00130     elif selected_title == "Ignore and proceed":
00131       # re-execute the plan left
00132       self.resumePlan()
00133       self.status_lock.acquire()
00134       self.mode = self.EXECUTING
00135       self.status_lock.release()
00136       self.publishMenu(close=True)
00137   def joyCB(self, status, history):
00138     if self.prev_mode != self.mode:
00139       print self.prev_mode, " -> ", self.mode
00140     if self.mode == self.PLANNING:
00141       JoyPose6D.joyCB(self, status, history)
00142       if history.new(status, "circle"):
00143         self.status_lock.acquire()
00144         self.mode = self.EXECUTING
00145         self.executePlan()
00146         self.ignore_next_status_flag = True
00147         self.status_lock.release()
00148       elif history.new(status, "cross"):
00149         self.resetGoalPose()
00150       elif history.new(status, "triangle"):
00151         if self.snapped_pose:
00152           self.pre_pose = self.snapped_pose
00153     elif self.mode == self.CANCELED:
00154       # show menu
00155       if history.new(status, "circle"):
00156         # choosing
00157         self.procCancelMenu(self.current_selecting_index)
00158       else:
00159         if history.new(status, "up"):
00160           self.current_selecting_index = self.current_selecting_index - 1
00161         elif history.new(status, "down"):
00162           self.current_selecting_index = self.current_selecting_index + 1
00163           # menu is only cancel/ignore
00164         if self.current_selecting_index < 0:
00165           self.current_selecting_index = len(self.CANCELED_MENUS) - 1
00166         elif self.current_selecting_index > len(self.CANCELED_MENUS) - 1:
00167           self.current_selecting_index = 0
00168         self.publishMenu()
00169     elif self.mode == self.EXECUTING:
00170       # if history.new(status, "triangle"):
00171       #   self.command_pub.publish(UInt8(1))
00172       if history.new(status, "cross"):
00173         self.status_lock.acquire()
00174         self.exec_client.cancel_all_goals()
00175         self.mode = self.WAIT_FOR_CANCEL
00176         self.status_lock.release()
00177     self.prev_mode = self.mode


jsk_teleop_joy
Author(s): Ryohei Ueda
autogenerated on Mon Oct 6 2014 01:11:11