ArduPilot DataFlash#

Nominal reads ArduPilot DataFlash logs (.bin). Each field of each log message becomes a channel named <message>.<field>, such as IMU.GyrX. The vehicle’s parameters become channels named PARM.<parameter>, such as PARM.ARMING_CHECK.

Upload a file#

  1. In the sidebar, click + (New), then Upload data. Drop the .bin file onto Upload files, or click SELECT FILES.

  2. Click SELECT A DESTINATION and choose Standalone dataset. Pick a dataset, or click NEW DATASET, enter a name and click CREATE DATASET.

  3. Click CONFIRM & INGEST.

from nominal.core import NominalClient

client = NominalClient.from_profile("default")
dataset = client.create_dataset("Flight 42")
file = dataset.add_ardupilot_dataflash("flight.bin")
file.poll_until_ingestion_completed()  # raises if ingestion fails
nomctl ingest ardupilot-dataflash --name "Flight 42" flight.bin

Options#

Setting

Nominal app

Python

nomctl

A tag on every point

Tags

tags

--file-tag

Logs with invalid timestamps#

If a log fails with INVALID_TIMESTAMPS, because a timestamp can’t be represented, run Nominal’s first-party ArduPilot DataFlash extractor on it with Ignore invalid timestamps (IGNORE_INVALID_TIMESTAMPS) set to true. The extractor drops the records with those timestamps and keeps the rest. Its input, INPUT_FILE_1, also takes logs compressed with zstd, gzip, bzip2 or xz.

If ArduPilot DataFlash isn’t in the File extraction menu, enable it first: in the sidebar, open Data > File extractors, click NEW EXTRACTOR > Native extractor, choose ArduPilot DataFlash and click ENABLE EXTRACTOR.

  1. In the sidebar, click + (New), then Upload data.

  2. On the File extraction card, click SELECT and choose ArduPilot DataFlash.

  3. Click SELECT A DESTINATION and choose Standalone dataset. Pick a dataset, or click NEW DATASET, enter a name and click CREATE DATASET.

  4. Next to INPUT_FILE_1, click Select file and choose the .bin file. Enter true in Ignore invalid timestamps.

  5. Click CONFIRM & INGEST.

Select the extractor’s row on the File extractors page to see its RID.

from nominal.core import NominalClient

client = NominalClient.from_profile("default")
extractor = client.get_containerized_extractor("<EXTRACTOR_RID>")
dataset = client.create_dataset("Flight 42")
job = dataset.add_containerized(
    extractor,
    sources={"INPUT_FILE_1": "flight.bin"},
    arguments={"IGNORE_INVALID_TIMESTAMPS": "true"},
)
for file in job.as_files_ingested():  # waits for ingestion
    print(file.name, file.ingest_status.name)