Skip to content

Commit 8133adc

Browse files
committed
Merge pull request #559 from dronekit/flight-replay-localfile
Rejig flight replay example to use a telemetry log peter.barker 5:08 PM All looks good to me. You OK if I merge that one? hamishwillee 5:08 PM Yes please!
2 parents 4b9dfa8 + ba1d104 commit 8133adc

File tree

4 files changed

+341
-152
lines changed

4 files changed

+341
-152
lines changed

docs/examples/flight_replay.rst

Lines changed: 132 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1-
=========================
1+
======================
22
Example: Flight Replay
3-
=========================
3+
======================
44

5-
This example requests a past flight from Droneshare, and then writes the recorded path to the vehicle as mission waypoints.
6-
For safety reasons, the altitude for the waypoints is set to 30 meters (irrespective of the recorded height).
5+
This example creates and runs a waypoint mission using position information from a TLOG file.
76

8-
.. note::
7+
The log used in this example contains around 2700 points. This is too many points to upload
8+
to the autopilot (and to usefully display). Instead we only add points that are more than
9+
3 metres away from the previously kept point, and only store 99 points in total.
10+
After 60 seconds the mission is ended by setting the mode to RTL (return to launch).
911

10-
The mission is not actually run by this code - though it easily could be by taking off and putting the vehicle into
11-
AUTO mode.
12+
.. figure:: flight_replay_example.png
13+
:width: 50%
1214

15+
99 point mission generated from log
1316

14-
You can specify which mission to replay using a parameter when starting the script (for example, to replay your own local flights).
15-
By default the code gets the public `Droneshare mission with ID 101 <http://www.droneshare.com/mission/101>`_.
1617

17-
.. figure:: flight_replay_example.png
18+
.. note::
1819

19-
Droneshare Mission #101
20+
The method used to reduce the number of points is fairly effective, but we
21+
could do better by grouping some of the waypoints, and mapping others using
22+
spline waypoints. This might be a
23+
`fun research project <https://github.com/dronekit/dronekit-python/issues/561>`_!
2024

2125

2226

@@ -26,82 +30,155 @@ Running the example
2630
The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
2731
and DroneKit have been set up as described in :ref:`installing_dronekit`).
2832

29-
If you're using a simulated vehicle, remember to :ref:`disable arming checks <disable-arming-checks>` so
30-
that the example can run.
31-
3233
In summary, after cloning the repository:
3334

3435
#. Navigate to the example folder as shown:
3536

3637
.. code-block:: bash
3738
3839
cd dronekit-python/examples/flight_replay/
39-
40-
41-
#. Start the example, passing the :ref:`connection string <get_started_connect_string>`
42-
you wish to use in the ``--connect`` parameter and specifying the mission to replay.
40+
41+
#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
42+
The example will download SITL binaries if needed, start the simulator, and then connect to it:
4343

4444
.. code-block:: bash
4545
46-
python flight_replay.py --connect 127.0.0.1:14550 --mission_id 101
46+
python flight_replay.py
4747
48-
.. note::
48+
On the command prompt you should see (something like):
4949

50-
The ``--connect`` parameter above connects to SITL on udp port 127.0.0.1:14550, while
51-
``--mission_id`` specifies we're replaying mission 101. Both of these are the default
52-
values for the parameters, and may be omitted.
53-
50+
.. code:: bash
51+
52+
Generating waypoints from tlog...
53+
Generated 100 waypoints from tlog
54+
Starting copter simulator (SITL)
55+
SITL already Downloaded.
56+
Connecting to vehicle on: tcp:127.0.0.1:5
57+
>>> APM:Copter V3.3 (d6053245)
58+
>>> Frame: QUAD
59+
>>> Calibrating barometer
60+
>>> Initialising APM...
61+
>>> barometer calibration complete
62+
>>> GROUND START
63+
Uploading 100 waypoints to vehicle...
64+
Arm and Takeoff
65+
Waiting for vehicle to initialise...
66+
>>> flight plan received
67+
Waiting for arming...
68+
Waiting for arming...
69+
Waiting for arming...
70+
Waiting for arming...
71+
>>> ARMING MOTORS
72+
>>> GROUND START
73+
Waiting for arming...
74+
>>> Initialising APM...
75+
Waiting for arming...
76+
>>> ARMING MOTORS
77+
Taking off!
78+
Altitude: 0.000000 < 28.500000
79+
Altitude: 0.010000 < 28.500000
80+
...
81+
Altitude: 26.350000 < 28.500000
82+
Altitude: 28.320000 < 28.500000
83+
Reached target altitude of ~30.000000
84+
Starting mission
85+
Distance to waypoint (1): 3.02389745499
86+
>>> Reached Command #1
87+
Distance to waypoint (2): 5.57718471895
88+
Distance to waypoint (2): 4.1504263025
89+
>>> Reached Command #2
90+
Distance to waypoint (3): 0.872847106279
91+
Distance to waypoint (3): 1.88967925144
92+
Distance to waypoint (3): 2.16157704522
93+
>>> Reached Command #3
94+
Distance to waypoint (4): 4.91867197924
95+
...
96+
...
97+
Distance to waypoint (35): 4.37309981133
98+
>>> Reached Command #35
99+
Distance to waypoint (36): 5.61829417257
100+
>>> Reached Command #36
101+
Return to launch
102+
Close vehicle object
103+
Completed...
104+
105+
106+
.. tip::
107+
It is more interesting to watch the example run on a map than the console. The topic :ref:`viewing_uav_on_map`
108+
explains how to set up *Mission Planner* to view a vehicle running on the simulator (SITL).
54109

55-
.. tip::
56-
57-
It is more interesting to watch the example above on a map than the console. The topic :ref:`viewing_uav_on_map`
58-
explains how to set up *Mission Planner* to view a vehicle running on the simulator (SITL).
110+
#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string <get_started_connect_string>` for your vehicle in the ``--connect`` parameter.
59111

60-
On the command prompt you should see (something like):
112+
For example, to connect to SITL running on UDP port 14550 on your local computer:
61113

62-
.. code-block:: bash
63-
64-
Connecting to vehicle on: 127.0.0.1:14550
65-
>>> APM:Copter V3.3 (d6053245)
66-
>>> Frame: QUAD
67-
JSON downloaded...
68-
Generating 95 waypoints from replay...
69-
Close vehicle object
70-
Completed...
114+
.. code-block:: bash
71115
116+
python simple_goto.py --connect 127.0.0.1:14550
117+
72118
119+
73120
How it works
74121
============
75122

76-
The example requests the web server for representative points from the flight, parses the JSON response
77-
and uses that data to generate 100 waypoints. These are then sent to the vehicle.
78-
79-
80123
Getting the points
81124
------------------
82125

83-
The following simple function asks for the droneshare flight data:
126+
The example parses the **flight.tlog** file for position information. First we read all the points.
127+
We then keep the first 99 points that are at least 3 metres separated from the preceding kept point.
84128

85-
.. code:: python
129+
For safety reasons, the altitude for the waypoints is set to 30 meters (irrespective of the recorded height).
86130

87-
def download_messages(mission_id, max_freq = 1.0):
88-
"""Download a public mission from droneshare (as JSON)"""
89-
f = urllib.urlopen("%s/api/v1/mission/%s/messages.json?max_freq=%s&api_key=%s" % (api_server, mission_id, max_freq, api_key))
90-
j = json.load(f, object_hook=_decode_dict)
91-
f.close()
92-
return j
131+
.. code:: python
93132
94-
Some comments:
133+
def position_messages_from_tlog(filename):
134+
"""
135+
Given telemetry log, get a series of wpts approximating the previous flight
136+
"""
137+
# Pull out just the global position msgs
138+
messages = []
139+
mlog = mavutil.mavlink_connection(filename)
140+
while True:
141+
try:
142+
m = mlog.recv_match(type=['GLOBAL_POSITION_INT'])
143+
if m is None:
144+
break
145+
except Exception:
146+
break
147+
# ignore we get where there is no fix:
148+
if m.lat == 0:
149+
continue
150+
messages.append(m)
151+
152+
# Shrink the number of points for readability and to stay within autopilot memory limits.
153+
# For coding simplicity we:
154+
# - only keep points that are with 3 metres of the previous kept point.
155+
# - only keep the first 100 points that meet the above criteria.
156+
num_points = len(messages)
157+
keep_point_distance=3 #metres
158+
kept_messages = []
159+
kept_messages.append(messages[0]) #Keep the first message
160+
pt1num=0
161+
pt2num=1
162+
while True:
163+
#Keep the last point. Only record 99 points.
164+
if pt2num==num_points-1 or len(kept_messages)==99:
165+
kept_messages.append(messages[pt2num])
166+
break
167+
pt1 = LocationGlobalRelative(messages[pt1num].lat/1.0e7,messages[pt1num].lon/1.0e7,0)
168+
pt2 = LocationGlobalRelative(messages[pt2num].lat/1.0e7,messages[pt2num].lon/1.0e7,0)
169+
distance_between_points = get_distance_metres(pt1,pt2)
170+
if distance_between_points > keep_point_distance:
171+
kept_messages.append(messages[pt2num])
172+
pt1num=pt2num
173+
pt2num=pt2num+1
174+
175+
return kept_messages
95176
96-
* ``max_freq`` is used to throttle the messages found in the raw flight data to a lower message rate
97-
* ``_decode_dict`` is a utility function found on stack overflow which extracts usable strings from unicode encoded JSON (see `flight_replay.py <https://github.com/hamishwillee/dronekit-python/blob/master/examples/flight_replay/flight_replay.py>`_ for its implementation).
98177
99178
100179
Setting the new waypoints
101180
-------------------------
102181

103-
If necessary, the example then reduces the number of messages retrieved into a set that can fit on the vehicle (in this case 100 waypoints).
104-
105182
The following code shows how the vehicle writes the received messages as commands (this part of the code is very similar to that
106183
shown in :ref:`example_mission_basic`):
107184

-181 KB
Loading

examples/flight_replay/flight.tlog

2.6 MB
Binary file not shown.

0 commit comments

Comments
 (0)