Fixo Data Model

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 — FixoActuatorType says "this is an RC servo, takes one PWM pin, has these wire bits". Instances describe what your robot actually has — FixoActuator says "actuator number 3 is an RC servo on pin 9, named 'left-shoulder'". Types live in Books; instances live inside a FixoPreset.


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:

FixoActuator

An instance of an actuator type inside a preset:

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:

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 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:

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:


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