move_base_square.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #!/usr/bin/env python
  2. """ move_base_square.py - Version 1.1 2013-12-20
  3. Command a robot to move in a square using move_base actions..
  4. Created for the Pi Robot Project: http://www.pirobot.org
  5. Copyright (c) 2012 Patrick Goebel. All rights reserved.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.5
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details at:
  14. http://www.gnu.org/licenses/gpl.htmlPoint
  15. """
  16. import rospy
  17. import actionlib
  18. from actionlib_msgs.msg import *
  19. from geometry_msgs.msg import Pose, Point, Quaternion, Twist
  20. from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
  21. from tf.transformations import quaternion_from_euler
  22. from visualization_msgs.msg import Marker
  23. from math import radians, pi
  24. class MoveBaseSquare():
  25. def __init__(self):
  26. rospy.init_node('nav_test', anonymous=False)
  27. rospy.on_shutdown(self.shutdown)
  28. # How big is the square we want the robot to navigate?
  29. square_size = rospy.get_param("~square_size", 1.0) # meters
  30. # Create a list to hold the target quaternions (orientations)
  31. quaternions = list()
  32. # First define the corner orientations as Euler angles
  33. euler_angles = (pi/2, pi, 3*pi/2, 0)
  34. # Then convert the angles to quaternions
  35. for angle in euler_angles:
  36. q_angle = quaternion_from_euler(0, 0, angle, axes='sxyz')
  37. q = Quaternion(*q_angle)
  38. quaternions.append(q)
  39. # Create a list to hold the waypoint poses
  40. waypoints = list()
  41. # Append each of the four waypoints to the list. Each waypoint
  42. # is a pose consisting of a position and orientation in the map frame.
  43. waypoints.append(Pose(Point(square_size, 0.0, 0.0), quaternions[0]))
  44. waypoints.append(Pose(Point(square_size, square_size, 0.0), quaternions[1]))
  45. waypoints.append(Pose(Point(0.0, square_size, 0.0), quaternions[2]))
  46. waypoints.append(Pose(Point(0.0, 0.0, 0.0), quaternions[3]))
  47. # Initialize the visualization markers for RViz
  48. self.init_markers()
  49. # Set a visualization marker at each waypoint
  50. for waypoint in waypoints:
  51. p = Point()
  52. p = waypoint.position
  53. self.markers.points.append(p)
  54. # Publisher to manually control the robot (e.g. to stop it, queue_size=5)
  55. self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
  56. # Subscribe to the move_base action server
  57. self.move_base = actionlib.SimpleActionClient("move_base", MoveBaseAction)
  58. rospy.loginfo("Waiting for move_base action server...")
  59. # Wait 60 seconds for the action server to become available
  60. self.move_base.wait_for_server(rospy.Duration(60))
  61. rospy.loginfo("Connected to move base server")
  62. rospy.loginfo("Starting navigation test")
  63. # Initialize a counter to track waypoints
  64. i = 0
  65. # Cycle through the four waypoints
  66. while i < 4 and not rospy.is_shutdown():
  67. # Update the marker display
  68. self.marker_pub.publish(self.markers)
  69. # Intialize the waypoint goal
  70. goal = MoveBaseGoal()
  71. # Use the map frame to define goal poses
  72. goal.target_pose.header.frame_id = 'map'
  73. # Set the time stamp to "now"
  74. goal.target_pose.header.stamp = rospy.Time.now()
  75. # Set the goal pose to the i-th waypoint
  76. goal.target_pose.pose = waypoints[i]
  77. # Start the robot moving toward the goal
  78. self.move(goal)
  79. i += 1
  80. def move(self, goal):
  81. # Send the goal pose to the MoveBaseAction server
  82. self.move_base.send_goal(goal)
  83. # Allow 1 minute to get there
  84. finished_within_time = self.move_base.wait_for_result(rospy.Duration(60))
  85. # If we don't get there in time, abort the goal
  86. if not finished_within_time:
  87. self.move_base.cancel_goal()
  88. rospy.loginfo("Timed out achieving goal")
  89. else:
  90. # We made it!
  91. state = self.move_base.get_state()
  92. if state == GoalStatus.SUCCEEDED:
  93. rospy.loginfo("Goal succeeded!")
  94. def init_markers(self):
  95. # Set up our waypoint markers
  96. marker_scale = 0.2
  97. marker_lifetime = 0 # 0 is forever
  98. marker_ns = 'waypoints'
  99. marker_id = 0
  100. marker_color = {'r': 1.0, 'g': 0.7, 'b': 1.0, 'a': 1.0}
  101. # Define a marker publisher.
  102. self.marker_pub = rospy.Publisher('waypoint_markers', Marker, queue_size=5)
  103. # Initialize the marker points list.
  104. self.markers = Marker()
  105. self.markers.ns = marker_ns
  106. self.markers.id = marker_id
  107. self.markers.type = Marker.CUBE_LIST
  108. self.markers.action = Marker.ADD
  109. self.markers.lifetime = rospy.Duration(marker_lifetime)
  110. self.markers.scale.x = marker_scale
  111. self.markers.scale.y = marker_scale
  112. self.markers.color.r = marker_color['r']
  113. self.markers.color.g = marker_color['g']
  114. self.markers.color.b = marker_color['b']
  115. self.markers.color.a = marker_color['a']
  116. self.markers.header.frame_id = 'odom'
  117. self.markers.header.stamp = rospy.Time.now()
  118. self.markers.points = list()
  119. def shutdown(self):
  120. rospy.loginfo("Stopping the robot...")
  121. # Cancel any active goals
  122. self.move_base.cancel_goal()
  123. rospy.sleep(2)
  124. # Stop the robot
  125. self.cmd_vel_pub.publish(Twist())
  126. rospy.sleep(1)
  127. if __name__ == '__main__':
  128. try:
  129. MoveBaseSquare()
  130. except rospy.ROSInterruptException:
  131. rospy.loginfo("Navigation test finished.")