Fixo Controller
Static firmware controller (compile-time configuration)
Reference for the Fixo controller, which compiles robot hardware configuration into purpose-built firmware via embedded LLVM/Clang.
Design Note
Fixo firmware contains zero runtime configuration overhead: no config parser, no dynamic arrays, no type dispatch. Every actuator type, pin number, and sensor configuration is a compile-time constant. The optimizer eliminates all dead code paths, producing the smallest and fastest possible binary for the exact hardware configuration.
Overview
Fixo is the controller in OctoMY™. It bakes the entire hardware configuration into firmware as C++ template parameters and compiles it via embedded LLVM/Clang. The earlier runtime-config path (Fluxo / ArduMY) and Servotor32 binding were retired in 2026.
The trade-off is a rebuild+reflash cycle on every configuration change — acceptable because LLVM compilation takes seconds and the flash cycle is approximately 5 seconds for a typical binary.
See Why Fixo for the design rationale, and the Fixo data model for the type vocabulary used below (FixoPreset, FixoStanza, FixoActuatorType, etc.).
Supported hardware
| Board | MCU | Flash | SRAM | Pins | PWM |
|---|---|---|---|---|---|
| Arduino Uno | ATmega328P | 32 KB | 2 KB | 14 digital, 6 analog | 6 |
| Arduino Mega 2560 | ATmega2560 | 256 KB | 8 KB | 54 digital, 16 analog | 15 |
Compilation backends
| Backend | Output | Purpose |
|---|---|---|
| AVR | ELF binary, flashed to MCU | Production deployment on physical Arduino boards |
| Harness | Native x64 shared library | Host-side testing with virtual actuator/sensor UI — no physical hardware required |
The harness backend compiles the same template code but links against Qt stubs instead of AVR register code. Virtual servos, motors, and sensors appear as widgets in the controller UI.
Actuator types
Fixo supports the same actuator types as Actuators:
| Type | Description | Pins required |
|---|---|---|
| RC Servo | PWM-driven position servo | 1 (PWM) |
| DC Motor | Speed-controlled motor with direction | 2 (PWM + direction) |
| Stepper Motor | Step/direction stepper driver | 2 (step + direction) |
| Relay | On/off digital output | 1 (digital) |
Each actuator can optionally declare additional pins for limit switches, incremental encoders, tachometers, and position feedback sensors.
Sensor types
| Type | Description | Pins | Resolution |
|---|---|---|---|
| Digital Input | Polled digital pin | 1 | 1-bit |
| Analog Input | ADC reading | 1 | 10-bit (configurable) |
| Encoder | Quadrature incremental encoder | 2 (A + B) | Count-based |
| Counter | Pulse counter (IRQ-driven) | 1 | Count-based |
| Limit Switch | Active-low digital input | 1 | 1-bit |
| Tachometer | RPM from pulse frequency | 1 | Frequency-based |
Lobes
Fixo compiles lobe logic directly into the firmware as C++ template code. Built-in lobes:
| Lobe | Description |
|---|---|
identity |
Passthrough — actuator values map 1:1 to outputs |
wheeled |
Differential-drive controller; outputs left_motor / right_motor |
tracked |
Tracked-vehicle controller; outputs left_track / right_track |
legged_gait |
Multi-leg gait engine (used by the hexapod template) |
hovering, limb_placement, trim, blink_led |
Specialised controllers; see Lobes reference |
Each FixoLobeType carries a placement capability — board-only, native-only, or both — that determines whether the lobe runs in the firmware (compiled into the AVR ELF) or on the node (loaded from the matched native .so via dlopen). See the Lobes reference for placement details and the per-lobe input/output port lists.
Capabilities
FixoController declares the following capability flags:
| Capability | Description |
|---|---|
CAP_ADD_ACTUATORS |
Add actuators at configuration time |
CAP_REMOVE_ACTUATORS |
Remove actuators at configuration time |
CAP_ACTUATOR_TYPE_SELECTION |
Choose from RC Servo, DC Motor, Stepper, Relay |
CAP_PIN_ASSIGNMENT |
Assign physical pins to actuators |
CAP_RANGE_CONFIG |
Configure actuator value ranges |
CAP_LIMIT_SWITCHES |
Attach limit switch sensors |
CAP_POSITION_FEEDBACK |
Attach position feedback sensors |
CAP_INCREMENTAL_ENCODER |
Attach quadrature encoder sensors |
CAP_TACHOMETER |
Attach tachometer sensors |
CAP_GEAR_RATIO |
Configure mechanical gear ratios |
CAP_CONTINUOUS_MODE |
Support continuous-rotation servos |
CAP_LINEAR_MODE |
Support linear actuators |
Build workflow
FixoRuntime (see the FixoRuntime reference) drives the build / inject / start lifecycle. Triggers:
| Trigger | Description |
|---|---|
| Manual | User clicks Build, then Inject, then Start |
| Auto-build | Preemptive background compile on preset change (500 ms debounce) |
| Autonomous (future) | Runtime decides it is safe to rebuild and reflash |
Build pipeline
- Source generation —
FirmwareGenerator::generateFromPreset()synthesises C++ source from the activeFixoPreset. - Compilation —
FixoBuildManagerinvokes the embedded LLVM/Clang to produce both an AVR ELF (board-side) and a native.so(node-side). - Size check —
FirmwareSizeInfovalidates that the AVR ELF fits in the target board's flash. - Cache —
FixoFirmwareCachecontent-addresses the compiled artefacts by BLAKE3 hash so unchanged presets don't recompile. - Inject —
FirmwareFlasherwrites the AVR ELF to the board via stk500v2 over serial. - Load —
FirmwareRuntimedlopens the native.so(when present) into the Agent process; the runtime opens the numex serial link and starts ticking the firmware.
Firmware size visualization
The preset editor exposes a live size bar driven by FirmwareSizeInfo:
| Colour | Meaning |
|---|---|
| Default | Usage below 80 % of available flash |
| Orange | Usage between 80 % and 100 % |
| Red | Firmware exceeds available flash — will not fit |
Configuration persistence
Fixo configuration lives in fixo.json files, not in the legacy fixo/* agent settings. See the Fixo Books reference for how presets, types, and templates are stored, and the fixo.json schema reference for the file format.
A typical layout:
<personality>/fixo/
presets/
rc-car.fixo.json
hexy-explorer.fixo.json
actuator-types/ # custom types (built-ins live in libfixo's qrc)
sensor-types/
lobe-types/
stanza-templates/
preset-templates/
Files are discovered recursively by FixoLibrary::scan(); routing by fixoType field places each into the matching Fixo*Book.
UI surface
Fixo's UI lives in the Fixo Studio activity (see the Fixo Studio reference). The Studio is the entry point for:
- Preset Manager — list / create / duplicate / import / export presets, plus the From template wizard
- Preset Editor — edit a preset's actuators, sensors, stanzas, board
- Type managers — actuator / sensor / lobe / board / stanza-template / preset-template
- Type editors — open a type for inline pin / source / placement editing
The retired multi-screen "BoardSelect → Configure → Build → Dashboard" widget has been replaced by the Studio + a per-preset FixoRuntime view. The Studio runs on Hub, Agent, or Remote (each node can author and share presets); only "set as active runtime" is Agent-specific.
Source code
| Component | Library | Path |
|---|---|---|
FixoController |
libfixo | fixo/controller/FixoController.hpp |
FirmwareGenerator |
libfixo | fixo/controller/FirmwareGenerator.hpp |
FixoBuildManager |
libfixo | fixo/controller/FixoBuildManager.hpp |
FirmwareSizeInfo |
libfixo | fixo/controller/FirmwareSizeInfo.hpp |
FixoRuntime |
libfixo | fixo/runtime/FixoRuntime.hpp |
FirmwareRuntime |
libfixo | fixo/runtime/FirmwareRuntime.hpp |
FixoLibrary and Books |
libfixo | fixo/library/Fixo*.hpp |
| Studio activities | libfixo | fixo/studio/Fixo*.hpp |
| Type editors | libfixo | fixo/type/Fixo*Editor*.hpp |
| Preset editor | libfixo | fixo/studio/FixoPresetEditorActivity.hpp |
| Control widgets | libfixo | fixo/widget/Fixo*.hpp |