Skip to content

Commit e2c9120

Browse files
Pushed Geolocation Updated Software that is formatted as a class for ROS and can handle rotated UAV geolocation
1 parent 9988f59 commit e2c9120

File tree

1 file changed

+130
-133
lines changed

1 file changed

+130
-133
lines changed

src/uavfpy/odcl/location.py

+130-133
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,130 @@
1-
"""
2-
GeoLocation Library
3-
--------------------
4-
5-
Should include stufff like:
6-
- trig calculations
7-
- lidar or any form of depth estimation needec
8-
- any additional calculations to estimate relative distance
9-
10-
Requires:
11-
- pixel -> relative distance REQUIRES -> camera to be calibrated in vsutils.py
12-
- rotating x,y translations to absolute REQUIRES -> heading from UAV
13-
- getting depth REQUIRES -> altitude from UAV
14-
- doing any rotation w/ altitude REQUIRES -> rotation angles of gimbal
15-
16-
"""
17-
import numpy as np
18-
19-
EARTH_RADIUS = 6378137 # meters of radius of earth
20-
21-
22-
def depth_givenAltitude(altitude, pitch=0, roll=0, yaw=0):
23-
"""
24-
Input:
25-
-------
26-
altitude: float (altitude of the UAV)
27-
pitch,roll,yaw: float (radians)
28-
(represents 3 possible axis of rotations of gimbal)
29-
30-
31-
Output:
32-
--------
33-
depth = float (distance from the camera (depth)) in (m) meters.
34-
"""
35-
if pitch == roll == yaw == 0:
36-
return altitude
37-
else:
38-
39-
"""
40-
do math by hand if you want to reduce matrix multiplications to just one matrix.
41-
"""
42-
roll_mtx = np.array(
43-
[
44-
[np.cos(roll), 0, -np.sin(roll)],
45-
[0, 1, 0],
46-
[np.sin(roll), 0, np.cos(roll)],
47-
]
48-
)
49-
pitch_mtx = np.array(
50-
[
51-
[1, 0, 0],
52-
[0, np.cos(pitch), -np.sin(pitch)],
53-
[0, np.sin(pitch), np.cos(pitch)],
54-
]
55-
)
56-
57-
yaw_mtx = np.array(
58-
[[np.cos(yaw), np.sin(yaw), 0], [-np.sin(yaw), np.cos(yaw), 0], [0, 0, 1]]
59-
)
60-
61-
# determine final rotation matrix
62-
rot_mtx = yaw_mtx @ roll_mtx @ pitch_mtx # matrix multiplication
63-
64-
alt_vector = np.array([[0], [0], [altitude]])
65-
rot_vec = np.matmul(rot_mtx, alt_vector)
66-
67-
# get angle between 2 vectors
68-
angle = np.arccos(
69-
np.vdot(alt_vector.T, rot_vec)
70-
/ np.linalg.norm(alt_vector)
71-
/ np.linalg.norm(rot_vec)
72-
)
73-
# assuming ground is flat, we can use right triangle to get depth
74-
return altitude / np.cos(angle)
75-
76-
77-
def get_relDist(pixel_coord, img_shape, focal, depth):
78-
"""
79-
Inputs:
80-
--------
81-
pixel_coord: (x,y) of the pixel
82-
img_shape: (h,w,3) of the shape
83-
focal: (x,y) of respective fo
84-
Outputs:
85-
--------
86-
returns x,y relative to camera
87-
"""
88-
px, py = pixel_coord
89-
h, w, _ = img_shape
90-
focalx, focaly = focal
91-
92-
cx = w / 2
93-
cy = h / 2
94-
x = (px - cx) * depth / focalx
95-
y = (py - cy) * depth / focaly
96-
97-
return x, y
98-
99-
100-
def get_absCoord(tvecs, heading):
101-
"""
102-
Inputs:
103-
--------
104-
tvecs: (x,y) translation
105-
heading: yaw of the UAV
106-
Outputs:
107-
--------
108-
x: newly rotated x vector
109-
y: newly rotated y vector
110-
"""
111-
rad = heading * np.pi / 180
112-
rot = np.array([[np.cos(-rad), -np.sin(-rad)], [np.sin(-rad), np.cos(-rad)]])
113-
x, y = tvecs
114-
115-
return rot @ x, rot @ y
116-
117-
118-
def meters_to_gps(dx, dy):
119-
"""
120-
Input:
121-
dx: distance in x (in meters)
122-
dy: distance in y (in meters)
123-
Output:
124-
latitude: degrees
125-
longitude: degrees
126-
127-
converts distances from meters to gps coordinates.
128-
"""
129-
y = (180 / np.pi) * (dy / EARTH_RADIUS)
130-
x = (180 / np.pi) * (dx / EARTH_RADIUS) / np.cos(np.pi / 180 * dy)
131-
132-
# returns lat, lon
133-
return (y, x)
1+
'''
2+
GeoLocation Library
3+
--------------------
4+
5+
Should include:
6+
- trig calculations
7+
- lidar or any form of depth estimation needec
8+
- any additional calculations to estimate relative distance
9+
10+
Requires:
11+
- pixel -> relative distance REQUIRES -> camera to be calibrated in vsutils.py
12+
- rotating x,y translations to absolute REQUIRES -> heading from UAV
13+
- getting depth REQUIRES -> altitude from UAV
14+
- doing any rotation w/ altitude REQUIRES -> rotation angles of gimbal
15+
16+
'''
17+
import numpy as np
18+
19+
EARTH_RADIUS = 6378137 #meters of radius of earth
20+
21+
22+
class Geolocation:
23+
def __init__(self) -> None:
24+
self.focal_matrix = np.load("matrix.npy") # Created after performing
25+
self.focal = (self.focal_matrix[0, 0], self.focal_matrix[1, 1])
26+
self.img_shape = (3000, 4000, 3)
27+
28+
29+
def get_uavPerspective(self, x,y, altitude, yaw=0, pitch=0, roll=0):
30+
"""
31+
Inputs:
32+
x, y, z = from UAV in meters.
33+
altituded = from UAV in meters.
34+
yaw, pitch, roll = from UAV
35+
Output:
36+
37+
"""
38+
yaw = yaw * np.pi / 180;
39+
pitch = pitch * np.pi / 180;
40+
roll = roll * np.pi / 180;
41+
42+
yaw_Matrix = np.array(
43+
[[np.cos(yaw), -np.sin(yaw), 0],
44+
[np.sin(yaw), np.cos(yaw), 0],
45+
[0, 0 , 1]
46+
],dtype=float);
47+
pitch_Matrix = np.array(
48+
[[np.cos(pitch), 0, np.sin(pitch)],
49+
[0, 1, 0],
50+
[-np.sin(pitch), 0, np.cos(pitch)]
51+
],dtype=float);
52+
roll_Matrix = np.array(
53+
[[1,0,0],
54+
[0,np.cos(roll), -np.sin(roll)],
55+
[0,np.sin(roll), np.cos(roll)]
56+
],dtype=float);
57+
58+
# pitch -> roll -> yaw
59+
target_dist_Matrix = np.array([[x,y,altitude]]).T
60+
rotation_Matrix = pitch_Matrix @ roll_Matrix @ yaw_Matrix
61+
rotated_target_dist = rotation_Matrix @ target_dist_Matrix
62+
z_coord = target_dist_Matrix[2,:]
63+
projected = altitude / (z_coord) * rotated_target_dist # Column vector 1x3
64+
65+
return (projected[0,:], projected[1,:], projected[2,:])
66+
67+
68+
def get_relDist(self, pixel_coord, img_shape, focal, depth):
69+
'''
70+
Inputs:
71+
--------
72+
pixel_coord: (x,y) of the pixel -- center of box relative to drawing on ground
73+
img_shape: (h,w,3) of the shape
74+
focal: (x,y) of respective fo -- calculted with camera calibration
75+
depth: float (distance from the camera (depth)) in (m) meters
76+
Outputs:
77+
--------
78+
returns x,y of bounding box center relative to camera on drone in meters
79+
'''
80+
px, py = pixel_coord
81+
h, w , _ = img_shape
82+
focalx, focaly = focal
83+
84+
cx = w/2
85+
cy = h/2
86+
87+
print("cx", cx, "cy", cy)
88+
89+
x = (px - cx) * depth / focalx
90+
y = (py - cy) * depth / focaly
91+
92+
return x,y
93+
94+
95+
def meters_to_gps(self, dx,dy):
96+
'''
97+
Input:
98+
dx: distance in x (in meters)
99+
dy: distance in y (in meters)
100+
Output:
101+
latitude: degrees
102+
longitude: degrees
103+
104+
converts distances from meters to gps coordinates.
105+
'''
106+
y = (180/np.pi)*(dy/EARTH_RADIUS)
107+
x = (180/np.pi)*(dx/EARTH_RADIUS)/np.cos(np.pi/180 * dy)
108+
109+
#returns lat, lon
110+
return (y, x)
111+
112+
113+
def compute(self, altitude, pitch, roll, yaw, gps_coord, pixel_coord):
114+
"""
115+
Inputs:
116+
altitude and yaw: from Mavros data
117+
gps_coord: (lat, lon)
118+
pixel_coord: (x,y) of the pixel -- center of box relative to drawing on ground
119+
120+
Output:
121+
New GPS coordinate in format (lat, lon) type tuple
122+
"""
123+
124+
comp_dx, comp_dy = self.get_relDist(pixel_coord, self.img_shape, self.focal, altitude)
125+
x, y, z = self.get_uavPerspective(comp_dx,comp_dy, altitude, yaw, pitch, roll)
126+
127+
lat, lon = self.meters_to_gps(x, y)
128+
new_lat = gps_coord[0] + lat
129+
new_lon = gps_coord[1] + lon
130+
return (new_lat, new_lon)

0 commit comments

Comments
 (0)