Skip to content
This repository was archived by the owner on Sep 21, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions modules/bootcamp/decision_simple_waypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from .. import location
from ..private.decision import base_decision


# Disable for bootcamp use
# No enable
# pylint: disable=duplicate-code,unused-argument
Expand All @@ -37,7 +36,8 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non
# ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓
# ============

# Add your own
self.waypoint_found = False
self.landing_pad_found = False

# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
Expand All @@ -48,7 +48,6 @@ def run(
) -> commands.Command:
"""
Make the drone fly to the waypoint.

You are allowed to create as many helper methods as you want,
as long as you do not change the __init__() and run() signatures.

Expand All @@ -61,14 +60,31 @@ def run(
put_output(command)
```
"""
# Default command
command = commands.Command.create_null_command()

# ============
# ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓
# ============

# Do something based on the report and the state of this class...
status = report.status

current_position = report.position
diff_distance_x = self.waypoint.location_x - current_position.location_x
diff_distance_y = self.waypoint.location_y - current_position.location_y
distance_net_squared = (diff_distance_x**2) + (diff_distance_y**2)

if status == drone_status.DroneStatus.HALTED:
if distance_net_squared <= self.acceptance_radius**2: # squaring the acceptance radius
command = commands.Command.create_land_command()
print("Drone is landing!")

else:
command = commands.Command.create_set_relative_destination_command(
diff_distance_x, diff_distance_y
)
print("Going to waypoint!")

else:
command = commands.Command.create_null_command()

# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
Expand Down
86 changes: 62 additions & 24 deletions modules/bootcamp/decision_waypoint_landing_pads.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
BOOTCAMPERS TO COMPLETE.

Travel to designated waypoint and then land at a nearby landing pad.
Travel to the designated waypoint and then land at a nearby landing pad.
"""

from .. import commands
Expand All @@ -21,7 +21,7 @@

class DecisionWaypointLandingPads(base_decision.BaseDecision):
"""
Travel to the designed waypoint and then land at the nearest landing pad.
Travel to the designated waypoint and then land at the nearest landing pad.
"""

def __init__(self, waypoint: location.Location, acceptance_radius: float) -> None:
Expand All @@ -33,25 +33,25 @@ def __init__(self, waypoint: location.Location, acceptance_radius: float) -> Non

self.acceptance_radius = acceptance_radius

# ============
# ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓
# ============
self.halt_at_initialization = True
self.has_reached_waypoint = False
self.closest_landing_pad = None

# Add your own

# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
# ============
def squared_distance(self, point1: location.Location, point2: location.Location) -> float:
"""
Calculate the squared distance between two locations.
"""
diff_distance_x = point1.location_x - point2.location_x
diff_distance_y = point1.location_y - point2.location_y
distance_net_squared = (diff_distance_x**2) + (diff_distance_y**2)
return distance_net_squared

def run(
self, report: drone_report.DroneReport, landing_pad_locations: "list[location.Location]"
) -> commands.Command:
"""
Make the drone fly to the waypoint and then land at the nearest landing pad.

You are allowed to create as many helper methods as you want,
as long as you do not change the __init__() and run() signatures.

This method will be called in an infinite loop, something like this:

```py
Expand All @@ -61,17 +61,55 @@ def run(
put_output(command)
```
"""
# Default command
command = commands.Command.create_null_command()

# ============
# ↓ BOOTCAMPERS MODIFY BELOW THIS COMMENT ↓
# ============

# Do something based on the report and the state of this class...

# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
# ============

# get current position
current_position = report.position
distance_net_squared = self.squared_distance(self.waypoint, current_position)

if report.status == drone_status.DroneStatus.HALTED:
# check if at the waypoint
if not self.has_reached_waypoint and distance_net_squared <= self.acceptance_radius**2:
command = commands.Command.create_land_command()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to land at the waypoint, just get there and then go towards the landing pad (you land at the landing pad)

print("Drone is landing at the waypoint!")
self.has_reached_waypoint = True

elif not self.has_reached_waypoint:
diff_distance_x = self.waypoint.location_x - current_position.location_x
diff_distance_y = self.waypoint.location_y - current_position.location_y
command = commands.Command.create_set_relative_destination_command(
diff_distance_x, diff_distance_y
)
print("Going to waypoint!")
self.has_reached_waypoint = False

# find the closest landing pad
if self.has_reached_waypoint and not self.closest_landing_pad:
closest_distance_squared = float("inf") # infinity

for landing_pad in landing_pad_locations:
distance_from_waypoint_squared = self.squared_distance(
landing_pad, self.waypoint
)

# update closest_landing_pad
if distance_from_waypoint_squared < closest_distance_squared:
closest_distance_squared = distance_from_waypoint_squared
self.closest_landing_pad = landing_pad

# EGDE CASE: landing pad is on the waypoint
if closest_distance_squared == 0:
command = commands.Command.create_land_command()
print("Drone is landing directly on the waypoint!")
else:
diff_distance_x = (
self.closest_landing_pad.location_x - current_position.location_x
)
diff_distance_y = (
self.closest_landing_pad.location_y - current_position.location_y
)
command = commands.Command.create_set_relative_destination_command(
diff_distance_x, diff_distance_y
)
print("Moving to closest landing pad!")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't seem to be an implementation for actually reaching and landing on the landing pad, this just gets the drone to move towards the closest landing pad

return command
36 changes: 19 additions & 17 deletions modules/bootcamp/detect_landing_pad.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
# 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 ↑
# ============

Expand Down Expand Up @@ -94,35 +93,38 @@ def run(self, image: np.ndarray) -> "tuple[list[bounding_box.BoundingBox], np.nd

# Use the model's predict() method to run inference
# Parameters of interest:
# * source
# * conf
# * device
# * source: image
# * conf: 0.7 as outlined by the bootcamp
# * device:
# * verbose
predictions = ...
predictions = self.__model.predict(image, conf=0.7, device=self.__DEVICE, verbose=False)

# Get the Result object
prediction = ...
# Get the Result object: need to loop through the predictions
prediction = predictions[0]

# Plot the annotated image from the Result object
# Include the confidence value
image_annotated = ...
# Include the confidence value --> defaulted to be true anyways
image_annotated = prediction.plot()

# Get the xyxy boxes list from the Boxes object in the Result object
boxes_xyxy = ...
boxes_xyxy = prediction.boxes.xyxy
# boxes.xyxyn not needed

# 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 = ...

return [], image_annotated
for i in range(0, boxes_cpu.shape[0]):
# Create BoundingBox object and append to list
result, box = bounding_box.BoundingBox.create(boxes_cpu[i])
if result: # this way only valid boxes are added
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally in statistics, we discard the whole datapoint (the entire image) if a part of it goes wrong (one bounding box).
You do not need to change anything here, just something to think about.

bounding_boxes.append(box)

return bounding_boxes, image_annotated
# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
# ============
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ 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

# ============
# ↑ BOOTCAMPERS MODIFY ABOVE THIS COMMENT ↑
Expand Down