-
Notifications
You must be signed in to change notification settings - Fork 0
Controls and Variables
The core exposes state as named variables (LVARs). You write a subset of them — the controls — and read any of them. This page explains the two-sided discovery model and one behavior that surprises newcomers: nothing is seeded.
| Write side | Read side | |
|---|---|---|
| Curated |
list_controls() — the actuable cockpit controls, hand-written |
— |
| Raw |
set(lvar, …) also accepts raw LVARs |
list_variables() / snapshot() — the full registry |
The curated control catalog lives in
core-rs/src/controls.rs
as a hand-written table mapping a friendly name (bat_1, ext_pwr, bus_tie, apu_master,
eng_mode, hyd_ptu…) to its underlying LVAR, plus metadata: kind (bool / enum / float),
valid_values, a one-line description, a group (by system), and a domain.
set resolves both the friendly name and the raw LVAR — set("bat_1", 1) and
set("OVHD_ELEC_BAT_1_PB_IS_AUTO", 1) are equivalent. The MCP tool schema, by contrast, offers only
the friendly names (the curated half doing its job): an agent actuates controls a human curated and
cannot reach an arbitrary variable.
In the CLI, controls prints the catalog. In the MCP server, list_controls returns it as dicts.
Each control is cockpit or world:
-
cockpit— a real control a pilot actuates (a pushbutton, a knob). -
world— outside state a real simulator would provide and that we fake here — e.g.ext_pwr_avail(whether a ground power unit is plugged in), fuel quantities, ambient conditions.
This distinction matters for the benchmark: a scenario should pre-fix its world state and not offer world controls to the agent, or it measures whether the agent guesses it can alter the outside world rather than whether it knows the procedure. See Scenarios and Design-Decisions (D-009).
The raw registry is the source of truth for valid names: after the aircraft is built, it contains
every variable the systems read/write plus the environment. get of an unknown name is an error
that names the offender (not a silent 0.0) — discover names with vars <substr> (CLI) or
snapshot(contains=…) (MCP). Useful prefixes: ELEC_AC, ELEC_DC, OVHD_ELEC, APU.
Validation is layered and lives in the core:
- If the control is in the catalog,
setvalidates the value against itsvalid_values— a boolean rejects anything but 0/1, a range control rejects out-of-bounds — before writing. - If the name is an uncatalogued raw LVAR, only the weaker guard applies (must be finite and exist in the registry).
Errors surface as ApiError → Python exceptions (UnknownControlError, BadValueError,
UnknownFailureError) → one-line CLI messages. See Architecture.
FBW's test bed runs a seed() step that writes each element's programmed initial state (e.g.
pushbuttons that start ON). That path is private in the vendored crate, and the project does not
patch the vendor — so the persistent runtime starts without seed: every unwritten pushbutton reads
its default (0.0 / OFF).
For cold & dark this is the correct state — but it has consequences you will hit:
-
The bus tie starts OFF, so external power or the APU generator won't feed the AC network until
you
set bus_tie auto. (See Quickstart.) - A few panel resting states whose real value is not 0 are seeded once at startup anyway, because their 0 would silently mean something wrong (GEN 1 LINE, the X-BLEED selector, pushback state). These are both seeded and cataloged as controls. See Design-Decisions (D-007, D-012, D-021).
If a subsystem ever depends on a pushbutton whose default-0 leaves it genuinely wrong, the fix is to write that pushbutton explicitly in the start profile — never to patch the vendor.
A320 Systems Twin · GPLv3 · systems model by FlyByWire (vendored, pinned to 13bce4b) · repository
Get started
Operate
Benchmark
Reference