Aus dem Quell-Repository gerendert; Überschriften, Beispiele, Code, Tabellen, Links und Bilder bleiben erhalten.
wpilog-parser
WPILOG is the binary log format used by logging libraries in the FRC ecosystem. The wpilog-parser library makes it easy to read and analyze the log files using TS/JS.
Creating a project
- Init a project using
pnpm initor similar - Add
wpilog-parseras a dependency - Catalog the entries in the WPILOG file before deciding what to analyze
pnpm wpilog catalog ./example.wpilogThe default output is plaintext. Use --json, --jsonl/--ndjson, or --csv when another format is more useful.
Analyzing logs
Use parseDataLog to parse DataLog bytes. Filter by name and narrow on type:
import { readFile } from 'node:fs/promises';
import { isDataRecord, parseDataLog, RecordType } from 'wpilog-parser';
const bytes = await readFile('./example.wpilog');
for (const record of parseDataLog(bytes)) {
if (!isDataRecord(record)) continue;
if (record.name === '/Robot/Intake/Voltage' && record.type === RecordType.Double) {
console.log(record.timestamp, record.payload);
}
}Decoding structs
import { parseDataLog, RecordType, structPayloadToJson } from 'wpilog-parser';
for (const record of parseDataLog(bytes)) {
if (record.type === RecordType.Struct && record.name === '/Robot/Localization/EstimatedPose') {
console.log(record.timestamp, structPayloadToJson(record.payload));
// 18688018n {
// translation: { x: 10.289, y: 0.47 },
// rotation: { value: 1.5707961072652017 },
// }
}
}Strict mode
for (const record of parseDataLog(bytes, { strict: true })) {
// throws on orphan data records instead of skipping
}Robot state cheatsheet
When DriverStation logging is on, every WPILOG has these boolean entries:
| Entry | Meaning |
|---|---|
/DS:enabled | true while the robot is enabled (any mode). |
/DS:autonomous | true during autonomous. false means teleop (unless /DS:test). |
/DS:test | true during test mode. |
/DS:estop | true if e-stopped. |
The mode flags (autonomous, test) reflect what the DS would run if enabled, so check /DS:enabled together with them. Timestamps are microseconds (bigint).
Tracking enable/mode durations
import { isDataRecord, parseDataLog, RecordType } from 'wpilog-parser';
type Mode = 'auto' | 'teleop' | 'test';
function modeOf(auto: boolean, test: boolean): Mode {
if (test) return 'test';
if (auto) return 'auto';
return 'teleop';
}
let enabled = false;
let auto = false;
let test = false;
let enabledSince: bigint | null = null;
const totals = { auto: 0n, teleop: 0n, test: 0n };
for (const r of parseDataLog(bytes)) {
if (!isDataRecord(r) || r.type !== RecordType.Boolean) continue;
const wasEnabled = enabled;
const prevMode = modeOf(auto, test);
if (r.name === '/DS:enabled') enabled = r.payload;
else if (r.name === '/DS:autonomous') auto = r.payload;
else if (r.name === '/DS:test') test = r.payload;
else continue;
if (wasEnabled && (!enabled || modeOf(auto, test) !== prevMode)) {
totals[prevMode] += r.timestamp - (enabledSince ?? r.timestamp);
enabledSince = enabled ? r.timestamp : null;
} else if (!wasEnabled && enabled) {
enabledSince = r.timestamp;
}
}
// Durations in microseconds; divide by 1_000_000n for seconds.
console.log(totals);