20 from typing
import Any, Union
22 from action_msgs.msg
import GoalStatus
24 from geographic_msgs.msg
import GeoPose
26 from lifecycle_msgs.srv
import GetState
27 from nav2_msgs.action
import (AssistedTeleop, BackUp,
28 ComputeAndTrackRoute, ComputePathThroughPoses, ComputePathToPose,
29 ComputeRoute, DockRobot, DriveOnHeading, FollowGPSWaypoints,
30 FollowObject, FollowPath, FollowWaypoints, NavigateThroughPoses,
31 NavigateToPose, SmoothPath, Spin, UndockRobot)
32 from nav2_msgs.srv
import (ClearCostmapAroundPose, ClearCostmapAroundRobot,
33 ClearCostmapExceptRegion, ClearEntireCostmap, GetCostmap, LoadMap,
34 ManageLifecycleNodes, Toggle)
37 from rclpy.action
import ActionClient
38 from rclpy.client
import Client
39 from rclpy.duration
import Duration
as rclpyDuration
40 from rclpy.node
import Node
41 from rclpy.qos
import QoSDurabilityPolicy, QoSHistoryPolicy, QoSProfile, QoSReliabilityPolicy
58 NAVIGATE_THROUGH_POSES = 2
61 FOLLOW_GPS_WAYPOINTS = 5
68 COMPUTE_AND_TRACK_ROUTE = 12
74 def __init__(self, node_name: str =
'basic_navigator', namespace: str =
''):
75 super().__init__(node_name=node_name, namespace=namespace)
96 amcl_pose_qos = QoSProfile(
97 durability=QoSDurabilityPolicy.TRANSIENT_LOCAL,
98 reliability=QoSReliabilityPolicy.RELIABLE,
99 history=QoSHistoryPolicy.KEEP_LAST,
105 self, NavigateThroughPoses,
'navigate_through_poses')
106 self.
nav_to_pose_clientnav_to_pose_client = ActionClient(self, NavigateToPose,
'navigate_to_pose')
108 self, FollowWaypoints,
'follow_waypoints'
111 self, FollowGPSWaypoints,
'follow_gps_waypoints'
113 self.
follow_path_clientfollow_path_client = ActionClient(self, FollowPath,
'follow_path')
115 self, ComputePathToPose,
'compute_path_to_pose'
118 self, ComputePathThroughPoses,
'compute_path_through_poses'
120 self.
smoother_clientsmoother_client = ActionClient(self, SmoothPath,
'smooth_path')
121 self.
compute_route_clientcompute_route_client = ActionClient(self, ComputeRoute,
'compute_route')
124 ComputeAndTrackRoute,
125 'compute_and_track_route',
127 self.
spin_clientspin_client = ActionClient(self, Spin,
'spin')
129 self.
backup_clientbackup_client = ActionClient(self, BackUp,
'backup')
131 self, DriveOnHeading,
'drive_on_heading'
134 self, AssistedTeleop,
'assisted_teleop'
136 self.
docking_clientdocking_client = ActionClient(self, DockRobot,
'dock_robot')
137 self.
undocking_clientundocking_client = ActionClient(self, UndockRobot,
'undock_robot')
138 self.
following_clientfollowing_client = ActionClient(self, FollowObject,
'follow_object')
141 PoseWithCovarianceStamped,
147 PoseWithCovarianceStamped,
'initialpose', 10
150 self.create_client(LoadMap,
'map_server/load_map')
153 'global_costmap/clear_entirely_global_costmap',
157 'local_costmap/clear_entirely_local_costmap',
160 ClearCostmapExceptRegion,
161 'local_costmap/clear_costmap_except_region',
164 ClearCostmapAroundRobot,
165 'local_costmap/clear_costmap_around_robot',
168 ClearCostmapAroundPose,
169 'local_costmap/clear_costmap_around_pose',
172 ClearCostmapAroundPose,
173 'global_costmap/clear_costmap_around_pose',
177 'global_costmap/get_costmap',
181 'local_costmap/get_costmap',
185 'collision_monitor/toggle',
188 def destroyNode(self):
191 def destroy_node(self):
208 super().destroy_node()
211 """Set the initial pose to the localization system."""
217 """Send a `NavThroughPoses` action request."""
219 self.
debugdebug(
"Waiting for 'NavigateThroughPoses' action server")
221 self.
infoinfo(
"'NavigateThroughPoses' action server not available, waiting...")
223 goal_msg = NavigateThroughPoses.Goal()
224 goal_msg.poses = poses
225 goal_msg.behavior_tree = behavior_tree
227 self.
infoinfo(f
'Navigating with {len(poses.goals)} goals....')
231 rclpy.spin_until_future_complete(self, send_goal_future)
232 self.
goal_handlegoal_handle = send_goal_future.result()
235 msg = f
'NavigateThroughPoses request with {len(poses.goals)} was rejected!'
236 self.
setTaskErrorsetTaskError(NavigateThroughPoses.Result.UNKNOWN, msg)
241 return RunningTask.NAVIGATE_THROUGH_POSES
243 def goToPose(self, pose: PoseStamped, behavior_tree: str =
''):
244 """Send a `NavToPose` action request."""
246 self.
debugdebug(
"Waiting for 'NavigateToPose' action server")
248 self.
infoinfo(
"'NavigateToPose' action server not available, waiting...")
250 goal_msg = NavigateToPose.Goal()
252 goal_msg.behavior_tree = behavior_tree
255 'Navigating to goal: '
256 + str(pose.pose.position.x)
258 + str(pose.pose.position.y)
264 rclpy.spin_until_future_complete(self, send_goal_future)
265 self.
goal_handlegoal_handle = send_goal_future.result()
269 'NavigateToPose goal to '
270 + str(pose.pose.position.x)
272 + str(pose.pose.position.y)
275 self.
setTaskErrorsetTaskError(NavigateToPose.Result.UNKNOWN, msg)
280 return RunningTask.NAVIGATE_TO_POSE
283 self, poses: list[PoseStamped], number_of_loops: int = 0, goal_index: int = 0
285 """Send a `FollowWaypoints` action request."""
287 self.
debugdebug(
"Waiting for 'FollowWaypoints' action server")
289 self.
infoinfo(
"'FollowWaypoints' action server not available, waiting...")
291 goal_msg = FollowWaypoints.Goal()
292 goal_msg.poses = poses
293 goal_msg.number_of_loops = number_of_loops
294 goal_msg.goal_index = goal_index
296 self.
infoinfo(f
'Following {len(goal_msg.poses)} goals....')
300 rclpy.spin_until_future_complete(self, send_goal_future)
301 self.
goal_handlegoal_handle = send_goal_future.result()
304 msg = f
'Following {len(poses)} waypoints request was rejected!'
305 self.
setTaskErrorsetTaskError(FollowWaypoints.Result.UNKNOWN, msg)
310 return RunningTask.FOLLOW_WAYPOINTS
313 """Send a `FollowGPSWaypoints` action request."""
315 self.
debugdebug(
"Waiting for 'FollowWaypoints' action server")
317 self.
infoinfo(
"'FollowWaypoints' action server not available, waiting...")
319 goal_msg = FollowGPSWaypoints.Goal()
320 goal_msg.gps_poses = gps_poses
322 self.
infoinfo(f
'Following {len(goal_msg.gps_poses)} gps goals....')
326 rclpy.spin_until_future_complete(self, send_goal_future)
327 self.
goal_handlegoal_handle = send_goal_future.result()
330 msg = f
'Following {len(gps_poses)} gps waypoints request was rejected!'
331 self.
setTaskErrorsetTaskError(FollowGPSWaypoints.Result.UNKNOWN, msg)
336 return RunningTask.FOLLOW_GPS_WAYPOINTS
339 self, spin_dist: float = 1.57, time_allowance: int = 10,
340 disable_collision_checks: bool =
False):
342 self.
debugdebug(
"Waiting for 'Spin' action server")
343 while not self.
spin_clientspin_client.wait_for_server(timeout_sec=1.0):
344 self.
infoinfo(
"'Spin' action server not available, waiting...")
345 goal_msg = Spin.Goal()
346 goal_msg.target_yaw = spin_dist
347 goal_msg.time_allowance = Duration(sec=time_allowance)
348 goal_msg.disable_collision_checks = disable_collision_checks
350 self.
infoinfo(f
'Spinning to angle {goal_msg.target_yaw}....')
351 send_goal_future = self.
spin_clientspin_client.send_goal_async(
354 rclpy.spin_until_future_complete(self, send_goal_future)
355 self.
goal_handlegoal_handle = send_goal_future.result()
358 msg =
'Spin request was rejected!'
364 return RunningTask.SPIN
367 self, backup_dist: float = 0.15, backup_speed: float = 0.025,
368 time_allowance: int = 10,
369 disable_collision_checks: bool =
False):
371 self.
debugdebug(
"Waiting for 'Backup' action server")
372 while not self.
backup_clientbackup_client.wait_for_server(timeout_sec=1.0):
373 self.
infoinfo(
"'Backup' action server not available, waiting...")
374 goal_msg = BackUp.Goal()
375 goal_msg.target = Point(x=float(backup_dist))
376 goal_msg.speed = backup_speed
377 goal_msg.time_allowance = Duration(sec=time_allowance)
378 goal_msg.disable_collision_checks = disable_collision_checks
380 self.
infoinfo(f
'Backing up {goal_msg.target.x} m at {goal_msg.speed} m/s....')
381 send_goal_future = self.
backup_clientbackup_client.send_goal_async(
384 rclpy.spin_until_future_complete(self, send_goal_future)
385 self.
goal_handlegoal_handle = send_goal_future.result()
388 msg =
'Backup request was rejected!'
389 self.
setTaskErrorsetTaskError(BackUp.Result.UNKNOWN, msg)
394 return RunningTask.BACKUP
397 self, dist: float = 0.15, speed: float = 0.025,
398 time_allowance: int = 10,
399 disable_collision_checks: bool =
False):
401 self.
debugdebug(
"Waiting for 'DriveOnHeading' action server")
403 self.
infoinfo(
"'DriveOnHeading' action server not available, waiting...")
404 goal_msg = DriveOnHeading.Goal()
405 goal_msg.target = Point(x=float(dist))
406 goal_msg.speed = speed
407 goal_msg.time_allowance = Duration(sec=time_allowance)
408 goal_msg.disable_collision_checks = disable_collision_checks
410 self.
infoinfo(f
'Drive {goal_msg.target.x} m on heading at {goal_msg.speed} m/s....')
414 rclpy.spin_until_future_complete(self, send_goal_future)
415 self.
goal_handlegoal_handle = send_goal_future.result()
418 msg =
'Drive On Heading request was rejected!'
419 self.
setTaskErrorsetTaskError(DriveOnHeading.Result.UNKNOWN, msg)
424 return RunningTask.DRIVE_ON_HEADING
426 def assistedTeleop(self, time_allowance: int = 30):
429 self.
debugdebug(
"Wanting for 'assisted_teleop' action server")
432 self.
infoinfo(
"'assisted_teleop' action server not available, waiting...")
433 goal_msg = AssistedTeleop.Goal()
434 goal_msg.time_allowance = Duration(sec=time_allowance)
436 self.
infoinfo(
"Running 'assisted_teleop'....")
440 rclpy.spin_until_future_complete(self, send_goal_future)
441 self.
goal_handlegoal_handle = send_goal_future.result()
444 msg =
'Assisted Teleop request was rejected!'
445 self.
setTaskErrorsetTaskError(AssistedTeleop.Result.UNKNOWN, msg)
450 return RunningTask.ASSISTED_TELEOP
452 def followPath(self, path: Path, controller_id: str =
'',
453 goal_checker_id: str =
'', progress_checker_id: str =
'',
454 path_handler_id: str =
''):
456 """Send a `FollowPath` action request."""
457 self.
debugdebug(
"Waiting for 'FollowPath' action server")
459 self.
infoinfo(
"'FollowPath' action server not available, waiting...")
461 goal_msg = FollowPath.Goal()
463 goal_msg.controller_id = controller_id
464 goal_msg.goal_checker_id = goal_checker_id
465 goal_msg.progress_checker_id = progress_checker_id
466 goal_msg.path_handler_id = path_handler_id
468 self.
infoinfo(
'Executing path...')
472 rclpy.spin_until_future_complete(self, send_goal_future)
473 self.
goal_handlegoal_handle = send_goal_future.result()
476 msg =
'FollowPath goal was rejected!'
477 self.
setTaskErrorsetTaskError(FollowPath.Result.UNKNOWN, msg)
482 return RunningTask.FOLLOW_PATH
484 def dockRobotByPose(self, dock_pose: PoseStamped,
485 dock_type: str =
'', nav_to_dock: bool =
True):
487 """Send a `DockRobot` action request."""
488 self.
infoinfo(
"Waiting for 'DockRobot' action server")
489 while not self.
docking_clientdocking_client.wait_for_server(timeout_sec=1.0):
490 self.
infoinfo(
'"DockRobot" action server not available, waiting...')
492 goal_msg = DockRobot.Goal()
493 goal_msg.use_dock_id =
False
494 goal_msg.dock_pose = dock_pose
495 goal_msg.dock_type = dock_type
496 goal_msg.navigate_to_staging_pose = nav_to_dock
498 self.
infoinfo(
'Docking at pose: ' + str(dock_pose) +
'...')
499 send_goal_future = self.
docking_clientdocking_client.send_goal_async(
501 rclpy.spin_until_future_complete(self, send_goal_future)
502 self.
goal_handlegoal_handle = send_goal_future.result()
505 msg =
'DockRobot request was rejected!'
506 self.
setTaskErrorsetTaskError(DockRobot.Result.UNKNOWN, msg)
511 return RunningTask.DOCK_ROBOT
514 """Send a `DockRobot` action request."""
516 self.
infoinfo(
"Waiting for 'DockRobot' action server")
517 while not self.
docking_clientdocking_client.wait_for_server(timeout_sec=1.0):
518 self.
infoinfo(
'"DockRobot" action server not available, waiting...')
520 goal_msg = DockRobot.Goal()
521 goal_msg.use_dock_id =
True
522 goal_msg.dock_id = dock_id
523 goal_msg.navigate_to_staging_pose = nav_to_dock
525 self.
infoinfo(
'Docking at dock ID: ' + str(dock_id) +
'...')
526 send_goal_future = self.
docking_clientdocking_client.send_goal_async(
528 rclpy.spin_until_future_complete(self, send_goal_future)
529 self.
goal_handlegoal_handle = send_goal_future.result()
532 msg =
'DockRobot request was rejected!'
533 self.
setTaskErrorsetTaskError(DockRobot.Result.UNKNOWN, msg)
538 return RunningTask.DOCK_ROBOT
541 """Send a `UndockRobot` action request."""
543 self.
infoinfo(
"Waiting for 'UndockRobot' action server")
544 while not self.
undocking_clientundocking_client.wait_for_server(timeout_sec=1.0):
545 self.
infoinfo(
'"UndockRobot" action server not available, waiting...')
547 goal_msg = UndockRobot.Goal()
548 goal_msg.dock_type = dock_type
550 self.
infoinfo(
'Undocking from dock of type: ' + str(dock_type) +
'...')
553 rclpy.spin_until_future_complete(self, send_goal_future)
554 self.
goal_handlegoal_handle = send_goal_future.result()
557 msg =
'UndockRobot request was rejected!'
558 self.
setTaskErrorsetTaskError(UndockRobot.Result.UNKNOWN, msg)
563 return RunningTask.UNDOCK_ROBOT
566 """Send a `FollowObject` action request."""
568 self.
infoinfo(
"Waiting for 'FollowObject' action server")
569 while not self.
following_clientfollowing_client.wait_for_server(timeout_sec=1.0):
570 self.
infoinfo(
'"FollowObject" action server not available, waiting...')
572 goal_msg = FollowObject.Goal()
573 goal_msg.pose_topic = topic
574 goal_msg.max_duration = Duration(sec=max_duration)
576 self.
infoinfo(
'Following object on topic: ' + str(topic) +
'...')
579 rclpy.spin_until_future_complete(self, send_goal_future)
580 self.
goal_handlegoal_handle = send_goal_future.result()
583 msg =
'FollowObject request was rejected!'
584 self.
setTaskErrorsetTaskError(FollowObject.Result.UNKNOWN, msg)
589 return RunningTask.FOLLOW_OBJECT
592 """Send a `FollowObject` action request."""
594 self.
infoinfo(
"Waiting for 'FollowObject' action server")
595 while not self.
following_clientfollowing_client.wait_for_server(timeout_sec=1.0):
596 self.
infoinfo(
'"FollowObject" action server not available, waiting...')
598 goal_msg = FollowObject.Goal()
599 goal_msg.tracked_frame = frame
600 goal_msg.max_duration = Duration(sec=max_duration)
602 self.
infoinfo(
'Following object in frame: ' + str(frame) +
'...')
605 rclpy.spin_until_future_complete(self, send_goal_future)
606 self.
goal_handlegoal_handle = send_goal_future.result()
609 msg =
'FollowObject request was rejected!'
610 self.
setTaskErrorsetTaskError(FollowObject.Result.UNKNOWN, msg)
615 return RunningTask.FOLLOW_OBJECT
618 """Cancel pending task request of any type."""
619 self.
infoinfo(
'Canceling current task.')
622 future = self.
goal_handlegoal_handle.cancel_goal_async()
623 rclpy.spin_until_future_complete(self, future)
625 self.
errorerror(
'Cancel task failed, goal handle is None')
626 self.
setTaskErrorsetTaskError(0,
'Cancel task failed, goal handle is None')
631 rclpy.spin_until_future_complete(self, future)
633 self.
errorerror(
'Cancel route task failed, goal handle is None')
634 self.
setTaskErrorsetTaskError(0,
'Cancel route task failed, goal handle is None')
640 """Check if the task request of any type is complete yet."""
643 self.
errorerror(
'Task is None, cannot check for completion')
647 if task != RunningTask.COMPUTE_AND_TRACK_ROUTE:
651 if not result_future:
656 rclpy.spin_until_future_complete(self, result_future, timeout_sec=0.10)
657 result_response = result_future.result()
660 self.
statusstatus = result_response.status
661 if self.
statusstatus != GoalStatus.STATUS_SUCCEEDED:
662 result = result_response.result
663 if result
is not None:
664 self.
setTaskErrorsetTaskError(result.error_code, result.error_msg)
666 'Task with failed with'
667 f
' status code:{self.status}'
668 f
' error code:{result.error_code}'
669 f
' error msg:{result.error_msg}')
673 self.
debugdebug(
'Task failed with no result received')
679 self.
debugdebug(
'Task succeeded!')
683 """Get the pending action feedback message."""
684 if task != RunningTask.COMPUTE_AND_TRACK_ROUTE:
691 """Get the pending action result message."""
692 if self.
statusstatus == GoalStatus.STATUS_SUCCEEDED:
693 return TaskResult.SUCCEEDED
694 elif self.
statusstatus == GoalStatus.STATUS_ABORTED:
695 return TaskResult.FAILED
696 elif self.
statusstatus == GoalStatus.STATUS_CANCELED:
697 return TaskResult.CANCELED
699 return TaskResult.UNKNOWN
701 def clearPreviousState(self):
706 def setTaskError(self, error_code: int, error_msg: str):
710 def getTaskError(self):
714 localizer: str =
'amcl'):
715 """Block until the full navigation system is up and running."""
716 if localizer !=
'robot_localization':
718 if localizer ==
'amcl':
721 self.
infoinfo(
'Nav2 is ready for use!')
725 self, start: PoseStamped, goal: PoseStamped,
726 planner_id: str =
'', use_start: bool =
False
729 Send a `ComputePathToPose` action request.
731 Internal implementation to get the full result, not just the path.
733 self.
debugdebug(
"Waiting for 'ComputePathToPose' action server")
735 self.
infoinfo(
"'ComputePathToPose' action server not available, waiting...")
737 goal_msg = ComputePathToPose.Goal()
738 goal_msg.start = start
740 goal_msg.planner_id = planner_id
741 goal_msg.use_start = use_start
743 self.
infoinfo(
'Getting path...')
745 rclpy.spin_until_future_complete(self, send_goal_future)
746 self.
goal_handlegoal_handle = send_goal_future.result()
749 self.
errorerror(
'Get path was rejected!')
750 self.
statusstatus = GoalStatus.STATUS_UNKNOWN
751 result = ComputePathToPose.Result()
752 result.error_code = ComputePathToPose.Result.UNKNOWN
753 result.error_msg =
'Get path was rejected'
757 rclpy.spin_until_future_complete(self, self.
result_futureresult_future)
763 self, start: PoseStamped, goal: PoseStamped,
764 planner_id: str =
'', use_start: bool =
False):
765 """Send a `ComputePathToPose` action request."""
767 rtn = self.
_getPathImpl_getPathImpl(start, goal, planner_id, use_start)
769 if self.
statusstatus == GoalStatus.STATUS_SUCCEEDED:
772 self.
setTaskErrorsetTaskError(rtn.error_code, rtn.error_msg)
773 self.
warnwarn(
'Getting path failed with'
774 f
' status code:{self.status}'
775 f
' error code:{rtn.error_code}'
776 f
' error msg:{rtn.error_msg}')
779 def _getPathThroughPosesImpl(
780 self, start: PoseStamped, goals: list[PoseStamped],
781 planner_id: str =
'', use_start: bool =
False
784 Send a `ComputePathThroughPoses` action request.
786 Internal implementation to get the full result, not just the path.
788 self.
debugdebug(
"Waiting for 'ComputePathThroughPoses' action server")
793 "'ComputePathThroughPoses' action server not available, waiting..."
796 goal_msg = ComputePathThroughPoses.Goal()
797 goal_msg.start = start
798 goal_msg.goals.header.frame_id =
'map'
799 goal_msg.goals.header.stamp = self.get_clock().now().to_msg()
800 goal_msg.goals.goals = goals
801 goal_msg.planner_id = planner_id
802 goal_msg.use_start = use_start
804 self.
infoinfo(
'Getting path...')
808 rclpy.spin_until_future_complete(self, send_goal_future)
809 self.
goal_handlegoal_handle = send_goal_future.result()
812 self.
errorerror(
'Get path was rejected!')
813 result = ComputePathThroughPoses.Result()
814 result.error_code = ComputePathThroughPoses.Result.UNKNOWN
815 result.error_msg =
'Get path was rejected!'
819 rclpy.spin_until_future_complete(self, self.
result_futureresult_future)
825 self, start: PoseStamped, goals: list[PoseStamped],
826 planner_id: str =
'', use_start: bool =
False):
827 """Send a `ComputePathThroughPoses` action request."""
831 if self.
statusstatus == GoalStatus.STATUS_SUCCEEDED:
834 self.
setTaskErrorsetTaskError(rtn.error_code, rtn.error_msg)
835 self.
warnwarn(
'Getting path failed with'
836 f
' status code:{self.status}'
837 f
' error code:{rtn.error_code}'
838 f
' error msg:{rtn.error_msg}')
842 self, start: Union[int, PoseStamped],
843 goal: Union[int, PoseStamped], use_start: bool =
False
846 Send a `ComputeRoute` action request.
848 Internal implementation to get the full result, not just the sparse route and dense path.
850 self.
debugdebug(
"Waiting for 'ComputeRoute' action server")
852 self.
infoinfo(
"'ComputeRoute' action server not available, waiting...")
854 goal_msg = ComputeRoute.Goal()
855 goal_msg.use_start = use_start
858 if isinstance(start, int)
and isinstance(goal, int):
859 goal_msg.start_id = start
860 goal_msg.goal_id = goal
861 goal_msg.use_poses =
False
862 elif isinstance(start, PoseStamped)
and isinstance(goal, PoseStamped):
863 goal_msg.start = start
865 goal_msg.use_poses =
True
867 self.
errorerror(
'Invalid start and goal types. Must be PoseStamped for pose or int for ID')
868 result = ComputeRoute.Result()
869 result.error_code = ComputeRoute.Result.UNKNOWN
870 result.error_msg =
'Request type fields were invalid!'
873 self.
infoinfo(
'Getting route...')
875 rclpy.spin_until_future_complete(self, send_goal_future)
876 self.
goal_handlegoal_handle = send_goal_future.result()
879 self.
errorerror(
'Get route was rejected!')
880 result = ComputeRoute.Result()
881 result.error_code = ComputeRoute.Result.UNKNOWN
882 result.error_msg =
'Get route was rejected!'
886 rclpy.spin_until_future_complete(self, self.
result_futureresult_future)
892 self, start: Union[int, PoseStamped],
893 goal: Union[int, PoseStamped],
894 use_start: bool =
False):
895 """Send a `ComputeRoute` action request."""
897 rtn = self.
_getRouteImpl_getRouteImpl(start, goal, use_start=
False)
899 if self.
statusstatus != GoalStatus.STATUS_SUCCEEDED:
900 self.
setTaskErrorsetTaskError(rtn.error_code, rtn.error_msg)
902 'Getting route failed with'
903 f
' status code:{self.status}'
904 f
' error code:{rtn.error_code}'
905 f
' error msg:{rtn.error_msg}')
908 return [rtn.path, rtn.route]
911 self, start: Union[int, PoseStamped],
912 goal: Union[int, PoseStamped], use_start: bool =
False
914 """Send a `ComputeAndTrackRoute` action request."""
916 self.
debugdebug(
"Waiting for 'ComputeAndTrackRoute' action server")
918 self.
infoinfo(
"'ComputeAndTrackRoute' action server not available, waiting...")
920 goal_msg = ComputeAndTrackRoute.Goal()
921 goal_msg.use_start = use_start
924 if isinstance(start, int)
and isinstance(goal, int):
925 goal_msg.start_id = start
926 goal_msg.goal_id = goal
927 goal_msg.use_poses =
False
928 elif isinstance(start, PoseStamped)
and isinstance(goal, PoseStamped):
929 goal_msg.start = start
931 goal_msg.use_poses =
True
933 self.
setTaskErrorsetTaskError(ComputeAndTrackRoute.Result.UNKNOWN,
934 'Request type fields were invalid!')
935 self.
errorerror(
'Invalid start and goal types. Must be PoseStamped for pose or int for ID')
938 self.
infoinfo(
'Computing and tracking route...')
941 rclpy.spin_until_future_complete(self, send_goal_future)
945 msg =
'Compute and track route was rejected!'
946 self.
setTaskErrorsetTaskError(ComputeAndTrackRoute.Result.UNKNOWN, msg)
951 return RunningTask.COMPUTE_AND_TRACK_ROUTE
954 self, path: Path, smoother_id: str =
'',
955 max_duration: float = 2.0, check_for_collision: bool =
False
958 Send a `SmoothPath` action request.
960 Internal implementation to get the full result, not just the path.
962 self.
debugdebug(
"Waiting for 'SmoothPath' action server")
963 while not self.
smoother_clientsmoother_client.wait_for_server(timeout_sec=1.0):
964 self.
infoinfo(
"'SmoothPath' action server not available, waiting...")
966 goal_msg = SmoothPath.Goal()
968 goal_msg.max_smoothing_duration = rclpyDuration(seconds=max_duration).to_msg()
969 goal_msg.smoother_id = smoother_id
970 goal_msg.check_for_collisions = check_for_collision
972 self.
infoinfo(
'Smoothing path...')
973 send_goal_future = self.
smoother_clientsmoother_client.send_goal_async(goal_msg)
974 rclpy.spin_until_future_complete(self, send_goal_future)
975 self.
goal_handlegoal_handle = send_goal_future.result()
978 self.
errorerror(
'Smooth path was rejected!')
979 result = SmoothPath.Result()
980 result.error_code = SmoothPath.Result.UNKNOWN
981 result.error_msg =
'Smooth path was rejected'
985 rclpy.spin_until_future_complete(self, self.
result_futureresult_future)
991 self, path: Path, smoother_id: str =
'',
992 max_duration: float = 2.0, check_for_collision: bool =
False):
993 """Send a `SmoothPath` action request."""
995 rtn = self.
_smoothPathImpl_smoothPathImpl(path, smoother_id, max_duration, check_for_collision)
997 if self.
statusstatus == GoalStatus.STATUS_SUCCEEDED:
1000 self.
setTaskErrorsetTaskError(rtn.error_code, rtn.error_msg)
1001 self.
warnwarn(
'Getting path failed with'
1002 f
' status code:{self.status}'
1003 f
' error code:{rtn.error_code}'
1004 f
' error msg:{rtn.error_msg}')
1008 """Change the current static map in the map server."""
1009 while not self.
change_maps_srvchange_maps_srv.wait_for_service(timeout_sec=1.0):
1010 self.
infoinfo(
'change map service not available, waiting...')
1011 req = LoadMap.Request()
1012 req.map_url = map_filepath
1014 rclpy.spin_until_future_complete(self, future)
1016 future_result = future.result()
1017 if future_result
is None:
1018 self.
errorerror(
'Change map request failed!')
1021 result = future_result.result
1022 if result != LoadMap.Response.RESULT_SUCCESS:
1023 if result == LoadMap.Response.RESULT_MAP_DOES_NOT_EXIST:
1024 reason =
'Map does not exist'
1025 elif result == LoadMap.Response.RESULT_INVALID_MAP_DATA:
1026 reason =
'Invalid map data'
1027 elif result == LoadMap.Response.RESULT_INVALID_MAP_METADATA:
1028 reason =
'Invalid map metadata'
1029 elif result == LoadMap.Response.RESULT_UNDEFINED_FAILURE:
1030 reason =
'Undefined failure'
1034 self.
errorerror(f
'Change map request failed:{reason}!')
1037 self.
infoinfo(
'Change map request was successful!')
1041 """Clear all costmaps."""
1047 """Clear local costmap."""
1049 self.
infoinfo(
'Clear local costmaps service not available, waiting...')
1050 req = ClearEntireCostmap.Request()
1052 rclpy.spin_until_future_complete(self, future)
1054 result = future.result()
1056 self.
errorerror(
'Clear local costmap request failed!')
1061 """Clear global costmap."""
1063 self.
infoinfo(
'Clear global costmaps service not available, waiting...')
1064 req = ClearEntireCostmap.Request()
1066 rclpy.spin_until_future_complete(self, future)
1068 result = future.result()
1070 self.
errorerror(
'Clear global costmap request failed!')
1075 """Clear the costmap except for a specified region."""
1077 self.
infoinfo(
'ClearCostmapExceptRegion service not available, waiting...')
1078 req = ClearCostmapExceptRegion.Request()
1079 req.reset_distance = reset_distance
1081 rclpy.spin_until_future_complete(self, future)
1083 result = future.result()
1085 self.
errorerror(
'Clear costmap except region request failed!')
1090 """Clear the costmap around the robot."""
1092 self.
infoinfo(
'ClearCostmapAroundRobot service not available, waiting...')
1093 req = ClearCostmapAroundRobot.Request()
1094 req.reset_distance = reset_distance
1096 rclpy.spin_until_future_complete(self, future)
1098 result = future.result()
1100 self.
errorerror(
'Clear costmap around robot request failed!')
1105 """Clear the costmap around a given pose."""
1107 self.
infoinfo(
'ClearLocalCostmapAroundPose service not available, waiting...')
1108 req = ClearCostmapAroundPose.Request()
1110 req.reset_distance = reset_distance
1112 rclpy.spin_until_future_complete(self, future)
1114 result = future.result()
1116 self.
errorerror(
'Clear local costmap around pose request failed!')
1121 """Clear the global costmap around a given pose."""
1123 self.
infoinfo(
'ClearGlobalCostmapAroundPose service not available, waiting...')
1124 req = ClearCostmapAroundPose.Request()
1126 req.reset_distance = reset_distance
1128 rclpy.spin_until_future_complete(self, future)
1130 result = future.result()
1132 self.
errorerror(
'Clear global costmap around pose request failed!')
1137 """Get the global costmap."""
1139 self.
infoinfo(
'Get global costmaps service not available, waiting...')
1140 req = GetCostmap.Request()
1142 rclpy.spin_until_future_complete(self, future)
1144 result = future.result()
1146 self.
errorerror(
'Get global costmap request failed!')
1152 """Get the local costmap."""
1154 self.
infoinfo(
'Get local costmaps service not available, waiting...')
1155 req = GetCostmap.Request()
1157 rclpy.spin_until_future_complete(self, future)
1159 result = future.result()
1162 self.
errorerror(
'Get local costmap request failed!')
1168 """Toggle the collision monitor."""
1170 self.
infoinfo(
'Toggle collision monitor service not available, waiting...')
1171 req = Toggle.Request()
1175 rclpy.spin_until_future_complete(self, future)
1176 result = future.result()
1178 self.
errorerror(
'Toggle collision monitor request failed!')
1183 """Startup nav2 lifecycle system."""
1184 self.
infoinfo(
'Starting up lifecycle nodes based on lifecycle_manager.')
1185 for srv_name, srv_type
in self.get_service_names_and_types():
1186 if srv_type[0] ==
'nav2_msgs/srv/ManageLifecycleNodes':
1187 self.
infoinfo(f
'Starting up {srv_name}')
1188 mgr_client: Client[ManageLifecycleNodes.Request, ManageLifecycleNodes.Response] = \
1189 self.create_client(ManageLifecycleNodes, srv_name)
1190 while not mgr_client.wait_for_service(timeout_sec=1.0):
1191 self.
infoinfo(f
'{srv_name} service not available, waiting...')
1192 req = ManageLifecycleNodes.Request()
1193 req.command = ManageLifecycleNodes.Request.STARTUP
1194 future = mgr_client.call_async(req)
1199 rclpy.spin_until_future_complete(self, future, timeout_sec=0.10)
1204 self.
infoinfo(
'Nav2 is ready for use!')
1208 """Shutdown nav2 lifecycle system."""
1209 self.
infoinfo(
'Shutting down lifecycle nodes based on lifecycle_manager.')
1210 for srv_name, srv_type
in self.get_service_names_and_types():
1211 if srv_type[0] ==
'nav2_msgs/srv/ManageLifecycleNodes':
1212 self.
infoinfo(f
'Shutting down {srv_name}')
1213 mgr_client: Client[ManageLifecycleNodes.Request, ManageLifecycleNodes.Response] = \
1214 self.create_client(ManageLifecycleNodes, srv_name)
1215 while not mgr_client.wait_for_service(timeout_sec=1.0):
1216 self.
infoinfo(f
'{srv_name} service not available, waiting...')
1217 req = ManageLifecycleNodes.Request()
1218 req.command = ManageLifecycleNodes.Request.SHUTDOWN
1219 future = mgr_client.call_async(req)
1220 rclpy.spin_until_future_complete(self, future)
1224 def _waitForNodeToActivate(self, node_name: str):
1226 self.
debugdebug(f
'Waiting for {node_name} to become active..')
1227 node_service = f
'{node_name}/get_state'
1228 state_client: Client[GetState.Request, GetState.Response] = \
1229 self.create_client(GetState, node_service)
1230 while not state_client.wait_for_service(timeout_sec=1.0):
1231 self.
infoinfo(f
'{node_service} service not available, waiting...')
1233 req = GetState.Request()
1235 while state !=
'active':
1236 self.
debugdebug(f
'Getting {node_name} state...')
1237 future = state_client.call_async(req)
1238 rclpy.spin_until_future_complete(self, future)
1240 result = future.result()
1241 if result
is not None:
1242 state = result.current_state.label
1243 self.
debugdebug(f
'Result of get_state: {state}')
1247 def _waitForInitialPose(self):
1249 self.
infoinfo(
'Setting initial pose')
1251 self.
infoinfo(
'Waiting for amcl_pose to be received')
1252 rclpy.spin_once(self, timeout_sec=1.0)
1255 def _amclPoseCallback(self, msg: PoseWithCovarianceStamped):
1256 self.
debugdebug(
'Received amcl pose')
1260 def _feedbackCallback(self, msg: Any):
1261 self.
debugdebug(
'Received action feedback message')
1262 self.
feedbackfeedback = msg.feedback
1265 def _routeFeedbackCallback(
1266 self, msg: ComputeAndTrackRoute.Impl.FeedbackMessage):
1267 self.
debugdebug(
'Received route action feedback message')
1271 def _setInitialPose(self):
1272 msg = PoseWithCovarianceStamped()
1274 msg.header.frame_id = self.
initial_poseinitial_pose.header.frame_id
1275 msg.header.stamp = self.
initial_poseinitial_pose.header.stamp
1276 self.
infoinfo(
'Publishing Initial Pose')
1280 def info(self, msg: str):
1281 self.get_logger().info(msg)
1284 def warn(self, msg: str):
1285 self.get_logger().warning(msg)
1288 def error(self, msg: str):
1289 self.get_logger().error(msg)
1292 def debug(self, msg: str):
1293 self.get_logger().debug(msg)
def clearAllCostmaps(self)
def _getPathThroughPosesImpl(self, PoseStamped start, list[PoseStamped] goals, str planner_id='', bool use_start=False)
def goThroughPoses(self, Goals poses, str behavior_tree='')
def clearLocalCostmapAroundPose(self, PoseStamped pose, float reset_distance)
compute_path_to_pose_client
def getRoute(self, Union[int, PoseStamped] start, Union[int, PoseStamped] goal, bool use_start=False)
def _waitForNodeToActivate(self, str node_name)
def followWaypoints(self, list[PoseStamped] poses, int number_of_loops=0, int goal_index=0)
def getPath(self, PoseStamped start, PoseStamped goal, str planner_id='', bool use_start=False)
def waitUntilNav2Active(self, str navigator='bt_navigator', str localizer='amcl')
def isTaskComplete(self, RunningTask task=RunningTask.NONE)
def _getPathImpl(self, PoseStamped start, PoseStamped goal, str planner_id='', bool use_start=False)
def _feedbackCallback(self, Any msg)
def followObjectByFrame(self, str frame, int max_duration=0)
toggle_collision_monitor_srv
def dockRobotByID(self, str dock_id, bool nav_to_dock=True)
def toggleCollisionMonitor(self, bool enable)
def clearCostmapAroundRobot(self, float reset_distance)
def clearPreviousState(self)
def getLocalCostmap(self)
def setInitialPose(self, PoseStamped initial_pose)
def clearGlobalCostmapAroundPose(self, PoseStamped pose, float reset_distance)
def getPathThroughPoses(self, PoseStamped start, list[PoseStamped] goals, str planner_id='', bool use_start=False)
def _routeFeedbackCallback(self, ComputeAndTrackRoute.Impl.FeedbackMessage msg)
clear_costmap_except_region_srv
def lifecycleStartup(self)
follow_gps_waypoints_client
clear_costmap_around_robot_srv
def changeMap(self, str map_filepath)
def _waitForInitialPose(self)
def _amclPoseCallback(self, PoseWithCovarianceStamped msg)
def clearLocalCostmap(self)
def clearGlobalCostmap(self)
def getAndTrackRoute(self, Union[int, PoseStamped] start, Union[int, PoseStamped] goal, bool use_start=False)
def undockRobot(self, str dock_type='')
clear_local_costmap_around_pose_srv
def lifecycleShutdown(self)
def getFeedback(self, RunningTask task=RunningTask.NONE)
def getGlobalCostmap(self)
def clearCostmapExceptRegion(self, float reset_distance)
def followObjectByTopic(self, str topic, int max_duration=0)
def _getRouteImpl(self, Union[int, PoseStamped] start, Union[int, PoseStamped] goal, bool use_start=False)
compute_path_through_poses_client
def _smoothPathImpl(self, Path path, str smoother_id='', float max_duration=2.0, bool check_for_collision=False)
def setTaskError(self, int error_code, str error_msg)
compute_and_track_route_client
def _setInitialPose(self)
def goToPose(self, PoseStamped pose, str behavior_tree='')
clear_global_costmap_around_pose_srv
def smoothPath(self, Path path, str smoother_id='', float max_duration=2.0, bool check_for_collision=False)
def followGpsWaypoints(self, list[GeoPose] gps_poses)