From ca8d8e595137194bc5807133083ee5e5d32aea7d Mon Sep 17 00:00:00 2001 From: Trishna Saeharaseelan <trishna.saeharaseelan@noc.ac.uk> Date: Fri, 2 Dec 2022 17:09:06 +0000 Subject: [PATCH] refactor: update fields for all formats --- CONTRIBUTING.md | 2 +- README.md | 59 ++---- __init__.py | 3 + docs/generate_swagger.py | 87 ++++---- examples/autonomy_engine/configuration.jsonc | 71 ------- .../planning_configuration.json | 0 ...sample_autosub.alr-3.v1.mission_script.sbd | Bin 94 -> 0 bytes .../autosub_c2/sample_decoded_ah1_status.json | 199 ------------------ formats/__init__.py | 24 +-- formats/acknowledgement.py | 29 +++ formats/mission_plan.py | 91 ++++++-- formats/observation.py | 16 +- formats/planning_configuration.py | 132 +++++------- .../{vehicle_status.py => platform_status.py} | 95 +++------ project/SOAR_README.md | 31 +++ requirements.txt | 3 +- run-docs.sh | 6 - 17 files changed, 304 insertions(+), 544 deletions(-) delete mode 100644 examples/autonomy_engine/configuration.jsonc create mode 100644 examples/autonomy_engine/planning_configuration.json delete mode 100644 examples/autosub_c2/sample_autosub.alr-3.v1.mission_script.sbd delete mode 100644 examples/autosub_c2/sample_decoded_ah1_status.json rename formats/{vehicle_status.py => platform_status.py} (62%) create mode 100644 project/SOAR_README.md delete mode 100644 run-docs.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a13956e..b3412c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,7 +41,7 @@ To add/edit labels, go to [manage labels](https://git.noc.ac.uk/communications-b | -------- | ---------------------------------------------------------- | ----------------------------------------------------------------------- | | Project | `SoAR` | Associated project | | Partner | `Planet Ocean`, `Hydro-Surv`, `NOC`, `RHU` | Associated partner | -| Asset | `ah1`, `ecosub`, `reav`, `autonomy engine` | Associated vehicle | +| Asset | `ah1`, `ecosub`, `reav`, `autonomy engine` | Associated platform | | Status | `In Sprint Backlog`, `In Progress`, `In Review`, `BLOCKED` | Status of resolving issue | | Weight | `0`, `1`, `2`, `3`, `5`, `8` | Complexity of issue (0 - quick task and 8 - full 2 weeks worth of work) | | - | `bug`, `feature` | Type of issue i.e. new feature, bug | diff --git a/README.md b/README.md index 6ef61cb..567f58b 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,23 @@ # Overview -This project repository is a collaborative workspace. It consists of all messages transferred into and out of the Communications Backbone. Message type schemas will be developed once reviewing each vehicle's data and statuses defined by each partner. +This project repository is a collaborative workspace. It consists of all messages transferred into and out of the Communications Backbone. Message type schemas will be developed once reviewing each platform's data and statuses defined by each partner. # Message Types * Each message below will be treated as the `payload` that are wrapped in a `full_message_format` that includes a `message_header`. -| Type | Summary of File | Serialized/Compiled in Vehicle-Specific Format? | +| Type | Summary of File | Serialized/Compiled in Platform-Specific Format? | | --------------------------| ---------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| `planning_configuration` | Autonomy Engine's Configuration file (if c2 needs to update its respective vehicle directly) | No | -| `mission_plan` | Mission plan generated by Autonomy Engine per vehicle | No | -| `encoded_mission_plan` | Encoded/serialized vehicle-specific mission plan | Yes | -| `encoded_vehicle_status` | Encoded/serialized vehicle-specific vehicle status | Yes | -| `vehicle_status` | Decoded/de-serialized generic vehicle status | No | -| `encoded_observation` | Encoded/serialized observation data from vehicle for Autonomy Engine | Yes | -| `observation` | Decoded/de-serialized observation data from vehicle for Autonomy Engine | No | +| `planning_configuration` | Autonomy Engine's Configuration file (if c2 needs to update its respective platform directly)| No | +| `mission_plan` | Mission plan generated by Autonomy Engine per platform | No | +| `encoded_mission_plan` | Encoded/serialized platform-specific mission plan | Yes | +| `encoded_platform_status`| Encoded/serialized platform-specific platform status | Yes | +| `platform_status` | Decoded/de-serialized generic platform status | No | +| `encoded_observation` | Encoded/serialized observation data from platform for Autonomy Engine | Yes | +| `observation` | Decoded/de-serialized observation data from platform for Autonomy Engine | No | | `acknowledgement` | Decoded/de-serialized acknowledgement message from the Hydrosurv Adapater | No | ------------------------------------ -## Message Data Flow Summary -| Partner | Message Type | Source | Destination | Via Comms Backbone? | Contains Serialized Vehicle-Specific File? | Comment | -| --------------- | ---------------------- | ----------------- | ---------------------- | ------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------- | -| Autonomy Engine | vehicle status | C2’s | Autonomy Engine | Yes | No | | -| Autonomy Engine | Hydrosurv/Ecosub/Ah1 | -| Autonomy Engine | mission plan | Autonomy Engine | C2’s | Yes | No | | -| Autonomy Engine | Hydrosurv/Ecosub/Ah1 | -| Autonomy Engine | autonomy configuration | GUI | ALL | Yes | No | Common file sent to all partners – to store | -| Autonomy Engine | autonomy configuration | C2’s | Autonomy Engine | Yes | No | IF REQUIRED ONLY, UPDATE STORED FILE. | -| Autonomy Engine | Hydrosurv/Ecosub/Ah1 | -| Hydrosurv | vehicle status | Hydrosurv C2 | Autonomy Engine | Yes | No | | -| Hydrosurv | mission plan | Autonomy Engine | Hydrosurv C2 | Yes | No | | -| Hydrosurv | mission plan | Hydrosurv C2 | Reav-60 | No | Yes | | -| Hydrosurv | autonomy configuration | GUI | Hydrosurv C2 (ALL) | Yes | No | Common file sent to all partners – to store | -| Hydrosurv | autonomy configuration | Hydrosurv C2 | GUI | Yes | No | IF REQUIRED ONLY, UPDATE STORED FILE. | -| Hydrosurv | acknowledgment | Hydrosurv C2 | Comms Backbone (Audit) | Yes | No | When hydrosurv adapter has (a) Received, (b) Sent Plan to Reav, and (c) Executed by Reav | -| Planet Ocean | vehicle status | Ecosub | Hydrosurv Adapter | No | Yes | | -| Planet Ocean | vehicle status | Hydrosurv Adapter | Ecosub C2 | Yes | Yes | | -| Planet Ocean | vehicle status | Ecosub C2 | Autonomy Engine | Yes | No | | -| Planet Ocean | mission plan | Autonomy Engine | Ecosub C2 | Yes | No | | -| Planet Ocean | mission plan | Ecosub C2 | Hydrosurv Adapter | Yes | Yes | | -| Planet Ocean | mission plan | Hydrosurv Adapter | Ecosub | No | Yes | Via Hermes + Router | -| Planet Ocean | autonomy configuration | GUI | Ecosub C2 (ALL) | Yes | No | Common file sent to all partners – to store | -| Planet Ocean | autonomy configuration | Hydrosurv C2 | GUI | Yes | No | IF REQUIRED ONLY, UPDATE STORED FILE. | -| Planet Ocean | observation | Ecosub | Hydrosurv Adapter | No | Yes | Via Hermes + Router | -| Planet Ocean | observation | Hydrosurv Adapter | Ecosub C2 | Yes | Yes | | -| Planet Ocean | observation | Ecosub C2 | Autonomy Engine | Yes | No | | -| Planet Ocean | vehicle status | AH1 | Hydrosurv Adapter | No | Yes | Via Hermes + Router | -| NOC | vehicle status | Hydrosurv Adapter | NOC C2 | Yes | Yes | | -| NOC | vehicle status | NOC C2 | Autonomy Engine | Yes | No | | -| NOC | mission plan | Autonomy Engine | NOC C2 | Yes | No | | -| NOC | mission plan | NOC C2 | Hydrosurv Adapter | Yes | Yes | | -| NOC | mission plan | Hydrosurv Adapter | AH1 | No | Yes | Via Hermes + Router | -| NOC | autonomy configuration | GUI | NOC C2 (ALL) | Yes | No | Common file sent to all partners – to store | -| NOC | autonomy configuration | Hydrosurv C2 | GUI | Yes | No | IF REQUIRED ONLY, UPDATE STORED FILE. | \ No newline at end of file + +# Quick Links +1. [Schema Fields Definitions](https://git.noc.ac.uk/communications-backbone-system/backbone-message-format/-/tree/7-message-formats-initial/formats) +2. [JSON Schema Examples](https://git.noc.ac.uk/communications-backbone-system/backbone-message-format/-/tree/7-message-formats-initial/examples) +3. [SoAR README.md](https://git.noc.ac.uk/communications-backbone-system/backbone-message-format/-/tree/7-message-formats-initial/project/SOAR_README.md) \ No newline at end of file diff --git a/__init__.py b/__init__.py index 0f2a43d..61ab515 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,6 @@ +# from flask_marshmallow import Marshmallow from flask_restx import Api + from flask import Flask # import os @@ -8,4 +10,5 @@ __all__ = [ ] app = Flask(__name__) api = Api(app) +# api = Marshmallow(app) diff --git a/docs/generate_swagger.py b/docs/generate_swagger.py index 8e0339f..bbd8765 100644 --- a/docs/generate_swagger.py +++ b/docs/generate_swagger.py @@ -50,7 +50,7 @@ message_header_schema = api.model( "type": fields.String( required=True, description="Type of message", - example="vehicle_status", + example="platform_status", ), "payload": fields.Raw(required=True) # TODO: schema applicable changes according to "type" }, @@ -88,7 +88,7 @@ full_message_schema = api.model( "type": fields.String( required=True, description="Type of message", - example="vehicle_status", + example="platform_status", ), "payload": fields.Raw( required=True, @@ -120,28 +120,28 @@ constraints_schema = api.model( }, ) -vehicle_schema = api.model( - "VehicleSchema", +platform_schema = api.model( + "PlatformSchema", { - "vehicle_ID": fields.Integer( + "platform_ID": fields.Integer( required=True, - description="unique identifier for vehicle", + description="unique identifier for platform", example="ah-1", ), "serial": fields.Integer( required=True, - description="vehicle serial number", + description="platform serial number", example="ah-1", ), "model": fields.Integer( required=True, - description="vehicle serial number", + description="platform serial number", example="ah-1", ), "constraints": fields.Nested(constraints_schema), "active": fields.Boolean( required=False, - description="When a vehicle is in deployment (executing a mission plan) this should be True", + description="When a platform is in deployment (executing a mission plan) this should be True", example=True, ), }, @@ -155,15 +155,15 @@ squad_metadata_schema = api.model( description="Identifier of given squad", example="ah-1", ), - "no_of_vehicles": fields.Integer( + "no_of_platforms": fields.Integer( required=True, - description="number of vehicles", + description="number of platforms", example="ah-1", ), - "vehicles": fields.List( - fields.Nested(vehicle_schema), + "platforms": fields.List( + fields.Nested(platform_schema), required=True, - description="Squad consists of these vehicles", + description="Squad consists of these platforms", ), "squad_mission_type": fields.String( required=True, @@ -183,7 +183,7 @@ gps_schema = api.model( { "gps_source": fields.Float( # TODO: TBD with partners required=False, - description="Source of gps position. E.g. USBL (external), vehicle itself (internal)", + description="Source of gps position. E.g. USBL (external), platform itself (internal)", example="internal", ), "latitude_type": fields.String( @@ -232,7 +232,7 @@ observation_schema = api.model( required=True, description="Message header", ), - "vehicle": fields.Nested(vehicle_schema), + "platform": fields.Nested(platform_schema), "time": fields.String( required=True, description="Timestamp of message", @@ -242,17 +242,17 @@ observation_schema = api.model( # properties of each observation? "points_of_interest": fields.Float( required=False, - description="Points from features of interest identified by vehicle if any found. DEFINE FORMAT.", + description="Points from features of interest identified by platform if any found. DEFINE FORMAT.", example="", ), "region_surveyed": fields.Float( required=False, - description="Region surveyed by given vehicle. DEFINE FORMAT. GEOJSON?", + description="Region surveyed by given platform. DEFINE FORMAT. GEOJSON?", example="", ), "quality_of_points": fields.Float( required=False, - description="Quality/strength of points from features of interest identified by vehicle. DEFINE FORMAT.", + description="Quality/strength of points from features of interest identified by platform. DEFINE FORMAT.", example=0.98, ), "additional_data": fields.Raw( @@ -282,28 +282,28 @@ sensor_schema = api.model( ), } ) -vehicle_status_message_schema = api.model( - "VehicleStatusMessage", +platform_status_message_schema = api.model( + "platformStatusMessage", { "message": fields.Nested( message_header_schema, required=True, description="Message header", ), - "vehicle": fields.Nested(vehicle_schema), - "vehicle_state": fields.String( - # TODO: Define dictionary with potential STATES of each vehicle + "platform": fields.Nested(platform_schema), + "platform_state": fields.String( + # TODO: Define dictionary with potential STATES of each platform required=False, - description="Current state executed by vehicle. E.g. " + description="Current state executed by platform. E.g. " + "STOP, IDLE, ABORT.", example="IDLE", ), "autonomy_mission_ID": fields.Integer( required=False, - description="Last mission plan ID (according to Autonomy Engine's mission plan number) executed by vehicle", + description="Last mission plan ID (according to Autonomy Engine's mission plan number) executed by platform", example=1, ), - "mission_track_number": fields.Integer( + "mission_track_ID": fields.Integer( required=False, description=( "Track number - stage in mission (e.g. " @@ -311,6 +311,11 @@ vehicle_status_message_schema = api.model( ), example=4, ), + "mission_action_ID": fields.Integer( + required=False, + description="to add description", + example=1, + ), "range_to_go": fields.Float( required=False, description="Estimated distance to reach next waypoint", @@ -333,14 +338,14 @@ vehicle_status_message_schema = api.model( ), "health_status": fields.String( required=False, - description="Health status extracted by respective vehicle " + description="Health status extracted by respective platform " + "if any diagnosis available checks on sensors", example="Warning", ), "gps_data": fields.List( - fields.Nested(gps_schema), # TODO: TBD Do we want a list of gps readings to allow > 1 reading i.e. vehicle + usbl + fields.Nested(gps_schema), # TODO: TBD Do we want a list of gps readings to allow > 1 reading i.e. platform + usbl required=True, - description="Metadata pf each vehicle", + description="GPS of each platform", ), "localisation_error": fields.Float( required=False, @@ -353,8 +358,8 @@ vehicle_status_message_schema = api.model( example="", ), "battery_remaining_capacity": fields.Float( - required=False, - description="Battery remaining capacity % provided by respective C2 if any.", + required=True, + description="Battery remaining capacity % provided by respective platform/C2.", example=80.0, ), "sensor_config": fields.Nested(sensor_schema), # TODO: TBD Do we want a list of sensors to allow > 1 sensor @@ -380,7 +385,7 @@ mission_plan_schema = api.model( description="", example="", ), - "vehicle_ID": fields.Integer( + "platform_ID": fields.Integer( required=False, description="Details of each squad", ), @@ -514,16 +519,16 @@ class MessageWrapper(Resource): pass -ns2 = api.namespace("vehicle_status", description="vehicle Status Message Format") +ns2 = api.namespace("platform_status", description="platform Status Message Format") @ns2.route("") -class VehicleStatus(Resource): - @ns2.response(200, "Success", vehicle_status_message_schema) +class platformStatus(Resource): + @ns2.response(200, "Success", platform_status_message_schema) def get(self): pass ns3 = api.namespace( - "autonomy_configuration", description="Autonomy Configuration Format. Do we want region of interest to be per squad, per vehicle or in the main schema?" + "autonomy_configuration", description="Autonomy Configuration Format. Do we want region of interest to be per squad, per platform or in the main schema?" ) @ns3.route("") @@ -533,9 +538,9 @@ class AutonomyConfiguration(Resource): pass -# @api.route('/mission-plan/<str:vehicle_type') -# @api.doc(params={"vehicle_type": "The type of vehicle of the mission plan to target."}) -ns4 = api.namespace("mission_plan", description="Mission Plan Format Per vehicle") +# @api.route('/mission-plan/<str:platform_type') +# @api.doc(params={"platform_type": "The type of platform of the mission plan to target."}) +ns4 = api.namespace("mission_plan", description="Mission Plan Format Per platform") @ns4.route("") class MissionPlan(Resource): @@ -559,7 +564,7 @@ class MissionPlanAutosubHover(Resource): def get(self): pass -ns5 = api.namespace("observation", description="Observation Format --> Per vehicle or generic?") +ns5 = api.namespace("observation", description="Observation Format --> Per platform or generic?") @ns5.route("") class Observation(Resource): @ns5.response(200, "Success", observation_schema) diff --git a/examples/autonomy_engine/configuration.jsonc b/examples/autonomy_engine/configuration.jsonc deleted file mode 100644 index 1840a83..0000000 --- a/examples/autonomy_engine/configuration.jsonc +++ /dev/null @@ -1,71 +0,0 @@ -//**************************************************************** -// File: config.json (THIS FILE WILL BE IN JSON FORMAT, NOT JSONC) -// Description: This file is configured by the respective -// vehicle's C2 if a vehicle is no longer active or change -// a configured value. -// -// Notes: All comments in this document will be stripped out -// during SOAR operations. -// (TODO: RHU to identify values that can and cannot be -// configured). -//---------------------------------------------------------------- -// CHANGELOG -// ------------------- -// 11-11-2022 Trishna S. Added comments, header, and data types -// for each field. -// 10-11-2022 Izzat K. Converted contents to json schema. -// 06-10-2022 Trishna S. New initialisation file. -//**************************************************************** -{ - "mission_config": { - "execute_stage": { - "survey": true, // bool - "detail": false // bool - } - }, - "survey_team": { - "no_of_vehicles": 3, // int - "vehicles": [ - { - "id": 1, // int - "vehicle": "ecosub", // str - "vehicle_serial": "eco101", // str - "active": true // bool - }, - { - "id": 2, - "vehicle": "ecosub", // str - "vehicle_serial": "eco-102", // str - "active": true // bool - }, - { - "id": 3, // int - "vehicle": "ecosub", // str - "vehicle_serial": "ecosub3", // str - "active": true // bool - } - ], - "min_altitude": 0.0, // float - "min_velocity": 0.0, // float - "max_velocity": 0.0 // float - }, - "detail_team": { - "execute_stage": true, // bool - "no_of_vehicles": 1, // int - "vehicles": [ - { - "id": 1, // int - "vehicle": "autosub-hover", // str - "vehicle_serial": "ah1", // str - "active": true // bool - } - ], - "min_altitude": 0.0, // float - "min_velocity": 0.0, // float - "max_velocity": 0.0 // float - }, - "environment": { - "region_of_interest": 0.0, // float - "exclusion_zone": 0.0 // float - } -} \ No newline at end of file diff --git a/examples/autonomy_engine/planning_configuration.json b/examples/autonomy_engine/planning_configuration.json new file mode 100644 index 0000000..e69de29 diff --git a/examples/autosub_c2/sample_autosub.alr-3.v1.mission_script.sbd b/examples/autosub_c2/sample_autosub.alr-3.v1.mission_script.sbd deleted file mode 100644 index 8bb401d29c37cb88a6a069a2fe6d51ab536761e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94 zcmZQ%WS0N3;Jypnbw?&f200A|AUNoLRKuwG_Mcb5M>Q_V-28Kg^$x2fgCv872meQ) lv;z<`GH`|-)o}QH<Il6iqZ%1gul=cIsAb>+LL^1^x&YG`9?<{* diff --git a/examples/autosub_c2/sample_decoded_ah1_status.json b/examples/autosub_c2/sample_decoded_ah1_status.json deleted file mode 100644 index fe6c911..0000000 --- a/examples/autosub_c2/sample_decoded_ah1_status.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "reason": "ready", - "gps_source": "internal", - "gps_lat": 60.16048651129611, - "gps_lon": -1.156730960091541, - "gps_fix_seconds_ago": 1665580800, - "alr_data": { - "format_version": "ocsv3", - "message_type": "H", - "message_source": 3, - "transmit_timestamp": 1665580753.564244, - "content_mask": 18410715202459939000, - "depth": -1.304158329963684, - "water_conductivity": 0, - "water_temperature": 0, - "max_depth": 0, - "altitude": 1000, - "min_altitude": 0, - "vehicle_heading": -58.08430862426758, - "water_speed": -0.000008320044798892923, - "time_since_last_gps": 1665580800, - "time_on_surface": 7814.99365234375, - "w_hours": 28.418603897094727, - "battery_current": 0.4806833267211914, - "battery_max_current": 65.45500183105469, - "battery_voltage": 25.113433837890625, - "battery_min_voltage": 23.034000396728516, - "leak_sensor_output": 9, - "ground_fault_sensor_out": 752, - "propeller_rpm": 0, - "rs485_fault_flags": {}, - "rs232_fault_flags": {}, - "helm_state": { - "8": "idle" - }, - "max_abort_link_state": 358, - "health_events": {}, - "helm_events": { - "14": "waiting" - }, - "log_storage_space": 98649407488, - "sbd_parser_error": {}, - "alr_warning": 0, - "compass_align_value": -1.8788431882858276, - "battery_energy_used": 0, - "dead_nodes": {}, - "position": { - "latitude": 60.16048651129611, - "longitude": -1.156730960091541 - }, - "pth_1": { - "pressure_temp": 2.0399177074432373, - "pressure": 593, - "temp": 17.80158233642578, - "rel_humidity": 7 - }, - "pth_2": { - "pressure_temp": 1.9932914972305298, - "pressure": 574, - "temp": 14.916650772094727, - "rel_humidity": 16 - }, - "rs232_mute_counts": { - "port00": 0, - "port01": 0, - "port02": 0, - "port03": 0, - "port04": 0, - "port05": 0, - "port06": 0, - "port07": 0, - "port08": 0, - "port09": 0, - "port10": 0, - "port11": 0, - "port12": 0, - "port13": 0, - "port14": 0, - "port15": 0 - }, - "rs485_mute_counts": { - "port00": 0, - "port01": 0, - "port02": 0, - "port03": 0, - "port04": 0, - "port05": 0, - "port06": 0, - "port07": 0, - "port08": 0, - "port09": 0, - "port10": 0, - "port11": 0, - "port12": 0, - "port13": 0, - "port14": 0, - "port15": 0 - }, - "helm_state_bitmask": 8388608, - "helm_state_bitstring": "00000000100000000000000000000000", - "helm_events_bitmask": 562949953421312, - "helm_events_bitstring": "0000000000000010000000000000000000000000000000000000000000000000", - "health_events_bitmask": 0, - "health_events_bitstring": "0000000000000000000000000000000000000000000000000000000000000000", - "sbd_parser_error_bitmask": 128, - "sbd_parser_error_bitstring": "10000000", - "dead_nodes_bitmask": 0, - "dead_nodes_bitstring": "0000000000000000000000000000000000000000000000000000000000000000", - "rs232_fault_flags_bitmask": 0, - "rs232_fault_flags_bitstring": "0000000000000000", - "rs485_fault_flags_bitmask": 0, - "rs485_fault_flags_bitstring": "0000000000000000", - "rudder_status": { - "errors": [ - "current_info_not_received" - ], - "error_bitmask": 16, - "error_bitstring": "00010000", - "angle": 0 - }, - "sternplane_status": { - "errors": [ - "current_info_not_received" - ], - "error_bitmask": 16, - "error_bitstring": "00010000", - "angle": 0 - }, - "auv_roll": -0.8640746474266052, - "auv_pitch": 0.2900053858757019, - "biocam_status": { - "biocam_current_mode": 9, - "biocam_cam_0_image_count": 0, - "biocam_cam_1_image_count": 0, - "biocam_cpu_temperature": 273, - "biocam_cam_0_temperature": 273, - "biocam_cam_1_temperature": 273, - "biocam_available_disk_space": 0 - }, - "serial_states": { - "port01": { - "3": "on" - }, - "port02": { - "3": "on" - }, - "port03": { - "0": "off" - }, - "port04": { - "0": "off" - }, - "port05": { - "0": "off" - }, - "port06": { - "0": "off" - }, - "port07": { - "0": "off" - }, - "port08": { - "0": "off" - }, - "port09": { - "0": "off" - }, - "port10": { - "3": "on" - }, - "port11": { - "3": "on" - }, - "port12": { - "0": "off" - }, - "port13": { - "3": "on" - }, - "port14": { - "0": "off" - }, - "port15": { - "0": "off" - }, - "port16": { - "0": "off" - } - }, - "computed": {} - }, - "serial_number": "alr-3", - "time": 1665580753.564244, - "version": "ocsv3", - "_kind": "comms", - "autosub_message_format": { - "git_commit_hash": "ba3e33a9e786772d9642390711cf48b0a08755ea" - } -} \ No newline at end of file diff --git a/formats/__init__.py b/formats/__init__.py index 94160e1..bf46b07 100644 --- a/formats/__init__.py +++ b/formats/__init__.py @@ -9,8 +9,10 @@ __all__ = [ if x.endswith(".py") and x != "__init__.py" ] +# TODO: Define units for all schemas + message_types = [ - "vehicle_status", + "platform_status", "mission_plan_ecosub", "mission_plan_reav", "mission_plan_autosub", @@ -43,14 +45,14 @@ full_message_schema = api.model( "type": fields.String( required=True, description="Type of message", - example="vehicle_status", + example="platform_status", ), "payload": fields.Raw( required=True, description="Content of Message", # example="{}", ), - } + }, ) constraints_schema = api.model( @@ -74,31 +76,29 @@ constraints_schema = api.model( }, ) -vehicle_schema = api.model( - "vehicleSchema", +platform_schema = api.model( + "PlatformSchema", { - "vehicle_ID": fields.Integer( + "platform_ID": fields.Integer( required=True, - description="unique identifier for vehicle", + description="unique identifier for platform", example="ah-1", ), "serial": fields.Integer( required=True, - description="vehicle serial number", + description="platform serial number", example="ah-1", ), "model": fields.Integer( required=True, - description="vehicle serial number", + description="platform serial number", example="ah-1", ), "constraints": fields.Nested(constraints_schema), "active": fields.Boolean( required=False, - description="When a vehicle is in deployment (executing a mission plan) this should be True", + description="When a platform is in deployment (executing a mission plan) this should be True", example=True, ), }, ) -# TODO: Add generic positions schema -# TODO: Define units for all schemas diff --git a/formats/acknowledgement.py b/formats/acknowledgement.py index e69de29..b7f887e 100644 --- a/formats/acknowledgement.py +++ b/formats/acknowledgement.py @@ -0,0 +1,29 @@ +""" + schemas: Acknowledgement status sent by the surface platform to report + receipt of message. +""" +from . import api, full_message_schema +from flask_restx import fields + + +acknowledgement_schema = api.model( + "Acknowledgement", + { + "message": fields.Nested( + full_message_schema, + required=True, + description="Message header", + ), + "message_ID": fields.Integer( + required=True, + description="Identifier of message received and executed with " + + "success for mission plans sent by the Autonomy Engine.", + example=202, + ), + "status": fields.String( + required=True, + description="Highest level of acknowledgement. I.e. `c2_received`: Received by C2," + + " `c2_sent`: Sent from C2->Platform, `executed`: Executed by platform", + ), + }, +) diff --git a/formats/mission_plan.py b/formats/mission_plan.py index e0096ca..91bfa03 100644 --- a/formats/mission_plan.py +++ b/formats/mission_plan.py @@ -1,36 +1,93 @@ """ - schemas: configuration sent to Autonomy Engine (i.e. during an emergency, - if a vehicle needs to be removed from the mission planning) + schemas: Mission plan (un-complied) geenrated by the Autonomy Engine + sent to the respective platform's C2 to compile into a platform-specific + mission plan. """ -from . import api, message_header_schema +from . import api, full_message_schema from flask_restx import fields +action_schema = api.model( + "AutonomyEngineAction", + { + "action": fields.String( + required=True, + description="Autonomy Engine's action from `move`, `payload`," + + " `dive`, `send_hits`, `scanline`, `scanpoint`.", + example="move", + ), + "flight_style": fields.String( + required=False, + description="Platform-specific modes/flight styles to perform next action", + example="orbit", + ), + "latitude_waypoint": fields.Float( + required=True, + description="Next waypoint, x-coordinate", + example=-4.187143188645706, + ), + "longitude_waypoint": fields.Float( + required=True, + description="Next waypoint, y-coordinate", + example=50.37072283932642, + ), + "altitude": fields.Float( + required=False, + description="Altitude of next action", + example=15.0, + ), + "depth": fields.Float( + required=False, + description="Depth of next action", + example=15.0, + ), + "activate_payload": fields.Boolean( + required=False, + description="To activate/deactivate sensor for Autosub " + + "Hover-1 --> `MBES` sensor and for EcoSUB --> `Sidescan`", + example=True, + ), + "send_environmental_data": fields.Boolean( + required=False, + description="To trigger the platform to send list of observations if any found", + example=False, + ), + "scanline": fields.Boolean( + required=False, + description="To trigger the platform to scan-line", + example=False, + ), + "scanpoint": fields.Boolean( + required=False, + description="To trigger the platform to send list of observations if any found", + example=False, + ), + }, +) + mission_plan_schema = api.model( "MissionPlan", { "message": fields.Nested( - message_header_schema, + full_message_schema, required=True, description="Message header", ), - "ID": fields.Integer( + "plan_ID": fields.Integer( required=True, - description="Unique identifier tagged to version of this" - + " configuration plan", - example=3, + description="Identifier of given mission sequence planned", + example=1, ), - "time": fields.String( + "platform_serial": fields.String( required=True, - description="", - example="", + description="Serial of target platform to send mission to", + example="reav-60", ), - "vehicle_ID": fields.Integer( - required=False, - description="Details of each squad", - ), - "payload": fields.Raw( + "plan": fields.List( + fields.Nested(action_schema), required=True, - ) + description="Sequence of actions/instructions generated by the " + + " Autonomy Engine that should be compiled by the respective C2.", + ), }, ) diff --git a/formats/observation.py b/formats/observation.py index b86902f..a759406 100644 --- a/formats/observation.py +++ b/formats/observation.py @@ -1,7 +1,7 @@ """ - schema: vehicle-specific decoded status message (DRAFT) + schema: platform-specific decoded status message (DRAFT) """ -from . import message_header_schema, vehicle_schema, api +from . import message_header_schema, platform_schema, api from flask_restx import fields @@ -13,7 +13,7 @@ observation_schema = api.model( required=True, description="Message header", ), - "vehicle": fields.Nested(vehicle_schema), + "platform": fields.Nested(platform_schema), "time": fields.String( required=True, description="Timestamp of message", @@ -23,17 +23,17 @@ observation_schema = api.model( # properties of each observation? "points_of_interest": fields.Float( required=False, - description="Points from features of interest identified by vehicle if any found. DEFINE FORMAT.", + description="Points from features of interest identified by platform if any found. DEFINE FORMAT.", example="", ), "region_surveyed": fields.Float( required=False, - description="Region surveyed by given vehicle. DEFINE FORMAT. GEOJSON?", + description="Region surveyed by given platform. DEFINE FORMAT. GEOJSON?", example="", ), "quality_of_points": fields.Float( required=False, - description="Quality/strength of points from features of interest identified by vehicle. DEFINE FORMAT.", + description="Quality/strength of points from features of interest identified by platform. DEFINE FORMAT.", example=0.98, ), "additional_data": fields.Raw( @@ -41,5 +41,5 @@ observation_schema = api.model( description="Placeholder field for any additional data", example={"sensor_payload": False}, ), - } -) \ No newline at end of file + }, +) diff --git a/formats/planning_configuration.py b/formats/planning_configuration.py index 248a35f..ff336dc 100644 --- a/formats/planning_configuration.py +++ b/formats/planning_configuration.py @@ -1,28 +1,58 @@ """ schemas: configuration sent to Autonomy Engine (i.e. during an emergency, - if a vehicle needs to be removed from the mission planning) + if a platform needs to be removed from the mission planning) """ -from . import api, message_header_schema, vehicle_schema +from . import api, full_message_schema, platform_schema from flask_restx import fields +region_schema = api.model( + "RegionSchema", + { + "region": fields.Raw( + required=True, + description="Using GEOJSON, exact region of interest in rectangle format polygon", + example={ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-4.187143188645706, 50.37072283932642], + [-4.202697005964865, 50.368816892405874], + [-4.203156724702808, 50.365640144076906], + [-4.19449868846155, 50.362267670845654], + ] + ], + "type": "Polygon", + }, + } + ], + }, + ), + }, +) + squad_metadata_schema = api.model( "SquadMetadataSchema", { "squad_ID": fields.Integer( required=True, description="Identifier of given squad", - example="ah-1", + example=23, ), - "no_of_vehicles": fields.Integer( + "no_of_platforms": fields.Integer( required=True, - description="number of vehicles", - example="ah-1", + description="Number of platforms", + example=3, ), - "vehicles": fields.List( - fields.Nested(vehicle_schema), + "platforms": fields.List( + fields.Nested(platform_schema), required=True, - description="Squad consists of these vehicles", + description="Squad consists of these platforms", ), "squad_mission_type": fields.String( required=True, @@ -34,15 +64,25 @@ squad_metadata_schema = api.model( description="In execution, Waiting.. <define further>", example=False, ), + "region_of_interest": fields.List( + fields.Nested(region_schema), + required=False, + description="Region of interest and exclusion zones per squad.", + ), + "exclusion_zones": fields.List( + fields.Nested(region_schema), + required=True, + description="Exclusion zones exclusion zones per squad.", + ), }, ) -# Main Autonomy Configuration Schema -autonomy_configuration_schema = api.model( - "SquadConfigurationSchema", + +planning_configuration_schema = api.model( + "PlanningConfigurationSchema", { "message": fields.Nested( - message_header_schema, + full_message_schema, required=True, description="Message header", ), @@ -52,76 +92,10 @@ autonomy_configuration_schema = api.model( + " configuration plan", example=3, ), - "time": fields.String( - required=True, - description="", - example="", - ), "squads": fields.Nested( squad_metadata_schema, required=False, description="Details of each squad", ), - "region_of_operation": fields.Raw( - required=True, - description="Using GEOJSON, exact region of interest EXCLUDING exclusion zone", - example={ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - [ - [ - -4.187143188645706, - 50.37072283932642 - ], - [ - -4.202697005964865, - 50.368816892405874 - ], - [ - -4.203156724702808, - 50.365640144076906 - ], - [ - -4.19449868846155, - 50.362267670845654 - ], - [ - -4.187373048015246, - 50.35933489062816 - ], - [ - -4.1859938917992565, - 50.36207215780212 - ], - [ - -4.188598964651192, - 50.36471151593676 - ], - [ - -4.192506573927574, - 50.367350727294706 - ], - [ - -4.188675584440716, - 50.36837704762925 - ], - [ - -4.187143188645706, - 50.37072283932642 - ] - ] - ], - "type": "Polygon" - # "projection": coordinate system used - } - } - ] - } - ), }, ) diff --git a/formats/vehicle_status.py b/formats/platform_status.py similarity index 62% rename from formats/vehicle_status.py rename to formats/platform_status.py index 9eb7039..e11af4f 100644 --- a/formats/vehicle_status.py +++ b/formats/platform_status.py @@ -1,17 +1,15 @@ """ - schema: vehicle-specific decoded status message (DRAFT) + schema: platform-specific decoded status message (DRAFT) """ -from . import message_header_schema, vehicle_schema, api +from . import full_message_schema, platform_schema, api from flask_restx import fields -# TODO: Discuss nomenclature > vehicle or vehicle? - gps_schema = api.model( "GPS", { "gps_source": fields.Float( # TODO: TBD with partners required=False, - description="Source of gps position. E.g. USBL (external), vehicle itself (internal)", + description="Source of gps position. E.g. USBL (external), platform itself (internal)", example="internal", ), "latitude_type": fields.String( @@ -44,50 +42,10 @@ gps_schema = api.model( description="Altitude in <DEFINE UNITS>", example="", ), - # "gps_fix_seconds_ago": fields.Float( - # required=False, - # description="", - # example="", - # ), + # "gps_fix_seconds_ago" }, ) -# battery_schema = api.model( -# "Battery", -# { -# "voltage_v": fields.Float( -# required=True, -# description="Volts", -# example=23.0, -# ), -# "current_amps": fields.Float( -# required=False, -# description="Amps", -# example=1.2, -# ), -# "current_usage_amphours": fields.Float( -# required=False, -# description="Amp-Hours", -# example=1.2, -# ), -# "wattage_w": fields.Float( -# required=False, -# description="Watts", -# example=23.0, -# ), -# "wattage_usage_watthours": fields.Float( -# required=False, -# description="Watt-Hours", -# example=23.0, -# ), -# "remaining_capacity": fields.Float( -# required=False, -# description="Battery remaining capacity % provided by respective C2 if any.", -# example=80.0, -# ), -# } -# ) - sensor_schema = api.model( "Sensor", { @@ -106,30 +64,30 @@ sensor_schema = api.model( description="Add any additional sensor-related data here.", example={"sensor_loadtime_seconds": 30.0}, ), - } + }, ) -vehicle_status_message_schema = api.model( - "vehicleStatusMessage", +platform_status_message_schema = api.model( + "platformStatusMessage", { "message": fields.Nested( - message_header_schema, + full_message_schema, required=True, description="Message header", ), - "vehicle": fields.Nested(vehicle_schema), - "vehicle_state": fields.String( - # TODO: Define dictionary with potential STATES of each vehicle + "platform": fields.Nested(platform_schema), + "platform_state": fields.String( + # TODO: Define dictionary with potential STATES of each platform required=False, - description="Current state executed by vehicle. E.g. " + description="Current state executed by platform. E.g. " + "STOP, IDLE, ABORT.", example="IDLE", ), - "autonomy_mission_ID": fields.Integer( + "autonomy_plan_ID": fields.Integer( required=False, - description="Last mission plan ID (according to Autonomy Engine's mission plan number) executed by vehicle", + description="Last mission plan ID (according to Autonomy Engine's mission plan number) executed by platform", example=1, ), - "mission_track_number": fields.Integer( + "mission_track_ID": fields.Integer( required=False, description=( "Track number - stage in mission (e.g. " @@ -137,6 +95,11 @@ vehicle_status_message_schema = api.model( ), example=4, ), + "mission_action_ID": fields.Integer( + required=False, + description="to add description", + example=1, + ), "range_to_go": fields.Float( required=False, description="Estimated distance to reach next waypoint", @@ -159,14 +122,16 @@ vehicle_status_message_schema = api.model( ), "health_status": fields.String( required=False, - description="Health status extracted by respective vehicle " + description="Health status extracted by respective platform " + "if any diagnosis available checks on sensors", example="Warning", ), "gps_data": fields.List( - fields.Nested(gps_schema), # TODO: TBD Do we want a list of gps readings to allow > 1 reading i.e. vehicle + usbl + fields.Nested( + gps_schema + ), # TODO: TBD Do we want a list of gps readings to allow > 1 reading i.e. platform + usbl required=True, - description="Metadata pf each vehicle", + description="Metadata pf each platform", ), "localisation_error": fields.Float( required=False, @@ -179,12 +144,14 @@ vehicle_status_message_schema = api.model( example="", ), "battery_remaining_capacity": fields.Float( - required=False, - description="Battery remaining capacity % provided by respective C2 if any.", + required=True, + description="Battery remaining capacity % provided by respective platform/C2.", example=80.0, ), - "sensor_config": fields.Nested(sensor_schema), # TODO: TBD Do we want a list of sensors to allow > 1 sensor + "sensor_config": fields.Nested( + sensor_schema + ), # TODO: TBD Do we want a list of sensors to allow > 1 sensor }, ) -# TBD: Do we append beacon positions with vehicle positions? +# TBD: Do we append beacon positions with platform positions? diff --git a/project/SOAR_README.md b/project/SOAR_README.md new file mode 100644 index 0000000..a8c623f --- /dev/null +++ b/project/SOAR_README.md @@ -0,0 +1,31 @@ +# SoAR Project +Squad of Adaptive Robots Project + +----------------------------------- +## Message Data Flow Summary +| Partner | Message Type | Source | Destination | Via Comms Backbone? | Contains Serialized Vehicle-Specific File? | +| ------------ | ---------------------- | --------------------------- | --------------------------- | ------------------- | ------------------------------------------ | +| RHU | platform status | C2’s (Hydrosurv/Ecosub/Ah1) | Autonomy Engine | Yes | No | +| RHU | mission plan | Autonomy Engine | C2’s (Hydrosurv/Ecosub/Ah1) | Yes | No | +| RHU | planning configuration | GUI | Autonomy Engine | Yes | No | +| RHU | observation | Ecosub C2 | Autonomy Engine | Yes | No | +| Hydro-Surv | platform status | Reav-60 | Hydrosurv C2 | No | Yes | +| Hydro-Surv | platform status | Hydrosurv C2 | Autonomy Engine | Yes | No | +| Hydro-Surv | mission plan | Autonomy Engine | Hydrosurv C2 | Yes | No | +| Hydro-Surv | mission plan | Hydrosurv C2 | Reav-60 | No | Yes | +| Hydro-Surv | acknowledgement | Hydrosurv C2 | Comms Backbone (Audit) | Yes | No | +| Planet Ocean | platform status | Ecosub | Hydrosurv Adapter | No | Yes | +| Planet Ocean | platform status | Hydrosurv Adapter | Ecosub C2 | Yes | Yes | +| Planet Ocean | platform status | Ecosub C2 | Autonomy Engine | Yes | No | +| Planet Ocean | mission plan | Autonomy Engine | Ecosub C2 | Yes | No | +| Planet Ocean | mission plan | Ecosub C2 | Hydrosurv Adapter | Yes | Yes | +| Planet Ocean | mission plan | Hydrosurv Adapter | Ecosub | No | Yes | +| Planet Ocean | observation | Ecosub | Hydrosurv Adapter | No | Yes | +| Planet Ocean | observation | Hydrosurv Adapter | Ecosub C2 | Yes | Yes | +| Planet Ocean | observation | Ecosub C2 | Autonomy Engine | Yes | No | +| NOC | platform status | Ecosub | Hydrosurv Adapter | No | Yes | +| NOC | platform status | Hydrosurv Adapter | Ecosub C2 | Yes | Yes | +| NOC | platform status | Ecosub C2 | Autonomy Engine | Yes | No | +| NOC | mission plan | Autonomy Engine | Ecosub C2 | Yes | No | +| NOC | mission plan | Ecosub C2 | Hydrosurv Adapter | Yes | Yes | +| NOC | mission plan | Hydrosurv Adapter | Ecosub | No | Yes | diff --git a/requirements.txt b/requirements.txt index 18a6c82..584b277 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Flask flask-restx -flasgger \ No newline at end of file +flasgger +flask-marshmallow \ No newline at end of file diff --git a/run-docs.sh b/run-docs.sh deleted file mode 100644 index 34aae43..0000000 --- a/run-docs.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -firefox "$1" - -python3 docs/generate_swagger.py -./urlopener "https://google.com" \ No newline at end of file -- GitLab