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
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
00071 self.status_lock.acquire()
00072
00073 if self.mode == self.EXECUTING and msg.status_list[0].status == 0:
00074
00075 if self.ignore_next_status_flag:
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
00084
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
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
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
00111 self.execute_pub.publish(Empty())
00112 def resumePlan(self):
00113
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
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
00155 if history.new(status, "circle"):
00156
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
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
00171
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