Create a custom actuator type

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.


Before you start

You need:


Step 1: Open the Actuator Type Manager

  1. Open the Fixo Studio activity (Hub utilities or Agent configuration menu).
  2. Pick the Hardware group.
  3. Open Actuator Type Manager. The list shows built-in types greyed out and any custom ones you've already authored.

  1. Select the built-in that's nearest to what you want — e.g. for a brushless ESC, start from dc_motor (PWM-driven, has a direction option you'll repurpose for arming).
  2. Click Duplicate. A new entry appears named Copy of dc_motor.
  3. Click Rename. Use kebab-case, e.g. bldc-esc.
  4. Double-click the new entry to open the type editor.

If you'd rather start blank, click New instead and skip to Step 3.


Step 3: Fill in the metadata

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.


Step 4: Set pin count and pin purposes

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.


Step 5: Define the wire value representation

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.


Step 6: Write the C++ template source

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:


Live errors

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.


Step 7: Save and use

  1. Click Save. The Studio writes the JSON and source to <personality>/fixo/actuator-types/bldc-esc/ and reloads FixoLibrary so the type appears in the registry.
  2. Open a preset in the Preset Editor.
  3. Add an actuator; in the Type dropdown your new bldc-esc is now an option alongside the built-ins.
  4. Build — the firmware generator will pick up your 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

Step 8: Share the type (optional)

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.


See also