gps_goal.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 import rospy
3 import click
4 import math
5 import actionlib
6 import tf
7 
8 from geographiclib.geodesic import Geodesic
9 from actionlib_msgs.msg import GoalStatus
10 from geometry_msgs.msg import PoseStamped
11 from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
12 from sensor_msgs.msg import NavSatFix
13 
14 def DMS_to_decimal_format(lat,long):
15  # Check for degrees, minutes, seconds format and convert to decimal
16  if ',' in lat:
17  degrees, minutes, seconds = lat.split(',')
18  degrees, minutes, seconds = float(degrees), float(minutes), float(seconds)
19  if lat[0] == '-': # check for negative sign
20  minutes = -minutes
21  seconds = -seconds
22  lat = degrees + minutes/60 + seconds/3600
23  if ',' in long:
24  degrees, minutes, seconds = long.split(',')
25  degrees, minutes, seconds = float(degrees), float(minutes), float(seconds)
26  if long[0] == '-': # check for negative sign
27  minutes = -minutes
28  seconds = -seconds
29  long = degrees + minutes/60 + seconds/3600
30 
31  lat = float(lat)
32  long = float(long)
33  rospy.loginfo('Given GPS goal: lat %s, long %s.' % (lat, long))
34  return lat, long
35 
37  # Get the lat long coordinates of our map frame's origin which must be publshed on topic /local_xy_origin. We use this to calculate our goal within the map frame.
38  rospy.loginfo("Waiting for a message to initialize the origin GPS location...")
39  origin_pose = rospy.wait_for_message('local_xy_origin', PoseStamped)
40  origin_lat = origin_pose.pose.position.y
41  origin_long = origin_pose.pose.position.x
42  rospy.loginfo('Received origin: lat %s, long %s.' % (origin_lat, origin_long))
43  return origin_lat, origin_long
44 
45 def calc_goal(origin_lat, origin_long, goal_lat, goal_long):
46  # Calculate distance and azimuth between GPS points
47  geod = Geodesic.WGS84 # define the WGS84 ellipsoid
48  g = geod.Inverse(origin_lat, origin_long, goal_lat, goal_long) # Compute several geodesic calculations between two GPS points
49  hypotenuse = distance = g['s12'] # access distance
50  rospy.loginfo("The distance from the origin to the goal is {:.3f} m.".format(distance))
51  azimuth = g['azi1']
52  rospy.loginfo("The azimuth from the origin to the goal is {:.3f} degrees.".format(azimuth))
53 
54  # Convert polar (distance and azimuth) to x,y translation in meters (needed for ROS) by finding side lenghs of a right-angle triangle
55  # Convert azimuth to radians
56  azimuth = math.radians(azimuth)
57  x = adjacent = math.cos(azimuth) * hypotenuse
58  y = opposite = math.sin(azimuth) * hypotenuse
59  rospy.loginfo("The translation from the origin to the goal is (x,y) {:.3f}, {:.3f} m.".format(x, y))
60 
61  return x, y
62 
63 class GpsGoal():
64  def __init__(self):
65  rospy.init_node('gps_goal')
66 
67  rospy.loginfo("Connecting to move_base...")
68  self.move_base = actionlib.SimpleActionClient('move_base', MoveBaseAction)
69  self.move_base.wait_for_server()
70  rospy.loginfo("Connected.")
71 
72  rospy.Subscriber('gps_goal_pose', PoseStamped, self.gps_goal_pose_callback)
73  rospy.Subscriber('gps_goal_fix', NavSatFix, self.gps_goal_fix_callback)
74 
75  # Get the lat long coordinates of our map frame's origin which must be publshed on topic /local_xy_origin. We use this to calculate our goal within the map frame.
76  self.origin_lat, self.origin_long = get_origin_lat_long()
77 
78  def do_gps_goal(self, goal_lat, goal_long, z=0, yaw=0, roll=0, pitch=0):
79  # Calculate goal x and y in the frame_id given the frame's origin GPS and a goal GPS location
80  x, y = calc_goal(self.origin_lat, self.origin_long, goal_lat, goal_long)
81  # Create move_base goal
82  self.publish_goal(x=x, y=y, z=z, yaw=yaw, roll=roll, pitch=pitch)
83 
84  def gps_goal_pose_callback(self, data):
85  lat = data.pose.position.y
86  long = data.pose.position.x
87  z = data.pose.position.z
88  euler = tf.transformations.euler_from_quaternion(data.pose.orientation)
89  roll = euler[0]
90  pitch = euler[1]
91  yaw = euler[2]
92  self.do_gps_goal(lat, long, z=z, yaw=yaw, roll=roll, pitch=pitch)
93 
94  def gps_goal_fix_callback(self, data):
95  self.do_gps_goal(data.latitude, data.longitude)
96 
97  def publish_goal(self, x=0, y=0, z=0, yaw=0, roll=0, pitch=0):
98  # Create move_base goal
99  goal = MoveBaseGoal()
100  goal.target_pose.header.frame_id = rospy.get_param('~frame_id','map')
101  goal.target_pose.pose.position.x = x
102  goal.target_pose.pose.position.y = y
103  goal.target_pose.pose.position.z = z
104  quaternion = tf.transformations.quaternion_from_euler(roll, pitch, yaw)
105  goal.target_pose.pose.orientation.x = quaternion[0]
106  goal.target_pose.pose.orientation.y = quaternion[1]
107  goal.target_pose.pose.orientation.z = quaternion[2]
108  goal.target_pose.pose.orientation.w = quaternion[3]
109  rospy.loginfo('Executing move_base goal to position (x,y) %s, %s, with %s degrees yaw.' %
110  (x, y, yaw))
111  rospy.loginfo("To cancel the goal: 'rostopic pub -1 /move_base/cancel actionlib_msgs/GoalID -- {}'")
112 
113  # Send goal
114  self.move_base.send_goal(goal)
115  rospy.loginfo('Inital goal status: %s' % GoalStatus.to_string(self.move_base.get_state()))
116  status = self.move_base.get_goal_status_text()
117  if status:
118  rospy.loginfo(status)
119 
120  # Wait for goal result
121  self.move_base.wait_for_result()
122  rospy.loginfo('Final goal status: %s' % GoalStatus.to_string(self.move_base.get_state()))
123  status = self.move_base.get_goal_status_text()
124  if status:
125  rospy.loginfo(status)
126 
127 @click.command()
128 @click.option('--lat', prompt='Latitude', help='Latitude')
129 @click.option('--long', prompt='Longitude', help='Longitude')
130 @click.option('--roll', '-r', help='Set target roll for goal', default=0.0)
131 @click.option('--pitch', '-p', help='Set target pitch for goal', default=0.0)
132 @click.option('--yaw', '-y', help='Set target yaw for goal', default=0.0)
133 def cli_main(lat, long, roll, pitch, yaw):
134  """Send goal to move_base given latitude and longitude
135 
136  \b
137  Two usage formats:
138  gps_goal.py --lat 43.658 --long -79.379 # decimal format
139  gps_goal.py --lat 43,39,31 --long -79,22,45 # DMS format
140  """
141  gpsGoal = GpsGoal();
142 
143  # Check for degrees, minutes, seconds format and convert to decimal
144  lat, long = DMS_to_decimal_format(lat, long)
145  gpsGoal.do_gps_goal(lat, long, roll=roll, pitch=pitch, yaw=yaw)
146 
147 
148 def ros_main():
149  gpsGoal = GpsGoal();
150  rospy.spin()
151 
152 if __name__ == '__main__':
153  cli_main()
def gps_goal_fix_callback(self, data)
Definition: gps_goal.py:94
def gps_goal_pose_callback(self, data)
Definition: gps_goal.py:84
def cli_main(lat, long, roll, pitch, yaw)
Definition: gps_goal.py:133
def calc_goal(origin_lat, origin_long, goal_lat, goal_long)
Definition: gps_goal.py:45
def get_origin_lat_long()
Definition: gps_goal.py:36
def do_gps_goal(self, goal_lat, goal_long, z=0, yaw=0, roll=0, pitch=0)
Definition: gps_goal.py:78
def DMS_to_decimal_format(lat, long)
Definition: gps_goal.py:14
def publish_goal(self, x=0, y=0, z=0, yaw=0, roll=0, pitch=0)
Definition: gps_goal.py:97


gps_goal
Author(s): Daniel Snider
autogenerated on Mon Jun 10 2019 13:23:40