-
Notifications
You must be signed in to change notification settings - Fork 266
Himank Bootcamp PR #11
base: main
Are you sure you want to change the base?
Changes from 8 commits
8ec11f3
a7e0a33
3c67cb2
5e64fc5
318294d
43f0dc4
52da233
d8dc641
b521824
6851633
a7d9960
f42441a
20f6395
b6dbf23
adcd012
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 |
|---|---|---|
|
|
@@ -9,3 +9,6 @@ venv/ | |
|
|
||
| # Logging | ||
| *log* | ||
|
|
||
| # pyenv | ||
| .python-version | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,12 +37,43 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float): | |
| # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ | ||
| # ============ | ||
|
|
||
| # Add your own | ||
| self.action_dict = dict(zip(("MOVE", "HALT", "LAND"), range(3,6))) | ||
|
|
||
| # ============ | ||
| # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
| # ============ | ||
|
|
||
| def distance_between_waypoint(self, given_location:location.Location) -> bool: | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Returns the distance between the given location and waypoint. | ||
| """ | ||
| given_loc_from_waypoint_location_x = self.waypoint.location_x - given_location.location_x | ||
| given_loc_from_waypoint_location_y = self.waypoint.location_y - given_location.location_y | ||
| return (given_loc_from_waypoint_location_x, given_loc_from_waypoint_location_y) | ||
|
|
||
| def check_if_near_waypoint(self, given_location:location.Location) -> bool: | ||
| """ | ||
| Checks if the given location is on the waypoint by an acceptance radius. | ||
| """ | ||
| absolute_acceptance_radius = abs(self.acceptance_radius) | ||
| difference_location_x, difference_location_y = self.distance_between_waypoint(given_location) | ||
| if abs(difference_location_x) < absolute_acceptance_radius and abs(difference_location_y) < absolute_acceptance_radius: | ||
| return True | ||
| return False | ||
|
|
||
| def next_relative_coordinates_to_waypoint(self, given_location:location.Location) -> "tuple[float]": | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Returns the relative x and y coordinates for drone to be sent to. | ||
| """ | ||
| relative_x, relative_y = self.distance_between_waypoint(given_location) | ||
| divider = 1 | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if abs(relative_x) > abs(relative_y): | ||
| return (relative_x/divider, relative_y) | ||
| elif abs(relative_x) < abs(relative_y): | ||
| return (relative_x, relative_y/divider) | ||
| else: | ||
| return (relative_x/divider, relative_y/divider) | ||
|
|
||
| def run(self, | ||
| report: drone_report.DroneReport, | ||
| landing_pad_locations: "list[location.Location]") -> commands.Command: | ||
|
|
@@ -68,10 +99,32 @@ def run(self, | |
| # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ | ||
| # ============ | ||
|
|
||
| # Do something based on the report and the state of this class... | ||
| action = None | ||
| report_status = report.status | ||
| report_position = report.position | ||
|
|
||
| if report_status == drone_status.DroneStatus.LANDED: | ||
| action = None | ||
| elif report_status == drone_status.DroneStatus.HALTED: | ||
| if self.check_if_near_waypoint(report_position): | ||
| action = self.action_dict["LAND"] | ||
| else: | ||
| action = self.action_dict["MOVE"] | ||
| """ elif report_status == drone_status.DroneStatus.MOVING: | ||
| action = self.action_dict["HALT"] """ | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if action is None: | ||
| pass | ||
|
Comment on lines
+108
to
+109
Contributor
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. Redundant, remove. |
||
| elif action == self.action_dict["MOVE"]: | ||
| relative_x, relative_y = self.next_relative_coordinates_to_waypoint(report_position) | ||
| command = commands.Command.create_set_relative_destination_command(relative_x, relative_y) | ||
| elif action == self.action_dict["HALT"]: | ||
| command = commands.Command.create_halt_command() | ||
| elif action == self.action_dict["LAND"]: | ||
| command = commands.Command.create_land_command() | ||
|
|
||
| # Remove this when done | ||
| raise NotImplementedError | ||
| # raise NotImplementedError | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # ============ | ||
| # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,12 +37,67 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float): | |
| # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ | ||
| # ============ | ||
|
|
||
| # Add your own | ||
| self.action_dict = dict(zip(("MOVE", "HALT", "LAND"), range(3,6))) | ||
| self.origin = location.Location(0,0) | ||
|
Contributor
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. What if the drone didn't start at (0,0) , but could start anywhere?
Author
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. Then, in that case, wouldn't we need to keep track of the initial position of the drone?
Contributor
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. Yes. Alternatively, don't use the initial position of the drone. |
||
|
|
||
| # ============ | ||
| # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
| # ============ | ||
|
|
||
| def relative_coordinates_of_target(self, target_location:location.Location, given_location:location.Location) -> bool: | ||
| """ | ||
| Returns the relative coordinates of target w.r.t given location. | ||
| """ | ||
| relative_location_x = target_location.location_x - given_location.location_x | ||
| relative_location_y = target_location.location_y - given_location.location_y | ||
| return (relative_location_x, relative_location_y) | ||
|
Contributor
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. Remove unneeded parantheses. |
||
|
|
||
| def check_if_near_target(self, target_location:location.Location, given_location:location.Location) -> bool: | ||
| """ | ||
| Checks if the given location is near the target by an acceptance radius. | ||
| """ | ||
| absolute_acceptance_radius = abs(self.acceptance_radius) | ||
| difference_location_x, difference_location_y = self.relative_coordinates_of_target(target_location, given_location) | ||
| if abs(difference_location_x) < absolute_acceptance_radius and abs(difference_location_y) < absolute_acceptance_radius: | ||
| return True | ||
| return False | ||
|
|
||
| def next_relative_coordinates_to_target(self, | ||
| target_location:location.Location, | ||
| given_location:location.Location) -> "tuple[float]": | ||
| """ | ||
| Returns the relative x and y coordinates for drone to be sent to. | ||
| """ | ||
| relative_x, relative_y = self.relative_coordinates_of_target(target_location, given_location) | ||
| divider = 1 | ||
|
Contributor
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. Remove this since it doesn't do anything. |
||
| if abs(relative_x) > abs(relative_y): | ||
| return (relative_x/divider, relative_y) | ||
| elif abs(relative_x) < abs(relative_y): | ||
| return (relative_x, relative_y/divider) | ||
| else: | ||
| return (relative_x/divider, relative_y/divider) | ||
|
|
||
| def closest_landing_pad(self, | ||
| given_location:location.Location, | ||
| landing_pad_locations: "list[location.Location]") -> location.Location: | ||
| """ | ||
| Finds out the closest landing pad from the given location by checking out their distances. | ||
| """ | ||
| def shortest_distance(target_location:location.Location, given_location:location.Location) -> float: | ||
| """ | ||
| Finds out the shortest distance between two given locations. | ||
| """ | ||
| x_1, y_1 = given_location.location_x, given_location.location_y | ||
| x_2, y_2 = target_location.location_x, target_location.location_y | ||
| x_square = (x_2 - x_1) ** 2 | ||
| y_square = (y_2 - y_1) ** 2 | ||
| return (x_square + y_square) ** 0.5 | ||
|
||
| landing_pad_distances = list(map(lambda loc: shortest_distance(loc, given_location), landing_pad_locations)) | ||
| landing_pad_hashmap = dict(zip(landing_pad_locations, landing_pad_distances)) | ||
| landing_pad_hashmap = tuple(sorted(list(landing_pad_hashmap.items()), key=lambda i: i[1])) | ||
|
||
| return landing_pad_hashmap[0][0] | ||
|
|
||
|
|
||
| def run(self, | ||
| report: drone_report.DroneReport, | ||
| landing_pad_locations: "list[location.Location]") -> commands.Command: | ||
|
|
@@ -68,10 +123,53 @@ def run(self, | |
| # ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓ | ||
| # ============ | ||
|
|
||
| # Do something based on the report and the state of this class... | ||
| def shortest_distance(target_location:location.Location, given_location:location.Location) -> float: | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Finds out the shortest distance between two given locations. | ||
| """ | ||
| x_1, y_1 = given_location.location_x, given_location.location_y | ||
| x_2, y_2 = target_location.location_x, target_location.location_y | ||
| x_square = (x_2 - x_1) ** 2 | ||
| y_square = (y_2 - y_1) ** 2 | ||
| return (x_square + y_square) ** 0.5 | ||
|
|
||
| action = None | ||
| report_status = report.status | ||
| report_position = report.position | ||
| target = self.waypoint | ||
|
|
||
| if report_status in (drone_status.DroneStatus.LANDED, drone_status.DroneStatus.MOVING): | ||
| pass | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| elif report_status == drone_status.DroneStatus.HALTED: | ||
| landing_pad = self.closest_landing_pad(self.waypoint, landing_pad_locations) | ||
| action = self.action_dict["MOVE"] | ||
| if self.check_if_near_target(self.waypoint, report_position): | ||
| target = landing_pad | ||
| if (self.check_if_near_target(landing_pad, report_position) | ||
| and (shortest_distance(self.waypoint, report_position) - shortest_distance(self.waypoint, landing_pad) < 0.1) | ||
| and ( | ||
| (self.check_if_near_target(landing_pad, self.origin) and self.check_if_near_target(self.waypoint, self.origin)) | ||
| or (not self.check_if_near_target(report_position, self.origin)) | ||
| )): | ||
|
Contributor
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 is also a bit complex. What about checking whether the drone has already arrived at the waypoint (e.g. storing some state)?
Author
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 had tried doing that, but since this method runs in an infinite loop, any data that I try to store goes away.
Contributor
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. Declare variables (e.g. Those are instance/object variables and will persist with the lifetime of the object. |
||
| """ | ||
| self.check_if_near_target(landing_pad, self.origin) - if nearest landing pad is origin | ||
| self.check_if_near_target(self.waypoint, self.origin) - if waypoint is origin | ||
| self.check_if_near_target(report_position, self.origin) - if current position is origin | ||
| """ | ||
| action = self.action_dict["LAND"] | ||
|
|
||
| if action is None: | ||
| pass | ||
| elif action == self.action_dict["MOVE"]: | ||
| relative_x, relative_y = self.next_relative_coordinates_to_target(target, report_position) | ||
| command = commands.Command.create_set_relative_destination_command(relative_x, relative_y) | ||
| elif action == self.action_dict["HALT"]: | ||
| command = commands.Command.create_halt_command() | ||
| elif action == self.action_dict["LAND"]: | ||
| command = commands.Command.create_land_command() | ||
|
|
||
| # Remove this when done | ||
| raise NotImplementedError | ||
| # raise NotImplementedError | ||
|
|
||
| # ============ | ||
| # ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,32 +86,38 @@ 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 = ... | ||
| prediction = predictions.__getitem__(0) | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # Plot the annotated image from the Result object | ||
| # Include the confidence value | ||
| image_annotated = ... | ||
| image_annotated = prediction.plot(pil=True, conf=True) | ||
|
Contributor
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. The expected image is a numpy ndarray, not a PIL object.
Author
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. According to the Ultralytics documentation, setting When I tried running pytest with The error message was the following: I do not know whether this is a bug or something else.
Contributor
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. The If you leave |
||
|
|
||
| # 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 = prediction.boxes.cpu().xyxy.numpy() | ||
|
Contributor
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
Author
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. What do you mean by "detach"?
Contributor
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. Pytorch tensors have a |
||
|
|
||
| # 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, ...): | ||
| for i in range(0, boxes_cpu.shape[0]): | ||
| # Create BoundingBox object and append to list | ||
| # result, box = ... | ||
| result, box = bounding_box.BoundingBox.create(boxes_cpu[i]) | ||
| if result: | ||
| bounding_boxes.append(box) | ||
|
Comment on lines
+115
to
+116
Contributor
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. In statistics, it is preferred to remove the whole data point if there is an issue (here, the data point is an image). (You do not need to change anything here, just something to think about).
Author
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. Does that mean removing the entire list of bounding boxes if even one bounding box has an issue?
Contributor
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. Correct, an empty list would be returned instead (the entire image is skipped). But you don't need to change anything. |
||
|
|
||
| # Remove this when done | ||
| raise NotImplementedError | ||
| # raise NotImplementedError | ||
Xierumeng marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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.
Can use
enuminstead.