Project

General

Profile

Paparazzi interface » History » Version 1

Rafael Bailon-Ruiz, 2020-08-28 18:23

1 1 Rafael Bailon-Ruiz
h1. Paparazzi interface
2
3
**"Paparazzi UAV":http://wiki.paparazziuav.org/wiki/Main_Page** (Unmanned Aerial Vehicle) is an open-source drone hardware and software project encompassing autopilot systems and ground station software for multicopters/multirotors, fixed-wing, helicopters and hybrid aircraft that was founded in 2003. "Paparazzi UAV":http://wiki.paparazziuav.org/wiki/Main_Page was designed with autonomous flight as the primary focus and manual flying as the secondary. From the beginning it was designed with portability in mind and the ability to control multiple aircraft within the same system. Paparazzi features a dynamic flight plan system that is defined by mission states and using way points as “variables”. This makes it easy to create very complex fully automated missions without the operators intervention. For more project information, see "here":http://wiki.paparazziuav.org/wiki/General. 
4
5
h2. Paparazzi and Nephelae
6
7
Since Paparazzi is an autopilot, its job has many objectives related to the control of the aircrafts.
8
These jobs can be : control of the fleet and setting objectives using a flight plan, acquiring and displaying data, and much more. Paparazzi can also manage missions that have not a static objective (like adaptative missions) that uses data to update itself. However, since Paparazzi does not analyzes nor processes raw data in real-time, we need the intervention of CAMS. 
9
10
You'll find in this package how we achieve a communication with Paparazzi (middleware, sortof), and how we update the update the state of UAVs abstractions CAMS-side with Paparazzi and sending information to the real UAVs, using the processed data.
11
12
h2. Communication between Paparazzi and CAMS
13
14
h3. The "Ivy bus":https://www.eei.cena.fr/products/ivy/
15
16
Paparazzi data are exchanged between software components into the form ASCII messages. These ASCII messages are broadcasted onto the local network by all the software components of the Paparazzi framework, and are available to any software with access to local network (a "software BUS":https://en.wikipedia.org/wiki/Software_bus behavior). The process of transmitting and receiving data from/to the network is handled by the "Ivy bus":https://www.eei.cena.fr/products/ivy/, which provides a simple Python API.
17
18
In the Paparazzi framework, these ASCII messages are formatted, and define many messages types (for the full list of Paparazzi messages see "here":http://docs.paparazziuav.org/latest/paparazzi_messages.html). For more information on the message system in general see "here":https://wiki.paparazziuav.org/wiki/DevGuide/Server_GCS_com.
19
20
Paparazzi comes natively with Python APIs that manages the communication between softwares and also the parsing and encoding of messages. All of these functions are inside the pprzlink library.
21
To use the pprzlink lib :
22
23
<pre><code class="python">PPRZ_HOME = os.getenv("PAPARAZZI_HOME", None)
24
if PPRZ_HOME is not None:
25
    sys.path.append(PPRZ_HOME + "/var/lib/python")
26
else:    PPRZLINK_HOME = os.getenv("PAPARAZZI_PPRZLINK", None)                                                        
27
    if PPRZLINK_HOME is not None:
28
        print(os.path.join(PPRZLINK_HOME, 'lib/v2.0/python'))
29
        sys.path.append(os.path.join(PPRZLINK_HOME, 'lib/v2.0/python'))
30
# IvyMessagesInterface for communication (using the Ivy bus)
31
from pprzlink.ivy import IvyMessagesInterface
32
# PprzMessage for encoding/decoding messages (using a specific format)
33
from pprzlink.message import PprzMessage</code></pre>
34
35
h3. MessageInterface
36
37
To ease the usage of these libraries, CAMS uses an object called MessageInterface specifc for Paparazzi. With this object, it is possible to call aliases (sending and receiving messages) of IvyMessagesInterface and manages "bindings" (sortof topics). An example of alias implemented in MessageInterface :
38
39
<pre><code class="python">def bind(self, callback, ivyRegex):                                                                                                                  
40
"""                                                                                                                                              
41
Binds a function to call whenever a message is received, containing
42
the regex passed in parameter. The message received is then processed
43
using the prettify_message function of the class.
44
45
Parameters                                                                                                                                        
46
----------                                                                                                                                       
47
callback : function                                                                                                                              
48
    Function to call when a matching message is received
49
50
ivyRegex : str                                                                                                                                   
51
    Used to find the matching messages
52
53
Returns
54
-------
55
int
56
    Id of the message
57
"""
58
return self.messageInterface.subscribe(                                                                                                          
59
                 lambda sender, msg: callback(MessageInterface.prettify_message(msg)), ivyRegex) </code></pre>
60
Only one single instance of MessageInterface is created by instance of CAMS, meaning this instance is shared by multiple interfaces.
61
62
h3. PprzMsgHarmonizer
63
64
CAMS also uses for Paparazzi a specific object called PprzMsgHarmonizer. This object is meant to centralize the usage of PprzMessages object format and to process and retrieve the mandatory information into a CAMS generic object.
65
66
*/!\ Since the implementation of the PprzMsgHarmonizer is poorly made at the moment, there may be variations over time.  /!\*
67
68
It can subscribe to messages, by passing a single string. This string is then transformed into an ivy regex, and this regex itself is used to check if a message correponds to this regex. It can also builds messages. Based on the string passed, it'll need a certain amount of data to build the message and once done, will send it on the ivy bus, for Paparazzi.
69
Sending and subscribing messages are always managed by the MessageInterface object so if a binding is needed for instance, the PprzMsgHarmonizer will start by first finding the right regex, then calling the MessageInterface bind function with the regex and the callback function.
70
An example of code you can find in the class, when you want to subscribe to a type of messages :
71
<pre><code class="python">def subscribe_to(self, callback, msgType, raw=False):
72
"""
73
Subscribe to a topic using the msgType. Each time a message correponding
74
to the topic is received, the callback function passed in parameters is
75
called. An optional boolean parameter raw is used to subscribe to
76
messages that have not a PprzMessage structure.
77
&nbsp;
78
Parameters
79
----------
80
callback : function
81
    The function called when a message corresponding to the regex of the
82
    topic is used.
83
&nbsp;
84
msgType : str
85
    The topic we subscribe to
86
&nbsp;
87
raw : bool
88
    Optional parameter specific for paparazzi. Used to subscribe to
89
    messages that does not have a PprzMessage structure
90
&nbsp;
91
Returns
92
-------
93
int
94
    The bindId associated to subscription (used for unsubscribing)
95
"""
96
    if msgType not in self.subscribeTo.keys():
97
        raise ValueError('The type of subscribe message ' + msgType + ' is not defined for this class')
98
    if msgType in self.messagesToProcess:
99
        usedCallback = lamda msg : callback(self.__process_message(msg, msgType))
100
    else:
101
        usedCallback = callback
102
    if raw:
103
        bindId = self.msgInterface.bind_raw(usedCallback, self.subscribeTo[msgType])
104
    else:
105
        bindId = self.msgInterface.bind(usedCallback, self.subscribeTo[msgType])
106
    return bindId
107
</code></pre>
108
109
h2. Updating CAMS via messages
110
111
Once a message is received, we need to update the state of CAMS. There are two types of messages, those which changes the state of the aircraft and the database and those which only changes the state of the database. The AircraftPprz class and the plugins are here to solve those two problems by using the different functions of PprzMsgHarmonizer and MessageInterface and callbacks. Whenever a callback is triggered, it will call functions that will change the state of the database and if needed, the state of the aircraft.
112
113
An example of callback : 
114
115
<pre><code class="python">def flight_param_callback(self, flightParam):
116
"""
117
Sets the currentFlightParam attribute with the message passed in
118
parameters. If the statusNotified attribute is still False, sends a
119
message on the add_status to add it in the database.
120
121
Parameters
122
----------
123
flightParam : pprzlink.message.PprzMessage
124
    The new currentFlightParam attribute
125
"""
126
    self.currentFlightParam = flightParam
127
    #---------------- REPLAY ----------------
128
    utmUav = utm.from_latlon(flightParam['lat'], flightParam['long'])
129
    update_parameters = {
130
        'lat'       : flightParam['lat'],
131
        'long'      : flightParam['long'],
132
        'alt'       : flightParam['alt'],
133
        'agl'       : flightParam['agl'],
134
        'roll'      : flightParam['roll'],
135
        'pitch'     : flightParam['pitch'],
136
        'heading'   : flightParam['heading'],
137
        'course'    : flightParam['course'],
138
        'speed'     : flightParam['speed'],
139
        'air_speed' : flightParam['airspeed'],
140
        'climb'     : flightParam['climb'],
141
        'itow'      : flightParam['itow'],
142
        'utm_east'  : utmUav[0],
143
        'utm_north' : utmUav[1],
144
        'utm_zone'  : str(utmUav[2]) + utmUav[3]
145
    }
146
    pos = Position()
147
    pos.x = utmUav[0] - self.navFrame.position.x
148
    pos.y = utmUav[1] - self.navFrame.position.y
149
    pos.z = flightParam['alt'] - self.navFrame.position.z
150
    if self.replayTime is None:
151
        pos.t = flightParam.timestamp - self.navFrame.position.t
152
    else:
153
        pos.t = self.replayTime
154
    update_parameters['position'] = pos
155
    # changes the state of the AircraftStatus object
156
    self.status.set_status(update_parameters)
157
    #---------------- REPLAY ----------------
158
    if not self.statusNotified:
159
        # notifying status if not notified in ap_status_callback, changes the state of the database
160
        self.add_status(self.status.copy())
161
    self.statusNotified = False</code></pre>