Advertisement
Guest User

Untitled

a guest
Jul 3rd, 2024
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.74 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. from math import sin, cos
  4. import rclpy
  5. from rclpy.node import Node
  6. from nav2_simple_commander.robot_navigator import BasicNavigator
  7. import yaml
  8. from ament_index_python.packages import get_package_share_directory
  9. import os
  10. import sys
  11. import time
  12. from geometry_msgs.msg import PoseStamped, Quaternion
  13. from robot_localization.srv import FromLL
  14.  
  15. def yaw_to_quaternion(yaw):
  16. """Convert yaw (in radians) to a quaternion."""
  17. return Quaternion(
  18. x=0.0,
  19. y=0.0,
  20. z=sin(yaw * 0.5),
  21. w=cos(yaw * 0.5)
  22. )
  23.  
  24. class YamlWaypointParser:
  25. """
  26. Parse a set of GPS waypoints from a YAML file.
  27. """
  28. def __init__(self, wps_file_path: str):
  29. with open(wps_file_path, 'r') as wps_file:
  30. self.wps_dict = yaml.safe_load(wps_file)
  31.  
  32. def get_wps(self):
  33. """
  34. Get an array of geographic coordinates and yaw from the YAML file.
  35. """
  36. return self.wps_dict["waypoints"]
  37.  
  38. class GpsWpCommander(Node):
  39. """
  40. Class to use Nav2 GPS waypoint follower to follow a set of waypoints logged in a YAML file.
  41. """
  42. def __init__(self, wps_file_path):
  43. super().__init__('gps_wp_commander')
  44. self.navigator = BasicNavigator("basic_navigator")
  45. self.wp_parser = YamlWaypointParser(wps_file_path)
  46. self.from_ll_client = self.create_client(FromLL, 'fromLL')
  47. while not self.from_ll_client.wait_for_service(timeout_sec=1.0):
  48. self.get_logger().info('fromLL service not available, waiting again...')
  49.  
  50. def convert_geo_pose_to_pose_stamped(self, latitude, longitude, yaw):
  51. self.get_logger().info(f'Converting latitude: {latitude}, longitude: {longitude}, yaw: {yaw}')
  52. request = FromLL.Request()
  53. request.ll_point.latitude = float(latitude)
  54. request.ll_point.longitude = float(longitude)
  55. future = self.from_ll_client.call_async(request)
  56. rclpy.spin_until_future_complete(self, future)
  57. response = future.result()
  58. if response and response.map_point:
  59. pose_stamped = PoseStamped()
  60. pose_stamped.header.frame_id = 'map'
  61. pose_stamped.header.stamp = self.get_clock().now().to_msg()
  62. pose_stamped.pose.position.x = response.map_point.x
  63. pose_stamped.pose.position.y = response.map_point.y
  64. pose_stamped.pose.position.z = 0.0
  65. pose_stamped.pose.orientation = yaw_to_quaternion(yaw)
  66. self.get_logger().info(f'Converted to local coordinates: x={response.map_point.x}, y={response.map_point.y}')
  67. return pose_stamped
  68. else:
  69. self.get_logger().error('Failed to get valid response from fromLL service')
  70. return None
  71.  
  72.  
  73. def start_wpf(self):
  74. """Function to start the waypoint following using NavigateThroughPoses."""
  75. self.navigator.waitUntilNav2Active(localizer='robot_localization')
  76. gps_waypoints = self.wp_parser.get_wps()
  77. poses = [self.convert_geo_pose_to_pose_stamped(wp['latitude'], wp['longitude'], wp['yaw']) for wp in gps_waypoints if self.convert_geo_pose_to_pose_stamped(wp['latitude'], wp['longitude'], wp['yaw']) is not None]
  78. self.navigator.goThroughPoses(poses)
  79. while not self.navigator.isTaskComplete():
  80. time.sleep(0.1)
  81. print("Waypoints completed successfully")
  82.  
  83. def main():
  84. rclpy.init()
  85. default_yaml_file_path = os.path.join(get_package_share_directory("nav2_gps_waypoint_follower_demo"), "config", "demo_waypoints.yaml")
  86. yaml_file_path = sys.argv[1] if len(sys.argv) > 1 else default_yaml_file_path
  87. gps_wpf = GpsWpCommander(yaml_file_path)
  88. gps_wpf.start_wpf()
  89. rclpy.shutdown()
  90.  
  91. if __name__ == "__main__":
  92. main()
  93.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement