Skip to content

Commit

Permalink
[uss_qualifier] Add ability to specify flight intents directly in con…
Browse files Browse the repository at this point in the history
…figuration (interuss#341)

Add ability to specify flight intents directly in configuration
  • Loading branch information
BenjaminPelletier authored Nov 15, 2023
1 parent 272784e commit 9c0e2f1
Show file tree
Hide file tree
Showing 14 changed files with 463 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,29 @@ v1:
conflicting_flights:
resource_type: resources.flight_planning.FlightIntentsResource
specification:
planning_time: '0:05:00'
file:
path: file://./test_data/che/flight_intents/conflicting_flights.yaml

# Details of priority-preemption flights (used in nominal planning priority scenario)
priority_preemption_flights:
resource_type: resources.flight_planning.FlightIntentsResource
specification:
planning_time: '0:05:00'
file:
path: test_data.che.flight_intents.conflicting_flights

# Details of flights with invalid operational intents (used in flight intent validation scenario)
invalid_flight_intents:
resource_type: resources.flight_planning.FlightIntentsResource
specification:
planning_time: '0:05:00'
file:
path: test_data.che.flight_intents.invalid_flight_intents
intent_collection:
$ref: test_data.che.flight_intents.invalid_flight_intents

# Details of non-conflicting flights (used in data validation scenario)
non_conflicting_flights:
resource_type: resources.flight_planning.FlightIntentsResource
specification:
planning_time: '0:05:00'
file:
path: file://./test_data/usa/kentland/flight_intents/non_conflicting.yaml
intent_collection:
$ref: file://../../test_data/usa/kentland/flight_intents/non_conflicting.yaml

# Location of DSS instance that can be used to verify flight planning outcomes
dss:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ che_invalid_flight_auth_flights:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
resource_type: resources.flight_planning.FlightIntentsResource
specification:
file:
path: file://./test_data/che/flight_intents/invalid_flight_auths.yaml
intent_collection:
# Note that $refs are relative to the file with the $ref (this one, in this case)
$ref: file://../../../test_data/che/flight_intents/invalid_flight_auths.yaml

che_conflicting_flights:
# Includes flight intents for both equal-priority-not-permitted and higher-priority
Expand All @@ -132,21 +133,24 @@ che_invalid_flight_intents:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
resource_type: resources.flight_planning.FlightIntentsResource
specification:
file:
path: test_data.che.flight_intents.invalid_flight_intents
intent_collection:
# Note that $refs may use package-based paths
$ref: test_data.che.flight_intents.invalid_flight_intents

che_general_flight_auth_flights:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
resource_type: resources.flight_planning.FlightIntentsResource
specification:
file:
# Note that ExternalFile local file paths are relative to the uss_qualifier folder
path: file://./test_data/che/flight_intents/general_flight_auth_flights.yaml

che_non_conflicting_flights:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
resource_type: resources.flight_planning.FlightIntentsResource
specification:
file:
# Note that ExternalFile paths may be package-based
path: test_data.che.flight_intents.non_conflicting

# ===== General flight authorization =====
Expand Down
16 changes: 13 additions & 3 deletions monitoring/uss_qualifier/fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,19 @@ def _load_dict_with_references_from_file_name(
and not base_file_name.startswith(HTTPS_PREFIX)
and not base_file_name.startswith("/")
):
# This is a relative file path; it should be relative to the context
root_path = os.path.dirname(context_file_name)
base_file_name = os.path.join(root_path, base_file_name)
if (
base_file_name.startswith(".")
or "/" in base_file_name
or "\\" in base_file_name
or base_file_name.lower().endswith(".yaml")
or base_file_name.lower().endswith(".json")
):
# This is a relative file path; it should be relative to the context
root_path = os.path.dirname(context_file_name)
base_file_name = os.path.join(root_path, base_file_name)
else:
# This is a package-based file path
base_file_name = resolve_filename(base_file_name)

base_file_name = os.path.abspath(base_file_name)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,10 @@ def resolve(self) -> Dict[FlightIntentID, FlightInfoTemplate]:


class FlightIntentsSpecification(ImplicitDict):
file: ExternalFile
"""Exactly one field must be specified."""

intent_collection: Optional[FlightIntentCollection]
"""Full flight intent collection, or a $ref to an external file containing a FlightIntentCollection."""

file: Optional[ExternalFile]
"""Location of file to load, containing a FlightIntentCollection"""
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,24 @@ class FlightIntentsResource(Resource[FlightIntentsSpecification]):
_intent_collection: FlightIntentCollection

def __init__(self, specification: FlightIntentsSpecification):
self._intent_collection = ImplicitDict.parse(
load_dict(specification.file), FlightIntentCollection
has_file = "file" in specification and specification.file
has_literal = (
"intent_collection" in specification and specification.intent_collection
)
if has_file and has_literal:
raise ValueError(
"Only one of `file` or `intent_collection` may be specified in FlightIntentsSpecification"
)
if not has_file and not has_literal:
raise ValueError(
"One of `file` or `intent_collection` must be specified in FlightIntentsSpecification"
)
if has_file:
self._intent_collection = ImplicitDict.parse(
load_dict(specification.file), FlightIntentCollection
)
elif has_literal:
self._intent_collection = specification.intent_collection

def get_flight_intents(self) -> Dict[FlightIntentID, FlightInfoTemplate]:
return self._intent_collection.resolve()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/monitorlib/clients/flight_planning/flight_info/ASTMF354821OpIntentInformation.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Information provided about a flight plan that is necessary for ASTM F3548-21.\n\nmonitoring.monitorlib.clients.flight_planning.flight_info.ASTMF354821OpIntentInformation, as defined in monitoring/monitorlib/clients/flight_planning/flight_info.py",
"properties": {
"$ref": {
"description": "Path to content that replaces the $ref",
"type": "string"
},
"priority": {
"type": [
"integer",
"null"
]
}
},
"type": "object"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/monitorlib/clients/flight_planning/flight_info/FlightAuthorisationData.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "The details of a UAS flight authorization request, as received from the user.\n\nNote that a full description of a flight authorisation must include mandatory information required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664 for an UAS flight authorisation request. Reference: https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32021R0664&from=EN#d1e32-178-1\n\nmonitoring.monitorlib.clients.flight_planning.flight_info.FlightAuthorisationData, as defined in monitoring/monitorlib/clients/flight_planning/flight_info.py",
"properties": {
"$ref": {
"description": "Path to content that replaces the $ref",
"type": "string"
},
"connectivity_methods": {
"description": "Connectivity methods. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 7.",
"items": {
"type": "string"
},
"type": "array"
},
"emergency_procedure_url": {
"description": "The URL at which the applicable emergency procedure in case of a loss of command and control link may be retrieved. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 9.",
"type": "string"
},
"endurance_minutes": {
"description": "Endurance of the UAS. This is expressed in minutes. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 8.",
"type": "integer"
},
"identification_technologies": {
"description": "Technology used to identify the UAS. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 6.",
"items": {
"type": "string"
},
"type": "array"
},
"operation_category": {
"description": "Category of UAS operation (\u2018open\u2019, \u2018specific\u2019, \u2018certified\u2019) as defined in COMMISSION DELEGATED REGULATION (EU) 2019/945. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 4.",
"enum": [
"Unknown",
"Open",
"Specific",
"Certified"
],
"type": "string"
},
"operation_mode": {
"enum": [
"Undeclared",
"Vlos",
"Bvlos"
],
"type": "string"
},
"operator_id": {
"description": "Registration number of the UAS operator.\nThe format is defined in EASA Easy Access Rules for Unmanned Aircraft Systems GM1 to AMC1\nArticle 14(6) Registration of UAS operators and \u2018certified\u2019 UAS.\nRequired by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 10.",
"type": "string"
},
"uas_class": {
"enum": [
"Other",
"C0",
"C1",
"C2",
"C3",
"C4",
"C5",
"C6"
],
"type": "string"
},
"uas_id": {
"description": "When applicable, the registration number of the unmanned aircraft.\nThis is expressed using the nationality and registration mark of the unmanned aircraft in\nline with ICAO Annex 7.\nSpecified by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 10.",
"type": [
"string",
"null"
]
},
"uas_serial_number": {
"description": "Unique serial number of the unmanned aircraft or, if the unmanned aircraft is privately built, the unique serial number of the add-on. This is expressed in the ANSI/CTA-2063 Physical Serial Number format. Required by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 1.",
"type": "string"
},
"uas_type_certificate": {
"description": "Provisional field. Not applicable as of September 2021. Required only if `uas_class` is set to `other` by ANNEX IV of COMMISSION IMPLEMENTING REGULATION (EU) 2021/664, paragraph 4.",
"type": [
"string",
"null"
]
}
},
"required": [
"connectivity_methods",
"emergency_procedure_url",
"endurance_minutes",
"identification_technologies",
"operation_category",
"operation_mode",
"operator_id",
"uas_class",
"uas_serial_number"
],
"type": "object"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/monitorlib/clients/flight_planning/flight_info/RPAS26FlightDetails.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Information about a flight necessary to plan successfully using the RPAS Platform Operating Rules version 2.6.\n\nmonitoring.monitorlib.clients.flight_planning.flight_info.RPAS26FlightDetails, as defined in monitoring/monitorlib/clients/flight_planning/flight_info.py",
"properties": {
"$ref": {
"description": "Path to content that replaces the $ref",
"type": "string"
},
"aircraft_type": {
"description": "Type of vehicle being used as per ASTM F3411-22a.",
"enum": [
"NotDeclared",
"Aeroplane",
"Helicopter",
"Gyroplane",
"HybridLift",
"Ornithopter",
"Glider",
"Kite",
"FreeBalloon",
"CaptiveBalloon",
"Airship",
"FreeFallOrParachute",
"Rocket",
"TetheredPoweredAircraft",
"GroundObstacle",
"Other"
],
"type": [
"string",
"null"
]
},
"flight_profile": {
"description": "Type of flight profile.",
"enum": [
"AutomatedGrid",
"AutomatedWaypoint",
"Manual"
],
"type": [
"string",
"null"
]
},
"operator_number": {
"description": "Operator number.",
"type": [
"string",
"null"
]
},
"operator_type": {
"description": "The type of operator.",
"enum": [
"Recreational",
"CommercialExcluded",
"ReOC"
],
"type": [
"string",
"null"
]
},
"pilot_license_number": {
"description": "License number for the pilot.",
"type": [
"string",
"null"
]
},
"pilot_phone_number": {
"description": "Contact phone number for the pilot.",
"type": [
"string",
"null"
]
},
"uas_registration_numbers": {
"description": "The list of UAS/drone registration numbers that will be operated during the operation.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"uas_serial_numbers": {
"description": "The list of UAS/drone serial numbers that will be operated during the operation.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/monitorlib/clients/flight_planning/flight_info_template/BasicFlightPlanInformationTemplate.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Template to provide (at runtime) basic information about a flight plan that an operator and/or UAS can be expected to provide in most flight planning scenarios.\n\nmonitoring.monitorlib.clients.flight_planning.flight_info_template.BasicFlightPlanInformationTemplate, as defined in monitoring/monitorlib/clients/flight_planning/flight_info_template.py",
"properties": {
"$ref": {
"description": "Path to content that replaces the $ref",
"type": "string"
},
"uas_state": {
"description": "State of the user's UAS associated with this flight plan.",
"enum": [
"Nominal",
"OffNominal",
"Contingent"
],
"type": "string"
},
"usage_state": {
"description": "User's current usage of the airspace specified in the flight plan.",
"enum": [
"Planned",
"InUse"
],
"type": "string"
}
},
"required": [
"uas_state",
"usage_state"
],
"type": "object"
}
Loading

0 comments on commit 9c0e2f1

Please sign in to comment.