move_action_server.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
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     # Determine desired distance and direction
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     # Convert distance units to meters
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     # Determine desired distance and direction
00088     if filled_semantic_frame.name == "turning_left":
00089       direction = 1 # (like in math/physics -- right hand rule)
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     # Convert distance units to meters
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     # Get initial position
00124     start_x = robot_x
00125     start_y = robot_y
00126 
00127     # Wait until we've moved desired distance
00128     r = rospy.Rate(25) # hz
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       # Tell robot to start moving
00134       t = Twist()
00135       t.linear.x = math.copysign(0.5, distance) # m/s
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     # Tell robot to stop moving forward
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     # Get initial position.  Angle is in [-pi, pi]
00170     start_z = robot_z_rot
00171     end_z = (start_z + distance + math.pi) % (2 * math.pi) - math.pi
00172 
00173 
00174     # WARNING: The below calculation is numerically unstable
00175     #   near the poles!
00176     # Wait until we've moved desired distance
00177     r = rospy.Rate(25) # hz
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       # Tell robot to start moving
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) # rad/s
00192       pub.publish(t)
00193       r.sleep()
00194 
00195     # Tell robot to stop moving forward
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   # Rotation is between -pi and pi (in radians)
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 


move_action_server
Author(s): Brian Thomas
autogenerated on Fri Dec 6 2013 20:42:45