-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alex Liu - Autonomy Bootcamp 2023 #105
Changes from 9 commits
8d7d5d0
fc218e2
878401f
b201dd3
db67208
3215413
ab66aba
44bad08
519532c
9f7df4d
ac09940
1c24b3d
302a4cd
26ebc01
c7f887a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,11 +38,60 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non | |
# ============ | ||
|
||
# Add your own | ||
self.acceptance_radius_squared = self.acceptance_radius**2 # used for distance calculation | ||
|
||
self.goals = [ | ||
commands.Command.create_set_relative_destination_command( | ||
self.waypoint.location_x, self.waypoint.location_y | ||
) | ||
] | ||
|
||
self.landing = False | ||
# ============ | ||
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
# ============ | ||
|
||
@staticmethod | ||
def find_nearest_pad( | ||
reference_location: location.Location, landing_pad_locations: list[location.Location] | ||
) -> location.Location: | ||
""" | ||
Calculates returns nearest landing pad location based on a given reference location | ||
""" | ||
# assuming landing_pad_locations is always populated, but just in-case | ||
closest_location = min( | ||
landing_pad_locations, | ||
key=lambda location: ( | ||
(location.location_x - reference_location.location_x) ** 2 | ||
+ (location.location_y - reference_location.location_y) ** 2 | ||
), | ||
default=location.Location(0, 0), | ||
) | ||
return closest_location | ||
|
||
@staticmethod | ||
def calculate_distance_squared( | ||
location_1: location.Location, location_2: location.Location | ||
) -> float: | ||
""" | ||
Calculate the non-square rooted distance between two locations | ||
""" | ||
return (location_2.location_x - location_1.location_x) ** 2 + ( | ||
location_2.location_y - location_1.location_y | ||
) ** 2 | ||
|
||
@staticmethod | ||
def get_relative_position( | ||
location_1: location.Location, location_2: location.Location | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use more descriptive variable names |
||
) -> tuple[float, float]: | ||
""" | ||
Calculates the relative position of one position to another | ||
""" | ||
return ( | ||
location_2.location_x - location_1.location_x, | ||
location_2.location_y - location_1.location_y, | ||
) | ||
|
||
def run( | ||
self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" | ||
) -> commands.Command: | ||
|
@@ -70,6 +119,31 @@ def run( | |
|
||
# Do something based on the report and the state of this class... | ||
|
||
# only execute when "drone" is ready for another instruction | ||
if report.status == drone_status.DroneStatus.HALTED: | ||
if self.goals: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really see why you have a list of "goals". You can simply check if the drone is within the acceptance radius, land if true, set relative destination if false. |
||
command = self.goals.pop(0) | ||
elif not self.landing: | ||
# try to find a landing pad | ||
self.landing = True | ||
nearest_landing_pad_location = DecisionWaypointLandingPads.find_nearest_pad( | ||
report.position, landing_pad_locations | ||
) | ||
# tuple unwrapping | ||
relative_x, relative_y = DecisionWaypointLandingPads.get_relative_position( | ||
report.position, nearest_landing_pad_location | ||
) | ||
command = commands.Command.create_set_relative_destination_command( | ||
relative_x, relative_y | ||
) | ||
elif ( | ||
DecisionWaypointLandingPads.calculate_distance_squared( | ||
report.position, report.destination | ||
) | ||
<= self.acceptance_radius_squared | ||
): | ||
command = commands.Command.create_land_command() | ||
|
||
# ============ | ||
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
# ============ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,31 +98,48 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd | |
# * conf | ||
# * device | ||
# * verbose | ||
predictions = ... | ||
# BC NOTE: May need to create instantiate model object with create() | ||
predictions = self.__model.predict( | ||
source=image, conf=0.7, device=self.__DEVICE, verbose=False | ||
) | ||
# BC NOTE: See https://docs.ultralytics.com/modes/predict/#working-with-results | ||
|
||
# Get the Result object | ||
prediction = ... | ||
# BOOTCAMPER NOTE: may raise ValueError | ||
prediction = predictions[0] | ||
|
||
# Plot the annotated image from the Result object | ||
# Include the confidence value | ||
image_annotated = ... | ||
image_annotated = prediction.plot() | ||
# BC NOTE: conf & boxes True by default | ||
|
||
# Get the xyxy boxes list from the Boxes object in the Result object | ||
boxes_xyxy = ... | ||
boxes_xyxy = prediction.boxes.xyxy | ||
# BC NOTE: Result.boxes may be None, could cause error trying to access Boxes.xyxy | ||
|
||
# Detach the xyxy boxes to make a copy, | ||
# move the copy into CPU space, | ||
# and convert to a numpy array | ||
boxes_cpu = ... | ||
boxes_cpu = boxes_xyxy.detach().cpu().numpy() | ||
|
||
# Loop over the boxes list and create a list of bounding boxes | ||
# BC NOTE: Need for error checking from returned tuple from BoundingBox.create() | ||
bounding_boxes = [] | ||
for rectangle in boxes_cpu: | ||
# unwrap returned tuple | ||
result, box = bounding_box.BoundingBox.create(rectangle) | ||
if result: | ||
bounding_boxes.append(box) | ||
else: | ||
# return an empty list if any of them fail??? | ||
bounding_boxes.clear() # clear the boxes if any were made before the failed one | ||
break | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This solution works, but consider that if not result:
return [], image_annotated achieves the same result with less code (and slightly more performance since you don't have to clear There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mhm, this one was a bit of a 50/50 choice for me. I was thinking "if the flow goes to the return statement anyways, I'll just make sure the return tuple is correct then return". HOWEVER, I like the idea of better efficiency :P |
||
# Hint: .shape gets the dimensions of the numpy array | ||
# for i in range(0, ...): | ||
# # Create BoundingBox object and append to list | ||
# result, box = ... | ||
|
||
return [], image_annotated | ||
return bounding_boxes, image_annotated | ||
# ============ | ||
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
# ============ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really see why you have a list of "goals". You can simply check if the drone is within the acceptance radius, land if true, set relative destination if false.