From 8d7d5d0ea4637a7c861f048a1220007d03920a51 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 12:17:21 -0400 Subject: [PATCH 01/15] Task #1 Possible missing error handling and redundancy --- modules/bootcamp/detect_landing_pad.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index f17aa677..6a17c480 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -98,31 +98,37 @@ 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 - bounding_boxes = [] + # BC NOTE: Need for error checking from returned tuple from BoundingBox.create() + bounding_boxes = [bounding_box.BoundingBox.create(rectangle)[1] for rectangle in boxes_cpu] # 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 ↑ # ============ From fc218e2ac45489f2547a71848752be0312758709 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 12:43:03 -0400 Subject: [PATCH 02/15] Task #2 --- modules/bootcamp/tests/run_decision_example.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/bootcamp/tests/run_decision_example.py b/modules/bootcamp/tests/run_decision_example.py index 7bf681ba..cd3a02c0 100644 --- a/modules/bootcamp/tests/run_decision_example.py +++ b/modules/bootcamp/tests/run_decision_example.py @@ -23,6 +23,8 @@ # Larger step size is smaller FPS TIME_STEP_SIZE = 0.1 # seconds +# Alex was here + # OpenCV ignores your display settings, # so if the window is too small or too large, # change this value (between 0.0 and 1.0) From 878401f898915c8aa4ead58ec6894ecc38a5c02a Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 12:56:58 -0400 Subject: [PATCH 03/15] Task #3 --- modules/bootcamp/decision_simple_waypoint.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 26098c2e..d36c1821 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -38,6 +38,8 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own + self.goal = commands.Command.create_set_relative_destination_command(10, 10) # top right? + self.should_land = False # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ @@ -70,6 +72,12 @@ def run( # Do something based on the report and the state of this class... + if report.status == drone_status.DroneStatus.HALTED: + if not self.should_land: + command = self.goal + self.should_land = True # should land on the next instruction + else: + command = commands.Command.create_land_command() # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ From b201dd32cb5dbde956a5bcbfd3145429497ab181 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 13:47:09 -0400 Subject: [PATCH 04/15] Task #3 tweaks and Task #4 --- modules/bootcamp/decision_simple_waypoint.py | 2 +- .../decision_waypoint_landing_pads.py | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index d36c1821..b3bb355e 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -38,7 +38,7 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own - self.goal = commands.Command.create_set_relative_destination_command(10, 10) # top right? + self.goal = commands.Command.create_set_relative_destination_command(self.waypoint.location_x, self.waypoint.location_y) # top right? self.should_land = False # ============ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index ade6f118..67b6219b 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -38,10 +38,32 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own + self.goal = commands.Command.create_set_relative_destination_command(waypoint.location_x, waypoint.location_y) # top right? + self.finished_goal = False + self.should_land = False + # BC NOTE: From Task #3 + + self.closest_landing_pad = None # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ + + def create_close_pad_goal(self, reference_location : location.Location, landing_pad_locations : list[location.Location]) -> commands.Command: + """ + Calculates and sets self.closest_landing_pad based on a given reference location + """ + # assuming landing_pad_locations is always populated, but just in-case + if not landing_pad_locations: + return commands.Command.create_null_command() + sorted_locations = landing_pad_locations.copy() + sorted_locations.sort( + key=lambda location: ((location.location_x - reference_location.location_x) ** 2 + (location.location_y - reference_location.location_y) ** 2 + )) + closest_pad : location.Location = sorted_locations[0] + rel_x = closest_pad.location_x - reference_location.location_x + rel_y = closest_pad.location_y - reference_location.location_y + return commands.Command.create_set_relative_destination_command(rel_x, rel_y) def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" @@ -70,6 +92,17 @@ 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.should_land: + command = commands.Command.create_land_command() + elif self.finished_goal: + command = self.create_close_pad_goal(report.position, landing_pad_locations) + self.should_land = True # should land on the next instruction + else: + command = self.goal + self.finished_goal = True + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ From db67208172f3a6c6bed89bf7ba4999e3f8ba2df0 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 13:48:10 -0400 Subject: [PATCH 05/15] Linting --- modules/bootcamp/decision_simple_waypoint.py | 6 ++++-- .../decision_waypoint_landing_pads.py | 21 ++++++++++++------- modules/bootcamp/detect_landing_pad.py | 4 +++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index b3bb355e..6068c6b5 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -38,7 +38,9 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own - self.goal = commands.Command.create_set_relative_destination_command(self.waypoint.location_x, self.waypoint.location_y) # top right? + self.goal = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x, self.waypoint.location_y + ) # top right? self.should_land = False # ============ @@ -75,7 +77,7 @@ def run( if report.status == drone_status.DroneStatus.HALTED: if not self.should_land: command = self.goal - self.should_land = True # should land on the next instruction + self.should_land = True # should land on the next instruction else: command = commands.Command.create_land_command() # ============ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 67b6219b..e078abe7 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -38,7 +38,9 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own - self.goal = commands.Command.create_set_relative_destination_command(waypoint.location_x, waypoint.location_y) # top right? + self.goal = commands.Command.create_set_relative_destination_command( + waypoint.location_x, waypoint.location_y + ) # top right? self.finished_goal = False self.should_land = False # BC NOTE: From Task #3 @@ -48,8 +50,10 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ - - def create_close_pad_goal(self, reference_location : location.Location, landing_pad_locations : list[location.Location]) -> commands.Command: + + def create_close_pad_goal( + self, reference_location: location.Location, landing_pad_locations: list[location.Location] + ) -> commands.Command: """ Calculates and sets self.closest_landing_pad based on a given reference location """ @@ -58,9 +62,12 @@ def create_close_pad_goal(self, reference_location : location.Location, landing_ return commands.Command.create_null_command() sorted_locations = landing_pad_locations.copy() sorted_locations.sort( - key=lambda location: ((location.location_x - reference_location.location_x) ** 2 + (location.location_y - reference_location.location_y) ** 2 - )) - closest_pad : location.Location = sorted_locations[0] + key=lambda location: ( + (location.location_x - reference_location.location_x) ** 2 + + (location.location_y - reference_location.location_y) ** 2 + ) + ) + closest_pad: location.Location = sorted_locations[0] rel_x = closest_pad.location_x - reference_location.location_x rel_y = closest_pad.location_y - reference_location.location_y return commands.Command.create_set_relative_destination_command(rel_x, rel_y) @@ -98,7 +105,7 @@ def run( command = commands.Command.create_land_command() elif self.finished_goal: command = self.create_close_pad_goal(report.position, landing_pad_locations) - self.should_land = True # should land on the next instruction + self.should_land = True # should land on the next instruction else: command = self.goal self.finished_goal = True diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index 6a17c480..023978d8 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -99,7 +99,9 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # * device # * verbose # 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) + 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 From 3215413f20d1fc58ad850fded81764c63c9b6a7a Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 19:34:08 -0400 Subject: [PATCH 06/15] Generalized pathing for Task #3 and Task #4 Improved Task 1, 3, and 4 based on feedback --- modules/bootcamp/decision_simple_waypoint.py | 33 ++++++--- .../decision_waypoint_landing_pads.py | 74 +++++++++++-------- modules/bootcamp/detect_landing_pad.py | 8 +- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 6068c6b5..b2d40e0d 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -38,15 +38,22 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own - self.goal = commands.Command.create_set_relative_destination_command( + 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 - ) # top right? - self.should_land = False - + )] # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ + @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 + def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" ) -> commands.Command: @@ -74,12 +81,18 @@ def run( # Do something based on the report and the state of this class... - if report.status == drone_status.DroneStatus.HALTED: - if not self.should_land: - command = self.goal - self.should_land = True # should land on the next instruction - else: - command = commands.Command.create_land_command() + match (report.status): + # this case should mean the drone is ready for the next instruction + case drone_status.DroneStatus.HALTED: + # if list queue is not empty + if self.goals: + command = self.goals.pop(0) + else: + command = commands.Command.create_land_command() + case drone_status.DroneStatus.MOVING: + # if the current position is close enough to the destination. + if DecisionSimpleWaypoint.calculate_distance_squared(report.position, report.destination) <= self.acceptance_radius_squared: + command = commands.Command.create_halt_command() # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index e078abe7..462e9dbf 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -38,39 +38,43 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ # Add your own - self.goal = commands.Command.create_set_relative_destination_command( - waypoint.location_x, waypoint.location_y - ) # top right? - self.finished_goal = False - self.should_land = False - # BC NOTE: From Task #3 + self.acceptance_radius_squared = self.acceptance_radius ** 2 # used for distance calculation - self.closest_landing_pad = None + 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 ↑ # ============ - - def create_close_pad_goal( - self, reference_location: location.Location, landing_pad_locations: list[location.Location] - ) -> commands.Command: + + @staticmethod + def find_nearest_pad( + reference_location: location.Location, landing_pad_locations: list[location.Location] + ) -> location.Location: """ - Calculates and sets self.closest_landing_pad based on a given reference location + Calculates returns nearest landing pad location based on a given reference location """ # assuming landing_pad_locations is always populated, but just in-case - if not landing_pad_locations: - return commands.Command.create_null_command() - sorted_locations = landing_pad_locations.copy() - sorted_locations.sort( + 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) ) - closest_pad: location.Location = sorted_locations[0] - rel_x = closest_pad.location_x - reference_location.location_x - rel_y = closest_pad.location_y - reference_location.location_y - return commands.Command.create_set_relative_destination_command(rel_x, rel_y) + 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) -> tuple[float, float]: + 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]" @@ -100,15 +104,25 @@ 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.should_land: - command = commands.Command.create_land_command() - elif self.finished_goal: - command = self.create_close_pad_goal(report.position, landing_pad_locations) - self.should_land = True # should land on the next instruction - else: - command = self.goal - self.finished_goal = True + match (report.status): + # this case should mean the drone is ready for the next instruction + case drone_status.DroneStatus.HALTED: + # if list queue is not empty + if self.goals: + 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) + else: + command = commands.Command.create_land_command() + case drone_status.DroneStatus.MOVING: + # if the current position is close enough to the destination. + if DecisionWaypointLandingPads.calculate_distance_squared(report.position, report.destination) <= self.acceptance_radius_squared: + command = commands.Command.create_halt_command() # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index 023978d8..b0586b1a 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -124,7 +124,13 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # 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 = [bounding_box.BoundingBox.create(rectangle)[1] for rectangle in boxes_cpu] + bounding_boxes = [] + for rectangle in boxes_cpu: + optional_bounding_box = bounding_box.BoundingBox.create(rectangle) + # why is it that this one returns False while other functions might return None for a failure? + # still unsure why .shape() is required + if optional_bounding_box[0]: + bounding_boxes.append(optional_bounding_box[1]) # Hint: .shape gets the dimensions of the numpy array # for i in range(0, ...): # # Create BoundingBox object and append to list From ab66aba8cb7cc730c24ce631c556b73d992bb443 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 19:34:51 -0400 Subject: [PATCH 07/15] Linting --- modules/bootcamp/decision_simple_waypoint.py | 31 ++++++---- .../decision_waypoint_landing_pads.py | 60 +++++++++++++------ 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index b2d40e0d..4c9471d7 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -38,21 +38,27 @@ 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.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 + ) + ] # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ @staticmethod - def calculate_distance_squared(location_1 : location.Location, location_2 : location.Location) -> float: - ''' + 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 + """ + return (location_2.location_x - location_1.location_x) ** 2 + ( + location_2.location_y - location_1.location_y + ) ** 2 def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" @@ -91,7 +97,12 @@ def run( command = commands.Command.create_land_command() case drone_status.DroneStatus.MOVING: # if the current position is close enough to the destination. - if DecisionSimpleWaypoint.calculate_distance_squared(report.position, report.destination) <= self.acceptance_radius_squared: + if ( + DecisionSimpleWaypoint.calculate_distance_squared( + report.position, report.destination + ) + <= self.acceptance_radius_squared + ): command = commands.Command.create_halt_command() # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 462e9dbf..c55757c1 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -38,17 +38,19 @@ 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.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.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] @@ -57,24 +59,35 @@ def find_nearest_pad( 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, + 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) + ), + default=location.Location(0, 0), ) return closest_location @staticmethod - def calculate_distance_squared(location_1 : location.Location, location_2 : location.Location) -> float: - ''' + 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 - + """ + 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) -> tuple[float, float]: - return (location_2.location_x - location_1.location_x, location_2.location_y - location_1.location_y) + def get_relative_position( + location_1: location.Location, location_2: location.Location + ) -> tuple[float, float]: + 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]" @@ -113,15 +126,26 @@ def run( 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) + 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) + 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 + ) else: command = commands.Command.create_land_command() case drone_status.DroneStatus.MOVING: # if the current position is close enough to the destination. - if DecisionWaypointLandingPads.calculate_distance_squared(report.position, report.destination) <= self.acceptance_radius_squared: + if ( + DecisionWaypointLandingPads.calculate_distance_squared( + report.position, report.destination + ) + <= self.acceptance_radius_squared + ): command = commands.Command.create_halt_command() # ============ From 44bad0814595e2eaed49646c868adb4cc40703f5 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 24 Sep 2024 19:40:06 -0400 Subject: [PATCH 08/15] Add docstring --- modules/bootcamp/decision_waypoint_landing_pads.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index c55757c1..68046f09 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -84,6 +84,9 @@ def calculate_distance_squared( def get_relative_position( location_1: location.Location, location_2: location.Location ) -> 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, From 519532c0610d7ab63cacb7af0a81a67a4bdc5f45 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 Sep 2024 21:41:16 -0400 Subject: [PATCH 09/15] Attempted to fix misunderstood instructions --- modules/bootcamp/decision_simple_waypoint.py | 28 ++++------ .../decision_waypoint_landing_pads.py | 53 ++++++++----------- modules/bootcamp/detect_landing_pad.py | 13 +++-- 3 files changed, 42 insertions(+), 52 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 4c9471d7..97034917 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -87,23 +87,17 @@ def run( # Do something based on the report and the state of this class... - match (report.status): - # this case should mean the drone is ready for the next instruction - case drone_status.DroneStatus.HALTED: - # if list queue is not empty - if self.goals: - command = self.goals.pop(0) - else: - command = commands.Command.create_land_command() - case drone_status.DroneStatus.MOVING: - # if the current position is close enough to the destination. - if ( - DecisionSimpleWaypoint.calculate_distance_squared( - report.position, report.destination - ) - <= self.acceptance_radius_squared - ): - command = commands.Command.create_halt_command() + if report.status == drone_status.DroneStatus.HALTED: + if self.goals: + command = self.goals.pop(0) + elif ( + DecisionSimpleWaypoint.calculate_distance_squared( + report.position, report.destination + ) + <= self.acceptance_radius_squared + ): + command = commands.Command.create_land_command() + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 68046f09..7db900c0 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -120,36 +120,29 @@ def run( # Do something based on the report and the state of this class... # only execute when "drone" is ready for another instruction - match (report.status): - # this case should mean the drone is ready for the next instruction - case drone_status.DroneStatus.HALTED: - # if list queue is not empty - if self.goals: - 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 - ) - else: - command = commands.Command.create_land_command() - case drone_status.DroneStatus.MOVING: - # if the current position is close enough to the destination. - if ( - DecisionWaypointLandingPads.calculate_distance_squared( - report.position, report.destination - ) - <= self.acceptance_radius_squared - ): - command = commands.Command.create_halt_command() + if report.status == drone_status.DroneStatus.HALTED: + if self.goals: + 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 ↑ diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index b0586b1a..b1a9b5a1 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -126,11 +126,14 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd # BC NOTE: Need for error checking from returned tuple from BoundingBox.create() bounding_boxes = [] for rectangle in boxes_cpu: - optional_bounding_box = bounding_box.BoundingBox.create(rectangle) - # why is it that this one returns False while other functions might return None for a failure? - # still unsure why .shape() is required - if optional_bounding_box[0]: - bounding_boxes.append(optional_bounding_box[1]) + # 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 # Hint: .shape gets the dimensions of the numpy array # for i in range(0, ...): # # Create BoundingBox object and append to list From 9f7df4d223564dc6ff28fc78024824415c21d675 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 09:01:31 -0400 Subject: [PATCH 10/15] Apply suggestions Hardcoded the decision tree for task #3 and task #4, this allows for simplicity and readability Switched the clearing of the list to an early return statement --- modules/bootcamp/decision_simple_waypoint.py | 14 ++++---- .../decision_waypoint_landing_pads.py | 33 +++++++++---------- modules/bootcamp/detect_landing_pad.py | 4 +-- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 97034917..f79d8076 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -39,12 +39,7 @@ 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 ↑ # ============ @@ -88,8 +83,11 @@ def run( # Do something based on the report and the state of this class... if report.status == drone_status.DroneStatus.HALTED: - if self.goals: - command = self.goals.pop(0) + if not self.landing: + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x, self.waypoint.location_y + ) + self.landing = True elif ( DecisionSimpleWaypoint.calculate_distance_squared( report.position, report.destination diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 7db900c0..5d9a2ceb 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -39,13 +39,7 @@ 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.finding_landing_pad = False self.landing = False # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ @@ -121,11 +115,20 @@ def run( # only execute when "drone" is ready for another instruction if report.status == drone_status.DroneStatus.HALTED: - if self.goals: - command = self.goals.pop(0) - elif not self.landing: + if not self.finding_landing_pad: + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x, self.waypoint.location_y + ) + self.finding_landing_pad = True + elif self.landing and ( + DecisionWaypointLandingPads.calculate_distance_squared( + report.position, report.destination + ) + <= self.acceptance_radius_squared + ): + command = commands.Command.create_land_command() + else: # try to find a landing pad - self.landing = True nearest_landing_pad_location = DecisionWaypointLandingPads.find_nearest_pad( report.position, landing_pad_locations ) @@ -136,13 +139,7 @@ def run( 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() + self.landing = True # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/detect_landing_pad.py b/modules/bootcamp/detect_landing_pad.py index b1a9b5a1..d86b8949 100644 --- a/modules/bootcamp/detect_landing_pad.py +++ b/modules/bootcamp/detect_landing_pad.py @@ -131,9 +131,7 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd 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 + return [], image_annotated # Hint: .shape gets the dimensions of the numpy array # for i in range(0, ...): # # Create BoundingBox object and append to list From ac0994001dda6ed419b984a15c21798664be81a7 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 09:08:16 -0400 Subject: [PATCH 11/15] Linting --- modules/bootcamp/decision_simple_waypoint.py | 4 ++-- modules/bootcamp/decision_waypoint_landing_pads.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index f79d8076..18f5b4ee 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -85,8 +85,8 @@ def run( if report.status == drone_status.DroneStatus.HALTED: if not self.landing: command = commands.Command.create_set_relative_destination_command( - self.waypoint.location_x, self.waypoint.location_y - ) + self.waypoint.location_x, self.waypoint.location_y + ) self.landing = True elif ( DecisionSimpleWaypoint.calculate_distance_squared( diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 5d9a2ceb..53a7e6fb 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -126,7 +126,7 @@ def run( ) <= self.acceptance_radius_squared ): - command = commands.Command.create_land_command() + command = commands.Command.create_land_command() else: # try to find a landing pad nearest_landing_pad_location = DecisionWaypointLandingPads.find_nearest_pad( From 1c24b3dd1bef5499f47cc8849177f2516c530a6d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 12:21:00 -0400 Subject: [PATCH 12/15] Implemented structure changes --- modules/bootcamp/decision_simple_waypoint.py | 21 +++--- .../decision_waypoint_landing_pads.py | 68 +++++++++++-------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 18f5b4ee..67628b64 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -45,15 +45,11 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ @staticmethod - def calculate_distance_squared( - location_1: location.Location, location_2: location.Location - ) -> float: + def calculate_distance_squared(location_1: location.Location, to_x: float, to_y) -> 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 + return (to_x - location_1.location_x) ** 2 + (to_y - location_1.location_y) ** 2 def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" @@ -83,18 +79,17 @@ def run( # Do something based on the report and the state of this class... if report.status == drone_status.DroneStatus.HALTED: - if not self.landing: - command = commands.Command.create_set_relative_destination_command( - self.waypoint.location_x, self.waypoint.location_y - ) - self.landing = True - elif ( + if ( DecisionSimpleWaypoint.calculate_distance_squared( - report.position, report.destination + report.position, self.waypoint.location_x, self.waypoint.location_y ) <= self.acceptance_radius_squared ): command = commands.Command.create_land_command() + else: + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x, self.waypoint.location_y + ) # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 53a7e6fb..cc662f4e 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -39,8 +39,9 @@ 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.finding_landing_pad = False - self.landing = False + self.finding_waypoint = True + self.nearest_landing_pad_location = location.Location(0, 0) + # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ # ============ @@ -65,14 +66,12 @@ def find_nearest_pad( @staticmethod def calculate_distance_squared( - location_1: location.Location, location_2: location.Location + location_1: location.Location, to_x: float, to_y: float ) -> 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 + return (to_x - location_1.location_x) ** 2 + (to_y - location_1.location_y) ** 2 @staticmethod def get_relative_position( @@ -115,31 +114,40 @@ def run( # only execute when "drone" is ready for another instruction if report.status == drone_status.DroneStatus.HALTED: - if not self.finding_landing_pad: - command = commands.Command.create_set_relative_destination_command( - self.waypoint.location_x, self.waypoint.location_y - ) - self.finding_landing_pad = True - elif self.landing and ( - DecisionWaypointLandingPads.calculate_distance_squared( - report.position, report.destination - ) - <= self.acceptance_radius_squared - ): - command = commands.Command.create_land_command() + if self.finding_waypoint: + if ( + DecisionWaypointLandingPads.calculate_distance_squared( + report.position, self.waypoint.location_x, self.waypoint.location_y + ) + <= self.acceptance_radius_squared + ): + self.finding_waypoint = False + self.nearest_landing_pad_location = ( + DecisionWaypointLandingPads.find_nearest_pad( + report.position, landing_pad_locations + ) + ) + else: + command = commands.Command.create_set_relative_destination_command( + self.waypoint.location_x, self.waypoint.location_y + ) else: - # try to find a landing pad - 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 - ) - self.landing = True + if ( + DecisionWaypointLandingPads.calculate_distance_squared( + report.position, + self.nearest_landing_pad_location.location_x, + self.nearest_landing_pad_location.location_y, + ) + <= self.acceptance_radius_squared + ): + command = commands.Command.create_land_command() + else: + relative_x, relative_y = DecisionWaypointLandingPads.get_relative_position( + report.position, self.nearest_landing_pad_location + ) + command = commands.Command.create_set_relative_destination_command( + relative_x, relative_y + ) # ============ # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ From 302a4cd77a7d841a054b4b50e289f2d8f4d035d1 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 19:05:59 -0400 Subject: [PATCH 13/15] Renamed function parameters to be more descriptive --- modules/bootcamp/decision_simple_waypoint.py | 4 ++-- modules/bootcamp/decision_waypoint_landing_pads.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 67628b64..a1cc1dcb 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -45,11 +45,11 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ @staticmethod - def calculate_distance_squared(location_1: location.Location, to_x: float, to_y) -> float: + def calculate_distance_squared(from_location: location.Location, to_location_x: float, to_location_y) -> float: """ Calculate the non-square rooted distance between two locations """ - return (to_x - location_1.location_x) ** 2 + (to_y - location_1.location_y) ** 2 + return (to_location_x - from_location.location_x) ** 2 + (to_location_y - from_location.location_y) ** 2 def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index cc662f4e..9897e7e0 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -66,23 +66,23 @@ def find_nearest_pad( @staticmethod def calculate_distance_squared( - location_1: location.Location, to_x: float, to_y: float + from_location: location.Location, to_location_x: float, to_location_y: float ) -> float: """ Calculate the non-square rooted distance between two locations """ - return (to_x - location_1.location_x) ** 2 + (to_y - location_1.location_y) ** 2 + return (to_location_x - from_location.location_x) ** 2 + (to_location_y - from_location.location_y) ** 2 @staticmethod def get_relative_position( - location_1: location.Location, location_2: location.Location + from_location: location.Location, to_location: location.Location ) -> 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, + to_location.location_x - from_location.location_x, + to_location.location_y - from_location.location_y, ) def run( From 26ebc018103403b276ae1b04720a5613215b9828 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 19:06:27 -0400 Subject: [PATCH 14/15] Linting --- modules/bootcamp/decision_simple_waypoint.py | 8 ++++++-- modules/bootcamp/decision_waypoint_landing_pads.py | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index a1cc1dcb..336e8e40 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -45,11 +45,15 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non # ============ @staticmethod - def calculate_distance_squared(from_location: location.Location, to_location_x: float, to_location_y) -> float: + def calculate_distance_squared( + from_location: location.Location, to_location_x: float, to_location_y + ) -> float: """ Calculate the non-square rooted distance between two locations """ - return (to_location_x - from_location.location_x) ** 2 + (to_location_y - from_location.location_y) ** 2 + return (to_location_x - from_location.location_x) ** 2 + ( + to_location_y - from_location.location_y + ) ** 2 def run( self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]" diff --git a/modules/bootcamp/decision_waypoint_landing_pads.py b/modules/bootcamp/decision_waypoint_landing_pads.py index 9897e7e0..b063563e 100644 --- a/modules/bootcamp/decision_waypoint_landing_pads.py +++ b/modules/bootcamp/decision_waypoint_landing_pads.py @@ -71,7 +71,9 @@ def calculate_distance_squared( """ Calculate the non-square rooted distance between two locations """ - return (to_location_x - from_location.location_x) ** 2 + (to_location_y - from_location.location_y) ** 2 + return (to_location_x - from_location.location_x) ** 2 + ( + to_location_y - from_location.location_y + ) ** 2 @staticmethod def get_relative_position( From c7f887a2ab2bf57a381e921ee41f6cba5d8530f2 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 27 Sep 2024 20:37:24 -0400 Subject: [PATCH 15/15] Added type hinting --- modules/bootcamp/decision_simple_waypoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/bootcamp/decision_simple_waypoint.py b/modules/bootcamp/decision_simple_waypoint.py index 336e8e40..abbbff03 100644 --- a/modules/bootcamp/decision_simple_waypoint.py +++ b/modules/bootcamp/decision_simple_waypoint.py @@ -46,7 +46,7 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non @staticmethod def calculate_distance_squared( - from_location: location.Location, to_location_x: float, to_location_y + from_location: location.Location, to_location_x: float, to_location_y: float ) -> float: """ Calculate the non-square rooted distance between two locations