waypoints_to_simple_goals.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 import math
4 import rospy
5 import tf2_ros
6 
7 from geometry_msgs.msg import PoseArray, PoseStamped, Pose
8 from std_msgs.msg import Bool, Empty
9 
10 """
11 Since many navigations stacks do not support multiple goals or even action servers,
12 this node serves is a demo example of sending simple goals sequentially, checking for range completion in between.
13 Goal timeouts and handling other edge cases is left as an excercise to the reader.
14 """
15 
17  def __init__(self):
18  rospy.init_node('waypoints_to_simple_goals')
19 
20  self.rate = rospy.get_param('~rate', 10)
21  self.robot_link = rospy.get_param('~robot_link', 'base_link')
22  self.goal_reached_range = rospy.get_param('~goal_reached_range', 0.1)
23 
24  # State management through waypoints list
25  self.waypoints = []
26  self.current_goal = None
27  self.waypoints_header = None
28 
29  self.last_robot_pose = None
30  self.tf_buffer = tf2_ros.Buffer()
31  self.tf_listener = tf2_ros.TransformListener(self.tf_buffer)
32 
33  # Remap this if your nav stack takes simple goals on another topic
34  self.goal_pub = rospy.Publisher('/move_base_simple/goal', PoseStamped, queue_size=1)
35 
36  # Sends out the current navigation state (active/idle)
37  self.state_pub = rospy.Publisher('/waypoints/state', Bool, queue_size=1, latch=True)
38 
39  # Point the Waypoints widget to this one
40  self.waypoints_sub = rospy.Subscriber('/waypoints', PoseArray, self.waypoints_callback)
41 
42  # Point a Button widget to this one to stop path execution at any time
43  self.estop_sub = rospy.Subscriber('/waypoints/estop', Empty, self.estop_callback)
44 
45  # Initialize state
46  self.publish_navigation_state(False)
47 
48  rospy.loginfo("Waypoints node started.")
49 
50  def waypoints_callback(self, msg):
51  poses = list(msg.poses)
52 
53  if len(poses) == 0:
54  #Empty array was sent as a preempt, we should just abort current execution
55  self.estop_callback(None)
56  return
57 
58  self.waypoints = poses
59  self.waypoints_header = msg.header
60  self.current_goal = None
61  rospy.loginfo("New path received!")
62 
63  def estop_callback(self, _):
64  if self.current_goal is not None and self.last_robot_pose is not None and self.waypoints_header is not None:
65  goal = PoseStamped()
66  goal.header = self.waypoints_header
67  goal.pose = self.last_robot_pose
68  self.goal_pub.publish(goal)
69 
70  self.waypoints = []
71  self.current_goal = None
72  self.publish_navigation_state(False)
73 
74  rospy.loginfo("Emergency stop triggered!")
75 
76  def update(self):
77  if not self.waypoints:
78  if self.current_goal is not None:
79  self.current_goal = None
80  self.publish_navigation_state(False)
81  return
82 
83  # Send next goal
84  if self.current_goal is None and self.waypoints:
85 
86  next_pose = self.waypoints[0]
87 
88  goal = PoseStamped()
89  goal.header = self.waypoints_header
90  goal.pose = next_pose
91  self.goal_pub.publish(goal)
92 
93  self.current_goal = goal
94  self.publish_navigation_state(True)
95  rospy.loginfo(f"Published: ({next_pose.position.x},{next_pose.position.y},{next_pose.position.z}), {len(self.waypoints)} goals left.")
96 
97  # Check if current goal is reached
98  if self.current_goal and self.check_goal_reached(self.current_goal):
99  self.waypoints.pop(0)
100  self.current_goal = None
101 
102  if not self.waypoints:
103  rospy.loginfo("Path finished!")
104 
105  def check_goal_reached(self, goal):
106  try:
107  transform = self.tf_buffer.lookup_transform(
108  goal.header.frame_id,
109  self.robot_link,
110  rospy.Time(0), # get most recent transform
111  rospy.Duration(1.0)
112  )
113 
114  self.last_robot_pose = Pose()
115  self.last_robot_pose.position = transform.transform.translation
116  self.last_robot_pose.orientation = transform.transform.rotation
117 
118  dx = transform.transform.translation.x - goal.pose.position.x
119  dy = transform.transform.translation.y - goal.pose.position.y
120  distance = math.sqrt(dx*dx + dy*dy)
121 
122  return distance <= self.goal_reached_range
123 
124  except (tf2_ros.LookupException,
125  tf2_ros.ConnectivityException,
126  tf2_ros.ExtrapolationException) as e:
127  return False
128 
129  def publish_navigation_state(self, state):
130  self.state_pub.publish(Bool(data=state))
131 
132  def cleanup(self):
133  self.waypoints = []
134  self.current_goal = None
135  self.publish_navigation_state(False)
136 
138 rate = rospy.Rate(node.rate)
139 rospy.on_shutdown(node.cleanup)
140 
141 while not rospy.is_shutdown():
142  node.update()
143  rate.sleep()
waypoints_to_simple_goals.WaypointsToSimpleGoals.goal_pub
goal_pub
Definition: waypoints_to_simple_goals.py:34
waypoints_to_simple_goals.WaypointsToSimpleGoals.estop_callback
def estop_callback(self, _)
Definition: waypoints_to_simple_goals.py:63
waypoints_to_simple_goals.WaypointsToSimpleGoals.update
def update(self)
Definition: waypoints_to_simple_goals.py:76
waypoints_to_simple_goals.WaypointsToSimpleGoals.last_robot_pose
last_robot_pose
Definition: waypoints_to_simple_goals.py:29
waypoints_to_simple_goals.WaypointsToSimpleGoals.estop_sub
estop_sub
Definition: waypoints_to_simple_goals.py:43
waypoints_to_simple_goals.WaypointsToSimpleGoals.rate
rate
Definition: waypoints_to_simple_goals.py:20
waypoints_to_simple_goals.WaypointsToSimpleGoals.waypoints_header
waypoints_header
Definition: waypoints_to_simple_goals.py:27
waypoints_to_simple_goals.WaypointsToSimpleGoals.goal_reached_range
goal_reached_range
Definition: waypoints_to_simple_goals.py:22
waypoints_to_simple_goals.WaypointsToSimpleGoals.tf_buffer
tf_buffer
Definition: waypoints_to_simple_goals.py:30
waypoints_to_simple_goals.WaypointsToSimpleGoals.current_goal
current_goal
Definition: waypoints_to_simple_goals.py:26
waypoints_to_simple_goals.WaypointsToSimpleGoals.tf_listener
tf_listener
Definition: waypoints_to_simple_goals.py:31
waypoints_to_simple_goals.WaypointsToSimpleGoals
Definition: waypoints_to_simple_goals.py:16
waypoints_to_simple_goals.WaypointsToSimpleGoals.waypoints_sub
waypoints_sub
Definition: waypoints_to_simple_goals.py:40
waypoints_to_simple_goals.WaypointsToSimpleGoals.check_goal_reached
def check_goal_reached(self, goal)
Definition: waypoints_to_simple_goals.py:105
waypoints_to_simple_goals.WaypointsToSimpleGoals.__init__
def __init__(self)
Definition: waypoints_to_simple_goals.py:17
waypoints_to_simple_goals.WaypointsToSimpleGoals.cleanup
def cleanup(self)
Definition: waypoints_to_simple_goals.py:132
waypoints_to_simple_goals.WaypointsToSimpleGoals.waypoints_callback
def waypoints_callback(self, msg)
Definition: waypoints_to_simple_goals.py:50
waypoints_to_simple_goals.WaypointsToSimpleGoals.state_pub
state_pub
Definition: waypoints_to_simple_goals.py:37
waypoints_to_simple_goals.WaypointsToSimpleGoals.publish_navigation_state
def publish_navigation_state(self, state)
Definition: waypoints_to_simple_goals.py:129
waypoints_to_simple_goals.WaypointsToSimpleGoals.waypoints
waypoints
Definition: waypoints_to_simple_goals.py:25
waypoints_to_simple_goals.WaypointsToSimpleGoals.robot_link
robot_link
Definition: waypoints_to_simple_goals.py:21


vizanti
Author(s): MoffKalast
autogenerated on Wed May 21 2025 02:34:06