Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for DJI Air 3 Drone #28

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
9 changes: 7 additions & 2 deletions drone_flightplan/add_elevation_from_dem.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

log = logging.getLogger(__name__)


def raster_data_format_string(input_datatype: str):
"""
Returns a format string for unpacking a c-style Struct object based
Expand Down Expand Up @@ -126,11 +127,15 @@ def add_elevation_from_dem(raster_file, points, outfile):
# It's almost certainly a nodata value, possibly over water
elevation = 0
except Exception as e:
log.error(f"Error reading elevation at point ({geom.GetX()}, {geom.GetY()}): {e}")
log.error(
f"Error reading elevation at point ({geom.GetX()}, {geom.GetY()}): {e}"
)
elevation = 0
else:
# Point is outside the raster bounds, set elevation to 0 or another fallback value
log.info(f"Point ({geom.GetX()}, {geom.GetY()}) is outside the raster bounds.")
log.info(
f"Point ({geom.GetX()}, {geom.GetY()}) is outside the raster bounds."
)
elevation = 0

# Create a new point with elevation
Expand Down
21 changes: 12 additions & 9 deletions drone_flightplan/calculate_parameters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import argparse
from drone_flightplan.drone_type import DroneType

# Configure logging
logging.basicConfig(level=logging.INFO, format="%(message)s")
Expand All @@ -12,6 +13,7 @@ def calculate_parameters(
agl: float,
gsd: float = None,
image_interval: int = 2,
drone_type: DroneType = DroneType.DJI_MINI_4_PRO,
):
"""
Parameters
Expand All @@ -34,11 +36,11 @@ def calculate_parameters(
ground speed = forward spacing / image interval = 10

"""

# Constants ( For DJI Mini 4 Pro)
VERTICAL_FOV = 0.71
HORIZONTAL_FOV = 1.26
GSD_to_AGL_CONST = 29.7
# Get the drone specifications from the Enum
drone_specs = drone_type.value
VERTICAL_FOV = drone_specs["VERTICAL_FOV"]
HORIZONTAL_FOV = drone_specs["HORIZONTAL_FOV"]
GSD_to_AGL_CONST = drone_specs["GSD_to_AGL_CONST"]

if gsd:
agl = gsd * GSD_to_AGL_CONST
Expand All @@ -52,13 +54,13 @@ def calculate_parameters(
side_spacing = side_photo_width - side_overlap_distance
ground_speed = forward_spacing / image_interval

# Cap ground speed at 11.5 m/s to avoid problems with the DJI Mini 4 Pro controller.
# Speeds over 12 m/s cause the controller to change the speed to 2.5 m/s, which is too slow.
# Cap ground speed at 11.5 m/s to avoid problems with the DJI Mini 4 Pro controller.
# Speeds over 12 m/s cause the controller to change the speed to 2.5 m/s, which is too slow.
# Keeping it below 12 m/s ensures the flight plan works correctly.

if ground_speed > 12:
ground_speed = 11.5

return {
"forward_photo_height": round(forward_photo_height, 0),
"side_photo_width": round(side_photo_width, 0),
Expand Down Expand Up @@ -114,6 +116,7 @@ def main():
args.altitude_above_ground_level,
args.gsd,
args.image_interval,
args.drone_type,
)

for key, value in results.items():
Expand Down
23 changes: 20 additions & 3 deletions drone_flightplan/create_flightplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from drone_flightplan.add_elevation_from_dem import add_elevation_from_dem
from drone_flightplan.create_placemarks import create_placemarks
from drone_flightplan.wpml import create_wpml
from drone_flightplan.drone_type import DroneType

# Instantiate logger
log = logging.getLogger(__name__)
Expand All @@ -24,7 +25,9 @@ def create_flightplan(
outfile: str = None,
generate_each_points: bool = False,
rotation_angle: float = 0.0,
take_off_point: list[float] = None,
take_off_point: list[float] = None,
drone_type: DroneType = DroneType.DJI_MINI_4_PRO,

):
"""
Arguments:
Expand All @@ -40,7 +43,12 @@ def create_flightplan(
"""

parameters = calculate_parameters(
forward_overlap, side_overlap, agl, gsd, image_interval
nrjadkry marked this conversation as resolved.
Show resolved Hide resolved
forward_overlap,
side_overlap,
agl,
gsd,
image_interval,
drone_type=drone_type,
)

waypoints = create_waypoint(
Expand All @@ -52,6 +60,7 @@ def create_flightplan(
rotation_angle,
generate_each_points,
take_off_point=take_off_point,
drone_type=drone_type,
)

# Add elevation data to the waypoints
Expand Down Expand Up @@ -109,7 +118,14 @@ def main():
type=float,
help="The ground sampling distance in cm/px.",
)


parser.add_argument(
"--drone_type",
type=lambda dt: DroneType[dt.upper()],
default=DroneType.DJI_MINI_4_PRO,
help="The type of drone to use, e.g., DJI_MINI_4_PRO.",
)

parser.add_argument(
"--forward_overlap",
type=float,
Expand Down Expand Up @@ -166,6 +182,7 @@ def main():
args.generate_each_points,
args.rotation_angle,
args.take_off_point,
args.drone_type,
)


Expand Down
27 changes: 27 additions & 0 deletions drone_flightplan/drone_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from enum import Enum

class DroneType(int, Enum):
DJI_MINI_4_PRO = {
# Constants (For DJI Mini 4 Pro)
"VERTICAL_FOV": 0.71,
"HORIZONTAL_FOV": 1.26,
"GSD_to_AGL_CONST": 29.7,
}

DJI_AIR_3 = {
# Constants (For DJI Air 3)
# Vertical Field of View (FOV):
# Formula: Vertical FOV = 2 * tan^(-1)(sensor height / 2 * focal length)
# The vertical FOV for DJI Air 3 is calculated as: 2 * tan^(-1)(6.3 / (2 * 19.4)) ≈ 0.3224 radians
"VERTICAL_FOV": 0.3224,

# Horizontal Field of View (FOV):
# Formula: Horizontal FOV = 2 * tan^(-1)(sensor width / 2 * focal length)
# The horizontal FOV for DJI Air 3 is calculated as: 2 * tan^(-1)(8.4 / (2 * 19.4)) ≈ 0.4269 radians
"HORIZONTAL_FOV": 0.4269,

# Ground Sampling Distance constant (GSD to AGL constant):
# GSD = (sensor height / focal length) * AGL
# This constant helps in determining the ground resolution per pixel at a given altitude (AGL).
"GSD_to_AGL_CONST": 30.5,
}
2 changes: 1 addition & 1 deletion drone_flightplan/terrain_following_waylines.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,4 +319,4 @@ def waypoints2waylines(injson, threshold):
outgeojson = waypoints2waylines(injson, a.threshold)

with open(a.outfile, "w") as output_file:
json.dump(outgeojson, output_file)
json.dump(outgeojson, output_file)
6 changes: 5 additions & 1 deletion drone_flightplan/waypoints.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import argparse
from math import sqrt
from drone_flightplan.drone_type import DroneType
import pyproj
import geojson
from shapely.geometry import Point, shape, Polygon
Expand Down Expand Up @@ -256,6 +257,7 @@ def create_waypoint(
no_fly_zones: dict = None,
take_off_point: list[float] = None,
mode: str = "waylines",
drone_type= DroneType.DJI_MINI_4_PRO,
) -> str:
"""
Create waypoints or waylines for a given project area based on specified parameters.
Expand Down Expand Up @@ -297,7 +299,9 @@ def create_waypoint(
}

"""
parameters = cp(forward_overlap, side_overlap, agl, gsd)
parameters = cp(
forward_overlap, side_overlap, agl, gsd, drone_type=drone_type
)
side_spacing = parameters["side_spacing"]
forward_spacing = parameters["forward_spacing"]

Expand Down