Post-mission review of ArduPilot dataflash (.bin) logs: a tool for the
desktop and the browser, written in Rust on
egui, reading logs
through dflog and drawing the map
with walkers. It is for looking
at what a vehicle did after the flight, drive or dive: plotting any field
of any message against time, over the flight modes, with the values under
the cursor read out, the track on a map, the log's events in a list and
its parameters in a table, the whole flight played back across them, a
second flight compared beside it, and the data out again as CSV, a
.param file or Parquet.
The pictures are of the demo log, which the app generates on the spot:
a quadcopter arms on a field in Iowa, climbs to 50 m, flies six survey
legs of 400 m in a crosswind, has its speed raised from the ground
station and its GPS fail for two seconds on the way, and returns to
land, eight and a half minutes in all. Every value in it is invented,
the date included. File > Open demo log opens it, as do the Demo button
of the empty window and ?demo on the web page's address: the demo
in the browser. File > Open demo
pair opens it beside a second sortie from the same field two hours later,
flown on retuned gains in a stronger wind with PID logging on, which the
first does not have, to try comparing two logs: the pair in the
browser. Map
tiles © OpenStreetMap
contributors.
The demo pair compared: both flights' pitch lined up at arming, the second sortie's lighter line leaning further into its stronger wind, read out with the difference at the cursor, over the five parameters whose values differ between the two.
Builds for Windows, Linux and macOS come with each release on the releases page, one archive per system:
| System | Archive |
|---|---|
| Windows, x86-64 | aftermission-<version>-x86_64-pc-windows-msvc.zip |
| Linux, x86-64 | aftermission-<version>-x86_64-unknown-linux-gnu.tar.gz |
| macOS, Apple silicon | aftermission-<version>-aarch64-apple-darwin.tar.gz |
| macOS, Intel | aftermission-<version>-x86_64-apple-darwin.tar.gz |
Each archive holds the program, the license, the licensing note, this
README and the third-party notices; SHA256SUMS beside them lists their
checksums. The programs are not signed, which each system meets in its
own way:
- Windows may stop the program with "Windows protected your PC", as it does any unsigned program from the internet; More info > Run anyway starts it.
- macOS keeps a downloaded archive's contents in quarantine and
refuses an unsigned program with "cannot be opened because the
developer cannot be verified". After extracting,
xattr -d com.apple.quarantine aftermissionlets it run, from the terminal or by a double-click. There is no.appbundle yet, so the Dock shows a generic icon. - Linux needs, at run time, the X11 or Wayland client libraries and xkbcommon, and for the file dialogs a running xdg-desktop-portal with a backend (GTK, GNOME or KDE). A full desktop has all of them; under a bare window manager without the portal, File > Open and the save dialogs do nothing, and a log opens from the command line. The program is built on Ubuntu 24.04, so it needs glibc 2.39 or later.
The tool is early. What works today:
- Opening a log by drag and drop, the file dialog (Ctrl+O) or a path on the command line. The file is mapped and indexed on a worker thread, so the window stays live; the last eight logs are kept under File > Open recent. File > Open demo log opens the demo flight above, to try the tool without a log at hand. The items that open a log wait while another is being indexed or an export written.
- The side panel lists every message type in the log with its record
count, and unfolds each to its fields, labeled with the units the log's
own
UNIT,MULTandFMTUrecords give them (Roll (deg),GyrX (rad/s)). A type logged in several instances, such asIMUon a board with three, unfolds toIMU[0],IMU[1]and so on, each with its own fields. A filter box narrows the list by type or field name. - The plot draws any number of fields at once. Each series sits on the left or the right axis, chosen from its chip above the plot; the right axis is scaled to the series on it and labeled in their values. Drag or scroll to pan, Ctrl+scroll or pinch to zoom, right-drag a box to zoom into it, double-click to see the whole flight again. Long series are thinned to the pixels on screen, keeping every spike. A legend names the series, and the readout under the plot gives every series' value at the cursor.
- Time reads in seconds since boot, or in UTC through the first GPS fix
(View > Time axis). Fields are converted to their unit where the log
says how, so
TimeUSplots in seconds. - Flight modes from the
MODErecords show as colored bands behind the plot, named per vehicle (Copter, Plane, Rover, Sub, AntennaTracker and Blimp mode tables), the vehicle read from the firmware banner. - The map draws the vehicle's track from the EKF's
POSrecords, or fromGPSwhen a log has none, over OpenStreetMap tiles, with the plot's cursor marked on it by an arrow along the vehicle's heading: the yaw of theATTrecords, or the course over the ground in a log without them. Hovering the track reads a point's time and altitude; a click seeks the plot to it. The tiles come fromtile.openstreetmap.orgunder its usage policy, cached on disk next to the settings; View > Map tiles turns them off, and the track then draws on a plain background with nothing downloaded. - Events: the
MSGtexts, theERRfaults andEVevents named per ArduPilot's tables, the mode changes and the parameter changes after boot, in one list in time order with a toggle per kind and a filter; parameter changes start hidden, since a mission upload can log dozens. A click on a row seeks the plot and the map to its time; the row the cursor has passed is highlighted, and a seek from the map or a parameter change scrolls the list to it, on the next switch to the tab when it was not showing. While the log plays, the list keeps the highlighted row in view; once you scroll it yourself, it stays put until the pointer leaves it; on a touch screen, until the next seek or a tap outside it. - Parameters: a tab beside the events with every
PARMname, its last value, its default where the log records one, and how often it changed after boot. A changed parameter unfolds to its history, the boot value first; a click on a change seeks the plot and the map to it. Toggles narrow the table to parameters off their default or changed after boot, and a filter to a name. - Comparing two logs: File > Compare with… opens a second log, B, beside the one under review, A, named in a row above the plot with a button that closes it and one that swaps the two; two files dropped on the window together open as A and B (desktop). Every series on the plot draws B's samples too, in its color but lighter, lined up with A's at arming, at the start, by UTC, or by an offset set by hand, and the readout gives B's value and the difference from A's. Opening another log as A closes B, so the two on screen are always a pair chosen together.
- B in the other panels: the parameter table shows B's values beside A's, and Differences narrows it to the parameters both logs have whose values differ at boot or at the end, with the values the autopilot learns by itself from flight to flight, such as the hover throttle, and the names only one log has, each added by a toggle of its own. What B logs and A does not, such as a newer firmware's messages and fields or those a logging setting adds, is listed under A's types as Only in B, to plot from B alone. The map draws B's track beside A's in a lighter orange with a marker of its own, the events list can take B's events in at their places, and a second lane names B's flight modes.
- Playback: the bar under the plot plays the log back at 0.25 to 60
times its pace, 5 at first, steps a second back or forward (ten with
Shift), and scrubs with its slider; Space, Left, Right,
[and]do the same while no field or control has the keyboard. The plot's readout, the map's arrow and the events list's highlight move along with the playhead, and a click on the plot puts the playhead there. A zoomed plot turns to the next page as the playhead nears its edge, and a view moved away from it by hand stays. With Follow on, the map centers on the vehicle as it nears the map's edge, until the map is moved by hand. Playback pauses while an export's window is open. - CSV export (File > Export) of the series on the plot: one row per
sample time, one column per series, a cell empty where a series has no
sample at that time, and nothing interpolated. A
time_scolumn in seconds since boot and, when the log has a GPS clock, autccolumn in ISO 8601 to the microsecond come first. Each value prints with the fewest digits that read back as it: a whole number scaled by a power of ten as the decimal it stands for, and a float32 field as the float32 the log stored, divided by that power when it has one. The whole log, or only the time range in view when the plot is zoomed. Series hidden through the legend stay out. - Parameter file export (File > Export) as a
.paramfile ofNAME,VALUElines, which Mission Planner and MAVProxy load: each parameter's last value in the log, or its value at boot. - Parquet export (File > Export) of the whole log, one Snappy-compressed
file per message type, or per instance value, with the record index and,
when the log has a GPS clock, a UTC timestamp column. The files go into
a new folder named after the log inside the folder chosen, never over
an earlier export; an export that fails leaves nothing behind. Built by
default through the
parquetfeature;--no-default-featuresleaves it and the Arrow dependency tree out. - A failed export leaves the file that was there (desktop): a CSV or
.paramfile is written beside its target and moved over it only when complete. - Closing during an export asks twice (desktop): the first close while one writes is held with a notice, and a second close quits anyway.
- Preferences persist: theme, time axis, mode bands, which panels are open and which tab the bottom one shows, map tiles, the playback speed and Follow, how a second log lines up with the first, the recent files and the export folder.
A plot set up on one log carries over when another opens: series the new log also has are re-read, the rest are dropped.
The same app builds for the web and runs as a page, which is online at
aftermission.poholos.com,
built from the latest main; its demo
flight opens with the
page. What differs there:
- The log stays in the browser. A file chosen through File > Open, or dropped on the page, is read into memory and indexed there; nothing is uploaded anywhere. The page holds while a log is indexed, longer for a large one, with the status line saying so first. There is no list of recent files, since the browser gives no path to open again. Of two files dropped together, the first opens; File > Compare with… opens a second log beside it.
- Exports download. CSV and
.paramfiles go to the browser's downloads folder, or wherever it asks, and replace nothing: the browser names a second one of the same name itself. The export runs to its end before the page draws again, so a tab cannot be closed partway, and there is no second close to ask for. The Parquet export is desktop only: its dependency tree and its folder picker have no place in a page. - Map tiles come from OpenStreetMap through the browser, with the browser's own cache and user agent.
- Memory. While a log is read, the browser holds it twice, once as the file it read and once in the app's memory, and the app's model on top; a wasm program's memory tops out at 4 GB. Logs of a few hundred megabytes are the practical ceiling in a page, for all the logs open together: two while comparing, and three while one of them is being replaced. The desktop app maps the file instead of reading it and builds the same model, so it is bounded by the machine's memory rather than by wasm's 4 GB.
?webglon the page's address makes the app draw through WebGL 2 instead of WebGPU, for a browser whose WebGPU draws wrong.?demoon the page's address opens the demo flight as the page loads; File > Open demo log opens it later, and the empty page has a Demo button. The page holds for a moment while the flight is generated and indexed.?compareopens the demo pair instead, the two flights side by side, and wins over?demo; File > Open demo pair opens it later. The page holds about twice as long, for two flights.
The toolchain's minor release is set in rust-toolchain.toml; rustup update brings its patch releases.
cargo run --release -- path/to/flight.binA release build on Windows opens no console window, so its log shows
nowhere unless redirected: aftermission flight.bin > aftermission.log
writes it to a file, with RUST_LOG as usual. A debug build (cargo run) keeps the console.
On Linux the build needs a C compiler and no system development
libraries: build-essential on Debian or Ubuntu is enough. The app
loads X11 or Wayland and xkbcommon when it starts, and the file dialogs
ask the desktop portal over D-Bus.
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo clippy --workspace --all-targets --no-default-features -- -D warnings
cargo test --workspace --no-default-features
cargo deny checkThe tests build their logs with dflog's writer, so no flight data is in the repository.
trunk builds the page; Trunk.toml at the root
leaves the parquet feature out and serves on 127.0.0.1:8081.
rustup target add wasm32-unknown-unknown
cargo binstall trunk # or: cargo install trunk --locked
trunk serve
trunk build --releaseThe release bundle lands in dist/.
Aftermission is licensed under the GNU Affero General Public License,
version 3.0 only, and is also available under a commercial license; see
LICENSING.md. The dflog parser it is built on is a separate
project under MIT OR Apache-2.0.



