Fixo Data Model
Type definitions, instances, ports, and presets
Reference for the type vocabulary used by every Fixo configuration: type definitions, instances, ports, presets, and the auto-derived stanza sets.
Two levels: types and instances
Type definitions describe what kinds of things exist —
FixoActuatorTypesays "this is an RC servo, takes one PWM pin, has these wire bits". Instances describe what your robot actually has —FixoActuatorsays "actuator number 3 is an RC servo on pin 9, named 'left-shoulder'". Types live in Books; instances live inside aFixoPreset.
Naming convention
| Level | Class shape | Examples | Stored in |
|---|---|---|---|
| Type definition | Fixo*Type |
FixoActuatorType, FixoSensorType, FixoLobeType, FixoBoardType |
Books, on disk as fixo.json |
| Instance | Fixo* |
FixoActuator, FixoSensor, FixoLobe, FixoStanza, FixoMapping, FixoInput |
Inside a FixoPreset, on disk as <preset>.fixo.json |
The Fixo prefix is intentional during the type-system rework; it will be stripped in one clean pass once the legacy types are fully out.
Core types
FixoActuatorType
Definition of an actuator family — RC servo, DC motor, stepper, relay. Carries:
name,title,description,iconpinCount,pinPurposes(e.g.["pwm"]for a servo,["pwm", "direction"]for a DC motor)mainHeaderandcppSource— paths/contents for the C++ template that the firmware generator stamps in- Wire
ValueRepresentation:totalBits,fractionalBits,isSigned,isFloat— how the actuator's value is packed for the numex protocol
FixoActuator
An instance of an actuator type inside a preset:
type— name of theFixoActuatorTypename— free-text labelpin— physical pin number (or empty for auto-assignment)trim,min,max,reverse— calibration knobssemanticTags— strings used by auto-connect (see FixoPort below)
FixoSensorType / FixoSensor
Same pattern: type defines the family (digital input, analog input, encoder, limit-switch, tachometer), instance configures one sensor in a preset (pin, pinB for two-pin sensors).
FixoLobeType / FixoLobe
FixoLobeType carries:
name,title,description,iconmainHeaderandcppSourcefor the C++ control logicplacement— one ofboard-only/native-only/both(see below)inputPorts,outputPorts—QVector<FixoPort>describing the lobe's interfaceinputParameters— runtime-tunable values (e.g.gait_speed)
FixoLobe is an instance configured inside a stanza: references a lobe type, optionally overrides placement (when the type allows both), supplies input parameter values.
Placement
The placement field on FixoLobeType declares where the lobe code can run:
| Value | Meaning |
|---|---|
board-only |
Compiled into the AVR ELF; runs on the MCU. Used for low-latency, hardware-bound logic. |
native-only |
Compiled into the node-side .so; runs on the Agent. Used for compute-heavy logic (gait planning, IK) that won't fit on a microcontroller. |
both |
Either; the preset editor can pick per-instance. Used for portable logic with no platform requirements. |
When a lobe runs on the node, the firmware acts as a passthrough: control values come in via numex, the node-side .so computes actuator values, and they go back out via numex. When it runs on the board, the node forwards control inputs but the firmware computes actuator values locally.
FixoBoardType
Describes a target board: references a board name in libboard (which provides the pin map, MCU details, USB IDs, bootloader config) and adds the C++ HAL template source. There are no instances of board types — a preset references one board type by name.
FixoPreset
The central configuration unit:
FixoPreset
├─ name, version
├─ board — references one FixoBoardType by name
├─ actuators[] — FixoActuator instances
├─ sensors[] — FixoSensor instances
├─ stanzas[] — FixoStanza instances (each has a lobe + actuator mapping)
└─ contentHash — BLAKE3 of the canonical JSON, drives firmware caching
Stanza sets — groups of mutually-exclusive stanzas — are not stored. They are derived at runtime from actuator overlap by FixoPreset::computeStanzaSets() using a union-find pass on the actuator indices each stanza touches. Two stanzas that share any actuator end up in the same set; only one stanza per set can run at a time.
FixoStanza
A concrete stanza inside a preset:
| Field | Description |
|---|---|
id |
Stable identifier (string) |
lobeType |
Name of the FixoLobeType this stanza uses |
lobeConfig |
Lobe-specific configuration (QVariantMap) |
mapping |
QVector<FixoMapping> — one entry per lobe output, pointing at an actuator index |
inputs |
QVector<FixoInput> — descriptors for the lobe's runtime-tunable inputs (name, min, max, default) |
namedWidget |
Optional UI hint (e.g. "CarSteeringWidget"); empty falls back to SliderBankWidget |
sendIntervalMs |
How often the runtime ticks this stanza |
FixoStanzaTemplate
Reusable stanza pattern. Carries the lobe type + widget hint + expected port tags, and can be instantiated against a preset's actuators. Auto-connect uses Jaccard similarity on the semantic tags to assign each lobe output to the best-matching actuator. See the Stanza Templates reference for the algorithm and the three built-ins (differential-drive, tracked-drive, hexapod-walk).
FixoPresetTemplate
A preset-level template. Parameterised: the user fills in a wizard, the template's substitution language expands {{paramName}} placeholders and forEachActuators rules, and a concrete FixoPreset is produced. See the Preset Templates reference for the substitution language and the three built-ins (rc-car, tracked-vehicle, hexapod).
FixoPort — universal named connection point
FixoPort
├─ name — "knee_joint_4"
├─ semanticTags — ["knee", "joint", "leg_4"]
├─ direction — Input | Output
├─ minValue — semantic-domain minimum (e.g. -1.0)
└─ maxValue — semantic-domain maximum (e.g. 1.0)
Every connectable thing exposes ports:
- Lobe types declare input and output ports
- Control widgets declare output ports they emit (
throttle,steering) - Stanza templates declare expected port tags so auto-connect can wire them
- (Future) actuator types may declare named input ports
Port values are semantic doubles — meaningful range, e.g. [-1.0, 1.0] for steering or [0.0, 180.0] for servo degrees. The numex serializer maps the port's (min, max) linearly into the actuator type's wire ValueRepresentation at the boundary; user code never has to think about wire bits.
Semantic tag vocabulary
Recommended but not enforced. The built-in stanza templates follow these conventions:
- Body structure —
leg,arm,joint,coxa,femur,tibia,shoulder,elbow,wrist,finger,mandible,gripper,turret,boom,stick,bucket - Locomotion —
wheel,track,motor,throttle,steering,brake,gear - Orientation —
left,right,front,rear,top,bottom,center - Numbering — append a 0-based index:
leg_0,joint_2 - Compounds — underscore-separate:
knee_joint_4,left_track_motor
File and class naming rules
| What | Convention | Example |
|---|---|---|
| Source files | kebab-case | rc-servo.hpp, legged-gait.hpp |
| C++ classes | CamelCase with Fixo prefix |
FixoActuatorType, FixoPreset |
fixo.json field names |
camelCase | fixoType, semanticTags, mainHeader |
| Semantic tags | snake_case | knee_joint, left_motor |
| Manager classes | "Manager" not "Management" | FixoPresetManager, not FixoPresetManagementActivity |
See also
fixo.jsonschema — the file-format reference for everything described here- Books and FixoLibrary — how these types are stored and discovered
- Stanza Templates — auto-connect, Jaccard scoring, the three built-ins
- Preset Templates — substitution language and the three built-ins
- FixoRuntime — how a preset becomes a running firmware