Go to the documentation of this file.00001
00002 import roslib; roslib.load_manifest('move_action_server')
00003 import rospy
00004 import math
00005 from geometry_msgs.msg import Twist, PoseWithCovarianceStamped
00006 from rfnserver import RFNServer
00007 from tf.transformations import euler_from_quaternion
00008
00009
00010 robot_x = False
00011 robot_y = False
00012 robot_z_rot = False
00013 pub = False
00014
00015
00016
00017 class MoveActionServer:
00018 server = None
00019
00020 def __init__(self):
00021 self.server = RFNServer("move", self.cb_rfn)
00022 self.server.register_with_frame("moving_forward")
00023 self.server.register_with_frame("moving_backward")
00024 self.server.register_with_frame("turning_left")
00025 self.server.register_with_frame("turning_right")
00026 self.server.start()
00027
00028
00029 def cb_rfn(self, filled_semantic_frame):
00030 rospy.loginfo("MoveActionServer: Starting callback.")
00031 if filled_semantic_frame.name in ["moving_forward", "moving_backward"]:
00032 self.parse_and_move_forward_backward(filled_semantic_frame)
00033 elif filled_semantic_frame.name in ["turning_left", "turning_right"]:
00034 self.parse_and_turn(filled_semantic_frame)
00035 else:
00036 rospy.logerr("MoveActionServer: I didn't sign up for this!: " +
00037 filled_semantic_frame.name)
00038
00039
00040 def parse_and_move_forward_backward(self, filled_semantic_frame):
00041
00042 if filled_semantic_frame.name == "moving_forward":
00043 direction = 1
00044 elif filled_semantic_frame.name == "moving_backward":
00045 direction = -1
00046 else:
00047 rospy.logerr("MoveActionServer: This is not moving forward/backward!: " +
00048 filled_semantic_frame.name)
00049 self.server.set_aborted()
00050 return
00051 distance_str = RFNServer.frame_argument(filled_semantic_frame,
00052 "distance")
00053 distance_unit_str = RFNServer.frame_argument(filled_semantic_frame,
00054 "distance_unit")
00055
00056
00057 if distance_unit_str in ["meter", "meters"]:
00058 distance_scale = 1
00059 elif distance_unit_str in ["millimeter", "millimeters"]:
00060 distance_scale = 0.001
00061 elif distance_unit_str in ["centimeter", "centimeters"]:
00062 distance_scale = 0.01
00063 elif distance_unit_str in ["kilometer", "kilometers"]:
00064 distance_scale = 1000
00065 elif distance_unit_str in ["inch", "inches"]:
00066 distance_scale = 0.0254
00067 elif distance_unit_str in ["foot", "feet"]:
00068 distance_scale = 0.3048
00069 elif distance_unit_str in ["yard", "yards"]:
00070 distance_scale = 0.9144
00071 elif distance_unit_str in ["furlong", "furlongs"]:
00072 distance_scale = 201.16800
00073 elif distance_unit_str in ["mile", "miles"]:
00074 distance_scale = 1609.344
00075 else:
00076 rospy.logerr("parse_and_move_forward_backward: Unrecognized distance " +
00077 " unit: " + distance_unit_str)
00078 self.server.set_aborted()
00079 return
00080
00081 distance = float(distance_str) * distance_scale
00082 self.move_forward_backward(direction * distance)
00083
00084
00085
00086 def parse_and_turn(self, filled_semantic_frame):
00087
00088 if filled_semantic_frame.name == "turning_left":
00089 direction = 1
00090 elif filled_semantic_frame.name == "turning_right":
00091 direction = -1
00092 else:
00093 rospy.logerr("MoveActionServer: This is not turning left/right!: " +
00094 filled_semantic_frame.name)
00095 self.server.set_aborted()
00096 return
00097 distance_str = RFNServer.frame_argument(filled_semantic_frame,
00098 "distance")
00099 distance_unit_str = RFNServer.frame_argument(filled_semantic_frame,
00100 "distance_unit")
00101
00102
00103 if distance_unit_str in ["radian", "radians"]:
00104 distance_scale = 1
00105 elif distance_unit_str in ["degree", "degrees"]:
00106 distance_scale = 0.0174532925
00107 else:
00108 rospy.logerr("parse_and_turn: Unrecognized distance unit: " +
00109 distance_unit_str)
00110 self.server.set_aborted()
00111 return
00112
00113 distance = float(distance_str) * distance_scale
00114 self.turn(direction * distance)
00115
00116
00117
00118 def move_forward_backward(self, distance):
00119 global robot_x, robot_y
00120 """ Move distance meters. (positive == forwards; negative == backwards)"""
00121 rospy.loginfo("Moving " + str(distance) + " meters.")
00122
00123
00124 start_x = robot_x
00125 start_y = robot_y
00126
00127
00128 r = rospy.Rate(25)
00129 while (not rospy.is_shutdown() and
00130 not self.server.is_preempt_requested() and
00131 (math.sqrt((start_x - robot_x)**2 + (start_y - robot_y)**2) <
00132 abs(distance))):
00133
00134 t = Twist()
00135 t.linear.x = math.copysign(0.5, distance)
00136 t.linear.y = 0
00137 t.linear.z = 0
00138 t.angular.x = 0
00139 t.angular.y = 0
00140 t.angular.z = 0
00141 pub.publish(t)
00142 r.sleep()
00143
00144
00145 t = Twist()
00146 t.linear.x = 0
00147 t.linear.y = 0
00148 t.linear.z = 0
00149 t.angular.x = 0
00150 t.angular.y = 0
00151 t.angular.z = 0
00152 pub.publish(t)
00153
00154 if self.server.is_preempt_requested():
00155 self.server.set_preempted()
00156 else:
00157 self.server.set_succeeded()
00158
00159
00160
00161 def turn(self, distance):
00162 global robot_z_rot
00163 """ Move distance radians.
00164
00165 (positive == counterclockwise; negative == clockwise)
00166 """
00167 rospy.loginfo("Moving " + str(distance) + " radians.")
00168
00169
00170 start_z = robot_z_rot
00171 end_z = (start_z + distance + math.pi) % (2 * math.pi) - math.pi
00172
00173
00174
00175
00176
00177 r = rospy.Rate(25)
00178 while (not rospy.is_shutdown() and
00179 not self.server.is_preempt_requested() and
00180 not (abs(robot_z_rot - end_z) < 0.15)):
00181 rospy.loginfo("robot_z_rot " + str(robot_z_rot) +
00182 " end_z " + str(end_z) +
00183 " absdiff " + str(abs(robot_z_rot - end_z)))
00184
00185 t = Twist()
00186 t.linear.x = 0
00187 t.linear.y = 0
00188 t.linear.z = 0
00189 t.angular.x = 0
00190 t.angular.y = 0
00191 t.angular.z = math.copysign(1.5, distance)
00192 pub.publish(t)
00193 r.sleep()
00194
00195
00196 t = Twist()
00197 t.linear.x = 0
00198 t.linear.y = 0
00199 t.linear.z = 0
00200 t.angular.x = 0
00201 t.angular.y = 0
00202 t.angular.z = 0
00203 pub.publish(t)
00204
00205 if self.server.is_preempt_requested():
00206 self.server.set_preempted()
00207 else:
00208 self.server.set_succeeded()
00209
00210
00211
00212 def cb_odom(msg):
00213 global robot_x, robot_y, robot_z_rot
00214 robot_x = msg.pose.pose.position.x
00215 robot_y = msg.pose.pose.position.y
00216 q = msg.pose.pose.orientation
00217 robot_z_rot = euler_from_quaternion([q.x, q.y, q.z, q.w])[2]
00218
00219
00220
00221
00222 def main():
00223 global pub
00224 rospy.init_node('move_action_server')
00225 pub = rospy.Publisher('turtlebot_node/cmd_vel', Twist)
00226 rospy.Subscriber('robot_pose_ekf/odom_combined', PoseWithCovarianceStamped, cb_odom)
00227 rospy.logwarn("move_action_server was implemented for a demo, not as a " +
00228 "serious navigation engine. So, be careful using this, " +
00229 "especially the turn commands, with any sort of expensive " +
00230 "robot. Otherwise, enjoy!")
00231 server = MoveActionServer()
00232 rospy.spin()
00233
00234
00235
00236 if __name__ == '__main__':
00237 main()
00238
00239
00240
00241