-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathamls.html
331 lines (299 loc) · 128 KB
/
amls.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="VuePress 2.0.0-beta.38">
<style>
:root {
--c-bg: #fff;
}
html.dark {
--c-bg: #22272e;
}
html, body {
background-color: var(--c-bg);
}
</style>
<script>
const userMode = localStorage.getItem('vuepress-color-scheme');
const systemDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
if (userMode === 'dark' || (userMode !== 'light' && systemDarkMode)) {
document.documentElement.classList.toggle('dark', true);
}
</script>
<title>Autonomous Multirotor Landing System (AMLS) | Clover</title><meta name="description" content="Clover Drone Kit">
<link rel="modulepreload" href="/clover-vuepress/assets/app.4f6a4bec.js"><link rel="modulepreload" href="/clover-vuepress/assets/amls.html.fccbbf23.js"><link rel="modulepreload" href="/clover-vuepress/assets/amls.html.6add1cc6.js"><link rel="modulepreload" href="/clover-vuepress/assets/follow_the_white_rabbit.302de01b.js">
<link rel="stylesheet" href="/clover-vuepress/assets/style.7a1025bf.css">
</head>
<body>
<div id="app"><!--[--><div class="theme-container"><!--[--><header ref_key="navbar" class="navbar"><div class="toggle-sidebar-button" title="true" aria-expanded="false" role="button" tabindex="0"><div class="icon" aria-hidden="true"><span></span><span></span><span></span></div></div><span><a href="/clover-vuepress/en/" class=""><img class="logo" src="/clover-vuepress/clover-logo.png" alt="Clover"><span class="site-name can-hide">Clover</span></a></span><div class="navbar-items-wrapper" style=""><!--[--><!--]--><nav class="navbar-items can-hide"><!--[--><div class="navbar-item"><a class="external-link" href="https://coex.tech" rel="noopener noreferrer" target="_blank" aria-label="Official Site"><!--[--><!--]--> Official Site <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><div class="navbar-item"><a class="external-link" href="https://t.me/COEXHelpdesk" rel="noopener noreferrer" target="_blank" aria-label="Support Chat"><!--[--><!--]--> Support Chat <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><div class="navbar-item"><div class="navbar-dropdown-wrapper"><button class="navbar-dropdown-title" type="button" aria-label="Select language"><span class="title">Languages</span><span class="arrow down"></span></button><button class="navbar-dropdown-title-mobile" type="button" aria-label="Select language"><span class="title">Languages</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="navbar-dropdown"><!--[--><li class="navbar-dropdown-item"><a aria-current="page" href="/clover-vuepress/en/amls.html" class="router-link-active router-link-exact-active router-link-active" aria-label="English"><!--[--><!--]--> English <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/clover-vuepress/ru/amls.html" class="" aria-label="Русский"><!--[--><!--]--> Русский <!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><div class="navbar-item"><a class="external-link" href="https://github.com/CopterExpress/clover" rel="noopener noreferrer" target="_blank" aria-label="GitHub"><!--[--><!--]--> GitHub <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><!--]--></nav><!--[--><!--]--><button class="toggle-dark-button" title="toggle dark mode"><svg style="" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M16 12.005a4 4 0 1 1-4 4a4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6a6 6 0 0 0-6-6z" fill="currentColor"></path><path d="M5.394 6.813l1.414-1.415l3.506 3.506L8.9 10.318z" fill="currentColor"></path><path d="M2 15.005h5v2H2z" fill="currentColor"></path><path d="M5.394 25.197L8.9 21.691l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 25.005h2v5h-2z" fill="currentColor"></path><path d="M21.687 23.106l1.414-1.415l3.506 3.506l-1.414 1.414z" fill="currentColor"></path><path d="M25 15.005h5v2h-5z" fill="currentColor"></path><path d="M21.687 8.904l3.506-3.506l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 2.005h2v5h-2z" fill="currentColor"></path></svg><svg style="display:none;" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z" fill="currentColor"></path></svg></button><form class="search-box" role="search"><input type="search" autocomplete="off" spellcheck="false" value><!----></form></div></header><!--]--><div class="sidebar-mask"></div><!--[--><aside class="sidebar"><nav class="navbar-items"><!--[--><div class="navbar-item"><a class="external-link" href="https://coex.tech" rel="noopener noreferrer" target="_blank" aria-label="Official Site"><!--[--><!--]--> Official Site <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><div class="navbar-item"><a class="external-link" href="https://t.me/COEXHelpdesk" rel="noopener noreferrer" target="_blank" aria-label="Support Chat"><!--[--><!--]--> Support Chat <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><div class="navbar-item"><div class="navbar-dropdown-wrapper"><button class="navbar-dropdown-title" type="button" aria-label="Select language"><span class="title">Languages</span><span class="arrow down"></span></button><button class="navbar-dropdown-title-mobile" type="button" aria-label="Select language"><span class="title">Languages</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="navbar-dropdown"><!--[--><li class="navbar-dropdown-item"><a aria-current="page" href="/clover-vuepress/en/amls.html" class="router-link-active router-link-exact-active router-link-active" aria-label="English"><!--[--><!--]--> English <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/clover-vuepress/ru/amls.html" class="" aria-label="Русский"><!--[--><!--]--> Русский <!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><div class="navbar-item"><a class="external-link" href="https://github.com/CopterExpress/clover" rel="noopener noreferrer" target="_blank" aria-label="GitHub"><!--[--><!--]--> GitHub <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><!--]--></nav><!--[--><!--]--><ul class="sidebar-items"><!--[--><li><a href="/clover-vuepress/en/" class="sidebar-item sidebar-heading" aria-label="COEX Clover"><!--[--><!--]--> COEX Clover <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/glossary.html" class="sidebar-item sidebar-heading" aria-label="Glossary"><!--[--><!--]--> Glossary <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/safety.html" class="sidebar-item sidebar-heading" aria-label="Safety tips"><!--[--><!--]--> Safety tips <!--[--><!--]--></a><!----></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Assembly <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/assembly.html" class="sidebar-item" aria-label="Clover drone assembly"><!--[--><!--]--> Clover drone assembly <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/assemble_4_2.html" class="sidebar-item" aria-label="Clover 4.2 assembly"><!--[--><!--]--> Clover 4.2 assembly <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/assemble_4_2_ws.html" class="sidebar-item" aria-label="Clover 4 assembly"><!--[--><!--]--> Clover 4 assembly <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/assemble_4.html" class="sidebar-item" aria-label="Clover 4 assembly"><!--[--><!--]--> Clover 4 assembly <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/assemble_3.html" class="sidebar-item" aria-label="Assembly of Clover 3"><!--[--><!--]--> Assembly of Clover 3 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/assemble_2.html" class="sidebar-item" aria-label="Clover 2 construction kit assembly instruction"><!--[--><!--]--> Clover 2 construction kit assembly instruction <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Configuration <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/setup.html" class="sidebar-item" aria-label="Initial setup"><!--[--><!--]--> Initial setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/calibration.html" class="sidebar-item" aria-label="Sensor calibration"><!--[--><!--]--> Sensor calibration <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/radio.html" class="sidebar-item" aria-label="RC setup"><!--[--><!--]--> RC setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/rc_flysky_a8s.html" class="sidebar-item" aria-label="Using Flysky FS-A8S"><!--[--><!--]--> Using Flysky FS-A8S <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/modes.html" class="sidebar-item" aria-label="Flight modes"><!--[--><!--]--> Flight modes <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/power.html" class="sidebar-item" aria-label="Power setup"><!--[--><!--]--> Power setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/failsafe.html" class="sidebar-item" aria-label="Failsafe configuration"><!--[--><!--]--> Failsafe configuration <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Manual flight <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/flight.html" class="sidebar-item" aria-label="Flight"><!--[--><!--]--> Flight <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/flight_exercises.html" class="sidebar-item" aria-label="Drone control exercises"><!--[--><!--]--> Drone control exercises <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Working with Raspberry Pi <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/raspberry.html" class="sidebar-item" aria-label="Raspberry Pi"><!--[--><!--]--> Raspberry Pi <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/image.html" class="sidebar-item" aria-label="Raspberry Pi image"><!--[--><!--]--> Raspberry Pi image <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/wifi.html" class="sidebar-item" aria-label="Connecting to Clover via Wi-Fi"><!--[--><!--]--> Connecting to Clover via Wi-Fi <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/connection.html" class="sidebar-item" aria-label="Connecting Raspberry Pi to the flight controller"><!--[--><!--]--> Connecting Raspberry Pi to the flight controller <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/gcs_bridge.html" class="sidebar-item" aria-label="Using QGroundControl via Wi-Fi"><!--[--><!--]--> Using QGroundControl via Wi-Fi <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/ssh.html" class="sidebar-item" aria-label="SSH access to Raspberry Pi"><!--[--><!--]--> SSH access to Raspberry Pi <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/cli.html" class="sidebar-item" aria-label="Command line interface"><!--[--><!--]--> Command line interface <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/selfcheck.html" class="sidebar-item" aria-label="Automatic check"><!--[--><!--]--> Automatic check <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/web_video_server.html" class="sidebar-item" aria-label="Viewing images from cameras"><!--[--><!--]--> Viewing images from cameras <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Programming <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/programming.html" class="sidebar-item" aria-label="Programming"><!--[--><!--]--> Programming <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/camera_setup.html" class="sidebar-item" aria-label="Camera setup"><!--[--><!--]--> Camera setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/aruco.html" class="sidebar-item" aria-label="ArUco markers"><!--[--><!--]--> ArUco markers <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/aruco_marker.html" class="sidebar-item" aria-label="ArUco marker detection"><!--[--><!--]--> ArUco marker detection <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/aruco_map.html" class="sidebar-item" aria-label="Map-based navigation with ArUco markers"><!--[--><!--]--> Map-based navigation with ArUco markers <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/optical_flow.html" class="sidebar-item" aria-label="Use of Optical Flow"><!--[--><!--]--> Use of Optical Flow <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simple_offboard.html" class="sidebar-item" aria-label="Autonomous flight"><!--[--><!--]--> Autonomous flight <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/frames.html" class="sidebar-item" aria-label="Coordinate systems (frames)"><!--[--><!--]--> Coordinate systems (frames) <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/snippets.html" class="sidebar-item" aria-label="Code examples"><!--[--><!--]--> Code examples <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/laser.html" class="sidebar-item" aria-label="Working with a laser rangefinder"><!--[--><!--]--> Working with a laser rangefinder <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/leds.html" class="sidebar-item" aria-label="Working with a LED strip"><!--[--><!--]--> Working with a LED strip <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/gpio.html" class="sidebar-item" aria-label="Working with GPIO"><!--[--><!--]--> Working with GPIO <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/sonar.html" class="sidebar-item" aria-label="Working with the ultrasonic distance gage"><!--[--><!--]--> Working with the ultrasonic distance gage <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/camera.html" class="sidebar-item" aria-label="Working with the camera"><!--[--><!--]--> Working with the camera <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/rviz.html" class="sidebar-item" aria-label="Using rviz and rqt"><!--[--><!--]--> Using rviz and rqt <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/autolaunch.html" class="sidebar-item" aria-label="Software autorun"><!--[--><!--]--> Software autorun <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/javascript.html" class="sidebar-item" aria-label="Work with ROS from browser"><!--[--><!--]--> Work with ROS from browser <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/blocks.html" class="sidebar-item" aria-label="Blocks programming for Clover"><!--[--><!--]--> Blocks programming for Clover <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simulation.html" class="sidebar-item" aria-label="Simulation overview"><!--[--><!--]--> Simulation overview <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simulation_native.html" class="sidebar-item" aria-label="Native setup"><!--[--><!--]--> Native setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simulation_vm.html" class="sidebar-item" aria-label="Simulation VM setup"><!--[--><!--]--> Simulation VM setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simulation_usage.html" class="sidebar-item" aria-label="Using the simulator"><!--[--><!--]--> Using the simulator <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/simulation_m1.html" class="sidebar-item" aria-label="Running simulator on M1 powered computer"><!--[--><!--]--> Running simulator on M1 powered computer <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/ros.html" class="sidebar-item" aria-label="ROS"><!--[--><!--]--> ROS <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/mavros.html" class="sidebar-item" aria-label="MAVROS"><!--[--><!--]--> MAVROS <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Supplementary materials <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/supplementary.html" class="sidebar-item" aria-label="Supplementary materials"><!--[--><!--]--> Supplementary materials <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/coex_pix.html" class="sidebar-item" aria-label="COEX Pix"><!--[--><!--]--> COEX Pix <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/coex_pdb.html" class="sidebar-item" aria-label="COEX PDB"><!--[--><!--]--> COEX PDB <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/coex_gps.html" class="sidebar-item" aria-label="COEX GPS"><!--[--><!--]--> COEX GPS <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/auto_setup.html" class="sidebar-item" aria-label="Step-by-step guide on autonomous flight with Clover 4"><!--[--><!--]--> Step-by-step guide on autonomous flight with Clover 4 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/hostname.html" class="sidebar-item" aria-label="Hostname"><!--[--><!--]--> Hostname <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/sitl.html" class="sidebar-item" aria-label="PX4 Simulation"><!--[--><!--]--> PX4 Simulation <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/wall_aruco.html" class="sidebar-item" aria-label="Navigation using vertical ArUco-markers"><!--[--><!--]--> Navigation using vertical ArUco-markers <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/calibratePID.html" class="sidebar-item" aria-label="Configuring the PID coefficients"><!--[--><!--]--> Configuring the PID coefficients <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/models.html" class="sidebar-item" aria-label="Model files for parts"><!--[--><!--]--> Model files for parts <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/ros-install.html" class="sidebar-item" aria-label="ROS Melodic package installation and setup"><!--[--><!--]--> ROS Melodic package installation and setup <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/camera_calibration.html" class="sidebar-item" aria-label="Camera calibration"><!--[--><!--]--> Camera calibration <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/zerotire_vpn.html" class="sidebar-item" aria-label="Creating a virtual network ZeroTier One and connecting to it"><!--[--><!--]--> Creating a virtual network ZeroTier One and connecting to it <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/4g.html" class="sidebar-item" aria-label="Multi-copter control with 4G communication"><!--[--><!--]--> Multi-copter control with 4G communication <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/jetson_nano.html" class="sidebar-item" aria-label="Clover and Jetson Nano"><!--[--><!--]--> Clover and Jetson Nano <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/rc.html" class="sidebar-item" aria-label="Controlling Clover from a smartphone"><!--[--><!--]--> Controlling Clover from a smartphone <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/network.html" class="sidebar-item" aria-label="Configuring Wi-Fi"><!--[--><!--]--> Configuring Wi-Fi <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/uart.html" class="sidebar-item" aria-label="UART interface"><!--[--><!--]--> UART interface <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/parameters.html" class="sidebar-item" aria-label="PX4 Parameters"><!--[--><!--]--> PX4 Parameters <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/flight_logs.html" class="sidebar-item" aria-label="PX4 Logs and Topics"><!--[--><!--]--> PX4 Logs and Topics <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/firmware.html" class="sidebar-item" aria-label="Pixhawk / Pixracer firmware flashing"><!--[--><!--]--> Pixhawk / Pixracer firmware flashing <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/mavlink.html" class="sidebar-item" aria-label="MAVLink"><!--[--><!--]--> MAVLink <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/test_connection.html" class="sidebar-item" aria-label="How to use a multimeter?"><!--[--><!--]--> How to use a multimeter? <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/radioerrors.html" class="sidebar-item" aria-label="Possible radio failures"><!--[--><!--]--> Possible radio failures <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/esc_firmware.html" class="sidebar-item" aria-label="Flashing ESCs using BLHeliSuite"><!--[--><!--]--> Flashing ESCs using BLHeliSuite <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/arduino.html" class="sidebar-item" aria-label="Controlling the copter from Arduino"><!--[--><!--]--> Controlling the copter from Arduino <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/gps.html" class="sidebar-item" aria-label="Connecting GPS"><!--[--><!--]--> Connecting GPS <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/ir_sensors.html" class="sidebar-item" aria-label="Working with IR sensors on Raspberry Pi 3"><!--[--><!--]--> Working with IR sensors on Raspberry Pi 3 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/fpv_clover_4_2.html" class="sidebar-item" aria-label="Installing and configuring FPV equipment"><!--[--><!--]--> Installing and configuring FPV equipment <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/fpv.html" class="sidebar-item" aria-label="Installation of FPV"><!--[--><!--]--> Installation of FPV <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/magnetic_grip.html" class="sidebar-item" aria-label="Assembling and setting up the electromagnetic gripper"><!--[--><!--]--> Assembling and setting up the electromagnetic gripper <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/mechanical_grip.html" class="sidebar-item" aria-label="Assembling and setting up a mechanical gripper"><!--[--><!--]--> Assembling and setting up a mechanical gripper <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/trainer_mode.html" class="sidebar-item" aria-label="FlySky Trainer mode settings"><!--[--><!--]--> FlySky Trainer mode settings <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/tinning.html" class="sidebar-item" aria-label="Blanching"><!--[--><!--]--> Blanching <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/connectortypes.html" class="sidebar-item" aria-label="Types of power connectors"><!--[--><!--]--> Types of power connectors <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/4in1.html" class="sidebar-item" aria-label="Connecting 4 in 1 ESCs"><!--[--><!--]--> Connecting 4 in 1 ESCs <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/tb.html" class="sidebar-item" aria-label="Soldering safety"><!--[--><!--]--> Soldering safety <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/leds_old.html" class="sidebar-item" aria-label="Working with a LED strip on Raspberry 3"><!--[--><!--]--> Working with a LED strip on Raspberry 3 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/contributing.html" class="sidebar-item" aria-label="Contribution to Clover"><!--[--><!--]--> Contribution to Clover <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/packages.html" class="sidebar-item" aria-label="COEX packages repository"><!--[--><!--]--> COEX packages repository <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/migrate20.html" class="sidebar-item" aria-label="Migration to version 0.20"><!--[--><!--]--> Migration to version 0.20 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/migrate22.html" class="sidebar-item" aria-label="Migration to version 0.22"><!--[--><!--]--> Migration to version 0.22 <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><li><p tabindex="0" class="sidebar-item sidebar-heading collapsible">Events <span class="right arrow"></span></p><!--[--><ul style="display:none;" class="sidebar-item-children"><!--[--><li><a href="/clover-vuepress/en/events.html" class="sidebar-item" aria-label="Events"><!--[--><!--]--> Events <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/copterhack2022.html" class="sidebar-item" aria-label="CopterHack 2022"><!--[--><!--]--> CopterHack 2022 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/copterhack2021.html" class="sidebar-item" aria-label="CopterHack 2021"><!--[--><!--]--> CopterHack 2021 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/copterhack2019.html" class="sidebar-item" aria-label="Copter Hack 2019"><!--[--><!--]--> Copter Hack 2019 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/copterhack2018.html" class="sidebar-item" aria-label="Copter Hack 2018"><!--[--><!--]--> Copter Hack 2018 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/copterhack2017.html" class="sidebar-item" aria-label="Copter Hack 2017"><!--[--><!--]--> Copter Hack 2017 <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/video_contest.html" class="sidebar-item" aria-label="Contest for the best educational video on assembly and configuration"><!--[--><!--]--> Contest for the best educational video on assembly and configuration <!--[--><!--]--></a><!----></li><li><a href="/clover-vuepress/en/educational_contests.html" class="sidebar-item" aria-label="Educational contests"><!--[--><!--]--> Educational contests <!--[--><!--]--></a><!----></li><!--]--></ul><!--]--></li><!--]--></ul><!--[--><!--]--></aside><!--]--><!--[--><main class="page"><!--[--><!--]--><div class="theme-default-content"><!--[--><h1 id="autonomous-multirotor-landing-system-amls" tabindex="-1"><a class="header-anchor" href="#autonomous-multirotor-landing-system-amls" aria-hidden="true">#</a> Autonomous Multirotor Landing System (AMLS)</h1><p><img src="/clover-vuepress/assets/logo_book.9d456bb4.png" alt="Logo" title="Logo"></p><h2 id="the-goal-is-to-automatically-land-a-drone-on-a-moving-platform" tabindex="-1"><a class="header-anchor" href="#the-goal-is-to-automatically-land-a-drone-on-a-moving-platform" aria-hidden="true">#</a> The goal is to automatically land a drone on a moving platform</h2><h3 id="amls-article" tabindex="-1"><a class="header-anchor" href="#amls-article" aria-hidden="true">#</a> AMLS Article</h3><p>In this Article we will describe AMLS project. Namely, AMLS Optical stabilization, GPS holding, GPS following, Altitude holding, Grabbing, Weather protection, Speed measurement and Illumination systems. In addition, we will make clear of how it works and how it was done!</p><h3 id="our-main-github-repository" tabindex="-1"><a class="header-anchor" href="#our-main-github-repository" aria-hidden="true">#</a> Our main GitHub repository</h3><p><a href="https://github.com/XxOinvizioNxX/Liberty-Way" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Liberty-Way<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><h3 id="developers" tabindex="-1"><a class="header-anchor" href="#developers" aria-hidden="true">#</a> Developers</h3><ul><li><a href="mailto:[email protected]">Pavel Neshumov</a></li><li><a href="mailto:[email protected]">Andrey Kabalin</a></li><li><a href="mailto:[email protected]">Vladislav Yasnetsky</a></li></ul><p><img src="/clover-vuepress/assets/drone_meme.cbae0c34.jpg" alt="Drone 1" title="Drone 1"></p><hr><h2 id="table-of-contents" tabindex="-1"><a class="header-anchor" href="#table-of-contents" aria-hidden="true">#</a> Table of contents</h2><ul><li><a href="#how-does-it-work">0. How does it work?</a><ul><li><a href="#short-video-about-our-project-clickable">0.1. A video about our project</a></li></ul></li><li><a href="#hold-and-flight-to-waypoints-functions">1. GPS hold and Flight to waypoints functions</a><ul><li><a href="#serial-reading">1.1. Serial reading</a></li><li><a href="#ublox-parsing">1.2. UBlox GPS parsing</a></li><li><a href="#set-current-waypoint">1.3. Set current waypoint</a></li><li><a href="#waypoint-edit-to-fly-to-waypoints">1.4. Waypoint edition (To fly to waypoints)</a></li><li><a href="#waypoint-stabilization">1.5. Waypoint stabilization</a></li></ul></li><li><a href="#following">2. GPS following</a></li><li><a href="#compass">3. Compass</a></li><li><a href="#altitude-stabilization-barometer">4. Altitude stabilization (barometer)</a></li><li><a href="#optical-stabilization">5. Optical stabilization</a><ul><li><a href="#so-difficult-and-so-important">5.1. So difficult and so important</a></li><li><a href="#first-steps">5.2. First steps</a></li><li><a href="#inverse-approach">5.3. Inverse approach</a></li><li><a href="#java-edition">5.4. Java edition</a></li><li><a href="#liberty-way">5.5. Liberty-Way</a></li><li><a href="#communication-with-the-drone">5.6. Communication with the drone</a></li><li><a href="#camera-gimbal">5.7. Camera gimbal</a></li></ul></li><li><a href="#eitude-amls-platform">6. Eitude AMLS Platform</a><ul><li><a href="#grabbing-system">6.1. Grabbing system</a></li><li><a href="#weather-protection-system">6.2. Weather protection system</a></li><li><a href="#platform-speedometer">6.3. Speed measurement system</a></li><li><a href="#platform-light-sensor">6.4. Illumination system</a></li></ul></li><li><a href="#conclusion">7. Conclusion</a></li></ul><hr><h2 id="how-does-it-work" tabindex="-1"><a class="header-anchor" href="#how-does-it-work" aria-hidden="true">#</a> 0. How does it work?</h2><p>The AMLS system consists of two parts:</p><ul><li><p>The drone</p><p><img src="/clover-vuepress/assets/liberty-x_side_cutout_2_small.97777a77.png" alt="Liberty-X" title="Liberty-X"></p></li><li><p>And the platform either mobile (implemented on a vehicle), either stable (pick-up-point)</p><p><img src="/clover-vuepress/assets/platform_side_transparent.9dc49b02.png" alt="Platform" title="Platform"></p></li></ul><p>How the system operates:</p><ul><li>Firstly, a drone with a delivery package is far from the platform and it has no visual contact with it. The drone recieves GPS coordinates of a platform by using cellular communication or any other radio channel (The drone has Liberty-Link implemented on it. This module is able to adjust its position, whatever the firmware of the flight controller. The module is installed inside the line between a receiver and a flight controller.</li><li>The drone is moving to received coordinates. The coordinates might be renewed in the process (but not frequently, thus preventing the channel from overloading)</li><li>When the drone is close to the platform but there is still no visual contact, the program runs GPS stabilization. Here the data is being transmitted over the closest radio communication channel of high freqency, so the drone can catch up with the platform.</li><li>Meanwhile, the drone descends (barometers are installed on both, the drone and the platform). Descending goes on untill altitude reaches 1.5-2 meters above the platform.</li><li>While descending and when visual contact with the platform camera is established, the program enables visual (precision) stabilization. And as soon as the drone's tag is within camera's field of view, the algorithm will capture the drone.</li><li>When optical stabilization is enabled, GPS is working as a back up plan (in case something goes wrong, GPS stabilization launches again).</li><li>In order to use optical stabilization the drone is equipped with ArUco tag which can be captured by a camera and by using the closest radio communication channel, the system transmits adjustment data to the drone.</li><li>Along with optical stabilization, the program launches landing algorithm. The algorithm artificially and smoothly reduces the setpoint of height (Z) until it reaches a certain threshold.</li><li>When the drone is approaching on the desirable height, the program enables grabbing system implemented on the platform. Those grips are used to catch and hold the drone in the process of landing and after the drone was caught.</li><li>When the landing is completed, the platform starts maintenance work and in order to protect the drone frome external influences, the program enables weather protection and closes the roof above landing area.</li><li>Landing accomplished!</li></ul><h3 id="short-video-about-our-project-clickable" tabindex="-1"><a class="header-anchor" href="#short-video-about-our-project-clickable" aria-hidden="true">#</a> Short video about our project (clickable)</h3><iframe width="560" height="315" src="https://www.youtube.com/embed/6qjS-iq6a3k" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><h2 id="hold-and-flight-to-waypoints-functions" tabindex="-1"><a class="header-anchor" href="#hold-and-flight-to-waypoints-functions" aria-hidden="true">#</a> 1. GPS hold and Flight to waypoints functions</h2><p>At the beginning, the drone with the package is far from the platform. Then via cellular communication or another suitable radio channel, platform GPS coordinates are sent to the drone (the Liberty-Link module is installed on the drone, this module is capable of correcting its position, regardless of the firmware of the flight controller. (The module is placed between the receiver (RC) and the flight controller)</p><p>GPS module will be built in Liberty-Link, so it would have the ability to maintain the drone's GPS position and follow GPS points.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/x364giIt6lc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>GPS-module will be used from the UBlox group (for instance, UBlox Neo-M8). There will be 1 or 3 (to minimize the error) modules.</p><p><img src="/clover-vuepress/assets/liberty-x_front_cutout_2_small_gps.51f5c6c5.png" alt="GPS Module" title="GPS Module"></p><p>Modules operate via UART, configured to send data 5 times per second. The Liberty-Link firmware will read data from the modules and calculate the coordinates of the current position.</p><h3 id="serial-reading" tabindex="-1"><a class="header-anchor" href="#serial-reading" aria-hidden="true">#</a> 1.1. Serial reading</h3><p>Reading data from a module into a buffer looks like this:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token comment">// Read data from the GPS module</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>GPS_serial<span class="token punctuation">.</span><span class="token function">available</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> new_line_found <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Stay in this loop as long as there is serial information from the GPS available</span>
<span class="token keyword">char</span> read_serial_byte <span class="token operator">=</span> GPS_serial<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>read_serial_byte <span class="token operator">==</span> <span class="token char">'$'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Clear the old data from the incoming buffer array if the new byte equals a $ character</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>message_counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> message_counter <span class="token operator"><=</span> <span class="token number">99</span><span class="token punctuation">;</span> message_counter<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
incoming_message<span class="token punctuation">[</span>message_counter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token char">'-'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Reset the message_counter variable because we want to start writing at the begin of the array</span>
message_counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// If the received byte does not equal a $ character, increase the message_counter variable</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>message_counter <span class="token operator"><=</span> <span class="token number">99</span><span class="token punctuation">)</span>
message_counter<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token comment">// Write the new received byte to the new position in the incoming_message array</span>
incoming_message<span class="token punctuation">[</span>message_counter<span class="token punctuation">]</span> <span class="token operator">=</span> read_serial_byte<span class="token punctuation">;</span>
<span class="token comment">// Every NMEA line ends with a '*'. If this character is detected the new_line_found variable is set to 1</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>read_serial_byte <span class="token operator">==</span> <span class="token char">'*'</span><span class="token punctuation">)</span> new_line_found <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="ublox-parsing" tabindex="-1"><a class="header-anchor" href="#ublox-parsing" aria-hidden="true">#</a> 1.2. UBlox GPS parsing</h3><p>After that, latitude, longitude, a type of correction (2D, 3D) and the number of satellites are calculated from the filled buffer. Parsing GPS data of the UBlox protocol looks like this:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token comment">// If the software has detected a new NMEA line it will check if it's a valid line that can be used</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>new_line_found <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Reset the new_line_found variable for the next line</span>
new_line_found <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'L'</span> <span class="token operator">&&</span> incoming_message<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'L'</span> <span class="token operator">&&</span> incoming_message<span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">','</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// When there is no GPS fix or latitude/longitude information available</span>
<span class="token comment">// Set some variables to 0 if no valid information is found by the GPS module. This is needed for the GPS loss when flying</span>
l_lat_gps <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
l_lon_gps <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
lat_gps_previous <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
lon_gps_previous <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
number_used_sats <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// If the line starts with GA and if there is a GPS fix we can scan the line for the latitude, longitude and number of satellites</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'G'</span> <span class="token operator">&&</span> incoming_message<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'A'</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">44</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'1'</span> <span class="token operator">||</span> incoming_message<span class="token punctuation">[</span><span class="token number">44</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'2'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Filter the minutes for the GGA line multiplied by 10</span>
lat_gps_actual <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">19</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">20</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">1000000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">22</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">23</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">24</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">1000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">25</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">26</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10</span><span class="token punctuation">;</span>
<span class="token comment">// To convert minutes to degrees we need to divide minutes by 6</span>
lat_gps_actual <span class="token operator">/=</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">6</span><span class="token punctuation">;</span>
<span class="token comment">// Add multiply degrees by 10</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">17</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100000000</span><span class="token punctuation">;</span>
lat_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">18</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000000</span><span class="token punctuation">;</span>
<span class="token comment">// Divide everything by 10</span>
lat_gps_actual <span class="token operator">/=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token comment">// Filter minutes for the GGA line multiplied by 10</span>
lon_gps_actual <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">33</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">34</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">1000000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">36</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">37</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">38</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">1000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">39</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">40</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10</span><span class="token punctuation">;</span>
<span class="token comment">// To convert minutes to degrees we need to divide minutes by 6</span>
lon_gps_actual <span class="token operator">/=</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">6</span><span class="token punctuation">;</span>
<span class="token comment">// Add multiply degrees by 10</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">30</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">1000000000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">100000000</span><span class="token punctuation">;</span>
lon_gps_actual <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10000000</span><span class="token punctuation">;</span>
<span class="token comment">// Divide everything by 10</span>
lon_gps_actual <span class="token operator">/=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">28</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'N'</span><span class="token punctuation">)</span>
<span class="token comment">// When flying north of the equator the latitude_north variable will be set to 1</span>
latitude_north <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token comment">// When flying south of the equator the latitude_north variable will be set to 0</span>
latitude_north <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">42</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'E'</span><span class="token punctuation">)</span>
<span class="token comment">// When flying east of the prime meridian the longiude_east variable will be set to 1</span>
longiude_east <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token comment">// When flying west of the prime meridian the longiude_east variable will be set to 0</span>
longiude_east <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// Filter the number of satillites from the GGA line</span>
number_used_sats <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">46</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token number">10</span><span class="token punctuation">;</span>
number_used_sats <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">47</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>lat_gps_previous <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">&&</span> lon_gps_previous <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// If this is the first time the GPS code is used</span>
<span class="token comment">// Set the lat_gps_previous variable to the lat_gps_actual variable</span>
lat_gps_previous <span class="token operator">=</span> lat_gps_actual<span class="token punctuation">;</span>
<span class="token comment">// Set the lon_gps_previous variable to the lon_gps_actual variable</span>
lon_gps_previous <span class="token operator">=</span> lon_gps_actual<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Divide the difference between the new and the previous latitudes by 10</span>
lat_gps_loop_add <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span><span class="token punctuation">(</span>lat_gps_actual <span class="token operator">-</span> lat_gps_previous<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">10.0</span><span class="token punctuation">;</span>
<span class="token comment">// Divide the difference between the new and the previous longitudes by 10</span>
lon_gps_loop_add <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span><span class="token punctuation">(</span>lon_gps_actual <span class="token operator">-</span> lon_gps_previous<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">10.0</span><span class="token punctuation">;</span>
<span class="token comment">// Set the l_lat_gps variable to the previous latitude value</span>
l_lat_gps <span class="token operator">=</span> lat_gps_previous<span class="token punctuation">;</span>
<span class="token comment">// Set the l_lon_gps variable to the previous longitude value</span>
l_lon_gps <span class="token operator">=</span> lon_gps_previous<span class="token punctuation">;</span>
<span class="token comment">// Remember the new latitude value in the lat_gps_previous variable for the next loop</span>
lat_gps_previous <span class="token operator">=</span> lat_gps_actual<span class="token punctuation">;</span>
<span class="token comment">// Remember the new longitude value in the lat_gps_previous variable for the next loop</span>
lon_gps_previous <span class="token operator">=</span> lon_gps_actual<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// If the line starts with SA and if there is a GPS fix we can scan the line for the fix type (none, 2D or 3D)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>incoming_message<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'S'</span> <span class="token operator">&&</span> incoming_message<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'A'</span><span class="token punctuation">)</span>
fix_type <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>incoming_message<span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">48</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="set-current-waypoint" tabindex="-1"><a class="header-anchor" href="#set-current-waypoint" aria-hidden="true">#</a> 1.3. Set current waypoint</h3><p>When required data is received the main magic happens. To enable maintaining of the current position it will be enough to set the flag <code>waypoint_set = 1;</code> and set current coordinates as a waypoint:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code>l_lat_waypoint <span class="token operator">=</span> l_lat_gps<span class="token punctuation">;</span>
l_lon_waypoint <span class="token operator">=</span> l_lon_gps<span class="token punctuation">;</span>
</code></pre></div><p>After that, the calculation of the error in the coordinates will begin, correction works with the help of a PD - regulator. For D - component we use rotation memory.</p><h3 id="waypoint-edit-to-fly-to-waypoints" tabindex="-1"><a class="header-anchor" href="#waypoint-edit-to-fly-to-waypoints" aria-hidden="true">#</a> 1.4. Waypoint edit (To fly to waypoints)</h3><p>If you just set the new <code>l_lat_waypoint</code> and <code>l_lon_wayoint</code>, which are located at a great distance from the drone, the drone will not be able to fly normally and stabilize at these coordinates. For smooth adjustments <code>l_lat_gps_float_adjust</code> and <code>l_lon_gps_float_adjust</code> can be used. These are <code>float</code> variables, changing which will smoothly shift <code>l_lat_waypoint</code> and <code>l_lon_waypoint</code>.</p><p>For example, if in the main loop you will constantly add a certain value to these variables:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code>l_lat_gps_float_adjust <span class="token operator">+=</span> <span class="token number">0.0015</span><span class="token punctuation">;</span>
</code></pre></div><p>With set waypoint, the drone will move smoothly in the given direction. In the future, this will be used for the smooth drone's acceleration and deceleration while moving to its destination.</p><h3 id="waypoint-stabilization" tabindex="-1"><a class="header-anchor" href="#waypoint-stabilization" aria-hidden="true">#</a> 1.5. Waypoint stabilization</h3><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token keyword">if</span> <span class="token punctuation">(</span>waypoint_set <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">//If the waypoints are stored</span>
<span class="token comment">// Adjust l_lat_waypoint</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>l_lat_gps_float_adjust <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
l_lat_waypoint<span class="token operator">++</span><span class="token punctuation">;</span>
l_lat_gps_float_adjust<span class="token operator">--</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>l_lat_gps_float_adjust <span class="token operator"><</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
l_lat_waypoint<span class="token operator">--</span><span class="token punctuation">;</span>
l_lat_gps_float_adjust<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Adjust l_lon_waypoint</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>l_lon_gps_float_adjust <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
l_lon_waypoint<span class="token operator">++</span><span class="token punctuation">;</span>
l_lon_gps_float_adjust<span class="token operator">--</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>l_lon_gps_float_adjust <span class="token operator"><</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
l_lon_waypoint<span class="token operator">--</span><span class="token punctuation">;</span>
l_lon_gps_float_adjust<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Calculate the latitude error between waypoint and actual position</span>
gps_lon_error <span class="token operator">=</span> l_lon_waypoint <span class="token operator">-</span> l_lon_gps<span class="token punctuation">;</span>
<span class="token comment">// Calculate the longitude error between waypoint and actual position</span>
gps_lat_error <span class="token operator">=</span> l_lat_gps <span class="token operator">-</span> l_lat_waypoint<span class="token punctuation">;</span>
<span class="token comment">// Subtract the current memory position to make room for the new value</span>
gps_lat_total_avarage <span class="token operator">-=</span> gps_lat_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// Calculate the new change between the actual pressure and the previous measurements</span>
gps_lat_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span> <span class="token operator">=</span> gps_lat_error <span class="token operator">-</span> gps_lat_error_previous<span class="token punctuation">;</span>
<span class="token comment">// Add the new value to the long term average value</span>
gps_lat_total_avarage <span class="token operator">+=</span> gps_lat_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// Subtract the current memory position to make room for the new value</span>
gps_lon_total_avarage <span class="token operator">-=</span> gps_lon_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// Calculate the new change between the actual pressure and the previous measurements</span>
gps_lon_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span> <span class="token operator">=</span> gps_lon_error <span class="token operator">-</span> gps_lon_error_previous<span class="token punctuation">;</span>
<span class="token comment">// Add the new value to the long term avarage value</span>
gps_lon_total_avarage <span class="token operator">+=</span> gps_lon_rotating_mem<span class="token punctuation">[</span>gps_rotating_mem_location<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// Increase the rotating memory location</span>
gps_rotating_mem_location<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gps_rotating_mem_location <span class="token operator">==</span> <span class="token number">35</span><span class="token punctuation">)</span>
<span class="token comment">// Start at 0 when the memory location 35 is reached</span>
gps_rotating_mem_location <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// Remember the error for the next loop</span>
gps_lat_error_previous <span class="token operator">=</span> gps_lat_error<span class="token punctuation">;</span>
gps_lon_error_previous <span class="token operator">=</span> gps_lon_error<span class="token punctuation">;</span>
<span class="token comment">//Calculate the GPS pitch and roll corrections as if the nose of the multicopter is facing north.</span>
<span class="token comment">//The Proportional part = (float)gps_lat_error * gps_p_gain.</span>
<span class="token comment">//The Derivative part = (float)gps_lat_total_avarage * gps_d_gain.</span>
gps_pitch_adjust_north <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_lat_error <span class="token operator">*</span> gps_p_gain <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_lat_total_avarage <span class="token operator">*</span> gps_d_gain<span class="token punctuation">;</span>
gps_roll_adjust_north <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_lon_error <span class="token operator">*</span> gps_p_gain <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_lon_total_avarage <span class="token operator">*</span> gps_d_gain<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>latitude_north<span class="token punctuation">)</span>
<span class="token comment">// Invert the pitch adjustmet because the quadcopter is flying south of the equator</span>
gps_pitch_adjust_north <span class="token operator">*=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>longiude_east<span class="token punctuation">)</span>
<span class="token comment">// Invert the roll adjustmet because the quadcopter is flying west of the prime meridian</span>
gps_roll_adjust_north <span class="token operator">*=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token comment">//Because the correction is calculated as if the nose was facing north, we need to convert it for the current heading.</span>
gps_roll_adjust <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_roll_adjust_north <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span>angle_yaw <span class="token operator">*</span> <span class="token number">0.017453</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_pitch_adjust_north <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span><span class="token punctuation">(</span>angle_yaw <span class="token operator">-</span> <span class="token number">90</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">0.017453</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gps_pitch_adjust <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_pitch_adjust_north <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span>angle_yaw <span class="token operator">*</span> <span class="token number">0.017453</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>gps_roll_adjust_north <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span><span class="token punctuation">(</span>angle_yaw <span class="token operator">+</span> <span class="token number">90</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">0.017453</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Limit the maximum correction to 300. This way we still have the full control of the drone with the pitch and roll sticks on the transmitter.</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gps_roll_adjust <span class="token operator">></span> <span class="token number">300</span><span class="token punctuation">)</span> gps_roll_adjust <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gps_roll_adjust <span class="token operator"><</span> <span class="token operator">-</span><span class="token number">300</span><span class="token punctuation">)</span> gps_roll_adjust <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">300</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gps_pitch_adjust <span class="token operator">></span> <span class="token number">300</span><span class="token punctuation">)</span> gps_pitch_adjust <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gps_pitch_adjust <span class="token operator"><</span> <span class="token operator">-</span><span class="token number">300</span><span class="token punctuation">)</span> gps_pitch_adjust <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">300</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="following" tabindex="-1"><a class="header-anchor" href="#following" aria-hidden="true">#</a> 2. GPS following</h2><p>The main part of stabilization using GPS coordinates was the development of an algorithm for predicting the position of the drone. The simplest idea was to use a mathematical calculation of the next drone's position. This is calculated for the most accurate positioning in relation to the landing platform.</p><p>At the beginning we developed a simple algorithm for calculating the coefficient of coordinates' change. The development was done using Python. At the stage of testing this algorithm, the problem of simulating the generation of GPS coordinates arose. To solve this problem, many different resources were used: from open source homemade navigators to trying to use the Google Maps, Yandex Maps or 2GIS APIs. And only after 3 months, we thought of a simple solution: to change the values with some delta and to visualize using MatPlotLib or PyQtGraph. Prior to this, all testing of the algorithm was carried out using the PX4 firmware toolkit and the Gazebo drone motion simulator. As a result, many formalities were overcome in terms of communicating with the simulator and increasing performance (click on the picture to see the video).</p><p>The result of the GPS prediction (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/Rg-Y_fl4BKQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>The end result reached a point when the error of the predicted position varies from 0 to 70 centimeters.</p><hr><h2 id="compass" tabindex="-1"><a class="header-anchor" href="#compass" aria-hidden="true">#</a> 3. Compass</h2><p>Before optical stabilization launches (during GPS stabilization process), to calculate the GPS correction vector, you need to know the exact angle from the compass. For this, a compass built into the GPS module is used.</p><p>Because during the flight, the roll and pitch angles change and a user needs to correct the values from the compass. In general, calculating the angle from the compass looks like this:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token comment">// The compass values change when the roll and pitch angles of the quadcopter change. That's the reason why the x and y values need to be calculated for a virtual horizontal position</span>
<span class="token comment">// The 0.0174533 value is phi/180 as the functions are in radians in stead of degrees</span>
compass_x_horizontal <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>compass_x <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span>angle_pitch <span class="token operator">*</span> <span class="token operator">-</span><span class="token number">0.0174533</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>compass_y <span class="token operator">*</span> <span class="token function">sin</span><span class="token punctuation">(</span>angle_roll <span class="token operator">*</span> <span class="token number">0.0174533</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token function">sin</span><span class="token punctuation">(</span>angle_pitch <span class="token operator">*</span> <span class="token operator">-</span><span class="token number">0.0174533</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>compass_z <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span>angle_roll <span class="token operator">*</span> <span class="token number">0.0174533</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token function">sin</span><span class="token punctuation">(</span>angle_pitch <span class="token operator">*</span> <span class="token operator">-</span><span class="token number">0.0174533</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
compass_y_horizontal <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>compass_y <span class="token operator">*</span> <span class="token function">cos</span><span class="token punctuation">(</span>angle_roll <span class="token operator">*</span> <span class="token number">0.0174533</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>compass_z <span class="token operator">*</span> <span class="token function">sin</span><span class="token punctuation">(</span>angle_roll <span class="token operator">*</span> <span class="token number">0.0174533</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Now that the horizontal values are known the heading can be calculated. With the following lines of code the heading is calculated in degrees.</span>
<span class="token comment">// Please note that the atan2 uses radians in stead of degrees. That is why the 180/3.14 is used.</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>compass_y_horizontal <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span>actual_compass_heading <span class="token operator">=</span> <span class="token number">180</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">180</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token function">atan2</span><span class="token punctuation">(</span>compass_y_horizontal<span class="token punctuation">,</span> compass_x_horizontal<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">180</span> <span class="token operator">/</span> <span class="token number">3.14</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span> actual_compass_heading <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token function">atan2</span><span class="token punctuation">(</span>compass_y_horizontal<span class="token punctuation">,</span> compass_x_horizontal<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">180</span> <span class="token operator">/</span> <span class="token number">3.14</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Add the declination to the magnetic compass heading to get the geographic north</span>
actual_compass_heading <span class="token operator">+=</span> declination<span class="token punctuation">;</span>
<span class="token comment">// If the compass heading becomes smaller than 0, 360 is added to keep it in the 0-360 degrees range</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>actual_compass_heading <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> actual_compass_heading <span class="token operator">+=</span> <span class="token number">360</span><span class="token punctuation">;</span>
<span class="token comment">// If the compass heading becomes larger then 360, 360 is subtracted to keep it in the 0-360 degrees range</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>actual_compass_heading <span class="token operator">>=</span> <span class="token number">360</span><span class="token punctuation">)</span> actual_compass_heading <span class="token operator">-=</span> <span class="token number">360</span><span class="token punctuation">;</span>
</code></pre></div><p>It is clear that the angle from the compass can also be used to maintain the yaw angle of the drone. With point-to-point flights, this may be realized. But at the moment, there is no urgent need for this, because after the start of optical stabilization, the algorithm is able to correct the drone regardless of its yaw angle. Also, during optical stabilization, the yaw angle is automatically corrected.</p><hr><h2 id="altitude-stabilization-barometer" tabindex="-1"><a class="header-anchor" href="#altitude-stabilization-barometer" aria-hidden="true">#</a> 4. Altitude stabilization (barometer)</h2><p>Before optical stabilization launches (during GPS stabilization process), our Liberty-Link module will be able to maintain altitude using a barometer.</p><p>The platform, as well as the Liberty-Link, will have MS5611 barometers.</p><p><img src="/clover-vuepress/assets/ms5611_barometer.cbd68a83.png" alt="MS5611" title="MS5611"></p><p>According to the documentation, the height resolution is 10 cm. The algorithm will take the pressure values and by passing it through the PID-controller will stabilize the drone's altitude by changing the Throttle (3rd channel).</p><p>Altitude hold test (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/xmvcGeZzEfc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>During the flight along the waypoint, the setpoint of the pressure will decrease in order to increase the altitude (it is safer to fly in a straight line at a high altitude, so the drone would not crash into anything). And during GPS stabilization (when the drone is already close to the platform), the drone will be set with a setpoint of pressure that correlates with ~ 1.5-2m height above the platform.</p><hr><h2 id="optical-stabilization" tabindex="-1"><a class="header-anchor" href="#optical-stabilization" aria-hidden="true">#</a> 5. Optical stabilization</h2><h3 id="so-difficult-and-so-important" tabindex="-1"><a class="header-anchor" href="#so-difficult-and-so-important" aria-hidden="true">#</a> 5.1. So difficult and so important</h3><p>Optical stabilization is the most important and challenging part of our project. In the current condition it is possible to keep the drone above the platform still only using these algorithms. The current version of the OIS algorithm, along with a description of the usage and making, is available in our main GitHub repository. In the future, GPS stabilization will be added to it.</p><h3 id="first-steps" tabindex="-1"><a class="header-anchor" href="#first-steps" aria-hidden="true">#</a> 5.2. First steps</h3><p>And as we couldn't predict the possibility of accomplishing our task, first of all, we started to think about the solution for the stabilization system. Afterwards, we settled with the stabilization using augmented reality tags. Firstly, it won't take much finances as we do not need GPS or RTK systems and it will be accurate enough to accomplish its purpose. Our first idea was to attach Raspberry Pi with Liberty_X as it was embodied in COEX Clover and to let Raspberry Pi handle all of the maths.</p><p>First optical stabilization prototype test (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/TrrxXOHAqbQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>But few tests showed that Raspberry Pi computing power is not enough for amount of data needed to stabilize the drone. Furthermore, the idea of installing a Raspberry Pi on each drone is irrational for its own.</p><p>Also, we had middling prototypes, for example, attempts to use color markers (circles of different colors), but these ideas did not work well enough.</p><h3 id="inverse-approach" tabindex="-1"><a class="header-anchor" href="#inverse-approach" aria-hidden="true">#</a> 5.3. Inverse approach</h3><p>Then we came up with the idea of separating drone and stabilization system so the main math will be accomplished on the landing platform with powerful machine.</p><p>This was how we ended up with our current optical stabilization algorithm - the camera which is connected to a powerful machine and the machine is attached to the platform. The drone only has 4x4 ArUco tag and its controller.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/A2oq6zCebVo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>Then, we came up with using Pose Estimation algorithms from OpenCV library. The first tests showed us that we are on the right track!</p><p>Pose Estimation Python (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/kE3UmJZ00so" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>But, the algorithms were far from perfect. For example, since the code was written in Python (<a href="https://github.com/XxOinvizioNxX/Liberty-X_Point" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Liberty-X_Point<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>), the performance was not satisfyingly, and there was no suitable threading control either. Therefore, we had to change something.</p><h3 id="java-edition" tabindex="-1"><a class="header-anchor" href="#java-edition" aria-hidden="true">#</a> 5.4. Java edition</h3><p>Having weighed all the pros and cons, it was decided to rewrite all optical stabilization using Java. This is how the first version of Liberty-Way appeared. This time, it was decided to approach the OOP thoroughly, and, after a little tweaking, an excellent stabilization and landing algorithm was obtained.</p><p>Landing test on Liberty-Way v.beta_0.0.1 (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/8VAobWPFG8g" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><h3 id="liberty-way" tabindex="-1"><a class="header-anchor" href="#liberty-way" aria-hidden="true">#</a> 5.5. Liberty-Way</h3><p>Then many improvements and bug fixes followed. As a result, Liberty-Way is a cross-platform web sarvar application that is very convenient for configuration and debugging. Also, in the latest versions (beta_1.0.3 - beta_1.1.2) a blackbox feature was introduced (for recording logs), as well as communication with the platform and many other necessary algorithms.</p><p>Full description, including all settings, startup, etc. you can find in our GitHub repository: <a href="https://github.com/XxOinvizioNxX/Liberty-Way" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Liberty-Way<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p>Video of static stabilization (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/adR38R27MEU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>Liberty-Way can even stabilize a "thrown" drone (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/gAaGQSC-r2g" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>There is a small bug in the video with the rotation angle, in the new release it has been fixed!</p><p>And, of course, example of how it works in motion (tested with beta_0.0.3 release) (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/8vB-8QIBoJU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>All basic settings are conveniently placed in separate JSON files (settings, PID), which allows a user to quickly change the required parameters without rebuilding the application. In fact, to run the application, you just need to download the latest release, unpack the archive and run it through the launcher corresponding to the preferable OS.</p><h3 id="communication-with-the-drone" tabindex="-1"><a class="header-anchor" href="#communication-with-the-drone" aria-hidden="true">#</a> 5.6. Communication with the drone</h3><p>The Liberty-Way connects to the Liberty-Link module installed on the drone and adjusts its position by directly controlling four main channels of the remote control. In one cycle (each frame from the camera), 12 bytes of correction data are sent to the module: <img src="/clover-vuepress/assets/data_structure.5198548c.png" alt="Packet" title="Data packet"></p><p>Bytes description:</p><ul><li><strong>Roll bytes</strong> - Roll correction values</li><li><strong>Pitch bytes</strong> - Pitch correction values</li><li><strong>Yaw bytes</strong> - Yaw correction values</li><li><strong>Altitude bytes</strong> - Altitude correction values</li><li><strong>Service info</strong> - sets the drone state (0 - Nothing to do, 1 - Stabilization, 2 - Landing (command not implemented and will be removed in the future. This is not a real landing, just to tell the drone to start decreasing altitude), 3 - Disable motors)</li><li><strong>Check byte</strong> - XOR sum of all previous bytes that is compared via transmittion in order to verify the data</li><li><strong>Data suffix</strong> - unique pair of ASCII symbols that is not represented in the packet in any form and that shows the end of the packet</li></ul><p>On the drone side (Liberty-Link module), data reading is performing as follows:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token keyword">while</span> <span class="token punctuation">(</span>Telemetry_serial<span class="token punctuation">.</span><span class="token function">available</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tdc_receive_buffer<span class="token punctuation">[</span>tdc_receive_buffer_counter<span class="token punctuation">]</span> <span class="token operator">=</span> Telemetry_serial<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>tdc_receive_byte_previous <span class="token operator">==</span> <span class="token char">'L'</span> <span class="token operator">&&</span> tdc_receive_buffer<span class="token punctuation">[</span>tdc_receive_buffer_counter<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'X'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tdc_receive_buffer_counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>tdc_receive_start_detect <span class="token operator">>=</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tdc_check_byte <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>tdc_temp_byte <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> tdc_temp_byte <span class="token operator"><=</span> <span class="token number">8</span><span class="token punctuation">;</span> tdc_temp_byte<span class="token operator">++</span><span class="token punctuation">)</span>
tdc_check_byte <span class="token operator">^=</span> tdc_receive_buffer<span class="token punctuation">[</span>tdc_temp_byte<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>tdc_check_byte <span class="token operator">==</span> tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
direct_roll_control <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator"><<</span> <span class="token number">8</span><span class="token punctuation">;</span>
direct_pitch_control <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator"><<</span> <span class="token number">8</span><span class="token punctuation">;</span>
direct_yaw_control <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator"><<</span> <span class="token number">8</span><span class="token punctuation">;</span>
direct_throttle_control <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">]</span> <span class="token operator"><<</span> <span class="token number">8</span><span class="token punctuation">;</span>
direct_service_info <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">uint32_t</span><span class="token punctuation">)</span>tdc_receive_buffer<span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>direct_roll_control <span class="token operator">></span> <span class="token number">1100</span> <span class="token operator">&&</span> direct_roll_control <span class="token operator"><</span> <span class="token number">1900</span> <span class="token operator">&&</span>
direct_pitch_control <span class="token operator">></span> <span class="token number">1100</span> <span class="token operator">&&</span> direct_pitch_control <span class="token operator"><</span> <span class="token number">1900</span> <span class="token operator">&&</span>
direct_yaw_control <span class="token operator">></span> <span class="token number">1100</span> <span class="token operator">&&</span> direct_yaw_control <span class="token operator"><</span> <span class="token number">1900</span> <span class="token operator">&&</span>
direct_throttle_control <span class="token operator">></span> <span class="token number">1100</span> <span class="token operator">&&</span> direct_throttle_control <span class="token operator"><</span> <span class="token number">1900</span> <span class="token operator">&&</span>
<span class="token comment">/*flight_mode == 2 &&*/</span> channel_7 <span class="token operator">></span> <span class="token number">1500</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tdc_timer <span class="token operator">=</span> <span class="token function">millis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
tdc_working <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
tdc_working <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
direct_roll_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
direct_pitch_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
tdc_working <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span>
tdc_receive_start_detect<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
tdc_receive_byte_previous <span class="token operator">=</span> tdc_receive_buffer<span class="token punctuation">[</span>tdc_receive_buffer_counter<span class="token punctuation">]</span><span class="token punctuation">;</span>
tdc_receive_buffer_counter<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>tdc_receive_buffer_counter <span class="token operator">></span> <span class="token number">11</span><span class="token punctuation">)</span>tdc_receive_buffer_counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">millis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> tdc_timer <span class="token operator">>=</span> <span class="token number">500</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tdc_working <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>tdc_working <span class="token operator">&&</span> direct_service_info <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">&&</span> <span class="token operator">!</span>return_to_home_step<span class="token punctuation">)</span>
return_to_home_step <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>tdc_working<span class="token punctuation">)</span>
return_to_home_step <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>tdc_working <span class="token operator">||</span> direct_service_info <span class="token operator"><</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
direct_roll_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
direct_pitch_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
direct_yaw_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
direct_throttle_control <span class="token operator">=</span> <span class="token number">1500</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>As a result, there are 4 variables:</p><div class="language-text ext-text"><pre class="language-text"><code>direct_roll_control
direct_pitch_control
direct_yaw_control
direct_throttle_control
</code></pre></div><p>Which are directly added to the data received from the control panel. Probably, in the future, other data will be added, at least for working with GPS. Stay tuned for updates in our repository.</p><h3 id="camera-gimbal" tabindex="-1"><a class="header-anchor" href="#camera-gimbal" aria-hidden="true">#</a> 5.7. Camera gimbal</h3><p>To operate our system in real conditions, it is required to minimize camera shaking if we don't want to lose the tag on the drone. For that reason, a 3D model of a gimbal for attaching the drone to the platform was developed to stabilize a conventional webcam.</p><p>Camera mount:</p><p><img src="/clover-vuepress/assets/gimbal_camera_mount.f4e239ff.png" alt="Camera mount" title="Camera mount"></p><p>Camera wire fixing (ferrite filter on the wire):</p><p><img src="/clover-vuepress/assets/gimbal_filter_mount.648325eb.png" alt="Filter mount" title="Filter mount"></p><p>Fixing of the "crabs" latches on the suspension substrate:</p><p><img src="/clover-vuepress/assets/gimbal_plane_mount.7beb93d0.png" alt="Plane mount" title="Plane mount"></p><p>An approximate view of the assembly of the entire suspension mechanism:</p><p><img src="/clover-vuepress/assets/gimbal_assembly.8a3e4f2f.png" alt="Assembly" title="Assembly"></p><hr><h2 id="eitude-amls-platform" tabindex="-1"><a class="header-anchor" href="#eitude-amls-platform" aria-hidden="true">#</a> 6. Eitude AMLS Platform</h2><p>The platform is an interconnected system for landing the drone. The platform was planned to be controlled via the Serial interface, using the G-Code commands: The current platform code can be found in the Eitude GitHub repository: <a href="https://github.com/XxOinvizioNxX/Eitude" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Eitude<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><h3 id="grabbing-system" tabindex="-1"><a class="header-anchor" href="#grabbing-system" aria-hidden="true">#</a> 6.1. Grabbing system</h3><p>As you may know it doesn't matter how good is our stabilization, without grabbing system the drone will crash eventually. Hence we developed a 3D model of a grabbing system with 4 grips that have a hook at the end of each one. This will allow the system to slowly grab the drone while it lands and hold it steady after landing.</p><p><img src="/clover-vuepress/assets/grabbing_system_1.095fdfb2.png" alt="Screenshot" title="Screenshot"></p><p><img src="/clover-vuepress/assets/grabbing_system_2.ef5115eb.png" alt="Screenshot" title="Screenshot"></p><h3 id="weather-protection-system" tabindex="-1"><a class="header-anchor" href="#weather-protection-system" aria-hidden="true">#</a> 6.2. Weather protection system</h3><p>As for the weather protection, we developed a 3D model to create a roof that will protect the drone from weather conditions while it is on the platform. The AMLS weather protection system consists of scissor-like mechanisms covered with a canvas, which are located around the edges of the platform. After a successful landing, the mechanisms on both sides of the platform close and protect the drone from external influences. The roof structure itself makes it light and strong, and the scissor-like mechanisms allow it to simply fold and unfold itself. Moreover, the assembly of such mechanisms will be simple and reliable.</p><p><img src="/clover-vuepress/assets/platform_side_transparent.9dc49b02.png" alt="Screenshot" title="Screenshot"></p><p><img src="/clover-vuepress/assets/platform_roof.95d0b6eb.png" alt="Screenshot" title="Screenshot"></p><h3 id="platform-speedometer" tabindex="-1"><a class="header-anchor" href="#platform-speedometer" aria-hidden="true">#</a> 6.3. Platform speedometer</h3><p>In order to land on a quickly moving platform, it is very useful to know its speed. For now, the platform does not have a GPS module, or any other way to measure absolute speed. Therefore, for a temporary solution to this problem, it was decided to calculate the speed using an accelerometer. For example, MPU6050. The IMU is mounted into the prototype platform through a soft backing and it's covered with a cap to protect it from the wind. The stabilization algorithm (Liberty-Way) sends a request to the platform <code>L1</code> to test the speed. A message <code>S0 L <speed in km / h></code> is returned as a response.</p><p><img src="/clover-vuepress/assets/mpu6050_gyro.edd8fb87.png" alt="MPU6050" title="MPU6050"></p><p>Speedometer test (inside the gray circle, lower right parameter (SPD) - speed in km / h) (Clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/yvCo6tYjdM0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>To calculate the speed, the acceleration is taken for short time periods, then multiplied with time, which results with the instantaneous speed. Then this speed is constantly added to the previous value:</p><div class="language-cpp ext-cpp"><pre class="language-cpp"><code><span class="token keyword">void</span> <span class="token function">speed_handler</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">gyro_signalen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Filter accelerations</span>
acc_x_filtered <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>acc_x_filtered <span class="token operator">*</span> ACC_FILTER_KOEFF <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span>acc_x <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1.0</span> <span class="token operator">-</span> ACC_FILTER_KOEFF<span class="token punctuation">)</span><span class="token punctuation">;</span>
speed <span class="token operator">=</span> acc_x_filtered<span class="token punctuation">;</span>
<span class="token comment">// Convert acceleration to G</span>
speed <span class="token operator">/=</span> <span class="token number">4096.0</span><span class="token punctuation">;</span>
<span class="token comment">// Convert to m/s^2</span>
speed <span class="token operator">*=</span> <span class="token number">9.81</span><span class="token punctuation">;</span>
<span class="token comment">// Multiply by dt to get instant speed in m/ms</span>
speed <span class="token operator">*=</span> <span class="token punctuation">(</span><span class="token function">millis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> speed_loop_timer<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Reset timer</span>
speed_loop_timer <span class="token operator">=</span> <span class="token function">millis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Convert to m/s</span>
speed <span class="token operator">/=</span> <span class="token number">1000.0</span><span class="token punctuation">;</span>
<span class="token comment">// Convert to km/h</span>
speed <span class="token operator">*=</span> <span class="token number">3.6</span><span class="token punctuation">;</span>
<span class="token comment">// Accumulate instantaneous speed</span>
speed_accumulator <span class="token operator">+=</span> speed<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>in_move_flag<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// If the platform is not moving, reset the speed</span>
speed_accumulator <span class="token operator">=</span> speed_accumulator <span class="token operator">*</span> SPEED_ZEROING_FACTOR<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Despite having various filters, due to the error, the speed may not "return" to 0, therefore, vibrations are also measured, and if they are less than the certain threshold, it is considered that the platform is at a standstill and the speed gradually resets to zero.</p><p>The complete code of the speedometer can be found in the Eitude repository on GitHub: <a href="https://github.com/XxOinvizioNxX/Eitude" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Eitude<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><h3 id="platform-light-sensor" tabindex="-1"><a class="header-anchor" href="#platform-light-sensor" aria-hidden="true">#</a> 6.4. Platform light sensor</h3><p>As our platform must work in various environmental conditions, and optical stabilization is very demanding on the visibility of the ArUco marker, it is important to have an automatic system for measuring the camera exposure by the level of illumination around it, and turning on additional illumination if there is a lack of lighting. In the long term, it is planned to use specialized sensors, for example, the BH1750, as light sensors.</p><p>In the current version of the prototype, 6 LEDs are used as a light sensor and an ADC built into the microcontroller. The stabilization algorithm (Liberty-Way) sends a request <code>L0</code> to the platform to check the illumination level. A message <code>S0 L <luminance></code> is returned as a response.</p><p><img src="/clover-vuepress/assets/light_sensors.878ff57e.png" alt="Light sensors" title="Light sensors"></p><p>Test for determining the level of illumination using LEDs (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/xQeiA945aRA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>Exposure adjustment and adding additional illumination tests (clickable):</p><iframe width="560" height="315" src="https://www.youtube.com/embed/iMORim6zxsg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><hr><h2 id="conclusion" tabindex="-1"><a class="header-anchor" href="#conclusion" aria-hidden="true">#</a> 7. Conclusion</h2><p>At the moment, there is a debugged prototype of optical stabilization, GPS holding, altitude stabilization via barometer, different platform prototypes and a great amount of 3D models eager to be constructed. The project of the automatical landing of a drone onto a moving platform is not yet complete.</p><p>Follow the updates:</p><ul><li>In our repository GitHub: <a href="https://github.com/XxOinvizioNxX/Liberty-Way" target="_blank" rel="noopener noreferrer">https://github.com/XxOinvizioNxX/Liberty-Way<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li><li>On our YouTube channel: <a href="https://www.youtube.com/channel/UCqN12Jzy-1eJLkcA32R0jdg" target="_blank" rel="noopener noreferrer">https://www.youtube.com/channel/UCqN12Jzy-1eJLkcA32R0jdg<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li></ul><p>In the future, we plan to do much more new and interesting stuff!</p><p><img src="/clover-vuepress/assets/follow_the_white_rabbit.d964d129.png" alt="Follow the white rabbit" title="Follow the white rabbit"></p><!--]--></div><footer class="page-meta"><div class="meta-item edit-link"><a class="external-link meta-item-label" href="https://github.com/CopterExpress/clover/edit/master/docs/en/amls.md" rel="noopener noreferrer" target="_blank" aria-label="Edit this page"><!--[--><!--]--> Edit this page <span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!--[--><!--]--></a></div><!----><!----></footer><!----><!--[--><!--]--></main><!--]--></div><!----><!--]--></div>
<script type="module" src="/clover-vuepress/assets/app.4f6a4bec.js" defer></script>
</body>
</html>