The four built-in actuator types — RC servo, DC motor, stepper motor, relay — cover most cases, but not all. This guide walks through authoring a new FixoActuatorType for hardware that doesn't fit the built-ins (e.g. a brushless ESC with a calibration pulse, a servo with an unusual pulse range, a stepper driver that takes a pre-divided clock). The result is a fixo.json plus .hpp pair the Fixo Studio picks up automatically.
Prefer duplicate-to-edit
The fastest path is Duplicate an existing built-in, rename, edit. The Studio's Actuator Type Manager has the button. The walkthrough below covers the field-by-field choices either way.
You need:
dc_motor (PWM-driven, has a direction option you'll repurpose for arming).Copy of dc_motor.bldc-esc.If you'd rather start blank, click New instead and skip to Step 3.
In the type editor's metadata form:
| Field | Example | Notes |
|---|---|---|
| Type id | bldc-esc |
Stable kebab-case id; what other JSON references |
| Title | "BLDC ESC" | Human-readable; shows in dropdowns |
| Description | "Brushless ESC with arming pulse" | One-line; shows in tooltips |
| Main header | bldc-esc.hpp |
The .hpp the firmware generator includes |
The Studio creates the file under <personality>/fixo/actuator-types/bldc-esc/ automatically.
Below the metadata form:
| Field | Description |
|---|---|
| Pin count | How many physical pins one instance occupies |
| Pin purposes | One label per pin; pinCount entries |
Examples:
| Actuator | pinCount |
pinPurposes |
|---|---|---|
| RC servo | 1 | ["pwm"] |
| DC motor (H-bridge) | 2 | ["pwm", "direction"] |
| Brushless ESC (one-line) | 1 | ["pwm"] |
| Stepper (step/dir) | 2 | ["step", "direction"] |
The names are conventions; the C++ template you write knows which name maps to which pin role.
The wire valueRep tells the numex protocol how to pack this actuator's value into bytes:
| Field | Example | Description |
|---|---|---|
totalBits |
16 | Total bits used on the wire |
fractionalBits |
0 | For fixed-point; 0 = integer |
isSigned |
false |
Two's-complement when true |
isFloat |
false |
IEEE-754 when true (16, 32, or 64 bits only) |
For an RC servo with 500–2500 µs pulse range you'd typically use {16, 0, false, false} — a uint16 covers it with room to spare.
The C++ source editor uses WidgetCodeEditor with syntax highlighting, line numbers, auto-indent on Enter, Tab indentation, and Ctrl+Shift+Up/Down to move lines. The minimal shape for an actuator template:
#pragma once
#include <fixo/board/Board.hpp>
#include <fixo/types/ValueRep.hpp>
namespace fixo {
template<typename Board, uint8_t PinPwm>
struct BldcEsc {
static constexpr ValueRep valueRep = {16, 0, false, false};
static void setup() {
Board::pinModePwm(PinPwm);
// arming pulse — 1 ms for ~3 seconds
Board::pwmWriteMicros(PinPwm, 1000);
}
/// value: 0..1 normalised throttle
static void write(double value) {
if (value < 0) value = 0;
if (value > 1) value = 1;
Board::pwmWriteMicros(PinPwm, 1000 + value * 1000);
}
};
} // namespace fixo
Key conventions:
.cpp). The firmware generator emits #include "your-type.hpp" and instantiates the template with the preset's pin assignments.Board provides the HAL primitives (pinModePwm, pwmWriteMicros, etc.).uint8_t template parameters — this lets the optimiser inline pin access.valueRep as a static constexpr matching the JSON.setup() and write(double). tick() is optional for actuators that need periodic updates.The type editor compiles your source after each pause with the LLVM diagnostic engine running against a small synthetic preset. Errors and warnings appear in the panel under the editor; click a row to jump to the offending line. Lines with diagnostics get a coloured gutter mark in the source editor.
The synthetic preset is the smallest valid firmware that uses your type
— one board (uno), one stanza, and one actuator of the type you're
editing. You don't need an open preset to get diagnostics; the generated
source mirrors what would land in a real firmware build.
If a diagnostic doesn't match anything in your source, the most common causes are a missing pin-purpose declaration or an out-of-range input range. Both are visible in the synthesized preset and surface as errors before the editor's source even gets reached.
<personality>/fixo/actuator-types/bldc-esc/ and reloads FixoLibrary so the type appears in the registry.bldc-esc is now an option alongside the built-ins.bldc-esc.hpp automatically.If the firmware build fails with a clang error, check the Build & Inject view's diagnostics. The most common issues:
| Symptom | Cause |
|---|---|
unknown member ‘pwmWriteMicros’ |
The board template doesn't expose that primitive — check your target board's HAL header |
| Loud type errors with template names | Your Board parameter doesn't match the boards the generator instantiates with — make sure your template parameters match the convention |
| Linker error about a symbol | You wrote a .cpp instead of header-only — move the implementation to the header |
The whole <personality>/fixo/actuator-types/bldc-esc/ folder is portable. Zip it and copy it to another node, or use Export in the Actuator Type Manager to write a single file the destination can Import. See Share a preset between nodes.
fixo.json schema — actuator-type — the file-format reference