diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 26098c2e..de936c8a 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -8,15 +8,12 @@ from .. import drone_report # Disable for bootcamp use -# pylint: disable-next=unused-import from .. import drone_status from .. import location from ..private.decision import base_decision # Disable for bootcamp use -# No enable -# pylint: disable=duplicate-code,unused-argument class DecisionSimpleWaypoint(base_decision.BaseDecision): @@ -39,6 +36,10 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # Add your own + self.has_sent_landing_command = False + self.min_bounds = -60 + self.max_bounds = 60 + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ @@ -69,6 +70,32 @@ def run( # ============ # Do something based on the report and the state of this class... + # ensuring drone is within bounds + if ( + self.waypoint.location_x >= self.min_bounds + and self.waypoint.location_x <= self.max_bounds + and self.waypoint.location_y >= self.min_bounds + and self.waypoint.location_y <= self.max_bounds + ): + proximity = (self.waypoint.location_x - report.position.location_x) ** 2 + ( + self.waypoint.location_y - report.position.location_y + ) ** 2 + # when the drone is halted but not at the destination + if ( + report.status == drone_status.DroneStatus.HALTED + and proximity > self.acceptance_radius**2 + ): + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x - report.position.location_x, + self.waypoint.location_y - report.position.location_y, + ) + # when the drone is at the destination and is halted + if ( + report.status == drone_status.DroneStatus.HALTED + and proximity < self.acceptance_radius**2 + ): + command = commands.Command.create_land_command() + self.has_sent_landing_command = True # ============ # ↑ 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..712a55d7 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -8,15 +8,12 @@ from .. import drone_report # Disable for bootcamp use -# pylint: disable-next=unused-import from .. import drone_status from .. import location from ..private.decision import base_decision # Disable for bootcamp use -# No enable -# pylint: disable=duplicate-code,unused-argument class DecisionWaypointLandingPads(base_decision.BaseDecision): @@ -38,11 +35,25 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own + self.has_sent_landing_command = False + self.send_landing_command = False + self.reached_landing_pad = False + self.min_bounds = -60 + self.max_bounds = 60 # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ + def distance_to_pad_squared( + self, report: drone_report.DroneReport, landing_pad: location.Location + ) -> float: + """returns distance squared""" + dist = (report.position.location_x - landing_pad.location_x) ** 2 + ( + report.position.location_y - landing_pad.location_y + ) ** 2 + return dist + def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" ) -> commands.Command: @@ -69,6 +80,59 @@ def run( # ============ # Do something based on the report and the state of this class... + if ( + self.waypoint.location_x >= self.min_bounds + and self.waypoint.location_x <= self.max_bounds + and self.waypoint.location_y >= self.min_bounds + and self.waypoint.location_y <= self.max_bounds + ): + + if report.status == drone_status.DroneStatus.HALTED: + + if self.send_landing_command: + command = commands.Command.create_land_command() + self.has_sent_landing_command = True + return command + + # calculating location of nearest landing pad + smallest_dist_x = float("inf") + smallest_dist_y = float("inf") + smallest_dist = smallest_dist_x**2 + smallest_dist_y**2 + for landing_pad in landing_pad_locations: + new_dist = self.distance_to_pad_squared(report, landing_pad) + if new_dist < smallest_dist: + smallest_dist = new_dist + smallest_dist_x = landing_pad.location_x + smallest_dist_y = landing_pad.location_y + + # if drone is at the waypoint + if ( + (self.waypoint.location_x - report.position.location_x) ** 2 + + (self.waypoint.location_y - report.position.location_y) ** 2 + ) < self.acceptance_radius**2: + + # if nearest landing pad is at the waypoint, land + if smallest_dist < self.acceptance_radius**2: + self.send_landing_command = True + + # if not, set relative destination to nearest landing pad + else: + command = commands.Command.create_set_relative_destination_command( + smallest_dist_x - report.position.location_x, + smallest_dist_y - report.position.location_y, + ) + self.reached_landing_pad = True + + # drone moves to nearest landing pad, then lands + elif self.reached_landing_pad: + self.send_landing_command = True + + # if drone halts unexpectedly, neither at the waypoint or at the nearest landing pad + else: + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x - report.position.location_x, + self.waypoint.location_y - report.position.location_y, + ) # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index f17aa677..fedf2a7b 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -17,9 +17,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 +96,41 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # * conf # * device # * verbose - predictions = ... + predictions = self.__model.predict(image, conf=0.7, device=self.__DEVICE, verbose=False) # Get the Result object - prediction = ... + prediction = predictions[0] # Plot the annotated image from the Result object # Include the confidence value - image_annotated = ... + image_annotated = prediction.plot(conf=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 = [] # Hint: .shape gets the dimensions of the numpy array # for i in range(0, ...): # # Create BoundingBox object and append to list - # result, box = ... + # result, box = ... + # result=0 + + for i in range(0, np.shape(boxes_cpu)[0]): + + (result, box) = bounding_box.BoundingBox.create(boxes_cpu[i]) + + if result: + bounding_boxes.append(box) + else: + return [], image_annotated - 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..60ee7d00 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 = 4 # seconds # OpenCV ignores your display settings, # so if the window is too small or too large, diff --git a/yolov8n.pt b/yolov8n.pt new file mode 100644 index 00000000..0db4ca4b Binary files /dev/null and b/yolov8n.pt differ