Skip to content

Commit 17e5663

Browse files
committed
updated
1 parent 6375ae6 commit 17e5663

File tree

1 file changed

+70
-33
lines changed

1 file changed

+70
-33
lines changed

modules/decision/search_pattern.py

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,97 @@
11
from .. import decision_command
2-
from .. import object_in_world
32
from .. import odometry_and_time
4-
from math import tan, pi, cos, sin
5-
6-
"""
7-
8-
"""
3+
from math import tan, pi, cos, sin, ceil
94

105
class SearchPattern:
6+
"""
7+
Implements a search pattern based on camera field of view, search height, and overlap.
8+
9+
Attributes:
10+
camera_fov (float):
11+
Camera's field of view, measured in degrees. Use the smallest measurement available.
12+
Is essentially assumed to be a circle
13+
search_height (float):
14+
The altitude at which the search is conducted. This is used to calculate the pattern.
15+
It does not make the drone go to this height
16+
search_overlap (float):
17+
Overlap between passes, between 0 and 1. Recomended probably 0.5-0.7.
18+
current_position (OdometryAndTime):
19+
The drone's current position.
20+
acceptable_variance_squared (float):
21+
The square of the acceptable distance from the target position.
22+
"""
23+
1124
def __init__(self,
12-
camera_fov: float,#fov should be the smallest measurement (e.g. vertical for landscape) essentially assumes its a cricle with that angle
25+
camera_fov: float,
1326
search_height: float,
1427
search_overlap: float,
15-
current_position: odometry_and_time.OdometryAndTime):#search overlap is float between 0 and 1. Represents how much overlap between passes (1 means fully overlaps (i.e. do not use). Likely value 0.2-0.5)
28+
current_position: odometry_and_time.OdometryAndTime,
29+
acceptable_variance_squared: float):
30+
31+
# Initialize the drone to the first position in the search pattern
1632
self.current_ring = 0
1733
self.current_pos_in_ring = 0
1834
self.max_pos_in_ring = 0
1935
self.search_radius = 0
20-
21-
self.acceptable_variance_squared = 1 #CHANGE THIS VALUE
36+
self.acceptable_variance_squared = acceptable_variance_squared
2237

23-
self.search_start_pos = current_position
24-
self.target_posx = self.search_start_pos.odometry_data.position.north
25-
self.target_posy = self.search_start_pos.odometry_data.position.east
38+
# Store the origin of the search and
39+
self.search_origin = current_position.odometry_data.position
40+
self.target_posx = self.search_origin.north
41+
self.target_posy = self.search_origin.east
2642

27-
self.search_width = 2 * search_height * tan(camera_fov / 2)
43+
# Calculate the gap between positions
44+
self.search_width = 2 * search_height * tan((camera_fov * 180 / pi) / 2)
2845
self.search_gap = self.search_width * (1 - search_overlap)
46+
47+
def set_target_location(self):
48+
"""
49+
Updates the target position to the next position in the search pattern.
50+
"""
2951

30-
31-
def set_next_location(self):
52+
# If it is done the current ring, move to the next ring. If not, next step in current ring
3253
if self.current_pos_in_ring >= self.max_pos_in_ring:
3354
self.current_ring += 1
3455
self.current_pos_in_ring = 0
3556
self.search_radius = self.search_gap * self.current_ring
36-
self.max_pos_in_ring = self.search_radius * 2 * pi / self.search_gap
57+
self.max_pos_in_ring = (ceil(self.search_radius * 2 * pi / self.search_gap))
58+
self.angle_between_positions = ((2 * pi) / (self.max_pos_in_ring + 1))
3759
else:
3860
self.current_pos_in_ring += 1
3961

40-
41-
def find_current_location(self) -> object_in_world.ObjectInWorld:
42-
# Based on curent ring and current pos in ring, set target_posx and target_posy
43-
self.relative_target_posx = self.search_radius * cos(2 * pi * self.current_pos_in_ring / self.max_pos_in_ring)
44-
self.relative_target_posy = self.search_radius * sin(2 * pi * self.current_pos_in_ring / self.max_pos_in_ring)
45-
self.target_posx = self.search_start_pos.odometry_data.position.north + self.relative_target_posx
46-
self.target_posy = self.search_start_pos.odometry_data.position.east + self.relative_target_posy
47-
return
62+
# Angle measured counter-clockwise from x-axis for the target location
63+
self.angle = self.angle_between_positions * self.current_pos_in_ring
64+
65+
# Calculate x and y coordinates of new target location
66+
self.relative_target_posx = self.search_radius * cos(self.angle)
67+
self.relative_target_posy = self.search_radius * sin(self.angle)
68+
69+
self.target_posx = self.search_origin.north + self.relative_target_posx
70+
self.target_posy = self.search_origin.east + self.relative_target_posy
4871

4972
def distance_to_target_squared(self,
50-
current_position: odometry_and_time.OdometryAndTime) -> float:
51-
return (self.target_posx - current_position.odometry_data.position.east) ** 2 + (self.target_posy - current_position.odometry_data.position.north) ** 2
73+
current_position: odometry_and_time.OdometryAndTime
74+
) -> float:
75+
"""
76+
Returns the square of the distance to it's target location
77+
"""
78+
return ((self.target_posx - current_position.odometry_data.position.east) ** 2
79+
+ (self.target_posy - current_position.odometry_data.position.north) ** 2)
5280

53-
def continue_search(self, current_position: odometry_and_time.OdometryAndTime) -> decision_command.DecisionCommand:
54-
#if drone is at target position, set next location, otherwise, move to target location
81+
def continue_search(self,
82+
current_position: odometry_and_time.OdometryAndTime
83+
)-> decision_command.DecisionCommand:
84+
85+
"""
86+
Call this function to have the drone go to the next location in the search pattern
87+
"""
88+
# If it is at it's current target location, update to the next target
5589
if self.distance_to_target_squared(current_position) < self.acceptable_variance_squared:
56-
self.set_next_location()
57-
self.find_current_location()
90+
self.set_target_location()
5891

59-
return decision_command.DecisionCommand.create_move_to_absolute_position_command(self.target_posx, self.target_posy, current_position.odometry_data.position.down)
60-
92+
# Send command to go to target
93+
return decision_command.DecisionCommand.create_move_to_absolute_position_command(
94+
self.target_posx,
95+
self.target_posy,
96+
current_position.odometry_data.position.down)
97+

0 commit comments

Comments
 (0)