From 2b5d6689fc52e7ccb757b37f1bbdcd594c906106 Mon Sep 17 00:00:00 2001 From: Manjot Dola Date: Thu, 19 Sep 2024 11:49:17 -0400 Subject: [PATCH 1/2] Initial Submission --- modules/bootcamp/decision_simple_waypoint.py | 21 +++++++- .../decision_waypoint_landing_pads.py | 48 ++++++++++++++++--- modules/bootcamp/detect_landing_pad.py | 27 ++++++----- .../bootcamp/tests/run_decision_example.py | 2 +- requirements.txt | 2 +- 5 files changed, 78 insertions(+), 22 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 26098c2e..02a82f78 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -37,7 +37,8 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ - # Add your own + # Boolean to check for completion + self.waypoint_reached = False # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ @@ -68,7 +69,23 @@ def run( # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ - # Do something based on the report and the state of this class... + # Check the report to see what the status of the drone is + if report.status == drone_status.DroneStatus.HALTED: + + # First check whether it has gotten to the waypoint + if not self.waypoint_reached: + # Moves towards the waypoint + x_dist = self.waypoint.location_x - report.position.location_x + y_dist = self.waypoint.location_y - report.position.location_y + command = commands.Command.create_set_relative_destination_command(x_dist, y_dist) + + self.waypoint_reached = True + + # Once it has gotten to waypoint, land it + else: + command = commands.Command.create_land_command() + + #raise NotImplementedError # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index ade6f118..e5593069 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -36,9 +36,8 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ - - # Add your own - + self.landpad_reached = False + self.waypoint_reached = False # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ @@ -68,10 +67,45 @@ def run( # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ - # Do something based on the report and the state of this class... + if report.status == drone_status.DroneStatus.HALTED: - # ============ - # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ - # ============ + if not self.waypoint_reached: + # Moves towards the waypoint + x_dist = self.waypoint.location_x - report.position.location_x + y_dist = self.waypoint.location_y - report.position.location_y + command = commands.Command.create_set_relative_destination_command(x_dist, y_dist) + + self.waypoint_reached = True + + # Once you get to the waypoint, you have to go to the nearest landpad + elif not self.landpad_reached: + # Find the closest pad and store it in closest_landpad + # This is using the min() method to iterate through each pad, get the distance to it and compare it with others + closest_pad = min(landing_pad_locations, key=lambda pad: self.get_distance(report.position, pad)) + print(f"Closest Landpad: {closest_pad.location_x}, {closest_pad.location_y}") + + # Move to the closest landpad + x_dist = closest_pad.location_x - report.position.location_x + y_dist = closest_pad.location_y - report.position.location_y + #print(f"{x_dist}, {y_dist}") + command = commands.Command.create_set_relative_destination_command(x_dist, y_dist) + + self.landpad_reached = True + + else: + command = commands.Command.create_land_command() + + #raise NotImplementedError return command + + # Method used to check distance sqaured between two locations + # We don't need the square root since this is for comparison only + def get_distance(self, loc_1: location.Location, loc_2: location.Location): + # Don't need to square root when comparing between squares + hypotenuse_squared = (loc_1.location_x - loc_2.location_x) ** 2 + (loc_1.location_y - loc_2.location_y) ** 2 + return hypotenuse_squared + + # ============ + # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ + # ============ \ No newline at end of file diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index f17aa677..06b7fac0 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -16,10 +16,7 @@ # ============ # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ -# Bootcampers remove the following lines: -# Allow linters and formatters to pass for bootcamp maintainers -# No enable -# pylint: disable=unused-argument,unused-private-member,unused-variable + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ @@ -98,31 +95,39 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # * conf # * device # * verbose - predictions = ... + predictions = self.__model.predict(source=image, conf=0.7, device=self.__DEVICE, verbose=False) # Get the Result object - prediction = ... - + # Only 1 image was used therefore we access the first result in the list + prediction = predictions[0] # Plot the annotated image from the Result object # Include the confidence value - image_annotated = ... + image_annotated = prediction.plot(conf=True, boxes=True) # Get the xyxy boxes list from the Boxes object in the Result object - boxes_xyxy = ... + boxes_xyxy = prediction.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 bounding_boxes = [] + # .shape returns a tuple with the 0th index being the number of lists in the numpy array + for i in range(0, boxes_cpu.shape[0]): + # This func returns a tuple, with whether the operation was a sucess (bool) & the bounding box itself + successful, box = bounding_box.BoundingBox.create(bounds=boxes_cpu[i]) + + if successful: + bounding_boxes.append(box) + # 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 ↑ # ============ diff --git a/modules/bootcamp/tests/run_decision_example.py b/modules/bootcamp/tests/run_decision_example.py index 7bf681ba..d67bec16 100644 --- a/modules/bootcamp/tests/run_decision_example.py +++ b/modules/bootcamp/tests/run_decision_example.py @@ -21,7 +21,7 @@ # to reach the 1st command # Increase the step size if your computer is lagging # Larger step size is smaller FPS -TIME_STEP_SIZE = 0.1 # seconds +TIME_STEP_SIZE = 0.15 # seconds # OpenCV ignores your display settings, # so if the window is too small or too large, diff --git a/requirements.txt b/requirements.txt index fa1ed662..b89d4e75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ pytest # If you are on MacOS, don't have a CUDA capable GPU, # or if things don't work and you just want to use the CPU, # comment out the "--extra-index-url" option ---extra-index-url https://download.pytorch.org/whl/cu124 +# --extra-index-url https://download.pytorch.org/whl/cu124 # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ From ad1990200266d8c5d62437397ec2fd1e46ba4f16 Mon Sep 17 00:00:00 2001 From: Manjot Dola Date: Thu, 19 Sep 2024 17:50:13 -0400 Subject: [PATCH 2/2] Fixed for Linter Errors --- modules/bootcamp/decision_simple_waypoint.py | 4 +-- .../decision_waypoint_landing_pads.py | 27 ++++++++++++------- modules/bootcamp/detect_landing_pad.py | 4 ++- .../bootcamp/tests/run_decision_example.py | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 02a82f78..6776989d 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -69,7 +69,7 @@ def run( # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ # ============ - # Check the report to see what the status of the drone is + # Check the report to see what the status of the drone is if report.status == drone_status.DroneStatus.HALTED: # First check whether it has gotten to the waypoint @@ -85,7 +85,7 @@ def run( else: command = commands.Command.create_land_command() - #raise NotImplementedError + # raise NotImplementedError # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index e5593069..49bac0c3 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -81,31 +81,40 @@ def run( elif not self.landpad_reached: # Find the closest pad and store it in closest_landpad # This is using the min() method to iterate through each pad, get the distance to it and compare it with others - closest_pad = min(landing_pad_locations, key=lambda pad: self.get_distance(report.position, pad)) + closest_pad = min( + landing_pad_locations, key=lambda pad: self.get_distance(report.position, pad) + ) print(f"Closest Landpad: {closest_pad.location_x}, {closest_pad.location_y}") # Move to the closest landpad x_dist = closest_pad.location_x - report.position.location_x y_dist = closest_pad.location_y - report.position.location_y - #print(f"{x_dist}, {y_dist}") + # print(f"{x_dist}, {y_dist}") command = commands.Command.create_set_relative_destination_command(x_dist, y_dist) - + self.landpad_reached = True else: command = commands.Command.create_land_command() - #raise NotImplementedError + # raise NotImplementedError return command - + # Method used to check distance sqaured between two locations # We don't need the square root since this is for comparison only - def get_distance(self, loc_1: location.Location, loc_2: location.Location): + def get_distance(self, loc_1: location.Location, loc_2: location.Location) -> float: + """ + This method is used to get the distance squared between any two locations + + """ + x = loc_1.location_x - loc_2.location_x + y = loc_1.location_y - loc_2.location_y + # Don't need to square root when comparing between squares - hypotenuse_squared = (loc_1.location_x - loc_2.location_x) ** 2 + (loc_1.location_y - loc_2.location_y) ** 2 + hypotenuse_squared = (x**2) + (y**2) return hypotenuse_squared - + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ - # ============ \ No newline at end of file + # ============ diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index 06b7fac0..098b2de6 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -95,7 +95,9 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # * conf # * device # * verbose - predictions = self.__model.predict(source=image, conf=0.7, device=self.__DEVICE, verbose=False) + predictions = self.__model.predict( + source=image, conf=0.7, device=self.__DEVICE, verbose=False + ) # Get the Result object # Only 1 image was used therefore we access the first result in the list diff --git a/modules/bootcamp/tests/run_decision_example.py b/modules/bootcamp/tests/run_decision_example.py index d67bec16..1cab3f7c 100644 --- a/modules/bootcamp/tests/run_decision_example.py +++ b/modules/bootcamp/tests/run_decision_example.py @@ -21,7 +21,7 @@ # to reach the 1st command # Increase the step size if your computer is lagging # Larger step size is smaller FPS -TIME_STEP_SIZE = 0.15 # seconds +TIME_STEP_SIZE = 0.15 # seconds # OpenCV ignores your display settings, # so if the window is too small or too large,