140 lines
5.1 KiB
Python
140 lines
5.1 KiB
Python
|
|
from enum import StrEnum
|
||
|
|
import numpy as np
|
||
|
|
from shapely.geometry import Point
|
||
|
|
|
||
|
|
from planning.beidou import LocationCode
|
||
|
|
from planning.config import FRONT_DISTANCE
|
||
|
|
|
||
|
|
class PayloadType(StrEnum):
|
||
|
|
optics_down = "optics_down"
|
||
|
|
optics_front = "optics_front"
|
||
|
|
sar = "SAR"
|
||
|
|
laser = "laser"
|
||
|
|
|
||
|
|
class Uav():
|
||
|
|
|
||
|
|
id: int
|
||
|
|
uav_type: str
|
||
|
|
start_coord: Point
|
||
|
|
start_code: str
|
||
|
|
end_coord: Point
|
||
|
|
end_code: str
|
||
|
|
|
||
|
|
# 通用
|
||
|
|
height: float # 飞行高度(m)
|
||
|
|
endurance: float # 续航里程(m)
|
||
|
|
length: float # x 方向幅宽(m)
|
||
|
|
width: float # y 方向幅宽(m)
|
||
|
|
|
||
|
|
# 光学
|
||
|
|
valid_length: float # x 方向有效幅宽(m)
|
||
|
|
valid_width: float # y 方向有效幅宽(m)
|
||
|
|
start_height: float = 0 # 起飞椭球高度(m)
|
||
|
|
end_height: float = 0 # 降落椭球高度(m)
|
||
|
|
|
||
|
|
# SAR
|
||
|
|
theta: float # 下视角(deg)
|
||
|
|
deviation_distance: float # 偏移距离(m)
|
||
|
|
reserved_distance: float # 预留距离(m)
|
||
|
|
direction: int # 推扫方向
|
||
|
|
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
id: int,
|
||
|
|
start_coord: Point,
|
||
|
|
end_coord: Point,
|
||
|
|
payload: dict,
|
||
|
|
constraint: dict
|
||
|
|
):
|
||
|
|
"""
|
||
|
|
初始化无人机类
|
||
|
|
|
||
|
|
Args:
|
||
|
|
id(int): 无人机ID
|
||
|
|
start_coord(NDArray): 无人机起始经纬度坐标(deg)
|
||
|
|
end_coord(NDArray): 无人机结束经纬度坐标(deg)
|
||
|
|
endurance(SupportsFloat): 无人机续航里程(m)
|
||
|
|
"""
|
||
|
|
|
||
|
|
self.id = id
|
||
|
|
self.start_coord = start_coord
|
||
|
|
self.start_code = LocationCode.to_code(
|
||
|
|
lon = start_coord.x,
|
||
|
|
lat = start_coord.y,
|
||
|
|
level = 10)
|
||
|
|
self.end_coord = end_coord
|
||
|
|
self.end_code = LocationCode.to_code(
|
||
|
|
lon = end_coord.x,
|
||
|
|
lat = end_coord.y,
|
||
|
|
level = 10)
|
||
|
|
|
||
|
|
self.endurance = constraint["endurance"]
|
||
|
|
self.height = constraint.get("height")
|
||
|
|
self.resolution = constraint.get("resolution")
|
||
|
|
self.x_overlap = constraint["x_overlap"] if "x_overlap" in constraint else 0
|
||
|
|
self.y_overlap = constraint["y_overlap"] if "y_overlap" in constraint else 0
|
||
|
|
|
||
|
|
if payload["type"] == PayloadType.optics_down:
|
||
|
|
|
||
|
|
sensor_size = payload["sensor_size"] * 0.0254
|
||
|
|
sensor_width = sensor_size * 0.6
|
||
|
|
sensor_length = sensor_size * 0.8
|
||
|
|
focus = payload["equivalent_focus"] / 43.27 * sensor_size
|
||
|
|
|
||
|
|
if self.height is not None:
|
||
|
|
self.resolution = sensor_width / payload["pixel_width"] * self.height / focus
|
||
|
|
# self.y_resolution = payload["sensorh"] / payload["ph"] * self.height / payload["focus"]
|
||
|
|
elif self.resolution is not None:
|
||
|
|
self.height = self.resolution / sensor_width * payload["pixel_width"] * focus
|
||
|
|
else:
|
||
|
|
raise ValueError("The \"height\" and \"resolution\" must have one that is not None.")
|
||
|
|
self.length = self.resolution * payload["pixel_width"]
|
||
|
|
self.width = self.resolution *payload["pixel_height"]
|
||
|
|
|
||
|
|
elif payload["type"] == PayloadType.optics_front:
|
||
|
|
|
||
|
|
if "start_height" in payload:
|
||
|
|
self.start_height = payload["start_height"]
|
||
|
|
if "end_height" in payload:
|
||
|
|
self.end_height = payload["end_height"]
|
||
|
|
|
||
|
|
sensor_size = payload["sensor_size"] * 0.0254
|
||
|
|
sensor_width = sensor_size * 0.6
|
||
|
|
sensor_length = sensor_size * 0.8
|
||
|
|
focus = payload["equivalent_focus"] / 43.27 * sensor_size
|
||
|
|
|
||
|
|
# 相似三角形推算地面实际覆盖
|
||
|
|
self.width = (sensor_width * FRONT_DISTANCE) / focus
|
||
|
|
self.length = (sensor_length * FRONT_DISTANCE) / focus
|
||
|
|
|
||
|
|
elif payload["type"] == PayloadType.sar:
|
||
|
|
if self.height < 0 or self.height > 500:
|
||
|
|
raise ValueError("The height must be more than 0m and less than 500m.")
|
||
|
|
|
||
|
|
self.theta = payload["theta"]
|
||
|
|
if self.theta < 0 or self.theta > 90:
|
||
|
|
raise ValueError("The theta must be more than 0 degree and less than 90 degree.")
|
||
|
|
|
||
|
|
# self.length = payload["length"]
|
||
|
|
self.width = payload["width"]
|
||
|
|
self.reserved_distance = payload["reserved_distance"]
|
||
|
|
self.deviation_distance = self.height * np.tan(np.radians(self.theta))
|
||
|
|
self.direction = payload["direction"]
|
||
|
|
# if payload["direction"] == "left":
|
||
|
|
# self.direction = 1
|
||
|
|
# elif payload["direction"] == "right":
|
||
|
|
# self.direction = -1
|
||
|
|
# else:
|
||
|
|
# raise ValueError("The direction must be left or right.")
|
||
|
|
self.length = self.height / np.cos(np.radians(self.theta)) * 26 / 180 * np.pi / 2
|
||
|
|
|
||
|
|
elif payload["type"] == PayloadType.laser:
|
||
|
|
self.length = 0
|
||
|
|
self.width = 0
|
||
|
|
|
||
|
|
self.valid_length = self.length * (1 - self.x_overlap)
|
||
|
|
self.valid_width = self.width * (1 - self.y_overlap)
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|