00001
00002 import roslib; roslib.load_manifest('simple_move_base')
00003 import rospy
00004 import tf.transformations as tr
00005 import hrl_lib.tf_utils as tfu
00006 import hrl_lib.util as ut
00007 import simple_move_base.msg as hm
00008 import tf
00009
00010 import geometry_msgs.msg as gm
00011 import sys
00012 import math
00013 import numpy as np
00014 import actionlib
00015
00016 class MoveBase:
00017
00018 def __init__(self):
00019 rospy.init_node('odom_move_base')
00020 self.tw_pub = rospy.Publisher('base_controller/command', gm.Twist)
00021
00022 self.tl = tf.TransformListener()
00023
00024 self.go_xy_server = actionlib.SimpleActionServer('go_xy', hm.GoXYAction, self._go_xy_cb, auto_start=False)
00025 self.go_xy_server.start()
00026
00027 self.go_ang_server = actionlib.SimpleActionServer('go_angle', hm.GoAngleAction, self._go_ang_cb, auto_start=False)
00028 self.go_ang_server.start()
00029
00030 def _go_xy_cb(self, goal):
00031 rospy.loginfo('received go_xy goal %f %f' % (goal.x, goal.y))
00032 def send_feed_back(error):
00033 feed_back_msg = hm.GoXYFeedback()
00034 feed_back_msg.error = np.linalg.norm(error)
00035 self.go_xy_server.publish_feedback(feed_back_msg)
00036 error = self.go_xy(np.matrix([goal.x, goal.y]).T, func=send_feed_back)
00037 result = hm.GoXYResult()
00038 result.error = np.linalg.norm(error)
00039 self.go_xy_server.set_succeeded(result)
00040
00041
00042 def _go_ang_cb(self, goal):
00043 rospy.loginfo('received go_angle goal %f' % (goal.angle))
00044
00045 def send_feed_back(error):
00046 feed_back_msg = hm.GoAngleFeedback()
00047 feed_back_msg.error = error
00048 self.go_ang_server.publish_feedback(feed_back_msg)
00049
00050 error = self.go_angle(goal.angle, func=send_feed_back)
00051 result = hm.GoAngleResult()
00052 result.error = error
00053 self.go_ang_server.set_succeeded(result)
00054
00055
00056 def go_xy(self, target_base, tolerance=.01, max_speed=.1, func=None):
00057 k = 2.
00058 self.tl.waitForTransform('base_footprint', 'odom_combined', rospy.Time(), rospy.Duration(10))
00059 rate = rospy.Rate(100)
00060
00061 od_T_bf = tfu.transform('odom_combined', 'base_footprint', self.tl)
00062 target_odom = (od_T_bf * np.row_stack([target_base, np.matrix([0,1.]).T]))[0:2,0]
00063
00064
00065
00066 robot_odom = np.matrix(tfu.transform('odom_combined', 'base_footprint', self.tl)[0:2,3])
00067 diff_odom = target_odom - robot_odom
00068 mag = np.linalg.norm(diff_odom)
00069 rospy.loginfo('go_xy: error %s' % str(mag))
00070 while not rospy.is_shutdown():
00071 robot_odom = np.matrix(tfu.transform('odom_combined', 'base_footprint', self.tl)[0:2,3])
00072
00073
00074 diff_odom = target_odom - robot_odom
00075 mag = np.linalg.norm(diff_odom)
00076 if func != None:
00077 func(diff_odom)
00078 if mag < tolerance:
00079 break
00080
00081 if self.go_xy_server.is_preempt_requested():
00082 self.go_xy_server.set_preempted()
00083 break
00084
00085 direc = diff_odom / mag
00086 speed = min(mag * k, max_speed)
00087 vel_odom = direc * speed
00088
00089
00090
00091 bf_T_odom = tfu.transform('base_footprint', 'odom_combined', self.tl)
00092 vel_base = bf_T_odom * np.row_stack([vel_odom, np.matrix([0,0.]).T])
00093
00094
00095
00096 tw = gm.Twist()
00097 tw.linear.x = vel_base[0,0]
00098 tw.linear.y = vel_base[1,0]
00099
00100 self.tw_pub.publish(tw)
00101 rate.sleep()
00102
00103 rospy.loginfo('go_xy: finished go_xy %f' % np.linalg.norm(diff_odom))
00104 return diff_odom
00105
00106
00107
00108 def go_angle(self, target_base, tolerance=math.radians(5.), max_ang_vel=math.radians(20.), func=None):
00109 self.tl.waitForTransform('odom_combined', 'base_footprint', rospy.Time(), rospy.Duration(10))
00110 rate = rospy.Rate(100)
00111 k = math.radians(80)
00112
00113 od_T_bf = tfu.transform('odom_combined', 'base_footprint', self.tl)
00114 target_odom_mat = od_T_bf * tfu.tf_as_matrix( ([0, 0, 0.], tr.quaternion_from_euler(0, 0, target_base)) )
00115 target_odom = tr.euler_from_quaternion(tfu.matrix_as_tf(target_odom_mat)[1])[2]
00116
00117
00118
00119
00120
00121 robot_odom = tfu.transform('odom_combined', 'base_footprint', self.tl)
00122 current_ang_odom = tr.euler_from_matrix(robot_odom[0:3, 0:3], 'sxyz')[2]
00123 diff = ut.standard_rad(current_ang_odom - target_odom)
00124 rospy.loginfo('go_angle: target %.2f' % np.degrees(target_odom))
00125 rospy.loginfo('go_angle: current %.2f' % np.degrees(current_ang_odom))
00126 rospy.loginfo('go_angle: diff %.2f' % np.degrees(diff))
00127
00128 while not rospy.is_shutdown():
00129 robot_odom = tfu.transform('odom_combined', 'base_footprint', self.tl)
00130 current_ang_odom = tr.euler_from_matrix(robot_odom[0:3, 0:3], 'sxyz')[2]
00131 diff = ut.standard_rad(target_odom - current_ang_odom)
00132 rospy.loginfo('go_angle: current %.2f diff %.2f' % (np.degrees(current_ang_odom), np.degrees(diff)))
00133 p = k * diff
00134 if func != None:
00135 func(diff)
00136 if np.abs(diff) < tolerance:
00137 break
00138
00139 if self.go_ang_server.is_preempt_requested():
00140 self.go_ang_server.set_preempted()
00141 break
00142
00143 tw = gm.Twist()
00144 vels = [p, np.sign(p) * max_ang_vel]
00145 tw.angular.z = vels[np.argmin(np.abs(vels))]
00146
00147 self.tw_pub.publish(tw)
00148
00149 rate.sleep()
00150 rospy.loginfo('go_ang: finished %.3f' % math.degrees(diff))
00151 return diff
00152
00153
00154 if __name__ == '__main__':
00155 m = MoveBase()
00156 rospy.loginfo('simple move base server up!')
00157 rospy.spin()
00158