diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a13956e2b4b6bcf78efe8423da25333a522aefc4..b3412c2c3f48e565f874d27f14c93d0b3203cc31 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 6ef61cb78686d0a246cc7099205833788a540d9f..567f58bb0330b5119823be33c3f43c415e901adc 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 0f2a43d412381fe7d4e7def9a395b4033a491262..61ab5158cdaa95bc8b036e76bf4e7c600d71dce1 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 8e0339f73bf95b243f6d78c4fd18b7365441e99c..bbd8765e2d2f178e62169d47efbe4ed0f93bc00e 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 1840a837d326369a9ac671c524147ecf975058bd..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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 Binary files a/examples/autosub_c2/sample_autosub.alr-3.v1.mission_script.sbd and /dev/null differ 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 fe6c91193aca786cef143f609365c2fc6060dfd1..0000000000000000000000000000000000000000 --- 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 94160e1378fc10cc6ed869eaa19fdf70ff8d43c4..bf46b074383f850daa1022e71c04e070f3d7e157 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b7f887e12058f122d1fe156ac5380db3c1a632c5 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 e0096caf6ac1a05a13a73349182588eff290a232..91bfa0347fb7eb2e939f74e97aeb8c3825c474c3 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 b86902fea2622ac05ce7054821085eea9c5c14c5..a759406db84779fe5993732519251c929e4943b9 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 248a35fd77b5c1223da981885ed3ba337a1acef4..ff336dc986395c90cf72b4c59fc32406877fc3b5 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 9eb703941f8561e0ca62fd1bd1b2fb5f9e31a21f..e11af4f48b62ac44db1bfe878f47734bc5b9d479 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 0000000000000000000000000000000000000000..a8c623ff7e89da94adfe9d74eb43c88989338692 --- /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 18a6c82df234b747f96aa739bc1b2d6fa9d48492..584b2776c5f1856c1e97d79c384df58e41b27ae9 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 34aae438a0fafcdad9470114915f39894095e3ee..0000000000000000000000000000000000000000 --- 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