diff --git a/doc/sphinx/source/user_guide/complex_shape.png b/doc/sphinx/source/user_guide/complex_shape.png new file mode 100644 index 0000000000..7663a553a3 Binary files /dev/null and b/doc/sphinx/source/user_guide/complex_shape.png differ diff --git a/doc/sphinx/source/user_guide/gcs_graphics.rst b/doc/sphinx/source/user_guide/gcs_graphics.rst new file mode 100644 index 0000000000..f3530903de --- /dev/null +++ b/doc/sphinx/source/user_guide/gcs_graphics.rst @@ -0,0 +1,149 @@ +.. user_guide flight_plan + +================ +GCS map graphics +================ + +GCS map can be enriched with intruders and shapes. + +Intruders +--------- + +Intruders represents vehicules that are not managed by paparazzi. They are updated with the `INTRUDER` message. + +Intruders positions are transmitted by the server to the ACs with ACINFO messages. + +.. image:: intruder.png + + +The **INTRUDER** message is defined as follow: + +.. code-block:: xml + + + + + + + altitude above WGS84 reference ellipsoid + + + + + + +Latitudes and longitudes are integers in 1e7deg: ``43.123456`` become ``431234560``. + +.. note:: + + You can use the **OpenSky-Network Intruders** tool (in the paparazzi center: Tools->OpenSky-Network Intruders) to view ADS-B aircrafts near your ACs. + + The **id** field will be the aircraft's hexadecimal ICAO 24 bits address, and the **name** field its callsign. + + + +Shapes +------ + +Shapes can be drawn in the GCS by sending the **SHAPE** message defined below. + +.. image:: shapes.png + +.. code-block:: xml + + + + The SHAPE message used to draw shapes onto the Paparazzi GCS. + Field name shape is used to define the type of shape i.e. Circle, Polygon, Line, or Text. + This is indexed from 0-3 respectively. + + Each shape drawn must have an id number associated with it. + This id number in conjuction with the shapetype will be needed to update or delete the shape. + A circle can be defined with the same id as a polygon but since they have different shape types they are considered unique. + + linecolor and fillcolor take in a color string ie: "red", "blue" + + opacity will change the level of transparency of the fill. + 0 - Transparent + 1 - Light Fill + 2 - Medium Fill + 3 - Opaque + + Passing a status of 0 will create or update the shape specified by id and type. + Passing a status of 1 will delete the shape specified by id and type. + + latarr is an array of coordinates that contain the latitude coordinate for each point in the shape. + The array is comma separated. + lonarr is similar to latarr but contain the longitude coordinate for each point in the shape. + + Circle and Text type will take the first coordinates given to place the shape. + Polygon will take all the coordinates given. + Line will take the first two coordinates given. + + Radius is only used for the circle. + + Text will always be populated with each message using the first set of coordinates. + The text field can not be blank or have spaces. + If text is not desired for a shape then pass "NULL" into the text field. + + + + + + + + + + + + + + +The embedded documentation is pretty explicit here. + + + +How is this different from sectors, and which one should I choose? +__________________________________________________________________ + +Sectors are defined in the flight plan with waypoints, and are embedded in the aircraft. The aircraft can react to it even if telemetry is down. +It is advised to keep the number of waypoints low, so this limits the sector "resolution". + +Shapes, on the other hand, are simply drawn in the GCS. It means that the aircraft has no knowledge of their existence, so it can't react to them by itself. +Being purely on the ground station also means that the number of waypoints can be much higher, allowing to draw e.g. detailled curved zones. + +.. image:: complex_shape.png + +Example +_______ + +This is the python script that was used to draw the 3 shapes on the first example. + +.. literalinclude:: shapes_example.py + +Draw shapes from the AC +----------------------- + +A future feature will be the addition of a DRAW message to the telemetry, that will be translated to a SHAPE message by the server. +This will allow to draw shapes on the GCS directly from the AC. + + +GCS position +------------ + +The GCS displays its position on the map when receiving a ``FLIGHT_PARAM`` message with the **ac_id** set to ``GCS``. + +This is used by the *rtcm2ivy* tool, that transmit the RTK corrections of a base station, and by the *GPSd position display* tool, dedicated to this task. + +Plumes +------ + +.. code-block:: xml + + + + + + + + diff --git a/doc/sphinx/source/user_guide/index_user_guide.rst b/doc/sphinx/source/user_guide/index_user_guide.rst index 34bfed7e6f..443a8468d3 100644 --- a/doc/sphinx/source/user_guide/index_user_guide.rst +++ b/doc/sphinx/source/user_guide/index_user_guide.rst @@ -15,5 +15,6 @@ Start conquering the wolrd, by making incredible :doc:`flight_plans`! flight_plans communication radio + gcs_graphics directories_structure diff --git a/doc/sphinx/source/user_guide/intruder.png b/doc/sphinx/source/user_guide/intruder.png new file mode 100644 index 0000000000..7378742afc Binary files /dev/null and b/doc/sphinx/source/user_guide/intruder.png differ diff --git a/doc/sphinx/source/user_guide/shapes.png b/doc/sphinx/source/user_guide/shapes.png new file mode 100644 index 0000000000..93f270f998 Binary files /dev/null and b/doc/sphinx/source/user_guide/shapes.png differ diff --git a/doc/sphinx/source/user_guide/shapes_example.py b/doc/sphinx/source/user_guide/shapes_example.py new file mode 100755 index 0000000000..9818cfb71f --- /dev/null +++ b/doc/sphinx/source/user_guide/shapes_example.py @@ -0,0 +1,104 @@ +#!/usr/bin/python3 + +import sys +from os import path, getenv +import time +from enum import Enum + +PPRZ_HOME = getenv("PAPARAZZI_HOME", path.normpath(path.dirname(path.abspath(__file__)))) +sys.path.append(PPRZ_HOME + "/var/lib/python") +sys.path.append(PPRZ_HOME + "/sw/lib/python") + +from pprzlink.ivy import IvyMessagesInterface +from pprzlink.message import PprzMessage +from pprz_connect import PprzConnect + + +class Shape(Enum): + CIRCLE = 0 + POLYGON = 1 + LINE = 2 + TEXT = 3 + + +class Opacity(Enum): + TRANSPARENT = 0 + LIGHT_FILL = 1 + MEDIUM_FILL = 2 + OPAQUE = 3 + + +class Status(Enum): + CREATE = 0 + DELETE = 1 + + +POLYGON_COORDS = [ + (43.462, 1.272), + (43.4622, 1.2684), + (43.4628, 1.2686), + (43.464, 1.2710), + (43.4657, 1.2714), + (43.4656, 1.2738) +] + + +def polygon(shape_id): + msg_shape = PprzMessage("ground", "SHAPE") + msg_shape['id'] = shape_id + msg_shape['linecolor'] = 'red' + msg_shape['fillcolor'] = 'red' + msg_shape['opacity'] = Opacity.LIGHT_FILL.value + msg_shape['shape'] = Shape.POLYGON.value + msg_shape['status'] = Status.CREATE.value + lonarr = [] + latarr = [] + for coord in POLYGON_COORDS: + latarr.append(int(coord[0] * 1e7)) + lonarr.append(int(coord[1] * 1e7)) + msg_shape['latarr'] = latarr + msg_shape['lonarr'] = lonarr + msg_shape['text'] = "Crop" + return msg_shape + +def circle(shape_id): + msg_shape = PprzMessage("ground", "SHAPE") + msg_shape['id'] = shape_id + msg_shape['linecolor'] = 'green' + msg_shape['fillcolor'] = 'yellow' + msg_shape['opacity'] = Opacity.MEDIUM_FILL.value + msg_shape['shape'] = Shape.CIRCLE.value + msg_shape['status'] = Status.CREATE.value + msg_shape['latarr'] = [int(43.4640*1e7)] + msg_shape['lonarr'] = [int(1.275*1e7)] + msg_shape['radius'] = int(100) + msg_shape['text'] = "hello" + return msg_shape + +def line(shape_id): + msg_shape = PprzMessage("ground", "SHAPE") + msg_shape['id'] = shape_id + msg_shape['linecolor'] = 'purple' + msg_shape['shape'] = Shape.LINE.value + msg_shape['status'] = Status.CREATE.value + msg_shape['latarr'] = [int(43.46296*1e7), int(43.46216*1e7)] + msg_shape['lonarr'] = [int(1.272*1e7), int(1.2744*1e7)] + msg_shape['text'] = "runway" + return msg_shape + +if __name__ == '__main__': + ivy = IvyMessagesInterface("Shape drawer") + # wait for ivy to be correctly started + time.sleep(0.1) + + msg = polygon(1) + ivy.send(msg) + + msg = circle(2) + ivy.send(msg) + + msg = line(3) + ivy.send(msg) + + ivy.shutdown() +